aboutsummaryrefslogtreecommitdiffstats
path: root/android
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:32 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:32 -0800
commit8b23a6c7e1aee255004dd19098d4c2462b61b849 (patch)
tree7a4d682ba51f0ff0364c5ca2509f515bdaf96de9 /android
parentf721e3ac031f892af46f255a47d7f54a91317b30 (diff)
downloadexternal_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.zip
external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.gz
external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'android')
-rw-r--r--android/android.h100
-rw-r--r--android/avd/hardware-properties.ini158
-rw-r--r--android/avd/hw-config-defs.h165
-rw-r--r--android/avd/hw-config.c39
-rw-r--r--android/avd/hw-config.h46
-rw-r--r--android/avd/info.c1865
-rw-r--r--android/avd/info.h171
-rw-r--r--android/build/binary.make34
-rw-r--r--android/build/clear_vars.make30
-rw-r--r--android/build/definitions.make109
-rw-r--r--android/build/getdir.make19
-rw-r--r--android/build/host_executable.make34
-rw-r--r--android/build/host_static_library.make35
-rwxr-xr-xandroid/build/mkdeps.sh51
-rw-r--r--android/charmap.c148
-rw-r--r--android/charmap.h133
-rw-r--r--android/cmdline-option.c255
-rw-r--r--android/cmdline-option.h42
-rw-r--r--android/cmdline-options.h137
-rw-r--r--android/config.c467
-rw-r--r--android/config.h57
-rw-r--r--android/config/Linux/config-host.h10
-rw-r--r--android/config/check-alsa.c107
-rw-r--r--android/config/check-esd.c67
-rw-r--r--android/config/config.h14
-rw-r--r--android/config/darwin-ppc/config-host.h13
-rw-r--r--android/config/darwin-x86/config-host.h13
-rw-r--r--android/config/linux-x86/config-host.h10
-rw-r--r--android/config/windows/config-host.h10
-rw-r--r--android/console.c2190
-rw-r--r--android/globals.h33
-rw-r--r--android/gps.c37
-rw-r--r--android/gps.h23
-rw-r--r--android/help.c1452
-rw-r--r--android/help.h36
-rw-r--r--android/hw-control.c204
-rw-r--r--android/hw-control.h38
-rw-r--r--android/hw-events.c223
-rw-r--r--android/hw-events.h184
-rw-r--r--android/hw-kmsg.c70
-rw-r--r--android/hw-kmsg.h31
-rw-r--r--android/icons.h984
-rw-r--r--android/main.c2836
-rw-r--r--android/qemud.c456
-rw-r--r--android/qemud.h72
-rw-r--r--android/resource.c64
-rw-r--r--android/resource.h26
-rw-r--r--android/skin/argb.h856
-rw-r--r--android/skin/composer.c401
-rw-r--r--android/skin/composer.h102
-rw-r--r--android/skin/default.h7414
-rw-r--r--android/skin/file.c693
-rw-r--r--android/skin/file.h132
-rw-r--r--android/skin/image.c742
-rw-r--r--android/skin/image.h92
-rw-r--r--android/skin/keyboard.c783
-rw-r--r--android/skin/keyboard.h59
-rw-r--r--android/skin/keyset.c542
-rw-r--r--android/skin/keyset.h122
-rw-r--r--android/skin/rect.c241
-rw-r--r--android/skin/rect.h71
-rw-r--r--android/skin/region.c1448
-rw-r--r--android/skin/region.h103
-rw-r--r--android/skin/scaler.c135
-rw-r--r--android/skin/scaler.h39
-rw-r--r--android/skin/surface.c613
-rw-r--r--android/skin/surface.h101
-rw-r--r--android/skin/trackball.c625
-rw-r--r--android/skin/trackball.h43
-rw-r--r--android/skin/window.c1516
-rw-r--r--android/skin/window.h65
-rwxr-xr-xandroid/tools/gen-hw-config.py141
-rw-r--r--android/user-config.c212
-rw-r--r--android/user-config.h51
-rw-r--r--android/utils/bufprint.c230
-rw-r--r--android/utils/bufprint.h76
-rw-r--r--android/utils/debug.c141
-rw-r--r--android/utils/debug.h91
-rw-r--r--android/utils/dirscanner.c203
-rw-r--r--android/utils/dirscanner.h51
-rw-r--r--android/utils/display-quartz.m111
-rw-r--r--android/utils/display.c245
-rw-r--r--android/utils/display.h31
-rw-r--r--android/utils/filelock.c414
-rw-r--r--android/utils/filelock.h38
-rw-r--r--android/utils/ini.c416
-rw-r--r--android/utils/ini.h131
-rw-r--r--android/utils/misc.c193
-rw-r--r--android/utils/misc.h67
-rw-r--r--android/utils/path.c559
-rw-r--r--android/utils/path.h152
-rw-r--r--android/utils/reflist.c203
-rw-r--r--android/utils/reflist.h129
-rw-r--r--android/utils/stralloc.c300
-rw-r--r--android/utils/stralloc.h60
-rw-r--r--android/utils/system.c172
-rw-r--r--android/utils/system.h161
-rw-r--r--android/utils/tempfile.c198
-rw-r--r--android/utils/tempfile.h52
-rw-r--r--android/utils/timezone.c721
-rw-r--r--android/utils/timezone.h31
101 files changed, 35816 insertions, 0 deletions
diff --git a/android/android.h b/android/android.h
new file mode 100644
index 0000000..71a20f6
--- /dev/null
+++ b/android/android.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _qemu_android_h
+#define _qemu_android_h
+
+#define ANDROID_VERSION_MAJOR 1
+#define ANDROID_VERSION_MINOR 9
+
+#define CONFIG_SHAPER 1
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/** in vl.c */
+
+/* emulated network up/down speeds, expressed in bits/seconds */
+extern double qemu_net_upload_speed;
+extern double qemu_net_download_speed;
+
+/* emulated network min-max latency, expressed in ms */
+extern int qemu_net_min_latency;
+extern int qemu_net_max_latency;
+
+/* global flag, when true, network is disabled */
+extern int qemu_net_disable;
+
+/* list of supported network speed names and values in bits/seconds */
+typedef struct {
+ const char* name;
+ const char* display;
+ int upload;
+ int download;
+} NetworkSpeed;
+
+extern const NetworkSpeed android_netspeeds[];
+
+/* list of supported network latency names and min-max values in ms */
+typedef struct {
+ const char* name;
+ const char* display;
+ int min_ms;
+ int max_ms;
+} NetworkLatency;
+
+extern const NetworkLatency android_netdelays[];
+
+/* enable/disable interrupt polling mode. the emulator will always use 100%
+ * of host CPU time, but will get high-quality time measurments. this is
+ * required for the tracing mode unless you can bear 10ms granularities
+ */
+extern void qemu_polling_enable(void);
+extern void qemu_polling_disable(void);
+
+/**in hw/goldfish_fb.c */
+
+/* framebuffer dimensions in pixels, note these can change dynamically */
+extern int android_framebuffer_w;
+extern int android_framebuffer_h;
+/* framebuffer dimensions in mm */
+extern int android_framebuffer_phys_w;
+extern int android_framebuffer_phys_h;
+
+/* framebuffer rotation, relative to device */
+typedef enum {
+ ANDROID_ROTATION_0 = 0,
+ ANDROID_ROTATION_90,
+ ANDROID_ROTATION_180,
+ ANDROID_ROTATION_270
+} AndroidRotation;
+
+extern AndroidRotation android_framebuffer_rotation;
+
+/** in android_main.c */
+
+/* this is the port used for the control console in this emulator instance.
+ * starts at 5554, with increments of 2 */
+extern int android_base_port;
+
+/* parses a network speed parameter and sets qemu_net_upload_speed and
+ * qemu_net_download_speed accordingly. returns -1 on failure, 0 on success */
+extern int android_parse_network_speed(const char* speed);
+
+/* parse a network delay parameter and sets qemu_net_min/max_latency
+ * accordingly. returns -1 on error, 0 on success */
+extern int android_parse_network_latency(const char* delay);
+
+extern void android_emulation_setup( void );
+extern void android_emulation_teardown( void );
+
+#endif /* _qemu_android_h */
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
new file mode 100644
index 0000000..f2293d1
--- /dev/null
+++ b/android/avd/hardware-properties.ini
@@ -0,0 +1,158 @@
+# This file describes the properties of a given virtual device configuration file.
+#
+# Note: Most top-level properties are boolean that control whether a feature is
+# present or not. Sub-features that depend on it are ignored if their
+# parent is set to 'false' or 'no'
+#
+# This file is parsed by 'android/tools/gen-hw-config.py' to generate
+# 'android/avd/hw-config-defs.h'. The latter is a special header containing
+# macro statements that is used several times:
+#
+# - once to define the fields of the AndroidHwConfig structure
+# (see android/avd/hw-config.h)
+#
+# - once to implement the hardware configuration loader
+# (see android/avd/hw-config.h)
+#
+# Hopefully, this file should also be read by a virtual device creation
+# tool/wizard to provide a nice user interface (hence the presence of
+# the 'abstract' and 'description' keys which are not currently used)
+#
+#
+# NOTE: if you remove items from this file, be sure that you do not break
+# the emulator build.
+#
+
+# Ram size
+name = hw.ramSize
+type = integer
+default = 96
+abstract = Device ram size
+description = The amount of physical RAM on the device, in megabytes.
+
+# Touch screen support
+name = hw.touchScreen
+type = boolean
+default = yes
+abstract = Touch-screen support
+description = Whether there is a touch screen or not on the device.
+
+# Trackball support
+name = hw.trackBall
+type = boolean
+default = yes
+abstract = Track-ball support
+description = Whether there is a trackball on the device.
+
+# Keyboard support (qwerty/azerty)
+name = hw.keyboard
+type = boolean
+default = yes
+abstract = Keyboard support
+description = Whether the device has a QWERTY keyboard.
+
+# DPad keys
+name = hw.dPad
+type = boolean
+default = yes
+abstract = DPad support
+description = Whether the device has DPad keys
+
+# GSM Modem support
+name = hw.gsmModem
+type = boolean
+default = yes
+abstract = GSM modem support
+description = Whether there is a GSM modem in the device.
+
+# Wifi support
+name = hw.wifi
+type = boolean
+default = no
+abstract = Wifi support
+description = Whether the device has a Wifi chipset.
+
+# Bluetooth support
+name = hw.bluetooth
+type = boolean
+default = no
+abstract = Bluetooth support
+description = Whether the device has a Bluetooth chipset.
+
+# Camera support
+name = hw.camera
+type = boolean
+default = no
+abstract = Camera support
+description = Whether the device has a camera.
+
+name = hw.camera.maxHorizontalPixels
+type = integer
+default = 640
+abstract = Maximum horizontal camera pixels
+
+name = hw.camera.maxVerticalPixels
+type = integer
+default = 480
+abstract = Maximum vertical camera pixels
+
+# GPS support
+name = hw.gps
+type = boolean
+default = no
+abstract = GPS support
+description = Whether there is a GPS in the device.
+
+# Accelerometer
+name = hw.accelerometer
+type = boolean
+default = no
+abstract = Accelerometer support
+description = Whether there is an accelerometer in the device.
+
+# Battery
+name = hw.battery
+type = boolean
+default = yes
+abstract = Battery support
+description = Whether the device can run on a battery.
+
+# Audio input
+name = hw.audioInput
+type = boolean
+default = yes
+abstract = Audio recording support
+description = Whether the device can record audio
+
+# Audio output
+name = hw.audioOutput
+type = boolean
+default = yes
+abstract = Audio playback support
+description = Whether the device can play audio
+
+# Compass
+name = hw.compass
+type = boolean
+default = no
+abstract = Compass support
+description = Whether there is a compass in the device.
+
+# SDCard support
+name = hw.sdCard
+type = boolean
+default = yes
+abstract = SD Card support
+description = Whether the device supports insertion/removal of virtual SD Cards.
+
+# Cache partition
+name = disk.cachePartition
+type = boolean
+default = yes
+abstract = Cache partition support
+description = Whether we use a /cache partition on the device.
+
+name = disk.cachePartition.size
+type = diskSize
+abstract = Cache partition size
+default = 66MB
diff --git a/android/avd/hw-config-defs.h b/android/avd/hw-config-defs.h
new file mode 100644
index 0000000..5c3b9ab
--- /dev/null
+++ b/android/avd/hw-config-defs.h
@@ -0,0 +1,165 @@
+/* this file is automatically generated from 'hardware-properties.ini'
+ * DO NOT EDIT IT. To re-generate it, use android/tools/gen-hw-config.py'
+ */
+#ifndef HWCFG_INT
+#error HWCFG_INT not defined
+#endif
+#ifndef HWCFG_BOOL
+#error HWCFG_BOOL not defined
+#endif
+#ifndef HWCFG_DISKSIZE
+#error HWCFG_DISKSIZE not defined
+#endif
+#ifndef HWCFG_STRING
+#error HWCFG_STRING not defined
+#endif
+#ifndef HWCFG_DOUBLE
+#error HWCFG_DOUBLE not defined
+#endif
+
+HWCFG_INT(
+ hw_ramSize,
+ "hw.ramSize",
+ 96,
+ "Device ram size",
+ "The amount of physical RAM on the device, in megabytes.")
+
+HWCFG_BOOL(
+ hw_touchScreen,
+ "hw.touchScreen",
+ "yes",
+ "Touch-screen support",
+ "Whether there is a touch screen or not on the device.")
+
+HWCFG_BOOL(
+ hw_trackBall,
+ "hw.trackBall",
+ "yes",
+ "Track-ball support",
+ "Whether there is a trackball on the device.")
+
+HWCFG_BOOL(
+ hw_keyboard,
+ "hw.keyboard",
+ "yes",
+ "Keyboard support",
+ "Whether the device has a QWERTY keyboard.")
+
+HWCFG_BOOL(
+ hw_dPad,
+ "hw.dPad",
+ "yes",
+ "DPad support",
+ "Whether the device has DPad keys")
+
+HWCFG_BOOL(
+ hw_gsmModem,
+ "hw.gsmModem",
+ "yes",
+ "GSM modem support",
+ "Whether there is a GSM modem in the device.")
+
+HWCFG_BOOL(
+ hw_wifi,
+ "hw.wifi",
+ "no",
+ "Wifi support",
+ "Whether the device has a Wifi chipset.")
+
+HWCFG_BOOL(
+ hw_bluetooth,
+ "hw.bluetooth",
+ "no",
+ "Bluetooth support",
+ "Whether the device has a Bluetooth chipset.")
+
+HWCFG_BOOL(
+ hw_camera,
+ "hw.camera",
+ "no",
+ "Camera support",
+ "Whether the device has a camera.")
+
+HWCFG_INT(
+ hw_camera_maxHorizontalPixels,
+ "hw.camera.maxHorizontalPixels",
+ 640,
+ "Maximum horizontal camera pixels",
+ "")
+
+HWCFG_INT(
+ hw_camera_maxVerticalPixels,
+ "hw.camera.maxVerticalPixels",
+ 480,
+ "Maximum vertical camera pixels",
+ "")
+
+HWCFG_BOOL(
+ hw_gps,
+ "hw.gps",
+ "no",
+ "GPS support",
+ "Whether there is a GPS in the device.")
+
+HWCFG_BOOL(
+ hw_accelerometer,
+ "hw.accelerometer",
+ "no",
+ "Accelerometer support",
+ "Whether there is an accelerometer in the device.")
+
+HWCFG_BOOL(
+ hw_battery,
+ "hw.battery",
+ "yes",
+ "Battery support",
+ "Whether the device can run on a battery.")
+
+HWCFG_BOOL(
+ hw_audioInput,
+ "hw.audioInput",
+ "yes",
+ "Audio recording support",
+ "Whether the device can record audio")
+
+HWCFG_BOOL(
+ hw_audioOutput,
+ "hw.audioOutput",
+ "yes",
+ "Audio playback support",
+ "Whether the device can play audio")
+
+HWCFG_BOOL(
+ hw_compass,
+ "hw.compass",
+ "no",
+ "Compass support",
+ "Whether there is a compass in the device.")
+
+HWCFG_BOOL(
+ hw_sdCard,
+ "hw.sdCard",
+ "yes",
+ "SD Card support",
+ "Whether the device supports insertion/removal of virtual SD Cards.")
+
+HWCFG_BOOL(
+ disk_cachePartition,
+ "disk.cachePartition",
+ "yes",
+ "Cache partition support",
+ "Whether we use a /cache partition on the device.")
+
+HWCFG_DISKSIZE(
+ disk_cachePartition_size,
+ "disk.cachePartition.size",
+ "66MB",
+ "Cache partition size",
+ "")
+
+#undef HWCFG_INT
+#undef HWCFG_BOOL
+#undef HWCFG_DISKSIZE
+#undef HWCFG_STRING
+#undef HWCFG_DOUBLE
+/* end of auto-generated file */
diff --git a/android/avd/hw-config.c b/android/avd/hw-config.c
new file mode 100644
index 0000000..2362b59
--- /dev/null
+++ b/android/avd/hw-config.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/avd/hw-config.h"
+#include "android/utils/ini.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+/* the global variable containing the hardware config for this device */
+AndroidHwConfig android_hw[1];
+
+int
+androidHwConfig_read( AndroidHwConfig* config,
+ IniFile* ini )
+{
+ if (ini == NULL)
+ return -1;
+
+ /* use the magic of macros to implement the hardware configuration loaded */
+
+#define HWCFG_BOOL(n,s,d,a,t) config->n = iniFile_getBoolean(ini, s, d);
+#define HWCFG_INT(n,s,d,a,t) config->n = iniFile_getInteger(ini, s, d);
+#define HWCFG_STRING(n,s,d,a,t) config->n = iniFile_getString(ini, s, d);
+#define HWCFG_DOUBLE(n,s,d,a,t) config->n = iniFile_getDouble(ini, s, d);
+#define HWCFG_DISKSIZE(n,s,d,a,t) config->n = iniFile_getDiskSize(ini, s, d);
+
+#include "android/avd/hw-config-defs.h"
+
+ return 0;
+}
diff --git a/android/avd/hw-config.h b/android/avd/hw-config.h
new file mode 100644
index 0000000..05eb828
--- /dev/null
+++ b/android/avd/hw-config.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_AVD_HW_CONFIG_H
+#define _ANDROID_AVD_HW_CONFIG_H
+
+#include <stdint.h>
+#include "android/utils/ini.h"
+
+typedef char hw_bool_t;
+typedef int hw_int_t;
+typedef int64_t hw_disksize_t;
+typedef char* hw_string_t;
+typedef double hw_double_t;
+
+/* these macros are used to define the fields of AndroidHwConfig
+ * declared below
+ */
+#define HWCFG_BOOL(n,s,d,a,t) hw_bool_t n;
+#define HWCFG_INT(n,s,d,a,t) hw_int_t n;
+#define HWCFG_STRING(n,s,d,a,t) hw_string_t n;
+#define HWCFG_DOUBLE(n,s,d,a,t) hw_double_t n;
+#define HWCFG_DISKSIZE(n,s,d,a,t) hw_disksize_t n;
+
+typedef struct {
+#include "android/avd/hw-config-defs.h"
+} AndroidHwConfig;
+
+/* reads a hardware configuration file from disk.
+ * returns -1 if the file could not be read, or 0 in case of success.
+ *
+ * note that default values are written to hwConfig if the configuration
+ * file doesn't have the corresponding hardware properties.
+ */
+int androidHwConfig_read( AndroidHwConfig* hwConfig,
+ IniFile* configFile );
+
+#endif /* _ANDROID_AVD_HW_CONFIG_H */
diff --git a/android/avd/info.c b/android/avd/info.c
new file mode 100644
index 0000000..230ddaa
--- /dev/null
+++ b/android/avd/info.c
@@ -0,0 +1,1865 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/avd/info.h"
+#include "android/utils/path.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/filelock.h"
+#include "android/utils/tempfile.h"
+#include "android/utils/debug.h"
+#include "android/utils/dirscanner.h"
+#include <ctype.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* define this to 1 to support obsolete platform/add-on
+ * specific parsing and path searching as was used temporarily
+ * in post-1.1 / pre-cupcake SDKs.
+ *
+ * the corresponding code should be removed soon.
+ */
+#define SUPPORT_PLATFORM_OR_ADDON 1
+
+/* global variables - see android/globals.h */
+AvdInfoParams android_avdParams[1];
+AvdInfo* android_avdInfo;
+
+/* for debugging */
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+#define DD(...) VERBOSE_PRINT(avd_config,__VA_ARGS__)
+
+/* technical note on how all of this is supposed to work:
+ *
+ * Each AVD corresponds to a "content directory" that is used to
+ * store persistent disk images and configuration files. Most remarkable
+ * are:
+ *
+ * - a "config.ini" file used to hold configuration information for the
+ * AVD
+ *
+ * - mandatory user data image ("userdata-qemu.img") and cache image
+ * ("cache.img")
+ *
+ * - optional mutable system image ("system-qemu.img"), kernel image
+ * ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
+ *
+ * When starting up an AVD, the emulator looks for relevant disk images
+ * in the content directory. If it doesn't find a given image there, it
+ * will try to search in the list of system directories listed in the
+ * 'config.ini' file through one of the following (key,value) pairs:
+ *
+ * images.sysdir.1 = <first search path>
+ * images.sysdir.2 = <second search path>
+ *
+ * The search paths can be absolute, or relative to the root SDK installation
+ * path (which is determined from the emulator program's location, or from the
+ * ANDROID_SDK_ROOT environment variable).
+ *
+ * Individual image disk search patch can be over-riden on the command-line
+ * with one of the usual options.
+ */
+
+#if SUPPORT_PLATFORM_OR_ADDON
+/*
+ * BELOW IS THE DOCUMENTATION FOR AN OBSOLETE SCHEME THAT USED TO BE MORE
+ * COMPLEX TO IMPLEMENT, AND EXPOSED TOO MUCH SDK INTERNALS WITHIN THE
+ * EMULATOR SOURCE CODE.
+ *
+ * THE CORRESPONDING CODE IS STILL THERE FOR LEGACY SUPPORT REASON BUT WILL
+ * SOON BE REMOVED FOR SIMPLIFICATION REASONS.
+ *
+ * we assume the following SDK layout:
+ *
+ * SDK/
+ * tools/
+ * emulator[.exe]
+ * libs/
+ * hardware-properties.ini
+ * ...
+ *
+ * platforms/
+ * <platform1>/
+ * build.prop
+ * images/
+ * <default kernel/disk images>
+ * skins/
+ * default/ --> default skin
+ * layout
+ * <skin bitmaps>
+ * <skin2>/ --> another skin
+ * layout
+ * <skin bitmaps>
+ * <skin3>/ --> skin alias to <skin2>
+ * alias-<skin2>
+ *
+ * <platform2>/
+ * build.prop
+ * images/
+ * <other default kernel/disk images>
+ *
+ * add-ons/
+ * <partner1>/
+ * manifest.ini
+ * images/
+ * <replacement disk images>
+ *
+ * <partner2>/
+ * manifest.ini
+ * <replacement disk images>
+ * hardware.ini
+ * skins/
+ * default/
+ * layout
+ * <skin bitmaps>
+ * <skin2>/
+ * layout
+ * <skin bitmaps>
+ *
+ *
+ * we define a 'platform' as a directory that provides a complete
+ * set of disk/kernel images, some skins, as well as a build.prop
+ * file.
+ *
+ * we define an 'addon' as a directory that provides additionnal
+ * or replacement files related to a given existing platform.
+ * each add-on provides at the minimum a 'manifest.ini' file
+ * that describes it (see below).
+ *
+ * important notes:
+ *
+ * - the build.prop file of a given platform directory contains
+ * a line that reads 'ro.build.version.sdk=<version>' where
+ * <version> is an integer corresponding to the corresponding
+ * official API version number as defined by Android.
+ *
+ * each platform provided with the SDK must have a unique
+ * version number.
+ *
+ * - the manifest.ini of a given addon must contain lines
+ * that include:
+ *
+ * name=<addOnName>
+ * vendor=<vendorName>
+ * api=<version>
+ *
+ * where <version> is used to identify the platform the add-on
+ * refers to. Note that the platform's directory name is
+ * irrelevant to the matching algorithm.
+ *
+ * each addon available must have a unique
+ * <vendor>:<name>:<sdk> triplet
+ *
+ * - an add-on can provide a hardware.ini file. If present, this
+ * is used to force the hardware setting of any virtual device
+ * built from the add-on.
+ *
+ * - the file in SDK/tools/lib/hardware-properties.ini declares which
+ * hardware properties are supported by the emulator binary.
+ * these can appear in the config.ini file of a given virtual
+ * device, or the hardware.ini of a given add-on.
+ *
+ * normally, a virtual device corresponds to:
+ *
+ * - a root configuration file, placed in ~/.android/avd/<foo>.ini
+ * where <foo> is the name of the virtual device.
+ *
+ * - a "content" directory, which contains disk images for the
+ * virtual device (e.g. at a minimum, the userdata.img file)
+ * plus some configuration information.
+ *
+ * - the root config file must have at least two lines like:
+ *
+ * path=<pathToContentDirectory>
+ * target=<targetAddonOrPlatform>
+ *
+ * the 'path' value must point to the location of
+ * the virtual device's content directory. By default, this
+ * should be ~/.android/avd/<foo>/, though the user should be
+ * able to choose an alternative path at creation time.
+ *
+ * the 'target' value can be one of:
+ *
+ * android-<version>
+ * <vendor>:<name>:<version>
+ *
+ * the first form is used to refer to a given platform.
+ * the second form is used to refer to a unique add-on.
+ * in both forms, <version> must be an integer that
+ * matches one of the available platforms.
+ *
+ * <vendor>:<name>:<version> must match the triplet of one
+ * of the available add-ons
+ *
+ * if the target value is incorrect, or if the content path
+ * is invalid, the emulator will abort with an error.
+ *
+ * - the content directory shall contain a 'config.ini' that
+ * contains hardware properties for the virtual device
+ * (as defined by SDK/tools/lib/hardware-properties.ini), as
+ * well as additional lines like:
+ *
+ * sdcard=<pathToDefaultSDCard>
+ * skin=<defaultSkinName>
+ * options=<additionalEmulatorStartupOptions>
+ *
+ *
+ * Finally, to find the skin to be used with a given virtual
+ * device, the following logic is used:
+ *
+ * - if no skin name has been manually specified on
+ * the command line, or in the config.ini file,
+ * look in $CONTENT/skin/layout and use it if available.
+ *
+ * - otherwise, set SKINNAME to 'default' if not manually
+ * specified, and look for $ADDON/skins/$SKINNAME/layout
+ * and use it if available
+ *
+ * - otherwise, look for $PLATFORM/skins/$SKINNAME/layout
+ * and use it if available.
+ *
+ * - otherwise, look for $PLATFORM/skins/$SKINNAME/alias-<other>.
+ * if a file exist by that name, look at $PLATFORM/skins/<other>/layout
+ * and use it if available. Aliases are not recursives :-)
+ */
+
+/* now, things get a little bit more complicated when working
+ * within the Android build system. In this mode, which can be
+ * detected by looking at the definition of the ANDROID_PRODUCT_OUT
+ * environment variable, we're going to simply pick the image files
+ * from the out directory, or from $BUILDROOT/prebuilt
+ */
+
+/* the name of the $SDKROOT subdirectory that contains all platforms */
+# define PLATFORMS_SUBDIR "platforms"
+
+/* the name of the $SDKROOT subdirectory that contains add-ons */
+# define ADDONS_SUBDIR "add-ons"
+
+#endif /* SUPPORT_PLATFORM_OR_ADDON */
+
+/* this is the subdirectory of $HOME/.android where all
+ * root configuration files (and default content directories)
+ * are located.
+ */
+#define ANDROID_AVD_DIR "avd"
+
+/* the prefix of config.ini keys that will be used for search directories
+ * of system images.
+ */
+#define SEARCH_PREFIX "images.sysdir."
+
+/* the maximum number of search path keys we're going to read from the
+ * config.ini file
+ */
+#define MAX_SEARCH_PATHS 2
+
+/* the config.ini key that will be used to indicate the full relative
+ * path to the skin directory (including the skin name).
+ *
+ * If SUPPORT_PLATFORM_OR_ADDON is defined, then this can also be
+ * the name of a skin, without any path, and platform/add-on directories
+ * will be searched for it.
+ */
+#define SKIN_PATH "skin"
+
+/* default skin name */
+#define SKIN_DEFAULT "HVGA"
+
+/* certain disk image files are mounted read/write by the emulator
+ * to ensure that several emulators referencing the same files
+ * do not corrupt these files, we need to lock them and respond
+ * to collision depending on the image type.
+ *
+ * the enumeration below is used to record information about
+ * each image file path.
+ *
+ * READONLY means that the file will be mounted read-only
+ * and this doesn't need to be locked. must be first in list
+ *
+ * MUSTLOCK means that the file should be locked before
+ * being mounted by the emulator
+ *
+ * TEMPORARY means that the file has been copied to a
+ * temporary image, which can be mounted read/write
+ * but doesn't require locking.
+ */
+typedef enum {
+ IMAGE_STATE_READONLY, /* unlocked */
+ IMAGE_STATE_MUSTLOCK, /* must be locked */
+ IMAGE_STATE_LOCKED, /* locked */
+ IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
+ IMAGE_STATE_TEMPORARY, /* copied to temp file (no lock needed) */
+} AvdImageState;
+
+struct AvdInfo {
+ /* for the Android build system case */
+ char inAndroidBuild;
+ char* androidOut;
+ char* androidBuildRoot;
+
+ /* for the normal virtual device case */
+ char* deviceName;
+ char* sdkRootPath;
+ char sdkRootPathFromEnv;
+ char* searchPaths[ MAX_SEARCH_PATHS ];
+ int numSearchPaths;
+#if SUPPORT_PLATFORM_OR_ADDON
+ int platformVersion;
+ char* platformPath;
+ char* addonTarget;
+ char* addonPath;
+#endif
+ char* contentPath;
+ IniFile* rootIni; /* root <foo>.ini file */
+ IniFile* configIni; /* virtual device's config.ini */
+
+ /* for both */
+ char* skinName; /* skin name */
+ char* skinDirPath; /* skin directory */
+
+ /* image files */
+ char* imagePath [ AVD_IMAGE_MAX ];
+ char imageState[ AVD_IMAGE_MAX ];
+};
+
+
+void
+avdInfo_free( AvdInfo* i )
+{
+ if (i) {
+ int nn;
+
+ for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
+ AFREE(i->imagePath[nn]);
+
+ AFREE(i->skinName);
+ AFREE(i->skinDirPath);
+
+ for (nn = 0; nn < i->numSearchPaths; nn++)
+ AFREE(i->searchPaths[nn]);
+
+ i->numSearchPaths = 0;
+
+ if (i->configIni) {
+ iniFile_free(i->configIni);
+ i->configIni = NULL;
+ }
+
+ if (i->rootIni) {
+ iniFile_free(i->rootIni);
+ i->rootIni = NULL;
+ }
+
+ AFREE(i->contentPath);
+ AFREE(i->sdkRootPath);
+
+ if (i->inAndroidBuild) {
+ AFREE(i->androidOut);
+ AFREE(i->androidBuildRoot);
+ } else {
+#if SUPPORT_PLATFORM_OR_ADDON
+ AFREE(i->platformPath);
+ AFREE(i->addonTarget);
+ AFREE(i->addonPath);
+#endif
+ }
+
+ AFREE(i->deviceName);
+ AFREE(i);
+ }
+}
+
+/* list of default file names for each supported image file type */
+static const char* const _imageFileNames[ AVD_IMAGE_MAX ] = {
+#define _AVD_IMG(x,y,z) y,
+ AVD_IMAGE_LIST
+#undef _AVD_IMG
+};
+
+/* list of short text description for each supported image file type */
+static const char* const _imageFileText[ AVD_IMAGE_MAX ] = {
+#define _AVD_IMG(x,y,z) z,
+ AVD_IMAGE_LIST
+#undef _AVD_IMG
+};
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** NORMAL VIRTUAL DEVICE SUPPORT
+ *****
+ *****/
+
+/* compute path to the root SDK directory
+ * assume we are in $SDKROOT/tools/emulator[.exe]
+ */
+static int
+_getSdkRoot( AvdInfo* i )
+{
+ const char* env;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+#define SDK_ROOT_ENV "ANDROID_SDK_ROOT"
+
+ env = getenv(SDK_ROOT_ENV);
+ if (env != NULL && env[0] != 0) {
+ if (path_exists(env)) {
+ D("found " SDK_ROOT_ENV ": %s", env);
+ i->sdkRootPath = ASTRDUP(env);
+ i->sdkRootPathFromEnv = 1;
+ return 0;
+ }
+ D(SDK_ROOT_ENV " points to unknown directory: %s", env);
+ }
+
+ (void) bufprint_app_dir(temp, end);
+
+ i->sdkRootPath = path_parent(temp, 1);
+ if (i->sdkRootPath == NULL) {
+ derror("can't find root of SDK directory");
+ return -1;
+ }
+ D("found SDK root at %s", i->sdkRootPath);
+ return 0;
+}
+
+static void
+_getSearchPaths( AvdInfo* i )
+{
+ char temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
+ int nn, count = 0;
+
+
+
+ for (nn = 0; nn < MAX_SEARCH_PATHS; nn++) {
+ char* path;
+
+ p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
+ if (p >= end)
+ continue;
+
+ path = iniFile_getString( i->configIni, temp );
+ if (path != NULL) {
+ DD(" found image search path: %s", path);
+ if (!path_is_absolute(path)) {
+ p = bufprint(temp, end, "%s/%s", i->sdkRootPath, path);
+ AFREE(path);
+ path = ASTRDUP(temp);
+ }
+ i->searchPaths[count++] = path;
+ }
+ }
+
+ i->numSearchPaths = count;
+ if (count == 0)
+ DD("no search paths found in this AVD's config.ini");
+ else
+ DD("found a total of %d search paths for this AVD", count);
+}
+
+#if SUPPORT_PLATFORM_OR_ADDON
+/* returns the full path of the platform subdirectory
+ * corresponding to a given API version
+ */
+static char*
+_findPlatformByVersion( const char* sdkRoot, int version )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
+ char* subdir = NULL;
+ DirScanner* scanner;
+
+ DD("> %s(%s,%d)", __FUNCTION__, sdkRoot, version);
+ p = bufprint(temp, end, "%s/%s", sdkRoot, PLATFORMS_SUBDIR);
+ if (p >= end) {
+ DD("! path too long");
+ return NULL;
+ }
+
+ scanner = dirScanner_new(temp);
+ if (scanner == NULL) {
+ DD("! cannot scan path %s: %s", temp, strerror(errno));
+ return NULL;
+ }
+
+ for (;;) {
+ IniFile* ini;
+ int apiVersion;
+
+ subdir = (char*) dirScanner_nextFull(scanner);
+ if (subdir == NULL)
+ break;
+
+ /* look for a file named "build.prop */
+ p = bufprint(temp, end, "%s/build.prop", subdir);
+ if (p >= end)
+ continue;
+
+ if (!path_exists(temp)) {
+ DD("! no file at %s", temp);
+ continue;
+ }
+
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL)
+ continue;
+
+ apiVersion = iniFile_getInteger(ini, "ro.build.version.sdk", -1);
+ iniFile_free(ini);
+
+ DD("! found %s (version %d)", temp, apiVersion);
+
+ if (apiVersion == version) {
+ /* Bingo */
+ subdir = ASTRDUP(subdir);
+ break;
+ }
+ }
+
+ if (!subdir) {
+ DD("< didn't found anything");
+ }
+
+ dirScanner_free(scanner);
+ return subdir;
+}
+
+/* returns the full path of the addon corresponding to a given target,
+ * or NULL if not found. on success, *pversion will contain the SDK
+ * version number
+ */
+static char*
+_findAddonByTarget( const char* sdkRoot, const char* target, int *pversion )
+{
+ char* targetCopy = ASTRDUP(target);
+ char* targetVendor = NULL;
+ char* targetName = NULL;
+ int targetVersion = -1;
+
+ char temp[PATH_MAX];
+ char* p;
+ char* end;
+ DirScanner* scanner;
+ char* subdir;
+
+ DD("> %s(%s,%s)", __FUNCTION__, sdkRoot, target);
+
+ /* extract triplet from target string */
+ targetVendor = targetCopy;
+
+ p = strchr(targetVendor, ':');
+ if (p == NULL) {
+ DD("< missing first column separator");
+ goto FAIL;
+ }
+ *p = 0;
+ targetName = p + 1;
+ p = strchr(targetName, ':');
+ if (p == NULL) {
+ DD("< missing second column separator");
+ goto FAIL;
+ }
+ *p++ = 0;
+
+ targetVersion = atoi(p);
+
+ if (targetVersion == 0) {
+ DD("< invalid version number");
+ goto FAIL;
+ }
+ /* now scan addons directory */
+ p = temp;
+ end = p + sizeof temp;
+
+ p = bufprint(p, end, "%s/%s", sdkRoot, ADDONS_SUBDIR);
+ if (p >= end) {
+ DD("< add-on path too long");
+ goto FAIL;
+ }
+ scanner = dirScanner_new(temp);
+ if (scanner == NULL) {
+ DD("< cannot scan add-on path %s: %s", temp, strerror(errno));
+ goto FAIL;
+ }
+ for (;;) {
+ IniFile* ini;
+ const char* vendor;
+ const char* name;
+ int version;
+ int matches;
+
+ subdir = (char*) dirScanner_nextFull(scanner);
+ if (subdir == NULL)
+ break;
+
+ /* try to open the manifest.ini file */
+ p = bufprint(temp, end, "%s/manifest.ini", subdir);
+ if (p >= end)
+ continue;
+
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL)
+ continue;
+
+ DD("! scanning manifest.ini in %s", temp);
+
+ /* find the vendor, name and version */
+ vendor = iniFile_getValue(ini, "vendor");
+ name = iniFile_getValue(ini, "name");
+ version = iniFile_getInteger(ini, "api", -1);
+
+ matches = 0;
+
+ matches += (version == targetVersion);
+ matches += (vendor && !strcmp(vendor, targetVendor));
+ matches += (name && !strcmp(name, targetName));
+
+ DD("! matches=%d vendor=[%s] name=[%s] version=%d",
+ matches,
+ vendor ? vendor : "<NULL>",
+ name ? name : "<NULL>",
+ version);
+
+ iniFile_free(ini);
+
+ if (matches == 3) {
+ /* bingo */
+ *pversion = version;
+ subdir = ASTRDUP(subdir);
+ break;
+ }
+ }
+
+ dirScanner_free(scanner);
+
+ DD("< returning %s", subdir ? subdir : "<NULL>");
+ return subdir;
+
+FAIL:
+ AFREE(targetCopy);
+ return NULL;
+}
+#endif /* SUPPORT_PLATFORM_OR_ADDON */
+
+static int
+_checkAvdName( const char* name )
+{
+ int len = strlen(name);
+ int len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789_.-");
+ return (len == len2);
+}
+
+/* parse the root config .ini file. it is located in
+ * ~/.android/avd/<name>.ini or Windows equivalent
+ */
+static int
+_getRootIni( AvdInfo* i )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint_config_path(temp, end);
+ p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", i->deviceName);
+ if (p >= end) {
+ derror("device name too long");
+ return -1;
+ }
+
+ i->rootIni = iniFile_newFromFile(temp);
+ if (i->rootIni == NULL) {
+ derror("unknown virtual device name: '%s'", i->deviceName);
+ return -1;
+ }
+ D("root virtual device file at %s", temp);
+ return 0;
+}
+
+/* the .ini variable name that points to the content directory
+ * in a root AVD ini file. This is required */
+# define ROOT_PATH_KEY "path"
+
+static int
+_getContentPath( AvdInfo* i )
+{
+ i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY);
+
+ if (i->contentPath == NULL) {
+ derror("bad config: %s",
+ "virtual device file lacks a "ROOT_PATH_KEY" entry");
+ return -1;
+ }
+ D("virtual device content at %s", i->contentPath);
+ return 0;
+}
+
+#if SUPPORT_PLATFORM_OR_ADDON
+# define ROOT_TARGET_KEY "target"
+
+/* retrieve the content path and target from the root .ini file */
+static int
+_getTarget( AvdInfo* i )
+{
+ i->addonTarget = iniFile_getString(i->rootIni, ROOT_TARGET_KEY);
+
+ if (i->addonTarget == NULL) {
+ derror("bad config: %s",
+ "virtual device file lacks a "ROOT_TARGET_KEY" entry");
+ return -1;
+ }
+
+ D("virtual device target is %s", i->addonTarget);
+
+ if (!strncmp(i->addonTarget, "android-", 8)) { /* target is platform */
+ char* end;
+ const char* versionString = i->addonTarget+8;
+ int version = (int) strtol(versionString, &end, 10);
+ if (*end != 0 || version <= 0) {
+ derror("bad config: invalid platform version: '%s'", versionString);
+ return -1;
+ }
+ i->platformVersion = version;
+ i->platformPath = _findPlatformByVersion(i->sdkRootPath,
+ version);
+ if (i->platformPath == NULL) {
+ derror("bad config: unknown platform version: '%d'", version);
+ return -1;
+ }
+ }
+ else /* target is add-on */
+ {
+ i->addonPath = _findAddonByTarget(i->sdkRootPath, i->addonTarget,
+ &i->platformVersion);
+ if (i->addonPath == NULL) {
+ derror("bad config: %s",
+ "unknown add-on target: '%s'", i->addonTarget);
+ return -1;
+ }
+
+ i->platformPath = _findPlatformByVersion(i->sdkRootPath,
+ i->platformVersion);
+ if (i->platformPath == NULL) {
+ derror("bad config: %s",
+ "unknown add-on platform version: '%d'", i->platformVersion);
+ return -1;
+ }
+ D("virtual device add-on path: %s", i->addonPath);
+ }
+ D("virtual device platform path: %s", i->platformPath);
+ D("virtual device platform version %d", i->platformVersion);
+ return 0;
+}
+#endif /* SUPPORT_PLATFORM_OR_ADDON */
+
+/* find and parse the config.ini file from the content directory */
+static int
+_getConfigIni(AvdInfo* i)
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint(p, end, "%s/config.ini", i->contentPath);
+ if (p >= end) {
+ derror("can't access virtual device content directory");
+ return -1;
+ }
+
+#if 1 /* XXX: TODO: remove this in the future */
+ /* for now, allow a non-existing config.ini */
+ if (!path_exists(temp)) {
+ D("virtual device has no config file - no problem");
+ return 0;
+ }
+#endif
+
+ i->configIni = iniFile_newFromFile(temp);
+ if (i->configIni == NULL) {
+ derror("bad config: %s",
+ "virtual device directory lacks config.ini");
+ return -1;
+ }
+ D("virtual device config file: %s", temp);
+ return 0;
+}
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** KERNEL/DISK IMAGE LOADER
+ *****
+ *****/
+
+/* a structure used to handle the loading of
+ * kernel/disk images.
+ */
+typedef struct {
+ AvdInfo* info;
+ AvdInfoParams* params;
+ AvdImageType id;
+ const char* imageFile;
+ const char* imageText;
+ char** pPath;
+ char* pState;
+ char temp[PATH_MAX];
+} ImageLoader;
+
+static void
+imageLoader_init( ImageLoader* l, AvdInfo* info, AvdInfoParams* params )
+{
+ memset(l, 0, sizeof(*l));
+ l->info = info;
+ l->params = params;
+}
+
+/* set the type of the image to load */
+static void
+imageLoader_set( ImageLoader* l, AvdImageType id )
+{
+ l->id = id;
+ l->imageFile = _imageFileNames[id];
+ l->imageText = _imageFileText[id];
+ l->pPath = &l->info->imagePath[id];
+ l->pState = &l->info->imageState[id];
+
+ l->pState[0] = IMAGE_STATE_READONLY;
+}
+
+/* change the image path */
+static char*
+imageLoader_setPath( ImageLoader* l, const char* path )
+{
+ path = path ? ASTRDUP(path) : NULL;
+
+ AFREE(l->pPath[0]);
+ l->pPath[0] = (char*) path;
+
+ return (char*) path;
+}
+
+static char*
+imageLoader_extractPath( ImageLoader* l )
+{
+ char* result = l->pPath[0];
+ l->pPath[0] = NULL;
+ return result;
+}
+
+/* flags used when loading images */
+enum {
+ IMAGE_REQUIRED = (1<<0), /* image is required */
+ IMAGE_SEARCH_SDK = (1<<1), /* search image in SDK */
+ IMAGE_EMPTY_IF_MISSING = (1<<2), /* create empty file if missing */
+ IMAGE_DONT_LOCK = (1<<4), /* don't try to lock image */
+ IMAGE_IGNORE_IF_LOCKED = (1<<5), /* ignore file if it's locked */
+};
+
+#define IMAGE_OPTIONAL 0
+
+/* find an image from the SDK search directories.
+ * returns the full path or NULL if the file could not be found.
+ *
+ * note: this stores the result in the image's path as well
+ */
+static char*
+imageLoader_lookupSdk( ImageLoader* l )
+{
+ AvdInfo* i = l->info;
+ const char* image = l->imageFile;
+ char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
+
+ do {
+ /* try the search paths */
+ int nn;
+
+ for (nn = 0; nn < i->numSearchPaths; nn++) {
+ const char* searchDir = i->searchPaths[nn];
+
+ p = bufprint(temp, end, "%s/%s", searchDir, image);
+ if (p < end && path_exists(temp)) {
+ DD("found %s in search dir: %s", image, searchDir);
+ goto FOUND;
+ }
+ DD(" no %s in search dir: %s", image, searchDir);
+ }
+
+#if SUPPORT_PLATFORM_OR_ADDON
+ /* try the add-on directory, if any */
+ if (i->addonPath != NULL) {
+ p = bufprint(temp, end, "%s/images/%s", i->addonPath, image);
+ if (p < end && path_exists(temp)) {
+ DD("found %s in add-on dir:", image, i->addonPath);
+ break;
+ }
+ DD(" no %s in add-on dir: ", image, i->addonPath);
+ }
+
+ /* or try the platform directory */
+ p = bufprint(temp, end, "%s/images/%s",
+ i->platformPath, image);
+ if (p < end && path_exists(temp)) {
+ DD("found %s in platform dir:", image, i->platformPath);
+ break;
+ }
+ DD(" no %s in platform dir: ", image, i->platformPath);
+#endif
+ return NULL;
+
+ } while (0);
+
+FOUND:
+ l->pState[0] = IMAGE_STATE_READONLY;
+
+ return imageLoader_setPath(l, temp);
+}
+
+/* search for a file in the content directory.
+ * returns NULL if the file cannot be found.
+ *
+ * note that this formats l->temp with the file's path
+ * allowing you to retrieve it if the function returns NULL
+ */
+static char*
+imageLoader_lookupContent( ImageLoader* l )
+{
+ AvdInfo* i = l->info;
+ char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
+
+ p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile);
+ if (p >= end) {
+ derror("content directory path too long");
+ exit(2);
+ }
+ if (!path_exists(temp)) {
+ DD(" no %s in content directory", l->imageFile);
+ return NULL;
+ }
+ DD("found %s in content directory", l->imageFile);
+
+ /* assume content image files must be locked */
+ l->pState[0] = IMAGE_STATE_MUSTLOCK;
+
+ return imageLoader_setPath(l, temp);
+}
+
+/* lock a file image depending on its state and user flags
+ * note that this clears l->pPath[0] if the lock could not
+ * be acquired and that IMAGE_IGNORE_IF_LOCKED is used.
+ */
+static void
+imageLoader_lock( ImageLoader* l, unsigned flags )
+{
+ const char* path = l->pPath[0];
+
+ if (flags & IMAGE_DONT_LOCK)
+ return;
+
+ if (l->pState[0] != IMAGE_STATE_MUSTLOCK)
+ return;
+
+ D(" locking %s image at %s", l->imageText, path);
+
+ if (filelock_create(path) != NULL) {
+ /* succesful lock */
+ l->pState[0] = IMAGE_STATE_LOCKED;
+ return;
+ }
+
+ if (flags & IMAGE_IGNORE_IF_LOCKED) {
+ dwarning("ignoring locked %s image at %s", l->imageText, path);
+ imageLoader_setPath(l, NULL);
+ return;
+ }
+
+ derror("the %s image is used by another emulator. aborting",
+ l->imageText);
+ exit(2);
+}
+
+/* make a file image empty, this may require locking */
+static void
+imageLoader_empty( ImageLoader* l, unsigned flags )
+{
+ const char* path;
+
+ imageLoader_lock(l, flags);
+
+ path = l->pPath[0];
+ if (path == NULL) /* failed to lock, caller will handle it */
+ return;
+
+ if (path_empty_file(path) < 0) {
+ derror("could not create %s image at %s: %s",
+ l->imageText, path, strerror(errno));
+ exit(2);
+ }
+ l->pState[0] = IMAGE_STATE_LOCKED_EMPTY;
+}
+
+
+/* copy image file from a given source
+ * assumes locking is needed.
+ */
+static void
+imageLoader_copyFrom( ImageLoader* l, const char* srcPath )
+{
+ const char* dstPath = NULL;
+
+ /* find destination file */
+ if (l->params) {
+ dstPath = l->params->forcePaths[l->id];
+ }
+ if (!dstPath) {
+ imageLoader_lookupContent(l);
+ dstPath = l->temp;
+ }
+
+ /* lock destination */
+ imageLoader_setPath(l, dstPath);
+ l->pState[0] = IMAGE_STATE_MUSTLOCK;
+ imageLoader_lock(l, 0);
+
+ /* make the copy */
+ if (path_copy_file(dstPath, srcPath) < 0) {
+ derror("can't initialize %s image from SDK: %s: %s",
+ l->imageText, dstPath, strerror(errno));
+ exit(2);
+ }
+}
+
+/* this will load and eventually lock and image file, depending
+ * on the flags being used. on exit, this function udpates
+ * l->pState[0] and l->pPath[0]
+ *
+ * returns the path to the file. Note that it returns NULL
+ * only if the file was optional and could not be found.
+ *
+ * if the file is required and missing, the function aborts
+ * the program.
+ */
+static char*
+imageLoader_load( ImageLoader* l,
+ unsigned flags )
+{
+ const char* path = NULL;
+
+ /* first, check user-provided path */
+ path = l->params->forcePaths[l->id];
+ if (path != NULL) {
+ imageLoader_setPath(l, path);
+ if (path_exists(path)) {
+ DD("found user-provided %s image: %s", l->imageText, l->imageFile);
+ goto EXIT;
+ }
+ D("user-provided %s image does not exist: %s",
+ l->imageText, path);
+
+ /* if the file is required, abort */
+ if (flags & IMAGE_REQUIRED) {
+ derror("user-provided %s image at %s doesn't exist",
+ l->imageText, path);
+ exit(2);
+ }
+ }
+ else {
+ const char* contentFile;
+
+ /* second, look in the content directory */
+ path = imageLoader_lookupContent(l);
+ if (path) goto EXIT;
+
+ contentFile = ASTRDUP(l->temp);
+
+ /* it's not there */
+ if (flags & IMAGE_SEARCH_SDK) {
+ /* third, look in the SDK directory */
+ path = imageLoader_lookupSdk(l);
+ if (path) {
+ AFREE((char*)contentFile);
+ goto EXIT;
+ }
+ }
+ DD("found no %s image (%s)", l->imageText, l->imageFile);
+
+ /* if the file is required, abort */
+ if (flags & IMAGE_REQUIRED) {
+ AvdInfo* i = l->info;
+
+ derror("could not find required %s image (%s).",
+ l->imageText, l->imageFile);
+
+ if (i->inAndroidBuild) {
+ dprint( "Did you build everything ?" );
+ } else if (!i->sdkRootPathFromEnv) {
+ dprint( "Maybe defining %s to point to a valid SDK "
+ "installation path might help ?", SDK_ROOT_ENV );
+ } else {
+ dprint( "Your %s is probably wrong: %s", SDK_ROOT_ENV,
+ i->sdkRootPath );
+ }
+ exit(2);
+ }
+
+ path = imageLoader_setPath(l, contentFile);
+ AFREE((char*)contentFile);
+ }
+
+ /* otherwise, do we need to create it ? */
+ if (flags & IMAGE_EMPTY_IF_MISSING) {
+ imageLoader_empty(l, flags);
+ return l->pPath[0];
+ }
+ return NULL;
+
+EXIT:
+ imageLoader_lock(l, flags);
+ return l->pPath[0];
+}
+
+
+
+/* find the correct path of all image files we're going to need
+ * and lock the files that need it.
+ */
+static int
+_getImagePaths(AvdInfo* i, AvdInfoParams* params )
+{
+ int wipeData = (params->flags & AVDINFO_WIPE_DATA) != 0;
+ int wipeCache = (params->flags & AVDINFO_WIPE_CACHE) != 0;
+ int noCache = (params->flags & AVDINFO_NO_CACHE) != 0;
+ int noSdCard = (params->flags & AVDINFO_NO_SDCARD) != 0;
+
+ ImageLoader l[1];
+
+ imageLoader_init(l, i, params);
+
+ /* pick up the kernel and ramdisk image files - these don't
+ * need a specific handling.
+ */
+ imageLoader_set ( l, AVD_IMAGE_KERNEL );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
+
+ imageLoader_set ( l, AVD_IMAGE_RAMDISK );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
+
+ /* the system image
+ *
+ * if there is one in the content directory just lock
+ * and use it.
+ */
+ imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK );
+
+ /* the data partition - this one is special because if it
+ * is missing, we need to copy the initial image file into it.
+ *
+ * first, try to see if it is in the content directory
+ * (or the user-provided path)
+ */
+ imageLoader_set( l, AVD_IMAGE_USERDATA );
+ if ( !imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING |
+ IMAGE_DONT_LOCK ) )
+ {
+ /* it's not, we're going to initialize it. simply
+ * forcing a data wipe should be enough */
+ D("initializing new data partition image: %s", l->pPath[0]);
+ wipeData = 1;
+ }
+
+ if (wipeData) {
+ /* find SDK source file */
+ const char* srcPath;
+
+ if (imageLoader_lookupSdk(l)) {
+ derror("can't locate initial %s image in SDK",
+ l->imageText);
+ exit(2);
+ }
+ srcPath = imageLoader_extractPath(l);
+
+ imageLoader_copyFrom( l, srcPath );
+ AFREE((char*) srcPath);
+ }
+ else
+ {
+ /* lock the data partition image */
+ l->pState[0] = IMAGE_STATE_MUSTLOCK;
+ imageLoader_lock( l, 0 );
+ }
+
+ /* the cache partition: unless the user doesn't want one,
+ * we're going to create it in the content directory
+ */
+ if (!noCache) {
+ imageLoader_set (l, AVD_IMAGE_CACHE);
+ imageLoader_load(l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING );
+
+ if (wipeCache) {
+ if (path_empty_file(l->pPath[0]) < 0) {
+ derror("cannot wipe %s image at %s: %s",
+ l->imageText, l->pPath[0],
+ strerror(errno));
+ exit(2);
+ }
+ }
+ }
+
+ /* the SD Card image. unless the user doesn't want to, we're
+ * going to mount it if available. Note that if the image is
+ * already used, we must ignore it.
+ */
+ if (!noSdCard) {
+ imageLoader_set (l, AVD_IMAGE_SDCARD);
+ imageLoader_load(l, IMAGE_OPTIONAL |
+ IMAGE_IGNORE_IF_LOCKED);
+
+ /* if the file was not found, ignore it */
+ if (l->pPath[0] && !path_exists(l->pPath[0]))
+ {
+ D("ignoring non-existing %s at %s: %s",
+ l->imageText, l->pPath[0], strerror(errno));
+
+ /* if the user provided the SD Card path by hand,
+ * warn him. */
+ if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
+ dwarning("ignoring non-existing SD Card image");
+
+ imageLoader_setPath(l, NULL);
+ }
+ }
+
+ return 0;
+}
+
+/* check that a given directory contains a valid skin.
+ * returns 1 on success, 0 on failure.
+ */
+static int
+_checkSkinPath( const char* skinPath )
+{
+ char temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
+
+ /* for now, if it has a 'layout' file, it is a valid skin path */
+ p = bufprint(temp, end, "%s/layout", skinPath);
+ if (p >= end || !path_exists(temp))
+ return 0;
+
+ return 1;
+}
+
+/* check that there is a skin named 'skinName' listed from 'skinDirRoot'
+ * this returns 1 on success, 0 on failure
+ * on success, the 'temp' buffer will get the path containing the real
+ * skin directory (after alias expansion), including the skin name.
+ */
+static int
+_checkSkinDir( char* temp,
+ char* end,
+ const char* skinDirRoot,
+ const char* skinName )
+{
+ DirScanner* scanner;
+ char *p;
+ int result;
+
+ p = bufprint(temp, end, "%s/skins/%s",
+ skinDirRoot, skinName);
+
+ if (p >= end || !path_exists(temp)) {
+ DD(" ignore bad skin directory %s", temp);
+ return 0;
+ }
+
+ /* first, is this a normal skin directory ? */
+ if (_checkSkinPath(temp)) {
+ /* yes */
+ DD(" found skin directory: %s", temp);
+ return 1;
+ }
+
+ /* second, is it an alias to another skin ? */
+ *p = 0;
+ result = 0;
+ scanner = dirScanner_new(temp);
+ if (scanner != NULL) {
+ for (;;) {
+ const char* file = dirScanner_next(scanner);
+
+ if (file == NULL)
+ break;
+
+ if (strncmp(file, "alias-", 6) || file[6] == 0)
+ continue;
+
+ p = bufprint(temp, end, "%s/skins/%s",
+ skinDirRoot, file+6);
+
+ if (p < end && _checkSkinPath(temp)) {
+ /* yes, it's an alias */
+ DD(" skin alias '%s' points to skin directory: %s",
+ file+6, temp);
+ result = 1;
+ break;
+ }
+ }
+ dirScanner_free(scanner);
+ }
+ return result;
+}
+
+/* try to see if the skin name leads to a magic skin or skin path directly
+ * returns 1 on success, 0 on error.
+ * on success, this sets up 'skinDirPath' and 'skinName' in the AvdInfo.
+ */
+static int
+_getSkinPathFromName( AvdInfo* i, const char* skinName )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ /* if the skin name has the format 'NNNNxNNN' where
+ * NNN is a decimal value, then this is a 'magic' skin
+ * name that doesn't require a skin directory
+ */
+ if (isdigit(skinName[0])) {
+ int width, height;
+ if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
+ D("'magic' skin format detected: %s", skinName);
+ i->skinName = ASTRDUP(skinName);
+ i->skinDirPath = NULL;
+ return 1;
+ }
+ }
+
+ /* is the skin name a direct path to the skin directory ? */
+ if (_checkSkinPath(skinName)) {
+ goto FOUND_IT;
+ }
+
+ /* is the skin name a relative path from the SDK root ? */
+ p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName);
+ if (p < end && _checkSkinPath(temp)) {
+ skinName = temp;
+ goto FOUND_IT;
+ }
+
+ /* nope */
+ return 0;
+
+FOUND_IT:
+ if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) {
+ derror("malformed skin name: %s", skinName);
+ exit(2);
+ }
+ D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
+ return 1;
+}
+
+/* return 0 on success, -1 on error */
+static int
+_getSkin( AvdInfo* i, AvdInfoParams* params )
+{
+ char* skinName;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ char explicitSkin = 1;
+
+ /* this function is used to compute the 'skinName' and 'skinDirPath'
+ * fields of the AvdInfo.
+ */
+
+ /* processing here is a bit tricky, so here's how it happens
+ *
+ * - command-line option '-skin <name>' can be used to specify the
+ * name of a skin, to override the AVD settings.
+ *
+ * - skins are searched from <dir>/../skins for each <dir> in the
+ * images search list, unless a '-skindir <path>' option has been
+ * provided on the command-line
+ *
+ * - otherwise, the config.ini can also contain a SKIN_PATH key that
+ * shall give the full path to the skin directory, either relative
+ * to the SDK root, or an absolute path.
+ *
+ * - skin names like '320x480' corresponds to "magic skins" that
+ * simply display a framebuffer, without any ornaments of the
+ * corresponding size. They do not correspond to any real skin
+ * directory / files and are handled later. But they must be
+ * recognized here and report a NULL skindir.
+ */
+ if (params->skinName) {
+ skinName = ASTRDUP(params->skinName);
+ } else {
+ skinName = iniFile_getString( i->configIni, SKIN_PATH );
+ explicitSkin = 0;
+ }
+
+ /* first, check that the skin name is not magic or a direct
+ * directory path
+ */
+ if (skinName != NULL && _getSkinPathFromName(i, skinName)) {
+ AFREE(skinName);
+ return 0;
+ }
+
+ /* if not, the default skinName is "HVGA" */
+ if (skinName == NULL) {
+ skinName = ASTRDUP(SKIN_DEFAULT);
+ explicitSkin = 0;
+ }
+
+ i->skinName = skinName;
+
+ /* now try to find the skin directory for that name -
+ * first try the content directory */
+ do {
+ /* if there is a single 'skin' directory in
+ * the content directory, assume that's what the
+ * user wants, unless an explicit name was given
+ */
+ if (!explicitSkin) {
+ p = bufprint(temp, end, "%s/skin", i->contentPath);
+ if (p < end && _checkSkinPath(temp)) {
+ D("using skin content from %s", temp);
+ AFREE(i->skinName);
+ i->skinName = ASTRDUP("skin");
+ i->skinDirPath = ASTRDUP(i->contentPath);
+ return 0;
+ }
+ }
+
+ /* look in content directory */
+ if (_checkSkinDir(temp, end, i->contentPath, skinName))
+ break;
+
+ /* look in the search paths. For each <dir> in the list,
+ * look the skins in <dir>/.. */
+ {
+ int nn;
+ for (nn = 0; nn < i->numSearchPaths; nn++) {
+ char* parentDir = path_parent(i->searchPaths[nn], 1);
+ int ret;
+ if (parentDir == NULL)
+ continue;
+ ret=_checkSkinDir(temp, end, parentDir, skinName);
+ AFREE(parentDir);
+ if (ret)
+ break;
+ }
+ if (nn < i->numSearchPaths)
+ break;
+ }
+
+#if SUPPORT_PLATFORM_OR_ADDON
+ /* look in the add-on directory, if any */
+ if (i->addonPath &&
+ _checkSkinDir(temp, end, i->addonPath, skinName))
+ break;
+
+ /* look in the platforms directory */
+ if (_checkSkinDir(temp, end, i->platformPath, skinName))
+ break;
+#endif
+ /* didn't find it */
+ if (explicitSkin) {
+ derror("could not find directory for skin '%s',"
+ " please use a different name", skinName);
+ exit(2);
+ } else {
+ dwarning("no skin directory matched '%s', so reverted to default",
+ skinName);
+ AFREE(i->skinName);
+ params->skinName = SKIN_DEFAULT;
+ return _getSkin(i, params);
+ }
+
+ return -1;
+
+ } while (0);
+
+ /* separate skin name from parent directory. the skin name
+ * returned in 'temp' might be different from the original
+ * one due to alias expansion so strip it.
+ */
+ AFREE(i->skinName);
+
+ if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) {
+ derror("weird skin path: %s", temp);
+ return -1;
+ }
+ DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
+ return 0;
+}
+
+
+AvdInfo*
+avdInfo_new( const char* name, AvdInfoParams* params )
+{
+ AvdInfo* i;
+
+ if (name == NULL)
+ return NULL;
+
+ if (!_checkAvdName(name)) {
+ derror("virtual device name contains invalid characters");
+ exit(1);
+ }
+
+ ANEW0(i);
+ i->deviceName = ASTRDUP(name);
+
+ if ( _getSdkRoot(i) < 0 ||
+ _getRootIni(i) < 0 ||
+ _getContentPath(i) < 0 ||
+ _getConfigIni(i) < 0 )
+ goto FAIL;
+
+ /* look for image search paths. handle post 1.1/pre cupcake
+ * obsolete SDKs.
+ */
+ _getSearchPaths(i);
+
+ if (i->numSearchPaths == 0) {
+#if SUPPORT_PLATFORM_OR_ADDON
+ /* no search paths, look for platform/add-on */
+ if (_getTarget(i) < 0)
+ goto FAIL;
+#endif
+ }
+
+ /* don't need this anymore */
+ iniFile_free(i->rootIni);
+ i->rootIni = NULL;
+
+ if ( _getImagePaths(i, params) < 0 ||
+ _getSkin (i, params) < 0 )
+ goto FAIL;
+
+ return i;
+
+FAIL:
+ avdInfo_free(i);
+ return NULL;
+}
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** ANDROID BUILD SUPPORT
+ *****
+ ***** The code below corresponds to the case where we're
+ ***** starting the emulator inside the Android build
+ ***** system. The main differences are that:
+ *****
+ ***** - the $ANDROID_PRODUCT_OUT directory is used as the
+ ***** content file.
+ *****
+ ***** - built images must not be modified by the emulator,
+ ***** so system.img must be copied to a temporary file
+ ***** and userdata.img must be copied to userdata-qemu.img
+ ***** if the latter doesn't exist.
+ *****
+ ***** - the kernel and default skin directory are taken from
+ ***** prebuilt
+ *****
+ ***** - there is no root .ini file, or any config.ini in
+ ***** the content directory, no SDK platform version
+ ***** and no add-on to consider.
+ *****/
+
+/* used to fake a config.ini located in the content directory */
+static int
+_getBuildConfigIni( AvdInfo* i )
+{
+ /* a blank file is ok at the moment */
+ i->configIni = iniFile_newFromMemory( "", 0 );
+ return 0;
+}
+
+static int
+_getBuildImagePaths( AvdInfo* i, AvdInfoParams* params )
+{
+ int wipeData = (params->flags & AVDINFO_WIPE_DATA) != 0;
+ int noCache = (params->flags & AVDINFO_NO_CACHE) != 0;
+ int noSdCard = (params->flags & AVDINFO_NO_SDCARD) != 0;
+
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
+ char* srcData;
+ ImageLoader l[1];
+
+ imageLoader_init(l, i, params);
+
+ /** load the kernel image
+ **/
+
+ /* if it is not in the out directory, get it from prebuilt
+ */
+ imageLoader_set ( l, AVD_IMAGE_KERNEL );
+
+ if ( !imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_DONT_LOCK ) )
+ {
+#define PREBUILT_KERNEL_PATH "prebuilt/android-arm/kernel/kernel-qemu"
+ p = bufprint(temp, end, "%s/%s", i->androidBuildRoot,
+ PREBUILT_KERNEL_PATH);
+ if (p >= end || !path_exists(temp)) {
+ derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
+ exit(1);
+ }
+ imageLoader_setPath(l, temp);
+ }
+
+ /** load the data partition. note that we use userdata-qemu.img
+ ** since we don't want to modify userdata.img at all
+ **/
+ imageLoader_set ( l, AVD_IMAGE_USERDATA );
+ imageLoader_load( l, IMAGE_OPTIONAL | IMAGE_DONT_LOCK );
+
+ /* get the path of the source file, and check that it actually exists
+ * if the user didn't provide an explicit data file
+ */
+ srcData = imageLoader_extractPath(l);
+ if (srcData == NULL && params->forcePaths[AVD_IMAGE_USERDATA] == NULL) {
+ derror("There is no %s image in your build directory. Please make a full build",
+ l->imageText, l->imageFile);
+ exit(2);
+ }
+
+ /* get the path of the target file */
+ l->imageFile = "userdata-qemu.img";
+ imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING |
+ IMAGE_IGNORE_IF_LOCKED );
+
+ /* force a data wipe if we just created the image */
+ if (l->pState[0] == IMAGE_STATE_LOCKED_EMPTY)
+ wipeData = 1;
+
+ /* if the image was already locked, create a temp file
+ * then force a data wipe.
+ */
+ if (l->pPath[0] == NULL) {
+ TempFile* temp = tempfile_create();
+ imageLoader_setPath(l, tempfile_path(temp));
+ dwarning( "Another emulator is running. user data changes will *NOT* be saved");
+ wipeData = 1;
+ }
+
+ /* in the case of a data wipe, copy userdata.img into
+ * the destination */
+ if (wipeData) {
+ if (srcData == NULL || !path_exists(srcData)) {
+ derror("There is no %s image in your build directory. Please make a full build",
+ l->imageText, _imageFileNames[l->id]);
+ exit(2);
+ }
+ if (path_copy_file( l->pPath[0], srcData ) < 0) {
+ derror("could not initialize %s image from %s: %s",
+ l->imageText, temp, strerror(errno));
+ exit(2);
+ }
+ }
+
+ AFREE(srcData);
+
+ /** load the ramdisk image
+ **/
+ imageLoader_set ( l, AVD_IMAGE_RAMDISK );
+ imageLoader_load( l, IMAGE_REQUIRED |
+ IMAGE_DONT_LOCK );
+
+ /** load the system image. read-only. the caller must
+ ** take care of checking the state
+ **/
+ imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK );
+
+ /* force the system image to read-only status */
+ l->pState[0] = IMAGE_STATE_READONLY;
+
+ /** cache partition handling
+ **/
+ if (!noCache) {
+ imageLoader_set (l, AVD_IMAGE_CACHE);
+
+ /* if the user provided one cache image, lock & use it */
+ if ( params->forcePaths[l->id] != NULL ) {
+ imageLoader_load(l, IMAGE_REQUIRED |
+ IMAGE_IGNORE_IF_LOCKED);
+ }
+ }
+
+ /** SD Card image
+ **/
+ if (!noSdCard) {
+ imageLoader_set (l, AVD_IMAGE_SDCARD);
+ imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
+ }
+
+ return 0;
+}
+
+static int
+_getBuildSkin( AvdInfo* i, AvdInfoParams* params )
+{
+ /* the (current) default skin name for our build system */
+ const char* skinName = params->skinName;
+ const char* skinDir = params->skinRootPath;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ char* q;
+
+ if (!skinName) {
+ /* the (current) default skin name for the build system */
+ skinName = SKIN_DEFAULT;
+ DD("selecting default skin name '%s'", skinName);
+ }
+
+ i->skinName = ASTRDUP(skinName);
+
+ if (!skinDir) {
+
+#define PREBUILT_SKINS_DIR "development/emulator/skins"
+
+ /* the (current) default skin directory */
+ p = bufprint( temp, end, "%s/%s",
+ i->androidBuildRoot, PREBUILT_SKINS_DIR );
+ } else {
+ p = bufprint( temp, end, "%s", skinDir );
+ }
+
+ q = bufprint(p, end, "/%s/layout", skinName);
+ if (q >= end || !path_exists(temp)) {
+ DD("skin content directory does not exist: %s", temp);
+ if (skinDir)
+ dwarning("could not find valid skin '%s' in %s:\n",
+ skinName, temp);
+ return -1;
+ }
+ *p = 0;
+ DD("found skin path: %s", temp);
+ i->skinDirPath = ASTRDUP(temp);
+
+ return 0;
+}
+
+AvdInfo*
+avdInfo_newForAndroidBuild( const char* androidBuildRoot,
+ const char* androidOut,
+ AvdInfoParams* params )
+{
+ AvdInfo* i;
+
+ ANEW0(i);
+
+ i->inAndroidBuild = 1;
+ i->androidBuildRoot = ASTRDUP(androidBuildRoot);
+ i->androidOut = ASTRDUP(androidOut);
+ i->contentPath = ASTRDUP(androidOut);
+
+ /* TODO: find a way to provide better information from the build files */
+ i->deviceName = ASTRDUP("<build>");
+
+ if (_getBuildConfigIni(i) < 0 ||
+ _getBuildImagePaths(i, params) < 0 )
+ goto FAIL;
+
+ /* we don't need to fail if there is no valid skin */
+ _getBuildSkin(i, params);
+
+ return i;
+
+FAIL:
+ avdInfo_free(i);
+ return NULL;
+}
+
+const char*
+avdInfo_getName( AvdInfo* i )
+{
+ return i ? i->deviceName : NULL;
+}
+
+const char*
+avdInfo_getImageFile( AvdInfo* i, AvdImageType imageType )
+{
+ if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
+ return NULL;
+
+ return i->imagePath[imageType];
+}
+
+int
+avdInfo_isImageReadOnly( AvdInfo* i, AvdImageType imageType )
+{
+ if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
+ return 1;
+
+ return (i->imageState[imageType] == IMAGE_STATE_READONLY);
+}
+
+const char*
+avdInfo_getSkinName( AvdInfo* i )
+{
+ return i->skinName;
+}
+
+const char*
+avdInfo_getSkinDir ( AvdInfo* i )
+{
+ return i->skinDirPath;
+}
+
+int
+avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw )
+{
+ IniFile* ini = i->configIni;
+ int ret;
+
+ if (ini == NULL)
+ ini = iniFile_newFromMemory("", 0);
+
+ ret = androidHwConfig_read(hw, ini);
+
+ if (ini != i->configIni)
+ iniFile_free(ini);
+
+ return ret;
+}
+
+const char*
+avdInfo_getContentPath( AvdInfo* i )
+{
+ return i->contentPath;
+}
+
+int
+avdInfo_inAndroidBuild( AvdInfo* i )
+{
+ return i->inAndroidBuild;
+}
+
+char*
+avdInfo_getTracePath( AvdInfo* i, const char* traceName )
+{
+ char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
+
+ if (i == NULL || traceName == NULL || traceName[0] == 0)
+ return NULL;
+
+ if (i->inAndroidBuild) {
+ p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
+ i->androidOut, traceName );
+ } else {
+ p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
+ i->contentPath, traceName );
+ }
+ return ASTRDUP(tmp);
+}
diff --git a/android/avd/info.h b/android/avd/info.h
new file mode 100644
index 0000000..6cd97dc
--- /dev/null
+++ b/android/avd/info.h
@@ -0,0 +1,171 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef ANDROID_AVD_INFO_H
+#define ANDROID_AVD_INFO_H
+
+#include "android/utils/ini.h"
+#include "android/avd/hw-config.h"
+
+/* An Android Virtual Device (AVD for short) corresponds to a
+ * directory containing all kernel/disk images for a given virtual
+ * device, as well as information about its hardware capabilities,
+ * SDK version number, skin, etc...
+ *
+ * Each AVD has a human-readable name and is backed by a root
+ * configuration file and a content directory. For example, an
+ * AVD named 'foo' will correspond to the following:
+ *
+ * - a root configuration file named ~/.android/avd/foo.ini
+ * describing where the AVD's content can be found
+ *
+ * - a content directory like ~/.android/avd/foo/ containing all
+ * disk image and configuration files for the virtual device.
+ *
+ * the 'foo.ini' file should contain at least one line of the form:
+ *
+ * rootPath=<content-path>
+ *
+ * it may also contain other lines that cache stuff found in the
+ * content directory, like hardware properties or SDK version number.
+ *
+ * it is possible to move the content directory by updating the foo.ini
+ * file to point to the new location. This can be interesting when your
+ * $HOME directory is located on a network share or in a roaming profile
+ * (Windows), given that the content directory of a single virtual device
+ * can easily use more than 100MB of data.
+ *
+ */
+
+/* a macro used to define the list of disk images managed by the
+ * implementation. This macro will be expanded several times with
+ * varying definitions of _AVD_IMG
+ */
+#define AVD_IMAGE_LIST \
+ _AVD_IMG(KERNEL,"kernel-qemu","kernel") \
+ _AVD_IMG(RAMDISK,"ramdisk.img","ramdisk") \
+ _AVD_IMG(INITSYSTEM,"system.img","init system") \
+ _AVD_IMG(INITDATA,"userdata.img","init data") \
+ _AVD_IMG(USERSYSTEM,"system-qemu.img","user system") \
+ _AVD_IMG(USERDATA,"userdata-qemu.img", "user data") \
+ _AVD_IMG(CACHE,"cache.img","cache") \
+ _AVD_IMG(SDCARD,"sdcard.img","SD Card") \
+
+/* define the enumared values corresponding to each AVD image type
+ * examples are: AVD_IMAGE_KERNEL, AVD_IMAGE_SYSTEM, etc..
+ */
+#define _AVD_IMG(x,y,z) AVD_IMAGE_##x ,
+typedef enum {
+ AVD_IMAGE_LIST
+ AVD_IMAGE_MAX /* do not remove */
+} AvdImageType;
+#undef _AVD_IMG
+
+/* AvdInfo is an opaque structure used to model the information
+ * corresponding to a given AVD instance
+ */
+typedef struct AvdInfo AvdInfo;
+
+/* various flags used when creating an AvdInfo object */
+typedef enum {
+ /* use to force a data wipe */
+ AVDINFO_WIPE_DATA = (1 << 0),
+ /* use to ignore the cache partition */
+ AVDINFO_NO_CACHE = (1 << 1),
+ /* use to wipe cache partition, ignored if NO_CACHE is set */
+ AVDINFO_WIPE_CACHE = (1 << 2),
+ /* use to ignore ignore SDCard image (default or provided) */
+ AVDINFO_NO_SDCARD = (1 << 3),
+ /* use to wipe the system image with new initial values */
+ AVDINFO_WIPE_SYSTEM = (1 << 4),
+} AvdFlags;
+
+typedef struct {
+ unsigned flags;
+ const char* skinName;
+ const char* skinRootPath;
+ const char* forcePaths[AVD_IMAGE_MAX];
+} AvdInfoParams;
+
+/* Creates a new AvdInfo object from a name. Returns NULL if name is NULL
+ * or contains characters that are not part of the following list:
+ * letters, digits, underscores, dashes and periods
+ */
+AvdInfo* avdInfo_new( const char* name, AvdInfoParams* params );
+
+/* A special function used to setup an AvdInfo for use when starting
+ * the emulator from the Android build system. In this specific instance
+ * we're going to create temporary files to hold all writable image
+ * files, and activate all hardware features by default
+ *
+ * 'androidBuildRoot' must be the absolute path to the root of the
+ * Android build system (i.e. the 'android' directory)
+ *
+ * 'androidOut' must be the target-specific out directory where
+ * disk images will be looked for.
+ */
+AvdInfo* avdInfo_newForAndroidBuild( const char* androidBuildRoot,
+ const char* androidOut,
+ AvdInfoParams* params );
+
+/* Frees an AvdInfo object and the corresponding strings that may be
+ * returned by its getXXX() methods
+ */
+void avdInfo_free( AvdInfo* i );
+
+/* Return the name of the Android Virtual Device
+ */
+const char* avdInfo_getName( AvdInfo* i );
+
+/* Try to find the path of a given image file, returns NULL
+ * if the corresponding file could not be found. the string
+ * belongs to the AvdInfo object.
+ */
+const char* avdInfo_getImageFile( AvdInfo* i, AvdImageType imageType );
+
+/* Returns 1 if the corresponding image file is read-only
+ */
+int avdInfo_isImageReadOnly( AvdInfo* i, AvdImageType imageType );
+
+/* lock an image file if it is writable. returns 0 on success, or -1
+ * otherwise. note that if the file is read-only, it doesn't need to
+ * be locked and the function will return success.
+ */
+int avdInfo_lockImageFile( AvdInfo* i, AvdImageType imageType, int abortOnError);
+
+/* Manually set the path of a given image file. */
+void avdInfo_setImageFile( AvdInfo* i, AvdImageType imageType, const char* imagePath );
+
+/* Returns the path of the skin directory */
+/* the string belongs to the AvdInfo object */
+const char* avdInfo_getSkinPath( AvdInfo* i );
+
+/* Returns the name of the virtual device's skin */
+const char* avdInfo_getSkinName( AvdInfo* i );
+
+/* Returns the root skin directory for this device */
+const char* avdInfo_getSkinDir ( AvdInfo* i );
+
+/* Returns the content path of the virtual device */
+const char* avdInfo_getContentPath( AvdInfo* i );
+
+/* Returns TRUE iff in the Android build system */
+int avdInfo_inAndroidBuild( AvdInfo* i );
+
+/* Reads the AVD's hardware configuration into 'hw'. returns -1 on error, 0 otherwise */
+int avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw );
+
+/* Returns a *copy* of the path used to store trace 'foo'. result must be freed by caller */
+char* avdInfo_getTracePath( AvdInfo* i, const char* traceName );
+
+/* */
+
+#endif /* ANDROID_AVD_INFO_H */
diff --git a/android/build/binary.make b/android/build/binary.make
new file mode 100644
index 0000000..1c75d52
--- /dev/null
+++ b/android/build/binary.make
@@ -0,0 +1,34 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# definitions shared by host_executable.make and host_static_library.make
+#
+
+# the directory where we're going to place our object files
+LOCAL_OBJS_DIR := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE))
+LOCAL_OBJECTS :=
+LOCAL_CC ?= $(CC)
+LOCAL_C_SOURCES := $(filter %.c,$(LOCAL_SRC_FILES))
+LOCAL_OBJC_SOURCES := $(filter %.m,$(LOCAL_SRC_FILES))
+
+$(foreach src,$(LOCAL_C_SOURCES), \
+ $(eval $(call compile-c-source,$(src))) \
+)
+
+$(foreach src,$(LOCAL_OBJC_SOURCES), \
+ $(eval $(call compile-objc-source,$(src))) \
+)
+
+CLEAN_OBJS_DIRS += $(LOCAL_OBJS_DIR)
diff --git a/android/build/clear_vars.make b/android/build/clear_vars.make
new file mode 100644
index 0000000..a9289b0
--- /dev/null
+++ b/android/build/clear_vars.make
@@ -0,0 +1,30 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# called multiple times to clear variables used to define a given 'module'
+#
+LOCAL_NO_DEFAULT_COMPILER_FLAGS:=
+LOCAL_CC :=
+LOCAL_CXX :=
+LOCAL_CFLAGS :=
+LOCAL_LDFLAGS :=
+LOCAL_LDLIBS :=
+LOCAL_SRC_FILES :=
+LOCAL_MODULE :=
+LOCAL_MODULE_PATH:=
+LOCAL_STATIC_LIBRARIES :=
+LOCAL_BUILT_MODULE :=
+LOCAL_PREBUILT_OBJ_FILES :=
+
diff --git a/android/build/definitions.make b/android/build/definitions.make
new file mode 100644
index 0000000..cd03f89
--- /dev/null
+++ b/android/build/definitions.make
@@ -0,0 +1,109 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# shared definitions
+ifeq ($(strip $(SHOW)),)
+define pretty
+@echo $1
+endef
+hide := @
+else
+define pretty
+endef
+hide :=
+endif
+
+define my-dir
+.
+endef
+
+# return the directory containing the intermediate files for a given
+# kind of executable
+# $1 = type (EXECUTABLES or STATIC_LIBRARIES)
+# $2 = module name
+# $3 = ignored
+#
+define intermediates-dir-for
+$(OBJS_DIR)/intermediates/$(2)
+endef
+
+# Generate the full path of a given static library
+define library-path
+$(OBJS_DIR)/$(1).a
+endef
+
+define executable-path
+$(OBJS_DIR)/$(1)$(EXE)
+endef
+
+# Compile a C source file
+#
+define compile-c-source
+SRC:=$(1)
+OBJ:=$$(LOCAL_OBJS_DIR)/$$(SRC:%.c=%.o)
+LOCAL_OBJECTS += $$(OBJ)
+DEPENDENCY_DIRS += $$(dir $$(OBJ))
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CC := $$(LOCAL_CC)
+$$(OBJ): PRIVATE_OBJ := $$(OBJ)
+$$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
+$$(OBJ): PRIVATE_SRC := $$(SRC_PATH)/$$(SRC)
+$$(OBJ): PRIVATE_SRC0 := $$(SRC)
+$$(OBJ): $$(SRC_PATH)/$$(SRC)
+ @mkdir -p $$(dir $$(PRIVATE_OBJ))
+ @echo "Compile: $$(PRIVATE_MODULE) <= $$(PRIVATE_SRC0)"
+ $(hide) $$(PRIVATE_CC) $$(PRIVATE_CFLAGS) -c -o $$(PRIVATE_OBJ) -MMD -MP -MF $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_SRC)
+ $(hide) $$(SRC_PATH)/android/build/mkdeps.sh $$(PRIVATE_OBJ) $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_OBJ).d
+endef
+
+# Compile an Objective-C source file
+#
+define compile-objc-source
+SRC:=$(1)
+OBJ:=$$(LOCAL_OBJS_DIR)/$$(SRC:%.m=%.o)
+LOCAL_OBJECTS += $$(OBJ)
+DEPENDENCY_DIRS += $$(dir $$(OBJ))
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CC := $$(LOCAL_CC)
+$$(OBJ): PRIVATE_OBJ := $$(OBJ)
+$$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
+$$(OBJ): PRIVATE_SRC := $$(SRC_PATH)/$$(SRC)
+$$(OBJ): PRIVATE_SRC0 := $$(SRC)
+$$(OBJ): $$(SRC_PATH)/$$(SRC)
+ @mkdir -p $$(dir $$(PRIVATE_OBJ))
+ @echo "Compile: $$(PRIVATE_MODULE) <= $$(PRIVATE_SRC0)"
+ $(hide) $$(PRIVATE_CC) $$(PRIVATE_CFLAGS) -c -o $$(PRIVATE_OBJ) -MMD -MP -MF $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_SRC)
+ $(hide) $$(SRC_PATH)/android/build/mkdeps.sh $$(PRIVATE_OBJ) $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_OBJ).d
+endef
+
+# for now, we only use prebuilt SDL libraries, so copy them
+define copy-prebuilt-lib
+_SRC := $(1)
+_SRC1 := $$(notdir $$(_SRC))
+_DST := $$(OBJS_DIR)/$$(_SRC1)
+LIBRARIES += $$(_DST)
+$$(_DST): PRIVATE_DST := $$(_DST)
+$$(_DST): PRIVATE_SRC := $$(_SRC)
+$$(_DST): $$(_SRC)
+ @mkdir -p $$(dir $$(PRIVATE_DST))
+ @echo "Prebuilt: $$(PRIVATE_DST)"
+ $(hide) cp -f $$(PRIVATE_SRC) $$(PRIVATE_DST)
+endef
+
+define create-dir
+$(1):
+ mkdir -p $(1)
+endef
+
diff --git a/android/build/getdir.make b/android/build/getdir.make
new file mode 100644
index 0000000..a4dadd3
--- /dev/null
+++ b/android/build/getdir.make
@@ -0,0 +1,19 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# used to return in 'dir' the name of the current operating system
+# we really get the value from the configuration script
+#
+dir := $(HOST_OS)
diff --git a/android/build/host_executable.make b/android/build/host_executable.make
new file mode 100644
index 0000000..62f4762
--- /dev/null
+++ b/android/build/host_executable.make
@@ -0,0 +1,34 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# first, call a library containing all object files
+LOCAL_BUILT_MODULE := $(call executable-path,$(LOCAL_MODULE))
+LOCAL_CC ?= $(CC)
+include $(BUILD_SYSTEM)/binary.make
+
+LOCAL_LDLIBS := $(foreach lib,$(LOCAL_STATIC_LIBRARIES),$(call library-path,$(lib))) $(LOCAL_LDLIBS)
+
+$(LOCAL_BUILT_MODULE): PRIVATE_LDFLAGS := $(LDFLAGS) $(LOCAL_LDFLAGS)
+$(LOCAL_BUILT_MODULE): PRIVATE_LDLIBS := $(LOCAL_LDLIBS)
+$(LOCAL_BUILT_MODULE): PRIVATE_OBJS := $(LOCAL_OBJECTS)
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
+ @ mkdir -p $(dir $@)
+ @ echo "Executable: $@"
+ $(hide) $(LD) $(PRIVATE_LDFLAGS) -o $@ $(PRIVATE_LIBRARY) $(PRIVATE_OBJS) $(PRIVATE_LDLIBS)
+
+EXECUTABLES += $(LOCAL_BUILT_MODULE)
+$(LOCAL_BUILT_MODULE): $(foreach lib,$(LOCAL_STATIC_LIBRARIES),$(call library-path,$(lib)))
+
diff --git a/android/build/host_static_library.make b/android/build/host_static_library.make
new file mode 100644
index 0000000..3de5a99
--- /dev/null
+++ b/android/build/host_static_library.make
@@ -0,0 +1,35 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 a host executable, the name of the final executable should be
+# put in LOCAL_BUILT_MODULE for use by the caller
+#
+
+#$(info STATIC_LIBRARY SRCS=$(LOCAL_SRC_FILES))
+LOCAL_BUILT_MODULE := $(call library-path,$(LOCAL_MODULE))
+LOCAL_CC ?= $(CC)
+include $(BUILD_SYSTEM)/binary.make
+
+LOCAL_AR ?= $(AR)
+ARFLAGS := crs
+
+$(LOCAL_BUILT_MODULE): PRIVATE_AR := $(LOCAL_AR)
+$(LOCAL_BUILT_MODULE): PRIVATE_OBJECTS := $(LOCAL_OBJECTS)
+$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
+ @mkdir -p $(dir $@)
+ @echo "Library: $@"
+ $(hide) $(PRIVATE_AR) $(ARFLAGS) $@ $(PRIVATE_OBJECTS)
+
+LIBRARIES += $(LOCAL_BUILT_MODULE)
diff --git a/android/build/mkdeps.sh b/android/build/mkdeps.sh
new file mode 100755
index 0000000..abecec7
--- /dev/null
+++ b/android/build/mkdeps.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is used to transform the dependency files generated by GCC
+# For example, a typical .d file will have a line like:
+#
+# source.o: /full/path/to/source.c other.h headers.h
+# ...
+#
+# the script is used to replace 'source.o' to a full path, as in
+#
+# objs/intermediates/emulator/source.o: /full/path/to/source.c other.h headers.h
+#
+# parameters
+#
+# $1: object file (full path)
+# $2: source dependency file to modify (erased on success)
+# $3: target source dependency file
+#
+
+# quote the object path. we change a single '.' into
+# a '\.' since this will be parsed by sed.
+#
+OBJECT=`echo $1 | sed -e s/\\\\./\\\\\\\\./g`
+#echo OBJECT=$OBJECT
+
+OBJ_NAME=`basename $OBJECT`
+#echo OBJ_NAME=$OBJ_NAME
+
+# we replace $OBJ_NAME with $OBJECT only if $OBJ_NAME starts the line
+# that's because some versions of GCC (e.g. 4.2.3) already produce
+# a correct dependency line with the full path to the object file.
+# In this case, we don't want to touch anything
+#
+cat $2 | sed -e s%^$OBJ_NAME%$OBJECT%g > $3 && rm -f $2
+
+
+
diff --git a/android/charmap.c b/android/charmap.c
new file mode 100644
index 0000000..c8ed2d6
--- /dev/null
+++ b/android/charmap.c
@@ -0,0 +1,148 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/charmap.h"
+
+/* the following is automatically generated by the 'gen-charmap.py' script
+ * do not touch. the generation command was:
+ * gen-charmap.py qwerty.kcm qwerty2.kcm
+ */
+
+static const AKeyEntry _qwerty_keys[] =
+{
+ /* keycode base caps fn caps+fn number */
+
+ { kKeyCodeA , 'a', 'A', '#', 0x00, '#' },
+ { kKeyCodeB , 'b', 'B', '<', 0x00, '<' },
+ { kKeyCodeC , 'c', 'C', '9', 0x00E7, '9' },
+ { kKeyCodeD , 'd', 'D', '5', 0x00, '5' },
+ { kKeyCodeE , 'e', 'E', '2', 0x0301, '2' },
+ { kKeyCodeF , 'f', 'F', '6', 0x00A5, '6' },
+ { kKeyCodeG , 'g', 'G', '-', '_', '-' },
+ { kKeyCodeH , 'h', 'H', '[', '{', '[' },
+ { kKeyCodeI , 'i', 'I', '$', 0x0302, '$' },
+ { kKeyCodeJ , 'j', 'J', ']', '}', ']' },
+ { kKeyCodeK , 'k', 'K', '"', '~', '"' },
+ { kKeyCodeL , 'l', 'L', '\'', '`', '\'' },
+ { kKeyCodeM , 'm', 'M', '!', 0x00, '!' },
+ { kKeyCodeN , 'n', 'N', '>', 0x0303, '>' },
+ { kKeyCodeO , 'o', 'O', '(', 0x00, '(' },
+ { kKeyCodeP , 'p', 'P', ')', 0x00, ')' },
+ { kKeyCodeQ , 'q', 'Q', '*', 0x0300, '*' },
+ { kKeyCodeR , 'r', 'R', '3', 0x20AC, '3' },
+ { kKeyCodeS , 's', 'S', '4', 0x00DF, '4' },
+ { kKeyCodeT , 't', 'T', '+', 0x00A3, '+' },
+ { kKeyCodeU , 'u', 'U', '&', 0x0308, '&' },
+ { kKeyCodeV , 'v', 'V', '=', '^', '=' },
+ { kKeyCodeW , 'w', 'W', '1', 0x00, '1' },
+ { kKeyCodeX , 'x', 'X', '8', 0x00, '8' },
+ { kKeyCodeY , 'y', 'Y', '%', 0x00A1, '%' },
+ { kKeyCodeZ , 'z', 'Z', '7', 0x00, '7' },
+ { kKeyCodeComma , ',', ';', ';', '|', ',' },
+ { kKeyCodePeriod , '.', ':', ':', 0x2026, '.' },
+ { kKeyCodeAt , '@', '0', '0', 0x2022, '0' },
+ { kKeyCodeSlash , '/', '?', '?', '\\', '/' },
+ { kKeyCodeSpace , 0x20, 0x20, 0x9, 0x9, 0x20 },
+ { kKeyCodeNewline , 0xa, 0xa, 0xa, 0xa, 0xa },
+ { kKeyCodeTab , 0x9, 0x9, 0x9, 0x9, 0x9 },
+ { kKeyCode0 , '0', ')', '0', ')', '0' },
+ { kKeyCode1 , '1', '!', '1', '!', '1' },
+ { kKeyCode2 , '2', '@', '2', '@', '2' },
+ { kKeyCode3 , '3', '#', '3', '#', '3' },
+ { kKeyCode4 , '4', '$', '4', '$', '4' },
+ { kKeyCode5 , '5', '%', '5', '%', '5' },
+ { kKeyCode6 , '6', '^', '6', '^', '6' },
+ { kKeyCode7 , '7', '&', '7', '&', '7' },
+ { kKeyCode8 , '8', '*', '8', '*', '8' },
+ { kKeyCode9 , '9', '(', '9', '(', '9' },
+ { kKeyCodeGrave , '`', '~', '`', '~', '`' },
+ { kKeyCodeMinus , '-', '_', '-', '_', '-' },
+ { kKeyCodeEquals , '=', '+', '=', '+', '=' },
+ { kKeyCodeLeftBracket , '[', '{', '[', '{', '[' },
+ { kKeyCodeRightBracket , ']', '}', ']', '}', ']' },
+ { kKeyCodeBackslash , '\\', '|', '\\', '|', '\\' },
+ { kKeyCodeSemicolon , ';', ':', ';', ':', ';' },
+ { kKeyCodeApostrophe , '\'', '"', '\'', '"', '\'' },
+};
+
+static const AKeyCharmap _qwerty_charmap =
+{
+ _qwerty_keys,
+ 51,
+ "qwerty"
+};
+
+static const AKeyEntry _qwerty2_keys[] =
+{
+ /* keycode base caps fn caps+fn number */
+
+ { kKeyCodeA , 'a', 'A', 'a', 'A', 'a' },
+ { kKeyCodeB , 'b', 'B', 'b', 'B', 'b' },
+ { kKeyCodeC , 'c', 'C', 0x00e7, 0x00E7, 'c' },
+ { kKeyCodeD , 'd', 'D', '\'', '\'', '\'' },
+ { kKeyCodeE , 'e', 'E', '"', 0x0301, '"' },
+ { kKeyCodeF , 'f', 'F', '[', '[', '[' },
+ { kKeyCodeG , 'g', 'G', ']', ']', ']' },
+ { kKeyCodeH , 'h', 'H', '<', '<', '<' },
+ { kKeyCodeI , 'i', 'I', '-', 0x0302, '-' },
+ { kKeyCodeJ , 'j', 'J', '>', '>', '>' },
+ { kKeyCodeK , 'k', 'K', ';', '~', ';' },
+ { kKeyCodeL , 'l', 'L', ':', '`', ':' },
+ { kKeyCodeM , 'm', 'M', '%', 0x00, '%' },
+ { kKeyCodeN , 'n', 'N', 0x00, 0x0303, 'n' },
+ { kKeyCodeO , 'o', 'O', '+', '+', '+' },
+ { kKeyCodeP , 'p', 'P', '=', 0x00A5, '=' },
+ { kKeyCodeQ , 'q', 'Q', '|', 0x0300, '|' },
+ { kKeyCodeR , 'r', 'R', '`', 0x20AC, '`' },
+ { kKeyCodeS , 's', 'S', '\\', 0x00DF, '\\' },
+ { kKeyCodeT , 't', 'T', '{', 0x00A3, '}' },
+ { kKeyCodeU , 'u', 'U', '_', 0x0308, '_' },
+ { kKeyCodeV , 'v', 'V', 'v', 'V', 'v' },
+ { kKeyCodeW , 'w', 'W', '~', '~', '~' },
+ { kKeyCodeX , 'x', 'X', 'x', 'X', 'x' },
+ { kKeyCodeY , 'y', 'Y', '}', 0x00A1, '}' },
+ { kKeyCodeZ , 'z', 'Z', 'z', 'Z', 'z' },
+ { kKeyCodeComma , ',', '<', ',', ',', ',' },
+ { kKeyCodePeriod , '.', '>', '.', 0x2026, '.' },
+ { kKeyCodeAt , '@', '@', '@', 0x2022, '@' },
+ { kKeyCodeSlash , '/', '?', '?', '?', '/' },
+ { kKeyCodeSpace , 0x20, 0x20, 0x9, 0x9, 0x20 },
+ { kKeyCodeNewline , 0xa, 0xa, 0xa, 0xa, 0xa },
+ { kKeyCode0 , '0', ')', ')', ')', '0' },
+ { kKeyCode1 , '1', '!', '!', '!', '1' },
+ { kKeyCode2 , '2', '@', '@', '@', '2' },
+ { kKeyCode3 , '3', '#', '#', '#', '3' },
+ { kKeyCode4 , '4', '$', '$', '$', '4' },
+ { kKeyCode5 , '5', '%', '%', '%', '5' },
+ { kKeyCode6 , '6', '^', '^', '^', '6' },
+ { kKeyCode7 , '7', '&', '&', '&', '7' },
+ { kKeyCode8 , '8', '*', '*', '*', '8' },
+ { kKeyCode9 , '9', '(', '(', '(', '9' },
+ { kKeyCodeTab , 0x9, 0x9, 0x9, 0x9, 0x9 },
+ { kKeyCodeGrave , '`', '~', '`', '~', '`' },
+ { kKeyCodeMinus , '-', '_', '-', '_', '-' },
+ { kKeyCodeEquals , '=', '+', '=', '+', '=' },
+ { kKeyCodeLeftBracket , '[', '{', '[', '{', '[' },
+ { kKeyCodeRightBracket , ']', '}', ']', '}', ']' },
+ { kKeyCodeBackslash , '\\', '|', '\\', '|', '\\' },
+ { kKeyCodeSemicolon , ';', ':', ';', ':', ';' },
+ { kKeyCodeApostrophe , '\'', '"', '\'', '"', '\'' },
+};
+
+static const AKeyCharmap _qwerty2_charmap =
+{
+ _qwerty2_keys,
+ 51,
+ "qwerty2"
+};
+
+const AKeyCharmap* android_charmaps[2] = { &_qwerty_charmap , &_qwerty2_charmap };
+const int android_charmap_count = 2;
diff --git a/android/charmap.h b/android/charmap.h
new file mode 100644
index 0000000..f300e68
--- /dev/null
+++ b/android/charmap.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _android_charmap_h
+#define _android_charmap_h
+
+#include "linux_keycodes.h"
+
+/* Keep it consistent with linux/input.h */
+typedef enum {
+ kKeyCodeSoftLeft = KEY_SOFT1,
+ kKeyCodeSoftRight = KEY_SOFT2,
+ kKeyCodeHome = KEY_HOME,
+ kKeyCodeBack = KEY_BACK,
+ kKeyCodeCall = KEY_SEND,
+ kKeyCodeEndCall = KEY_END,
+ kKeyCode0 = KEY_0,
+ kKeyCode1 = KEY_1,
+ kKeyCode2 = KEY_2,
+ kKeyCode3 = KEY_3,
+ kKeyCode4 = KEY_4,
+ kKeyCode5 = KEY_5,
+ kKeyCode6 = KEY_6,
+ kKeyCode7 = KEY_7,
+ kKeyCode8 = KEY_8,
+ kKeyCode9 = KEY_9,
+ kKeyCodeStar = KEY_STAR,
+ kKeyCodePound = KEY_SHARP,
+ kKeyCodeDpadUp = KEY_UP,
+ kKeyCodeDpadDown = KEY_DOWN,
+ kKeyCodeDpadLeft = KEY_LEFT,
+ kKeyCodeDpadRight = KEY_RIGHT,
+ kKeyCodeDpadCenter = KEY_CENTER,
+ kKeyCodeVolumeUp = KEY_VOLUMEUP,
+ kKeyCodeVolumeDown = KEY_VOLUMEDOWN,
+ kKeyCodePower = KEY_POWER,
+ kKeyCodeCamera = KEY_CAMERA,
+ kKeyCodeClear = KEY_CLEAR,
+ kKeyCodeA = KEY_A,
+ kKeyCodeB = KEY_B,
+ kKeyCodeC = KEY_C,
+ kKeyCodeD = KEY_D,
+ kKeyCodeE = KEY_E,
+ kKeyCodeF = KEY_F,
+ kKeyCodeG = KEY_G,
+ kKeyCodeH = KEY_H,
+ kKeyCodeI = KEY_I,
+ kKeyCodeJ = KEY_J,
+ kKeyCodeK = KEY_K,
+ kKeyCodeL = KEY_L,
+ kKeyCodeM = KEY_M,
+ kKeyCodeN = KEY_N,
+ kKeyCodeO = KEY_O,
+ kKeyCodeP = KEY_P,
+ kKeyCodeQ = KEY_Q,
+ kKeyCodeR = KEY_R,
+ kKeyCodeS = KEY_S,
+ kKeyCodeT = KEY_T,
+ kKeyCodeU = KEY_U,
+ kKeyCodeV = KEY_V,
+ kKeyCodeW = KEY_W,
+ kKeyCodeX = KEY_X,
+ kKeyCodeY = KEY_Y,
+ kKeyCodeZ = KEY_Z,
+
+ kKeyCodeComma = KEY_COMMA,
+ kKeyCodePeriod = KEY_DOT,
+ kKeyCodeAltLeft = KEY_LEFTALT,
+ kKeyCodeAltRight = KEY_RIGHTALT,
+ kKeyCodeCapLeft = KEY_LEFTSHIFT,
+ kKeyCodeCapRight = KEY_RIGHTSHIFT,
+ kKeyCodeTab = KEY_TAB,
+ kKeyCodeSpace = KEY_SPACE,
+ kKeyCodeSym = KEY_COMPOSE,
+ kKeyCodeExplorer = KEY_WWW,
+ kKeyCodeEnvelope = KEY_MAIL,
+ kKeyCodeNewline = KEY_ENTER,
+ kKeyCodeDel = KEY_BACKSPACE,
+ kKeyCodeGrave = 399,
+ kKeyCodeMinus = KEY_MINUS,
+ kKeyCodeEquals = KEY_EQUAL,
+ kKeyCodeLeftBracket = KEY_LEFTBRACE,
+ kKeyCodeRightBracket = KEY_RIGHTBRACE,
+ kKeyCodeBackslash = KEY_BACKSLASH,
+ kKeyCodeSemicolon = KEY_SEMICOLON,
+ kKeyCodeApostrophe = KEY_APOSTROPHE,
+ kKeyCodeSlash = KEY_SLASH,
+ kKeyCodeAt = KEY_EMAIL,
+ kKeyCodeNum = KEY_NUM,
+ kKeyCodeHeadsetHook = KEY_HEADSETHOOK,
+ kKeyCodeFocus = KEY_FOCUS,
+ kKeyCodePlus = KEY_PLUS,
+ kKeyCodeMenu = KEY_MENU,
+ kKeyCodeNotification = KEY_NOTIFICATION,
+ kKeyCodeSearch = KEY_SEARCH,
+
+ kKeyCodeBtnMouse = BTN_MOUSE,
+
+ kKeyCodeOrientation0 = 77,
+ kKeyCodeOrientation90 = 78,
+ kKeyCodeOrientation180 = 79,
+ kKeyCodeOrientation270 = 80
+} AndroidKeyCode;
+
+
+/* this defines a structure used to describe an Android keyboard charmap */
+typedef struct AKeyEntry {
+ unsigned short code;
+ unsigned short base;
+ unsigned short caps;
+ unsigned short fn;
+ unsigned short caps_fn;
+ unsigned short number;
+} AKeyEntry;
+
+typedef struct {
+ const AKeyEntry* entries;
+ int num_entries;
+ char name[ 32 ];
+} AKeyCharmap;
+
+extern const int android_charmap_count;
+extern const AKeyCharmap* android_charmaps[];
+
+#endif /* _android_charmap_h */
diff --git a/android/cmdline-option.c b/android/cmdline-option.c
new file mode 100644
index 0000000..b773d9d
--- /dev/null
+++ b/android/cmdline-option.c
@@ -0,0 +1,255 @@
+#include "android/cmdline-option.h"
+#include "android/utils/debug.h"
+#include "android/utils/misc.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
+static const struct { const char* name; int flag; const char* text; }
+debug_tags[] = {
+ VERBOSE_TAG_LIST
+ { 0, 0, 0 }
+};
+
+static void parse_debug_tags( const char* tags );
+void parse_env_debug_tags( void );
+
+
+typedef struct {
+ const char* name;
+ int var_offset;
+ int var_is_param;
+ int var_is_config;
+} OptionInfo;
+
+#define OPTION(_name,_type,_config) \
+ { #_name, offsetof(AndroidOptions,_name), _type, _config },
+
+
+static const OptionInfo option_keys[] = {
+#define OPT_PARAM(_name,_template,_descr) OPTION(_name,1,0)
+#define OPT_FLAG(_name,_descr) OPTION(_name,0,0)
+#define CFG_PARAM(_name,_template,_descr) OPTION(_name,1,1)
+#define CFG_FLAG(_name,_descr) OPTION(_name,0,1)
+#include "android/cmdline-options.h"
+ { NULL, 0, 0, 0 }
+};
+
+int
+android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt )
+{
+ int nargs = *pargc-1;
+ char** aread = *pargv+1;
+ char** awrite = aread;
+
+ memset( opt, 0, sizeof *opt );
+
+ while (nargs > 0) {
+ char* arg;
+ char arg2_tab[64], *arg2 = arg2_tab;
+ int nn;
+
+ /* process @<name> as a special exception meaning
+ * '-avd <name>'
+ */
+ if (aread[0][0] == '@') {
+ opt->avd = aread[0]+1;
+ nargs--;
+ aread++;
+ continue;
+ }
+
+ /* anything that isn't an option past this points
+ * exits the loop
+ */
+ if (aread[0][0] != '-') {
+ break;
+ }
+
+ arg = aread[0]+1;
+
+ /* an option cannot contain an underscore */
+ if (strchr(arg, '_') != NULL) {
+ break;
+ }
+
+ nargs--;
+ aread++;
+
+ /* for backwards compatibility with previous versions */
+ if (!strcmp(arg, "verbose")) {
+ arg = "debug-init";
+ }
+
+ /* special handing for -debug <tags> */
+ if (!strcmp(arg, "debug")) {
+ if (nargs == 0) {
+ derror( "-debug must be followed by tags (see -help-verbose)\n");
+ exit(1);
+ }
+ nargs--;
+ parse_debug_tags(*aread++);
+ continue;
+ }
+
+ /* NOTE: variable tables map option names to values
+ * (e.g. field offsets into the AndroidOptions structure).
+ *
+ * however, the names stored in the table used underscores
+ * instead of dashes. this means that the command-line option
+ * '-foo-bar' will be associated to the name 'foo_bar' in
+ * this table, and will point to the field 'foo_bar' or
+ * AndroidOptions.
+ *
+ * as such, before comparing the current option to the
+ * content of the table, we're going to translate dashes
+ * into underscores.
+ */
+ arg2 = arg2_tab;
+ buffer_translate_char( arg2_tab, sizeof(arg2_tab),
+ arg, '-', '_');
+
+ /* special handling for -debug-<tag> and -debug-no-<tag> */
+ if (!memcmp(arg2, "debug_", 6)) {
+ int remove = 0;
+ unsigned long mask = 0;
+ arg2 += 6;
+ if (!memcmp(arg2, "no_", 3)) {
+ arg2 += 3;
+ remove = 1;
+ }
+ if (!strcmp(arg2, "all")) {
+ mask = ~0;
+ }
+ for (nn = 0; debug_tags[nn].name; nn++) {
+ if (!strcmp(arg2, debug_tags[nn].name)) {
+ mask = (1UL << debug_tags[nn].flag);
+ break;
+ }
+ }
+ if (remove)
+ android_verbose &= ~mask;
+ else
+ android_verbose |= mask;
+ continue;
+ }
+
+ /* look into our table of options
+ *
+ */
+ {
+ const OptionInfo* oo = option_keys;
+
+ for ( ; oo->name; oo++ ) {
+ if ( !strcmp( oo->name, arg2 ) ) {
+ void* field = (char*)opt + oo->var_offset;
+
+ if (oo->var_is_param) {
+ /* parameter option */
+ if (nargs == 0) {
+ derror( "-%s must be followed by parameter (see -help-%s)",
+ arg, arg );
+ exit(1);
+ }
+ nargs--;
+ ((char**)field)[0] = *aread++;
+ } else {
+ /* flag option */
+ ((int*)field)[0] = 1;
+ }
+ break;
+ }
+ }
+
+ if (oo->name == NULL) { /* unknown option ? */
+ nargs++;
+ aread--;
+ break;
+ }
+ }
+ }
+
+ /* copy remaining parameters, if any, to command line */
+ *pargc = nargs + 1;
+
+ while (nargs > 0) {
+ awrite[0] = aread[0];
+ awrite ++;
+ aread ++;
+ nargs --;
+ }
+
+ awrite[0] = NULL;
+
+ return 0;
+}
+
+
+
+/* special handling of -debug option and tags */
+#define ENV_DEBUG "ANDROID_DEBUG"
+
+static void
+parse_debug_tags( const char* tags )
+{
+ char* x;
+ char* y;
+ char* x0;
+
+ if (tags == NULL)
+ return;
+
+ x = x0 = strdup(tags);
+ while (*x) {
+ y = strchr(x, ',');
+ if (y == NULL)
+ y = x + strlen(x);
+ else
+ *y++ = 0;
+
+ if (y > x+1) {
+ int nn, remove = 0;
+ unsigned mask = 0;
+
+ if (x[0] == '-') {
+ remove = 1;
+ x += 1;
+ }
+
+ if (!strcmp( "all", x ))
+ mask = ~0;
+ else {
+ char temp[32];
+ buffer_translate_char(temp, sizeof temp, x, '-', '_');
+
+ for (nn = 0; debug_tags[nn].name != NULL; nn++) {
+ if ( !strcmp( debug_tags[nn].name, temp ) ) {
+ mask |= (1 << debug_tags[nn].flag);
+ break;
+ }
+ }
+ }
+
+ if (mask == 0)
+ dprint( "ignoring unknown " ENV_DEBUG " item '%s'", x );
+ else {
+ if (remove)
+ android_verbose &= ~mask;
+ else
+ android_verbose |= mask;
+ }
+ }
+ x = y;
+ }
+
+ free(x0);
+}
+
+void
+parse_env_debug_tags( void )
+{
+ const char* env = getenv( ENV_DEBUG );
+ parse_debug_tags( env );
+}
+
diff --git a/android/cmdline-option.h b/android/cmdline-option.h
new file mode 100644
index 0000000..b87144d
--- /dev/null
+++ b/android/cmdline-option.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_OPTION_H
+#define _ANDROID_OPTION_H
+
+/* define a structure that will hold all option variables
+ */
+typedef struct {
+#define OPT_PARAM(n,t,d) char* n;
+#define OPT_FLAG(n,d) int n;
+#include "android/cmdline-options.h"
+} AndroidOptions;
+
+
+/* parse command-line arguments options and remove them from (argc,argv)
+ * 'opt' will be set to the content of parsed options
+ * returns 0 on success, -1 on error (unknown option)
+ */
+extern int
+android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt );
+
+/* name of default keyset file */
+#define KEYSET_FILE "default.keyset"
+
+/* the default device DPI if none is specified by the skin
+ */
+#define DEFAULT_DEVICE_DPI 165
+
+/* default network settings for emulator */
+#define DEFAULT_NETSPEED "full"
+#define DEFAULT_NETDELAY "none"
+
+#endif /* _ANDROID_OPTION_H */
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
new file mode 100644
index 0000000..e38b081
--- /dev/null
+++ b/android/cmdline-options.h
@@ -0,0 +1,137 @@
+/* this header file can be included several times by the same source code.
+ * it contains the list of support command-line options for the Android
+ * emulator program
+ */
+#ifndef OPT_PARAM
+#error OPT_PARAM is not defined
+#endif
+#ifndef OPT_FLAG
+#error OPT_FLAG is not defined
+#endif
+#ifndef CFG_PARAM
+#define CFG_PARAM OPT_PARAM
+#endif
+#ifndef CFG_FLAG
+#define CFG_FLAG OPT_FLAG
+#endif
+
+/* required to ensure that the CONFIG_XXX macros are properly defined */
+//XXX#include "config.h"
+
+/* Some options acts like flags, while others must be followed by a parameter
+ * string. Nothing really new here.
+ *
+ * Some options correspond to AVD (Android Virtual Device) configuration
+ * and will be ignored if you start the emulator with the -avd <name> flag.
+ *
+ * However, if you use them with -avd-create <name>, these options will be
+ * recorded into the new AVD directory. Once an AVD is created, there is no
+ * way to change these options.
+ *
+ * Several macros are used to define options:
+ *
+ * OPT_FLAG( name, "description" )
+ * used to define a non-config flag option.
+ * * 'name' is the option suffix that must follow the dash (-)
+ * as well as the name of an integer variable whose value will
+ * be 1 if the flag is used, or 0 otherwise.
+ * * "description" is a short description string that will be
+ * displayed by 'emulator -help'.
+ *
+ * OPT_PARAM( name, "<param>", "description" )
+ * used to define a non-config parameter option
+ * * 'name' will point to a char* variable (NULL if option is unused)
+ * * "<param>" is a template for the parameter displayed by the help
+ * * 'varname' is the name of a char* variable that will point
+ * to the parameter string, if any, or will be NULL otherwise.
+ *
+ * CFG_FLAG( name, "description" )
+ * used to define a configuration-specific flag option.
+ *
+ * CFG_PARAM( name, "<param>", "description" )
+ * used to define a configuration-specific parameter option.
+ *
+ * NOTE: Keep in mind that optio names are converted by translating
+ * dashes into underscore.
+ *
+ * This means that '-some-option' is equivalent to '-some_option'
+ * and will be backed by a variable name 'some_option'
+ *
+ */
+
+CFG_PARAM( sysdir, "<dir>", "search for system disk images in <dir>" )
+CFG_PARAM( system, "<file>", "read initial system image from <file>" )
+CFG_PARAM( datadir, "<dir>", "write user data into <dir>" )
+CFG_PARAM( kernel, "<file>", "use specific emulated kernel" )
+CFG_PARAM( ramdisk, "<file>", "ramdisk image (default <system>/ramdisk.img" )
+CFG_PARAM( image, "<file>", "obsolete, use -system <file> instead" )
+CFG_PARAM( init_data, "<file>", "initial data image (default <system>/userdata.img" )
+CFG_PARAM( initdata, "<file>", "same as '-init-data <file>'" )
+CFG_PARAM( data, "<file>", "data image (default <datadir>/userdata-qemu.img" )
+CFG_PARAM( cache, "<file>", "cache partition image (default is temporary file)" )
+CFG_FLAG ( no_cache, "disable the cache partition" )
+CFG_FLAG ( nocache, "same as -no-cache" )
+OPT_PARAM( sdcard, "<file>", "SD card image (default <system>/sdcard.img")
+OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" )
+CFG_PARAM( avd, "<name>", "use a specific android virtual device" )
+CFG_PARAM( skindir, "<dir>", "search skins in <dir> (default <system>/skins)" )
+CFG_PARAM( skin, "<name>", "select a given skin" )
+CFG_FLAG ( no_skin, "don't use any emulator skin" )
+CFG_FLAG ( noskin, "same as -no-skin" )
+CFG_PARAM( memory, "<size>", "physical RAM size in MBs" )
+
+OPT_PARAM( netspeed, "<speed>", "maximum network download/upload speeds" )
+OPT_PARAM( netdelay, "<delay>", "network latency emulation" )
+OPT_FLAG ( netfast, "disable network shaping" )
+
+OPT_PARAM( trace, "<name>", "enable code profiling (F9 to start)" )
+OPT_FLAG ( show_kernel, "display kernel messages" )
+OPT_FLAG ( shell, "enable root shell on current terminal" )
+OPT_FLAG ( no_jni, "disable JNI checks in the Dalvik runtime" )
+OPT_FLAG ( nojni, "same as -no-jni" )
+OPT_PARAM( logcat, "<tags>", "enable logcat output with given tags" )
+
+OPT_FLAG ( no_audio, "disable audio support" )
+OPT_FLAG ( noaudio, "same as -no-audio" )
+OPT_PARAM( audio, "<backend>", "use specific audio backend" )
+OPT_PARAM( audio_in, "<backend>", "use specific audio input backend" )
+OPT_PARAM( audio_out,"<backend>", "use specific audio output backend" )
+
+OPT_FLAG ( raw_keys, "disable Unicode keyboard reverse-mapping" )
+OPT_PARAM( radio, "<device>", "redirect radio modem interface to character device" )
+OPT_PARAM( port, "<port>", "TCP port that will be used for the console" )
+OPT_PARAM( ports, "<consoleport>,<adbport>", "TCP ports used for the console and adb bridge" )
+OPT_PARAM( onion, "<image>", "use overlay PNG image over screen" )
+OPT_PARAM( onion_alpha, "<%age>", "specify onion-skin translucency" )
+OPT_PARAM( onion_rotation, "0|1|2|3", "specify onion-skin rotation" )
+
+OPT_PARAM( scale, "<scale>", "scale emulator window" )
+OPT_PARAM( dpi_device, "<dpi>", "specify device's resolution in dpi (default "
+ STRINGIFY(DEFAULT_DEVICE_DPI) ")" )
+
+OPT_PARAM( http_proxy, "<proxy>", "make TCP connections through a HTTP/HTTPS proxy" )
+OPT_PARAM( timezone, "<timezone>", "use this timezone instead of the host's default" )
+OPT_PARAM( dns_server, "<servers>", "use this DNS server(s) in the emulated system" )
+OPT_PARAM( cpu_delay, "<cpudelay>", "throttle CPU emulation" )
+OPT_FLAG ( no_boot_anim, "disable animation for faster boot" )
+
+OPT_FLAG( no_window, "disable graphical window display" )
+OPT_FLAG( version, "display emulator version number" )
+
+OPT_PARAM( report_console, "<socket>", "report console port to remote socket" )
+OPT_PARAM( gps, "<device>", "redirect NMEA GPS to character device" )
+OPT_PARAM( keyset, "<name>", "specify keyset file name" )
+OPT_PARAM( shell_serial, "<device>", "specific character device for root shell" )
+OPT_FLAG ( old_system, "support old (pre 1.4) system images" )
+OPT_PARAM( tcpdump, "<file>", "capture network packets to file" )
+
+#ifdef CONFIG_NAND_LIMITS
+OPT_PARAM( nand_limits, "<nlimits>", "enforce NAND/Flash read/write thresholds" )
+#endif
+
+OPT_PARAM( bootchart, "<timeout>", "enable bootcharting")
+
+#undef CFG_FLAG
+#undef CFG_PARAM
+#undef OPT_FLAG
+#undef OPT_PARAM
diff --git a/android/config.c b/android/config.c
new file mode 100644
index 0000000..36fab11
--- /dev/null
+++ b/android/config.c
@@ -0,0 +1,467 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "android/config.h"
+#include "android/utils/path.h"
+
+AConfig*
+aconfig_node(const char *name, const char *value)
+{
+ AConfig *n;
+
+ n = (AConfig*) calloc(sizeof(AConfig), 1);
+ n->name = name ? name : "";
+ n->value = value ? value : "";
+
+ return n;
+}
+
+static AConfig*
+_aconfig_find(AConfig *root, const char *name, int create)
+{
+ AConfig *node;
+
+ for(node = root->first_child; node; node = node->next) {
+ if(!strcmp(node->name, name)) return node;
+ }
+
+ if(create) {
+ node = (AConfig*) calloc(sizeof(AConfig), 1);
+ node->name = name;
+ node->value = "";
+
+ if(root->last_child) {
+ root->last_child->next = node;
+ } else {
+ root->first_child = node;
+ }
+ root->last_child = node;
+ }
+
+ return node;
+}
+
+AConfig*
+aconfig_find(AConfig *root, const char *name)
+{
+ return _aconfig_find(root, name, 0);
+}
+
+int
+aconfig_bool(AConfig *root, const char *name, int _default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ switch(n->value[0]){
+ case 'y':
+ case 'Y':
+ case '1':
+ return 1;
+ default:
+ return 0;
+ }
+ }
+}
+
+unsigned
+aconfig_unsigned(AConfig *root, const char *name, unsigned _default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ return strtoul(n->value, 0, 0);
+ }
+}
+
+int
+aconfig_int(AConfig *root, const char *name, int _default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ return strtol(n->value, 0, 0);
+ }
+}
+
+
+const char*
+aconfig_str(AConfig *root, const char *name, const char *_default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ return n->value;
+ }
+}
+
+void
+aconfig_set(AConfig *root, const char *name, const char *value)
+{
+ AConfig *node = _aconfig_find(root, name, 1);
+ node->value = value;
+}
+
+#define T_EOF 0
+#define T_TEXT 1
+#define T_DOT 2
+#define T_OBRACE 3
+#define T_CBRACE 4
+
+typedef struct
+{
+ char *data;
+ char *text;
+ int len;
+ char next;
+} cstate;
+
+
+static int _lex(cstate *cs, int value)
+{
+ char c;
+ char *s;
+ char *data;
+
+ data = cs->data;
+
+ if(cs->next != 0) {
+ c = cs->next;
+ cs->next = 0;
+ goto got_c;
+ }
+
+restart:
+ for(;;) {
+ c = *data++;
+ got_c:
+ if(isspace(c)) continue;
+
+ switch(c) {
+ case 0:
+ return T_EOF;
+
+ /* a sharp sign (#) starts a line comment and everything
+ * behind that is ignored until the end of line
+ */
+ case '#':
+ for(;;) {
+ switch(*data) {
+ case 0:
+ cs->data = data;
+ return T_EOF;
+ case '\n':
+ cs->data = data + 1;
+ goto restart;
+ default:
+ data++;
+ }
+ }
+ break;
+
+ case '.':
+ cs->data = data;
+ return T_DOT;
+
+ case '{':
+ cs->data = data;
+ return T_OBRACE;
+
+ case '}':
+ cs->data = data;
+ return T_CBRACE;
+
+ default:
+ s = data - 1;
+
+ if(value) {
+ /* if we're looking for a value, then take anything
+ * until the end of line. note that sharp signs do
+ * not start comments then. the result will be stripped
+ * from trailing whitespace.
+ */
+ for(;;) {
+ if(*data == 0) {
+ cs->data = data;
+ break;
+ }
+ if(*data == '\n') {
+ cs->data = data + 1;
+ *data-- = 0;
+ break;
+ }
+ data++;
+ }
+
+ /* strip trailing whitespace */
+ while(data > s){
+ if(!isspace(*data)) break;
+ *data-- = 0;
+ }
+
+ goto got_text;
+ } else {
+ /* looking for a key name. we stop at whitspace,
+ * EOF, of T_DOT/T_OBRACE/T_CBRACE characters.
+ * note that the name can include sharp signs
+ */
+ for(;;) {
+ if(isspace(*data)) {
+ *data = 0;
+ cs->data = data + 1;
+ goto got_text;
+ }
+ switch(*data) {
+ case 0:
+ cs->data = data;
+ goto got_text;
+ case '.':
+ case '{':
+ case '}':
+ cs->next = *data;
+ *data = 0;
+ cs->data = data + 1;
+ goto got_text;
+ default:
+ data++;
+ }
+ }
+ }
+ }
+ }
+
+got_text:
+ cs->text = s;
+ return T_TEXT;
+}
+
+#if 0
+char *TOKENNAMES[] = { "EOF", "TEXT", "DOT", "OBRACE", "CBRACE" };
+
+static int lex(cstate *cs, int value)
+{
+ int tok = _lex(cs, value);
+ printf("TOKEN(%d) %s %s\n", value, TOKENNAMES[tok],
+ tok == T_TEXT ? cs->text : "");
+ return tok;
+}
+#else
+#define lex(cs,v) _lex(cs,v)
+#endif
+
+static int parse_expr(cstate *cs, AConfig *node);
+
+static int
+parse_block(cstate *cs, AConfig *node)
+{
+ for(;;){
+ switch(lex(cs, 0)){
+ case T_TEXT:
+ if(parse_expr(cs, node)) return -1;
+ continue;
+
+ case T_CBRACE:
+ return 0;
+
+ default:
+ return -1;
+ }
+ }
+}
+
+static int
+parse_expr(cstate *cs, AConfig *node)
+{
+ /* last token was T_TEXT */
+ node = _aconfig_find(node, cs->text, 1);
+
+ for(;;) {
+ switch(lex(cs, 1)) {
+ case T_DOT:
+ if(lex(cs, 0) != T_TEXT) return -1;
+ node = _aconfig_find(node, cs->text, 1);
+ continue;
+
+ case T_TEXT:
+ node->value = cs->text;
+ return 0;
+
+ case T_OBRACE:
+ return parse_block(cs, node);
+
+ default:
+ return -1;
+ }
+ }
+}
+
+void
+aconfig_load(AConfig *root, char *data)
+{
+ if(data != 0) {
+ cstate cs;
+ cs.data = data;
+ cs.next = 0;
+
+ for(;;) {
+ switch(lex(&cs, 0)){
+ case T_TEXT:
+ if(parse_expr(&cs, root)) return;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+}
+
+int
+aconfig_load_file(AConfig *root, const char *fn)
+{
+ char *data;
+ data = path_load_file(fn, NULL);
+ if (data == NULL)
+ return -1;
+
+ aconfig_load(root, data);
+ return 0;
+}
+
+
+typedef struct
+{
+ char buff[1024];
+ char* p;
+ char* end;
+ int fd;
+} Writer;
+
+static int
+writer_init( Writer* w, const char* fn )
+{
+ w->p = w->buff;
+ w->end = w->buff + sizeof(w->buff);
+
+ w->fd = creat( fn, 0755 );
+ if (w->fd < 0)
+ return -1;
+
+#ifdef _WIN32
+ _setmode( w->fd, _O_BINARY );
+#endif
+ return 0;
+}
+
+static void
+writer_write( Writer* w, const char* src, int len )
+{
+ while (len > 0) {
+ int avail = w->end - w->p;
+
+ if (avail > len)
+ avail = len;
+
+ memcpy( w->p, src, avail );
+ src += avail;
+ len -= avail;
+
+ w->p += avail;
+ if (w->p == w->end) {
+ write( w->fd, w->buff, w->p - w->buff );
+ w->p = w->buff;
+ }
+ }
+}
+
+static void
+writer_done( Writer* w )
+{
+ if (w->p > w->buff)
+ write( w->fd, w->buff, w->p - w->buff );
+ close( w->fd );
+}
+
+static void
+writer_margin( Writer* w, int margin)
+{
+ static const char spaces[10] = " ";
+ while (margin >= 10) {
+ writer_write(w,spaces,10);
+ margin -= 10;
+ }
+ if (margin > 0)
+ writer_write(w,spaces,margin);
+}
+
+static void
+writer_c(Writer* w, char c)
+{
+ writer_write(w, &c, 1);
+}
+
+static void
+writer_str(Writer* w, const char* str)
+{
+ writer_write(w, str, strlen(str));
+}
+
+static void
+writer_node(Writer* w, AConfig* node, int margin)
+{
+ writer_margin(w,margin);
+ writer_str(w, node->name);
+ writer_c(w,' ');
+
+ if (node->value[0]) {
+ writer_str(w, node->value);
+ writer_c(w,'\n');
+ }
+ else
+ {
+ AConfig* child;
+
+ writer_c(w, '{');
+ writer_c(w, '\n');
+
+ for (child = node->first_child; child; child = child->next)
+ writer_node(w,child,margin+4);
+
+ writer_margin(w,margin);
+ writer_c(w,'}');
+ writer_c(w,'\n');
+ }
+}
+
+int
+aconfig_save_file(AConfig *root, const char *fn)
+{
+ AConfig* child;
+ Writer w[1];
+
+ if (writer_init(w,fn) < 0)
+ return -1;
+
+ for (child = root->first_child; child; child = child->next)
+ writer_node(w,child,0);
+
+ writer_done(w);
+ return 0;
+}
diff --git a/android/config.h b/android/config.h
new file mode 100644
index 0000000..5e8b048
--- /dev/null
+++ b/android/config.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef ANDROID_CONFIG_H
+#define ANDROID_CONFIG_H
+
+/** ANDROID CONFIGURATION FILE SUPPORT
+ **
+ ** A configuration file is loaded as a simplre tree of (key,value)
+ ** pairs. keys and values are simple strings
+ **/
+typedef struct AConfig AConfig;
+
+struct AConfig
+{
+ AConfig* next;
+ AConfig* first_child;
+ AConfig* last_child;
+ const char* name;
+ const char* value;
+};
+
+/* parse a text string into a config node tree */
+extern void aconfig_load(AConfig* root, char* data);
+
+/* parse a file into a config node tree, return 0 in case of success, -1 otherwise */
+extern int aconfig_load_file(AConfig* root, const char* path);
+
+/* save a config node tree into a file, return 0 in case of success, -1 otherwise */
+extern int aconfig_save_file(AConfig* root, const char* path);
+
+/* create a single config node */
+extern AConfig* aconfig_node(const char *name, const char *value);
+
+/* locate a named child of a config node */
+extern AConfig* aconfig_find(AConfig *root, const char *name);
+
+/* add a named child to a config node (or modify it if it already exists) */
+extern void aconfig_set(AConfig *root, const char *name, const char *value);
+
+
+/* look up a child by name and return its value, eventually converted
+ * into a boolean or integer */
+extern int aconfig_bool (AConfig *root, const char *name, int _default);
+extern unsigned aconfig_unsigned(AConfig *root, const char *name, unsigned _default);
+extern int aconfig_int (AConfig *root, const char *name, int _default);
+extern const char* aconfig_str (AConfig *root, const char *name, const char *_default);
+
+#endif /* ANDROID_CONFIG_H */
diff --git a/android/config/Linux/config-host.h b/android/config/Linux/config-host.h
new file mode 100644
index 0000000..90defbd
--- /dev/null
+++ b/android/config/Linux/config-host.h
@@ -0,0 +1,10 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_I386 1
+#define HOST_LONG_BITS 32
+#define HAVE_BYTESWAP_H 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/check-alsa.c b/android/config/check-alsa.c
new file mode 100644
index 0000000..4ab2945
--- /dev/null
+++ b/android/config/check-alsa.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <dlfcn.h>
+#include <stdio.h>
+#include <alsa/asoundlib.h>
+
+#define D(...) fprintf(stderr,__VA_ARGS__)
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define DYN_SYMBOLS \
+ DYN_FUNCTION(size_t,snd_pcm_sw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(size_t,snd_pcm_hw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_prepare,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_drop,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(const char*,snd_strerror,(int errnum)) \
+ DYN_FUNCTION(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \
+ DYN_FUNCTION(int,snd_pcm_close,(snd_pcm_t *pcm)) \
+
+
+
+/* define pointers to library functions we're going to use */
+#define DYN_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+DYN_SYMBOLS
+
+#undef DYN_FUNCTION
+
+#define func_snd_pcm_hw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(func_snd_pcm_hw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_hw_params_sizeof()); } while (0)
+
+#define func_snd_pcm_sw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(func_snd_pcm_sw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_sw_params_sizeof()); } while (0)
+
+static void* alsa_lib;
+
+int main(void)
+{
+ int result = 1;
+
+ alsa_lib = dlopen( "libasound.so", RTLD_NOW );
+ if (alsa_lib == NULL)
+ alsa_lib = dlopen( "libasound.so.2", RTLD_NOW );
+
+ if (alsa_lib == NULL) {
+ D("could not find libasound on this system\n");
+ return 1;
+ }
+
+#undef DYN_FUNCTION
+#define DYN_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( alsa_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ D("could not find %s in libasound\n", STRINGIFY(name)); \
+ goto Fail; \
+ } \
+ } while (0);
+
+ DYN_SYMBOLS
+
+ result = 0;
+ goto Exit;
+
+Fail:
+ D("failed to open library\n");
+
+Exit:
+ dlclose(alsa_lib);
+ return result;
+}
diff --git a/android/config/check-esd.c b/android/config/check-esd.c
new file mode 100644
index 0000000..a8eb11b
--- /dev/null
+++ b/android/config/check-esd.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* this file is used to test that we can use libesd with lazy dynamic linking */
+
+#include <esd.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+#define D(...) fprintf(stderr,__VA_ARGS__)
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define ESD_SYMBOLS \
+ ESD_FUNCTION(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_open_sound,( const char *host )) \
+ ESD_FUNCTION(int,esd_close,(int)) \
+
+/* define pointers to library functions we're going to use */
+#define ESD_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+ESD_SYMBOLS
+
+#undef ESD_FUNCTION
+static void* esd_lib;
+
+int main( void )
+{
+ int fd;
+
+ esd_lib = dlopen( "libesd.so", RTLD_NOW );
+ if (esd_lib == NULL)
+ esd_lib = dlopen( "libesd.so.0", RTLD_NOW );
+
+ if (esd_lib == NULL) {
+ D("could not find libesd on this system");
+ return 1;
+ }
+
+#undef ESD_FUNCTION
+#define ESD_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( esd_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ D("could not find %s in libesd\n", STRINGIFY(name)); \
+ return 1; \
+ } \
+ } while (0);
+
+ ESD_SYMBOLS
+
+ return 0;
+}
diff --git a/android/config/config.h b/android/config/config.h
new file mode 100644
index 0000000..be83607
--- /dev/null
+++ b/android/config/config.h
@@ -0,0 +1,14 @@
+/* Automatically generated by configure - do not modify */
+#include "config-host.h"
+#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-arm"
+#define TARGET_ARCH "arm"
+#define TARGET_ARM 1
+#define CONFIG_TRACE 1
+#define CONFIG_NAND 1
+#define CONFIG_SHAPER 1
+#define CONFIG_SOFTMMU 1
+#define CONFIG_SOFTFLOAT 1
+#define CONFIG_SDL 1
+#ifndef _WIN32
+#define CONFIG_NAND_LIMITS 1
+#endif
diff --git a/android/config/darwin-ppc/config-host.h b/android/config/darwin-ppc/config-host.h
new file mode 100644
index 0000000..cbd43d1
--- /dev/null
+++ b/android/config/darwin-ppc/config-host.h
@@ -0,0 +1,13 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_PPC 1
+#define HOST_LONG_BITS 32
+#define CONFIG_DARWIN 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define O_LARGEFILE 0
+#define MAP_ANONYMOUS MAP_ANON
+#define _BSD 1
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/darwin-x86/config-host.h b/android/config/darwin-x86/config-host.h
new file mode 100644
index 0000000..aaf0195
--- /dev/null
+++ b/android/config/darwin-x86/config-host.h
@@ -0,0 +1,13 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_I386 1
+#define HOST_LONG_BITS 32
+#define CONFIG_DARWIN 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define O_LARGEFILE 0
+#define MAP_ANONYMOUS MAP_ANON
+#define _BSD 1
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/linux-x86/config-host.h b/android/config/linux-x86/config-host.h
new file mode 100644
index 0000000..90defbd
--- /dev/null
+++ b/android/config/linux-x86/config-host.h
@@ -0,0 +1,10 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_I386 1
+#define HOST_LONG_BITS 32
+#define HAVE_BYTESWAP_H 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/windows/config-host.h b/android/config/windows/config-host.h
new file mode 100644
index 0000000..8f9e0d9
--- /dev/null
+++ b/android/config/windows/config-host.h
@@ -0,0 +1,10 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_I386 1
+#define HOST_LONG_BITS 32
+#define CONFIG_WIN32 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/console.c b/android/console.c
new file mode 100644
index 0000000..3a769c1
--- /dev/null
+++ b/android/console.c
@@ -0,0 +1,2190 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+/*
+ * Android emulator control console
+ *
+ * this console is enabled automatically at emulator startup, on port 5554 by default,
+ * unless some other emulator is already running. See (android_emulation_start in android_sdl.c
+ * for details)
+ *
+ * you can telnet to the console, then use commands like 'help' or others to dynamically
+ * change emulator settings.
+ *
+ */
+
+#include "sockets.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "android/android.h"
+#include "sockets.h"
+#include "cpu.h"
+#include "hw/goldfish_device.h"
+#include "hw/power_supply.h"
+#include "shaper.h"
+#include "modem_driver.h"
+#include "android/gps.h"
+#include "android/globals.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+#include "android/utils/stralloc.h"
+#include "tcpdump.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "android/hw-events.h"
+#include "android/skin/keyboard.h"
+
+#if defined(CONFIG_SLIRP)
+#include "libslirp.h"
+#endif
+
+/* set to 1 to use the i/o and event functions
+ * defined in "telephony/sysdeps.h"
+ */
+#define USE_SYSDEPS 0
+
+#include "sysdeps.h"
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(console)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(x) do { if (D_ACTIVE) ( printf x , fflush(stdout) ); } while (0)
+#else
+# define D(x) do{}while(0)
+#endif
+
+extern int slirp_inited; /* in vl.c */
+
+typedef struct ControlGlobalRec_* ControlGlobal;
+
+typedef struct ControlClientRec_* ControlClient;
+
+typedef struct {
+ int host_port;
+ int host_udp;
+ unsigned int guest_ip;
+ int guest_port;
+} RedirRec, *Redir;
+
+
+#if USE_SYSDEPS
+typedef SysChannel Socket;
+#else /* !USE_SYSDEPS */
+typedef int Socket;
+#endif /* !USE_SYSDEPS */
+
+
+typedef struct ControlClientRec_
+{
+ struct ControlClientRec_* next; /* next client in list */
+ Socket sock; /* socket used for communication */
+ ControlGlobal global;
+ char finished;
+ char buff[ 4096 ];
+ int buff_len;
+
+} ControlClientRec;
+
+
+typedef struct ControlGlobalRec_
+{
+ /* listening socket */
+ Socket listen_fd;
+
+ /* the list of current clients */
+ ControlClient clients;
+
+ /* the list of redirections currently active */
+ Redir redirs;
+ int num_redirs;
+ int max_redirs;
+
+} ControlGlobalRec;
+
+
+static int
+control_global_add_redir( ControlGlobal global,
+ int host_port,
+ int host_udp,
+ unsigned int guest_ip,
+ int guest_port )
+{
+ Redir redir;
+
+ if (global->num_redirs >= global->max_redirs)
+ {
+ int old_max = global->max_redirs;
+ int new_max = old_max + (old_max >> 1) + 4;
+
+ Redir new_redirs = realloc( global->redirs, new_max*sizeof(global->redirs[0]) );
+ if (new_redirs == NULL)
+ return -1;
+
+ global->redirs = new_redirs;
+ global->max_redirs = new_max;
+ }
+
+ redir = &global->redirs[ global->num_redirs++ ];
+
+ redir->host_port = host_port;
+ redir->host_udp = host_udp;
+ redir->guest_ip = guest_ip;
+ redir->guest_port = guest_port;
+
+ return 0;
+}
+
+static int
+control_global_del_redir( ControlGlobal global,
+ int host_port,
+ int host_udp )
+{
+ int nn;
+
+ for (nn = 0; nn < global->num_redirs; nn++)
+ {
+ Redir redir = &global->redirs[nn];
+
+ if ( redir->host_port == host_port &&
+ redir->host_udp == host_udp )
+ {
+ memmove( redir, redir + 1, ((global->num_redirs - nn)-1)*sizeof(*redir) );
+ global->num_redirs -= 1;
+ return 0;
+ }
+ }
+ /* we didn't find it */
+ return -1;
+}
+
+static void
+control_client_destroy( ControlClient client )
+{
+ ControlGlobal global = client->global;
+ ControlClient *pnode = &global->clients;
+
+ D(( "destroying control client %p\n", client ));
+
+#if USE_SYSDEPS
+ sys_channel_on( client->sock, 0, NULL, NULL );
+#else
+ qemu_set_fd_handler( client->sock, NULL, NULL, NULL );
+#endif
+
+ for ( ;; ) {
+ ControlClient node = *pnode;
+ if ( node == NULL )
+ break;
+ if ( node == client ) {
+ *pnode = node->next;
+ node->next = NULL;
+ break;
+ }
+ pnode = &node->next;
+ }
+
+#if USE_SYSDEPS
+ sys_channel_close( client->sock );
+ client->sock = NULL;
+#else
+ socket_close( client->sock );
+ client->sock = -1;
+#endif
+
+ free( client );
+}
+
+static void control_client_read( void* _client ); /* forward */
+
+
+static void control_control_write( ControlClient client, const char* buff, int len )
+{
+ int ret;
+
+ if (len < 0)
+ len = strlen(buff);
+
+ while (len > 0) {
+#if USE_SYSDEPS
+ ret = sys_channel_write( client->sock, buff, len );
+#else
+ ret = socket_send( client->sock, buff, len);
+#endif
+ if (ret < 0) {
+ if (errno != EINTR && errno != EWOULDBLOCK)
+ return;
+ } else {
+ buff += ret;
+ len -= ret;
+ }
+ }
+}
+
+static void control_write( ControlClient client, const char* format, ... )
+{
+ static char temp[1024];
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf( temp, sizeof(temp), format, args );
+ va_end(args);
+
+ temp[ sizeof(temp)-1 ] = 0;
+
+ control_control_write( client, temp, -1 );
+}
+
+
+static ControlClient
+control_client_create( Socket socket,
+ ControlGlobal global )
+{
+ ControlClient client = calloc( sizeof(*client), 1 );
+
+ if (client) {
+#if !USE_SYSDEPS
+ socket_set_nodelay( socket );
+ socket_set_nonblock( socket );
+#endif
+ client->finished = 0;
+ client->global = global;
+ client->sock = socket;
+ client->next = global->clients;
+ global->clients = client;
+
+#if USE_SYSDEPS
+ sys_channel_on( socket, SYS_EVENT_READ,
+ (SysChannelCallback) control_client_read,
+ client );
+#else
+ qemu_set_fd_handler( socket, control_client_read, NULL, client );
+#endif
+ }
+ return client;
+}
+
+typedef const struct CommandDefRec_ *CommandDef;
+
+typedef struct CommandDefRec_ {
+ const char* names;
+ const char* abstract;
+ const char* description;
+ void (*descriptor)( ControlClient client );
+ int (*handler)( ControlClient client, char* args );
+ CommandDef subcommands; /* if handler is NULL */
+
+} CommandDefRec;
+
+static const CommandDefRec main_commands[]; /* forward */
+
+static CommandDef
+find_command( char* input, CommandDef commands, char* *pend, char* *pargs )
+{
+ int nn;
+ char* args = strchr(input, ' ');
+
+ if (args != NULL) {
+ while (*args == ' ')
+ args++;
+
+ if (args[0] == 0)
+ args = NULL;
+ }
+
+ for (nn = 0; commands[nn].names != NULL; nn++)
+ {
+ const char* name = commands[nn].names;
+ const char* sep;
+
+ do {
+ int len, c;
+
+ sep = strchr( name, '|' );
+ if (sep)
+ len = sep - name;
+ else
+ len = strlen(name);
+
+ c = input[len];
+ if ( !memcmp( name, input, len ) && (c == ' ' || c == 0) ) {
+ *pend = input + len;
+ *pargs = args;
+ return &commands[nn];
+ }
+
+ if (sep)
+ name = sep + 1;
+
+ } while (sep != NULL && *name);
+ }
+ /* NOTE: don't touch *pend and *pargs if no command is found */
+ return NULL;
+}
+
+static void
+dump_help( ControlClient client,
+ CommandDef cmd,
+ const char* prefix )
+{
+ if (cmd->description) {
+ control_write( client, "%s", cmd->description );
+ } else if (cmd->descriptor) {
+ cmd->descriptor( client );
+ } else
+ control_write( client, "%s\r\n", cmd->abstract );
+
+ if (cmd->subcommands) {
+ cmd = cmd->subcommands;
+ control_write( client, "\r\navailable sub-commands:\r\n" );
+ for ( ; cmd->names != NULL; cmd++ ) {
+ control_write( client, " %s %-15s %s\r\n", prefix, cmd->names, cmd->abstract );
+ }
+ control_write( client, "\r\n" );
+ }
+}
+
+static void
+control_client_do_command( ControlClient client )
+{
+ char* line = client->buff;
+ char* args = NULL;
+ CommandDef commands = main_commands;
+ char* cmdend = client->buff;
+ CommandDef cmd = find_command( line, commands, &cmdend, &args );
+
+ if (cmd == NULL) {
+ control_write( client, "KO: unknown command, try 'help'\r\n" );
+ return;
+ }
+
+ for (;;) {
+ CommandDef subcmd;
+
+ if (cmd->handler) {
+ if ( !cmd->handler( client, args ) )
+ control_write( client, "OK\r\n" );
+ break;
+ }
+
+ /* no handler means we should have sub-commands */
+ if (cmd->subcommands == NULL) {
+ control_write( client, "KO: internal error: buggy command table for '%.*s'\r\n",
+ cmdend - client->buff, client->buff );
+ break;
+ }
+
+ /* we need a sub-command here */
+ if ( !args ) {
+ dump_help( client, cmd, "" );
+ control_write( client, "KO: missing sub-command\r\n" );
+ break;
+ }
+
+ line = args;
+ commands = cmd->subcommands;
+ subcmd = find_command( line, commands, &cmdend, &args );
+ if (subcmd == NULL) {
+ dump_help( client, cmd, "" );
+ control_write( client, "KO: bad sub-command\r\n" );
+ break;
+ }
+ cmd = subcmd;
+ }
+}
+
+/* implement the 'help' command */
+static int
+do_help( ControlClient client, char* args )
+{
+ char* line;
+ char* start = args;
+ char* end = start;
+ CommandDef cmd = main_commands;
+
+ /* without arguments, simply dump all commands */
+ if (args == NULL) {
+ control_write( client, "Android console command help:\r\n\r\n" );
+ for ( ; cmd->names != NULL; cmd++ ) {
+ control_write( client, " %-15s %s\r\n", cmd->names, cmd->abstract );
+ }
+ control_write( client, "\r\ntry 'help <command>' for command-specific help\r\n" );
+ return 0;
+ }
+
+ /* with an argument, find the corresponding command */
+ for (;;) {
+ CommandDef subcmd;
+
+ line = args;
+ subcmd = find_command( line, cmd, &end, &args );
+ if (subcmd == NULL) {
+ control_write( client, "try one of these instead:\r\n\r\n" );
+ for ( ; cmd->names != NULL; cmd++ ) {
+ control_write( client, " %.*s %s\r\n",
+ end - start, start, cmd->names );
+ }
+ control_write( client, "\r\nKO: unknown command\r\n" );
+ return -1;
+ }
+
+ if ( !args || !subcmd->subcommands ) {
+ dump_help( client, subcmd, start );
+ return 0;
+ }
+ cmd = subcmd->subcommands;
+ }
+}
+
+
+static void
+control_client_read_byte( ControlClient client, unsigned char ch )
+{
+ if (ch == '\r')
+ {
+ /* filter them out */
+ }
+ else if (ch == '\n')
+ {
+ client->buff[ client->buff_len ] = 0;
+ control_client_do_command( client );
+ if (client->finished)
+ return;
+
+ client->buff_len = 0;
+ }
+ else
+ {
+ if (client->buff_len >= sizeof(client->buff)-1)
+ client->buff_len = 0;
+
+ client->buff[ client->buff_len++ ] = ch;
+ }
+}
+
+static void
+control_client_read( void* _client )
+{
+ ControlClient client = _client;
+ unsigned char buf[4096];
+ int size;
+
+ D(( "in control_client read: " ));
+#if USE_SYSDEPS
+ size = sys_channel_read( client->sock, buf, sizeof(buf) );
+#else
+ size = socket_recv( client->sock, buf, sizeof(buf) );
+#endif
+ if (size < 0) {
+ D(( "size < 0, exiting with %d: %s\n", errno, errno_str ));
+ if (errno != EWOULDBLOCK && errno != EINTR)
+ control_client_destroy( client );
+ return;
+ }
+
+ if (size == 0) {
+ /* end of connection */
+ D(( "end of connection detected !!\n" ));
+ control_client_destroy( client );
+ }
+ else {
+ int nn;
+#ifdef _WIN32
+# if DEBUG
+ char temp[16];
+ int count = size > sizeof(temp)-1 ? sizeof(temp)-1 : size;
+ for (nn = 0; nn < count; nn++) {
+ int c = buf[nn];
+ if (c == '\n')
+ temp[nn] = '!';
+ else if (c < 32)
+ temp[nn] = '.';
+ else
+ temp[nn] = (char)c;
+ }
+ temp[nn] = 0;
+ D(( "received %d bytes: %s\n", size, temp ));
+# endif
+#else
+ D(( "received %.*s\n", size, buf ));
+#endif
+ for (nn = 0; nn < size; nn++) {
+ control_client_read_byte( client, buf[nn] );
+ if (client->finished) {
+ control_client_destroy(client);
+ return;
+ }
+ }
+ }
+}
+
+
+/* this function is called on each new client connection */
+static void
+control_global_accept( void* _global )
+{
+ ControlGlobal global = _global;
+ ControlClient client;
+ Socket fd;
+
+ D(( "control_global_accept: just in (fd=%p)\n", (void*)global->listen_fd ));
+
+#if USE_SYSDEPS
+ fd = sys_channel_create_tcp_handler( global->listen_fd );
+ if (fd == NULL) {
+ perror("accept");
+ return;
+ }
+#else
+ for(;;) {
+ fd = socket_accept( global->listen_fd, NULL );
+ if (fd < 0 && errno != EINTR) {
+ D(( "problem in accept: %d: %s\n", errno, errno_str ));
+ perror("accept");
+ return;
+ } else if (fd >= 0) {
+ break;
+ }
+ D(( "relooping in accept()\n" ));
+ }
+
+ socket_set_xreuseaddr( fd );
+#endif
+
+ D(( "control_global_accept: creating new client\n" ));
+ client = control_client_create( fd, global );
+ if (client) {
+ D(( "control_global_accept: new client %p\n", client ));
+ control_write( client, "Android Console: type 'help' for a list of commands\r\n" );
+ control_write( client, "OK\r\n" );
+ }
+}
+
+
+static int
+control_global_init( ControlGlobal global,
+ int control_port )
+{
+ Socket fd;
+#if !USE_SYSDEPS
+ int ret;
+ SockAddress sockaddr;
+#endif
+
+ memset( global, 0, sizeof(*global) );
+
+ sys_main_init();
+
+#if USE_SYSDEPS
+ fd = sys_channel_create_tcp_server( control_port );
+ if (fd == NULL) {
+ return -1;
+ }
+
+ D(("global fd=%p\n", fd));
+
+ global->listen_fd = fd;
+ sys_channel_on( fd, SYS_EVENT_READ,
+ (SysChannelCallback) control_global_accept,
+ global );
+#else
+ fd = socket_create_inet( SOCKET_STREAM );
+ if (fd < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ socket_set_xreuseaddr( fd );
+
+ sock_address_init_inet( &sockaddr, SOCK_ADDRESS_INET_LOOPBACK, control_port );
+
+ ret = socket_bind(fd, &sockaddr );
+ if (ret < 0) {
+ perror("bind");
+ socket_close( fd );
+ return -1;
+ }
+
+ ret = socket_listen(fd, 0);
+ if (ret < 0) {
+ perror("listen");
+ socket_close( fd );
+ return -1;
+ }
+
+ socket_set_nonblock(fd);
+
+ global->listen_fd = fd;
+
+ qemu_set_fd_handler( fd, control_global_accept, NULL, global );
+#endif
+ return 0;
+}
+
+
+
+static int
+do_quit( ControlClient client, char* args )
+{
+ client->finished = 1;
+ return -1;
+}
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** N E T W O R K S E T T I N G S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_network_status( ControlClient client, char* args )
+{
+ control_write( client, "Current network status:\r\n" );
+
+ control_write( client, " download speed: %8d bits/s (%.1f KB/s)\r\n",
+ (long)qemu_net_download_speed, qemu_net_download_speed/8192. );
+
+ control_write( client, " upload speed: %8d bits/s (%.1f KB/s)\r\n",
+ (long)qemu_net_upload_speed, qemu_net_upload_speed/8192. );
+
+ control_write( client, " minimum latency: %ld ms\r\n", qemu_net_min_latency );
+ control_write( client, " maximum latency: %ld ms\r\n", qemu_net_max_latency );
+ return 0;
+}
+
+static void
+dump_network_speeds( ControlClient client )
+{
+ const NetworkSpeed* speed = android_netspeeds;
+ const char* const format = " %-8s %s\r\n";
+ for ( ; speed->name; speed++ ) {
+ control_write( client, format, speed->name, speed->display );
+ }
+ control_write( client, format, "<num>", "selects both upload and download speed" );
+ control_write( client, format, "<up>:<down>", "select individual upload/download speeds" );
+}
+
+
+static int
+do_network_speed( ControlClient client, char* args )
+{
+ if ( !args ) {
+ control_write( client, "KO: missing <speed> argument, see 'help network speed'\r\n" );
+ return -1;
+ }
+ if ( android_parse_network_speed( args ) < 0 ) {
+ control_write( client, "KO: invalid <speed> argument, see 'help network speed' for valid values\r\n" );
+ return -1;
+ }
+
+ netshaper_set_rate( slirp_shaper_in, qemu_net_download_speed );
+ netshaper_set_rate( slirp_shaper_out, qemu_net_upload_speed );
+
+ if (android_modem) {
+ amodem_set_data_network_type( android_modem,
+ android_parse_network_type( args ) );
+ }
+ return 0;
+}
+
+static void
+describe_network_speed( ControlClient client )
+{
+ control_write( client,
+ "'network speed <speed>' allows you to dynamically change the speed of the emulated\r\n"
+ "network on the device, where <speed> is one of the following:\r\n\r\n" );
+ dump_network_speeds( client );
+}
+
+static int
+do_network_delay( ControlClient client, char* args )
+{
+ if ( !args ) {
+ control_write( client, "KO: missing <delay> argument, see 'help network delay'\r\n" );
+ return -1;
+ }
+ if ( android_parse_network_latency( args ) < 0 ) {
+ control_write( client, "KO: invalid <delay> argument, see 'help network delay' for valid values\r\n" );
+ return -1;
+ }
+ netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency );
+ return 0;
+}
+
+static void
+describe_network_delay( ControlClient client )
+{
+ control_write( client,
+ "'network delay <latency>' allows you to dynamically change the latency of the emulated\r\n"
+ "network on the device, where <latency> is one of the following:\r\n\r\n" );
+ /* XXX: TODO */
+}
+
+static int
+do_network_capture_start( ControlClient client, char* args )
+{
+ if ( !args ) {
+ control_write( client, "KO: missing <file> argument, see 'help network capture start'\r\n" );
+ return -1;
+ }
+ if ( qemu_tcpdump_start(args) < 0) {
+ control_write( client, "KO: could not start capture: %s", strerror(errno) );
+ return -1;
+ }
+ return 0;
+}
+
+static int
+do_network_capture_stop( ControlClient client, char* args )
+{
+ /* no need to return an error here */
+ qemu_tcpdump_stop();
+ return 0;
+}
+
+static const CommandDefRec network_capture_commands[] =
+{
+ { "start", "start network capture",
+ "'network capture start <file>' starts a new capture of network packets\r\n"
+ "into a specific <file>. This will stop any capture already in progress.\r\n"
+ "the capture file can later be analyzed by tools like WireShark. It uses\r\n"
+ "the libpcap file format.\r\n\r\n"
+ "you can stop the capture anytime with 'network capture stop'\r\n", NULL,
+ do_network_capture_start, NULL },
+
+ { "stop", "stop network capture",
+ "'network capture stop' stops a currently running packet capture, if any.\r\n"
+ "you can start one with 'network capture start <file>'\r\n", NULL,
+ do_network_capture_stop, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+static const CommandDefRec network_commands[] =
+{
+ { "status", "dump network status", NULL, NULL,
+ do_network_status, NULL },
+
+ { "speed", "change network speed", NULL, describe_network_speed,
+ do_network_speed, NULL },
+
+ { "delay", "change network latency", NULL, describe_network_delay,
+ do_network_delay, NULL },
+
+ { "capture", "dump network packets to file",
+ "allows to start/stop capture of network packets to a file for later analysis\r\n", NULL,
+ NULL, network_capture_commands },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** P O R T R E D I R E C T I O N S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_redir_list( ControlClient client, char* args )
+{
+ ControlGlobal global = client->global;
+
+ if (global->num_redirs == 0)
+ control_write( client, "no active redirections\r\n" );
+ else {
+ int nn;
+ for (nn = 0; nn < global->num_redirs; nn++) {
+ Redir redir = &global->redirs[nn];
+ control_write( client, "%s:%-5d => %-5d\r\n",
+ redir->host_udp ? "udp" : "tcp",
+ redir->host_port,
+ redir->guest_port );
+ }
+ }
+ return 0;
+}
+
+/* parse a protocol:port specification */
+static int
+redir_parse_proto_port( char* args, int *pport, int *pproto )
+{
+ int proto = -1;
+ int len = 0;
+ char* end;
+
+ if ( !memcmp( args, "tcp:", 4 ) ) {
+ proto = 0;
+ len = 4;
+ }
+ else if ( !memcmp( args, "udp:", 4 ) ) {
+ proto = 1;
+ len = 4;
+ }
+ else
+ return 0;
+
+ args += len;
+ *pproto = proto;
+ *pport = strtol( args, &end, 10 );
+ if (end == args)
+ return 0;
+
+ len += end - args;
+ return len;
+}
+
+static int
+redir_parse_guest_port( char* arg, int *pport )
+{
+ char* end;
+
+ *pport = strtoul( arg, &end, 10 );
+ if (end == arg)
+ return 0;
+
+ return end - arg;
+}
+
+static Redir
+redir_find( ControlGlobal global, int port, int isudp )
+{
+ int nn;
+
+ for (nn = 0; nn < global->num_redirs; nn++) {
+ Redir redir = &global->redirs[nn];
+
+ if (redir->host_port == port && redir->host_udp == isudp)
+ return redir;
+ }
+ return NULL;
+}
+
+
+static int
+do_redir_add( ControlClient client, char* args )
+{
+ int len, host_proto, host_port, guest_port;
+ uint32_t guest_ip;
+ Redir redir;
+
+ if ( !args )
+ goto BadFormat;
+
+ if (!slirp_inited) {
+ slirp_inited = 1;
+ slirp_init();
+ }
+
+ len = redir_parse_proto_port( args, &host_port, &host_proto );
+ if (len == 0 || args[len] != ':')
+ goto BadFormat;
+
+ args += len + 1;
+ len = redir_parse_guest_port( args, &guest_port );
+ if (len == 0 || args[len] != 0)
+ goto BadFormat;
+
+ redir = redir_find( client->global, host_port, host_proto );
+ if ( redir != NULL ) {
+ control_write( client, "KO: host port already active, use 'redir del' to remove first\r\n" );
+ return -1;
+ }
+
+ if (!inet_strtoip("10.0.2.15", &guest_ip)) {
+ control_write( client, "KO: unexpected internal failure when resolving 10.0.2.15\r\n" );
+ return -1;
+ }
+
+ D(("pattern hport=%d gport=%d proto=%d\n", host_port, guest_port, host_proto ));
+ if ( control_global_add_redir( client->global, host_port, host_proto,
+ guest_ip, guest_port ) < 0 )
+ {
+ control_write( client, "KO: not enough memory to allocate redirection\r\n" );
+ return -1;
+ }
+
+ if (slirp_redir(host_proto, host_port, guest_ip, guest_port) < 0) {
+ control_write( client, "KO: can't setup redirection, port probably used by another program on host\r\n" );
+ control_global_del_redir( client->global, host_port, host_proto );
+ return -1;
+ }
+
+ return 0;
+
+BadFormat:
+ control_write( client, "KO: bad redirection format, try (tcp|udp):hostport:guestport\r\n", -1 );
+ return -1;
+}
+
+
+static int
+do_redir_del( ControlClient client, char* args )
+{
+ int len, proto, port;
+ Redir redir;
+
+ if ( !args )
+ goto BadFormat;
+ len = redir_parse_proto_port( args, &port, &proto );
+ if ( len == 0 || args[len] != 0 )
+ goto BadFormat;
+
+ redir = redir_find( client->global, port, proto );
+ if (redir == NULL) {
+ control_write( client, "KO: can't remove unknown redirection (%s:%d)\r\n",
+ proto ? "udp" : "tcp", port );
+ return -1;
+ }
+
+ slirp_unredir( redir->host_udp, redir->host_port );
+ control_global_del_redir( client->global, port, proto );\
+
+ return 0;
+
+BadFormat:
+ control_write( client, "KO: bad redirection format, try (tcp|udp):hostport\r\n" );
+ return -1;
+}
+
+static const CommandDefRec redir_commands[] =
+{
+ { "list", "list current redirections",
+ "list current port redirections. use 'redir add' and 'redir del' to add and remove them\r\n", NULL,
+ do_redir_list, NULL },
+
+ { "add", "add new redirection",
+ "add a new port redirection, arguments must be:\r\n\r\n"
+ " redir add <protocol>:<host-port>:<guest-port>\r\n\r\n"
+ "where: <protocol> is either 'tcp' or 'udp'\r\n"
+ " <host-port> a number indicating which port on the host to open\r\n"
+ " <guest-port> a number indicating which port to route to on the device\r\n"
+ "\r\nas an example, 'redir tcp:5000:6000' will allow any packets sent to\r\n"
+ "the host's TCP port 5000 to be routed to TCP port 6000 of the emulated device\r\n", NULL,
+ do_redir_add, NULL },
+
+ { "del", "remove existing redirection",
+ "remove a port redirecion that was created with 'redir add', arguments must be:\r\n\r\n"
+ " redir del <protocol>:<host-port>\r\n\r\n"
+ "see the 'help redir add' for the meaning of <protocol> and <host-port>\r\n", NULL,
+ do_redir_del, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** G S M M O D E M ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static const struct {
+ const char* name;
+ const char* display;
+ ARegistrationState state;
+} _gsm_states[] = {
+ { "unregistered", "no network available", A_REGISTRATION_UNREGISTERED },
+ { "home", "on local network, non-roaming", A_REGISTRATION_HOME },
+ { "roaming", "on roaming network", A_REGISTRATION_ROAMING },
+ { "searching", "searching networks", A_REGISTRATION_SEARCHING },
+ { "denied", "emergency calls only", A_REGISTRATION_DENIED },
+ { "off", "same as 'unregistered'", A_REGISTRATION_UNREGISTERED },
+ { "on", "same as 'home'", A_REGISTRATION_HOME },
+ { NULL, NULL, A_REGISTRATION_UNREGISTERED }
+};
+
+static const char*
+gsm_state_to_string( ARegistrationState state )
+{
+ int nn;
+ for (nn = 0; _gsm_states[nn].name != NULL; nn++) {
+ if (state == _gsm_states[nn].state)
+ return _gsm_states[nn].name;
+ }
+ return "<unknown>";
+}
+
+static int
+do_gsm_status( ControlClient client, char* args )
+{
+ if (args) {
+ control_write( client, "KO: no argument required\r\n" );
+ return -1;
+ }
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ control_write( client, "gsm voice state: %s\r\n",
+ gsm_state_to_string(
+ amodem_get_voice_registration(android_modem) ) );
+ control_write( client, "gsm data state: %s\r\n",
+ gsm_state_to_string(
+ amodem_get_data_registration(android_modem) ) );
+ return 0;
+}
+
+
+static void
+help_gsm_data( ControlClient client )
+{
+ int nn;
+ control_write( client,
+ "the 'gsm data <state>' allows you to change the state of your GPRS connection\r\n"
+ "valid values for <state> are the following:\r\n\r\n" );
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ const char* display = _gsm_states[nn].display;
+
+ if (!name)
+ break;
+
+ control_write( client, " %-15s %s\r\n", name, display );
+ }
+ control_write( client, "\r\n" );
+}
+
+
+static int
+do_gsm_data( ControlClient client, char* args )
+{
+ int nn;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm data <state>'\r\n" );
+ return -1;
+ }
+
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ ARegistrationState state = _gsm_states[nn].state;
+
+ if (!name)
+ break;
+
+ if ( !strcmp( args, name ) ) {
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ amodem_set_data_registration( android_modem, state );
+ qemu_net_disable = (state != A_REGISTRATION_HOME &&
+ state != A_REGISTRATION_ROAMING );
+ return 0;
+ }
+ }
+ control_write( client, "KO: bad GSM data state name, try 'help gsm data' for list of valid values\r\n" );
+ return -1;
+}
+
+static void
+help_gsm_voice( ControlClient client )
+{
+ int nn;
+ control_write( client,
+ "the 'gsm voice <state>' allows you to change the state of your GPRS connection\r\n"
+ "valid values for <state> are the following:\r\n\r\n" );
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ const char* display = _gsm_states[nn].display;
+
+ if (!name)
+ break;
+
+ control_write( client, " %-15s %s\r\n", name, display );
+ }
+ control_write( client, "\r\n" );
+}
+
+
+static int
+do_gsm_voice( ControlClient client, char* args )
+{
+ int nn;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm voice <state>'\r\n" );
+ return -1;
+ }
+
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ ARegistrationState state = _gsm_states[nn].state;
+
+ if (!name)
+ break;
+
+ if ( !strcmp( args, name ) ) {
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ amodem_set_voice_registration( android_modem, state );
+ return 0;
+ }
+ }
+ control_write( client, "KO: bad GSM data state name, try 'help gsm voice' for list of valid values\r\n" );
+ return -1;
+}
+
+
+static int
+gsm_check_number( char* args )
+{
+ int nn;
+
+ for (nn = 0; args[nn] != 0; nn++) {
+ int c = args[nn];
+ if ( !isdigit(c) && c != '+' && c != '#' ) {
+ return -1;
+ }
+ }
+ if (nn == 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+do_gsm_call( ControlClient client, char* args )
+{
+ /* check that we have a phone number made of digits */
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" );
+ return -1;
+ }
+
+ if (gsm_check_number(args)) {
+ control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" );
+ return -1;
+ }
+
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ amodem_add_inbound_call( android_modem, args );
+ return 0;
+}
+
+static int
+do_gsm_cancel( ControlClient client, char* args )
+{
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" );
+ return -1;
+ }
+ if (gsm_check_number(args)) {
+ control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" );
+ return -1;
+ }
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ if ( amodem_disconnect_call( android_modem, args ) < 0 ) {
+ control_write( client, "KO: could not cancel this number\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+
+static const char*
+call_state_to_string( ACallState state )
+{
+ switch (state) {
+ case A_CALL_ACTIVE: return "active";
+ case A_CALL_HELD: return "held";
+ case A_CALL_ALERTING: return "ringing";
+ case A_CALL_WAITING: return "waiting";
+ case A_CALL_INCOMING: return "incoming";
+ default: return "unknown";
+ }
+}
+
+static int
+do_gsm_list( ControlClient client, char* args )
+{
+ /* check that we have a phone number made of digits */
+ int count = amodem_get_call_count( android_modem );
+ int nn;
+ for (nn = 0; nn < count; nn++) {
+ ACall call = amodem_get_call( android_modem, nn );
+ const char* dir;
+
+ if (call == NULL)
+ continue;
+
+ if (call->dir == A_CALL_OUTBOUND)
+ dir = "outbound to ";
+ else
+ dir = "inbound from";
+
+ control_write( client, "%s %-10s : %s\r\n", dir,
+ call->number, call_state_to_string(call->state) );
+ }
+ return 0;
+}
+
+static int
+do_gsm_busy( ControlClient client, char* args )
+{
+ ACall call;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm busy <phonenumber>'\r\n" );
+ return -1;
+ }
+ call = amodem_find_call_by_number( android_modem, args );
+ if (call == NULL || call->dir != A_CALL_OUTBOUND) {
+ control_write( client, "KO: no current outbound call to number '%s' (call %p)\r\n", args, call );
+ return -1;
+ }
+ if ( amodem_disconnect_call( android_modem, args ) < 0 ) {
+ control_write( client, "KO: could not cancel this number\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+static int
+do_gsm_hold( ControlClient client, char* args )
+{
+ ACall call;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm out hold <phonenumber>'\r\n" );
+ return -1;
+ }
+ call = amodem_find_call_by_number( android_modem, args );
+ if (call == NULL) {
+ control_write( client, "KO: no current call to/from number '%s'\r\n", args );
+ return -1;
+ }
+ if ( amodem_update_call( android_modem, args, A_CALL_HELD ) < 0 ) {
+ control_write( client, "KO: could put this call on hold\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+do_gsm_accept( ControlClient client, char* args )
+{
+ ACall call;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm accept <phonenumber>'\r\n" );
+ return -1;
+ }
+ call = amodem_find_call_by_number( android_modem, args );
+ if (call == NULL) {
+ control_write( client, "KO: no current call to/from number '%s'\r\n", args );
+ return -1;
+ }
+ if ( amodem_update_call( android_modem, args, A_CALL_ACTIVE ) < 0 ) {
+ control_write( client, "KO: could not activate this call\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+
+#if 0
+static const CommandDefRec gsm_in_commands[] =
+{
+ { "new", "create a new 'waiting' inbound call",
+ "'gsm in create <phonenumber>' creates a new inbound phone call, placed in\r\n"
+ "the 'waiting' state by default, until the system answers/holds/closes it\r\n", NULL
+ do_gsm_in_create, NULL },
+
+ { "hold", "change the state of an oubtound call to 'held'",
+ "change the state of an outbound call to 'held'. this is only possible\r\n"
+ "if the call in the 'waiting' or 'active' state\r\n", NULL,
+ do_gsm_out_hold, NULL },
+
+ { "accept", "change the state of an outbound call to 'active'",
+ "change the state of an outbound call to 'active'. this is only possible\r\n"
+ "if the call is in the 'waiting' or 'held' state\r\n", NULL,
+ do_gsm_out_accept, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+#endif
+
+
+static const CommandDefRec gsm_commands[] =
+{
+ { "list", "list current phone calls",
+ "'gsm list' lists all inbound and outbound calls and their state\r\n", NULL,
+ do_gsm_list, NULL },
+
+ { "call", "create inbound phone call",
+ "'gsm call <phonenumber>' allows you to simulate a new inbound call\r\n", NULL,
+ do_gsm_call, NULL },
+
+ { "busy", "close waiting outbound call as busy",
+ "'gsm busy <remoteNumber>' closes an outbound call, reporting\r\n"
+ "the remote phone as busy. only possible if the call is 'waiting'.\r\n", NULL,
+ do_gsm_busy, NULL },
+
+ { "hold", "change the state of an oubtound call to 'held'",
+ "'gsm hold <remoteNumber>' change the state of a call to 'held'. this is only possible\r\n"
+ "if the call in the 'waiting' or 'active' state\r\n", NULL,
+ do_gsm_hold, NULL },
+
+ { "accept", "change the state of an outbound call to 'active'",
+ "'gsm accept <remoteNumber>' change the state of a call to 'active'. this is only possible\r\n"
+ "if the call is in the 'waiting' or 'held' state\r\n", NULL,
+ do_gsm_accept, NULL },
+
+ { "cancel", "disconnect an inbound or outbound phone call",
+ "'gsm cancel <phonenumber>' allows you to simulate the end of an inbound or outbound call\r\n", NULL,
+ do_gsm_cancel, NULL },
+
+ { "data", "modify data connection state", NULL, help_gsm_data,
+ do_gsm_data, NULL },
+
+ { "voice", "modify voice connection state", NULL, help_gsm_voice,
+ do_gsm_voice, NULL },
+
+ { "status", "display GSM status",
+ "'gsm status' displays the current state of the GSM emulation\r\n", NULL,
+ do_gsm_status, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** S M S C O M M A N D ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_sms_send( ControlClient client, char* args )
+{
+ char* p;
+ int textlen;
+ SmsAddressRec sender;
+ SmsPDU* pdus;
+ int nn;
+
+ /* check that we have a phone number made of digits */
+ if (!args) {
+ MissingArgument:
+ control_write( client, "KO: missing argument, try 'sms send <phonenumber> <text message>'\r\n" );
+ return -1;
+ }
+ p = strchr( args, ' ' );
+ if (!p) {
+ goto MissingArgument;
+ }
+
+ if ( sms_address_from_str( &sender, args, p - args ) < 0 ) {
+ control_write( client, "KO: bad phone number format, must be [+](0-9)*\r\n" );
+ return -1;
+ }
+
+
+ /* un-secape message text into proper utf-8 (conversion happens in-site) */
+ p += 1;
+ textlen = strlen(p);
+ textlen = sms_utf8_from_message_str( p, textlen, (unsigned char*)p, textlen );
+ if (textlen < 0) {
+ control_write( client, "message must be utf8 and can use the following escapes:\r\n"
+ " \\n for a newline\r\n"
+ " \\xNN where NN are two hexadecimal numbers\r\n"
+ " \\uNNNN where NNNN are four hexadecimal numbers\r\n"
+ " \\\\ to send a '\\' character\r\n\r\n"
+ " anything else is an error\r\n"
+ "KO: badly formatted text\r\n" );
+ return -1;
+ }
+
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+
+ /* create a list of SMS PDUs, then send them */
+ pdus = smspdu_create_deliver_utf8( (cbytes_t)p, textlen, &sender, NULL );
+ if (pdus == NULL) {
+ control_write( client, "KO: internal error when creating SMS-DELIVER PDUs\n" );
+ return -1;
+ }
+
+ for (nn = 0; pdus[nn] != NULL; nn++)
+ amodem_receive_sms( android_modem, pdus[nn] );
+
+ smspdu_free_list( pdus );
+ return 0;
+}
+
+static int
+do_sms_sendpdu( ControlClient client, char* args )
+{
+ SmsPDU pdu;
+
+ /* check that we have a phone number made of digits */
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'sms sendpdu <hexstring>'\r\n" );
+ return -1;
+ }
+
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+
+ pdu = smspdu_create_from_hex( args, strlen(args) );
+ if (pdu == NULL) {
+ control_write( client, "KO: badly formatted <hexstring>\r\n" );
+ return -1;
+ }
+
+ amodem_receive_sms( android_modem, pdu );
+ smspdu_free( pdu );
+ return 0;
+}
+
+static const CommandDefRec sms_commands[] =
+{
+ { "send", "send inbound SMS text message",
+ "'sms send <phonenumber> <message>' allows you to simulate a new inbound sms message\r\n", NULL,
+ do_sms_send, NULL },
+
+ { "pdu", "send inbound SMS PDU",
+ "'sms pdu <hexstring>' allows you to simulate a new inbound sms PDU\r\n"
+ "(used internally when one emulator sends SMS messages to another instance).\r\n"
+ "you probably don't want to play with this at all\r\n", NULL,
+ do_sms_sendpdu, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+static void
+do_control_write(void* data, const char* string)
+{
+ control_write((ControlClient)data, string);
+}
+
+static int
+do_power_display( ControlClient client, char* args )
+{
+ goldfish_battery_display(do_control_write, client);
+ return 0;
+}
+
+static int
+do_ac_state( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "on") == 0) {
+ goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 1);
+ return 0;
+ }
+ if (strcasecmp(args, "off") == 0) {
+ goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 0);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"ac on\" or \"ac off\"\n" );
+ return -1;
+}
+
+static int
+do_battery_status( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "unknown") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_UNKNOWN);
+ return 0;
+ }
+ if (strcasecmp(args, "charging") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_CHARGING);
+ return 0;
+ }
+ if (strcasecmp(args, "discharging") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_DISCHARGING);
+ return 0;
+ }
+ if (strcasecmp(args, "not-charging") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_NOT_CHARGING);
+ return 0;
+ }
+ if (strcasecmp(args, "full") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_FULL);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"status unknown|charging|discharging|not-charging|full\"\n" );
+ return -1;
+}
+
+static int
+do_battery_present( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "true") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 1);
+ return 0;
+ }
+ if (strcasecmp(args, "false") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 0);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"present true\" or \"present false\"\n" );
+ return -1;
+}
+
+static int
+do_battery_health( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "unknown") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNKNOWN);
+ return 0;
+ }
+ if (strcasecmp(args, "good") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_GOOD);
+ return 0;
+ }
+ if (strcasecmp(args, "overheat") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERHEAT);
+ return 0;
+ }
+ if (strcasecmp(args, "dead") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_DEAD);
+ return 0;
+ }
+ if (strcasecmp(args, "overvoltage") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERVOLTAGE);
+ return 0;
+ }
+ if (strcasecmp(args, "failure") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNSPEC_FAILURE);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"health unknown|good|overheat|dead|overvoltage|failure\"\n" );
+ return -1;
+}
+
+static int
+do_battery_capacity( ControlClient client, char* args )
+{
+ if (args) {
+ int capacity;
+
+ if (sscanf(args, "%d", &capacity) == 1 && capacity >= 0 && capacity <= 100) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_CAPACITY, capacity);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"capacity <percentage>\"\n" );
+ return -1;
+}
+
+
+static const CommandDefRec power_commands[] =
+{
+ { "display", "display battery and charger state",
+ "display battery and charger state\r\n", NULL,
+ do_power_display, NULL },
+
+ { "ac", "set AC charging state",
+ "'ac on|off' allows you to set the AC charging state to on or off\r\n", NULL,
+ do_ac_state, NULL },
+
+ { "status", "set battery status",
+ "'status unknown|charging|discharging|not-charging|full' allows you to set battery status\r\n", NULL,
+ do_battery_status, NULL },
+
+ { "present", "set battery present state",
+ "'present true|false' allows you to set battery present state to true or false\r\n", NULL,
+ do_battery_present, NULL },
+
+ { "health", "set battery health state",
+ "'health unknown|good|overheat|dead|overvoltage|failure' allows you to set battery health state\r\n", NULL,
+ do_battery_health, NULL },
+
+ { "capacity", "set battery capacity state",
+ "'capacity <percentage>' allows you to set battery capacity to a value 0 - 100\r\n", NULL,
+ do_battery_capacity, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** E V E N T C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+
+static int
+do_event_send( ControlClient client, char* args )
+{
+ char* p;
+
+ if (!args) {
+ control_write( client, "KO: Usage: event send <type>:<code>:<value> ...\r\n" );
+ return -1;
+ }
+
+ p = args;
+ while (*p) {
+ char* q;
+ int type, code, value, ret;
+
+ p += strspn( args, " \t" ); /* skip spaces */
+ if (*p == 0)
+ break;
+
+ q = p + strcspn( p, " \t" );
+
+ if (q == p)
+ break;
+
+ ret = android_event_from_str( p, &type, &code, &value );
+ if (ret < 0) {
+ if (ret == -1) {
+ control_write( client,
+ "KO: invalid event type in '%.*s', try 'event list types' for valid values\r\n",
+ q-p, p );
+ } else if (ret == -2) {
+ control_write( client,
+ "KO: invalid event code in '%.*s', try 'event list codes <type>' for valid values\r\n",
+ q-p, p );
+ } else {
+ control_write( client,
+ "KO: invalid event value in '%.*s', must be an integer\r\n",
+ q-p, p);
+ }
+ return -1;
+ }
+
+ kbd_generic_event( type, code, value );
+ p = q;
+ }
+ return 0;
+}
+
+static int
+do_event_types( ControlClient client, char* args )
+{
+ int count = android_event_get_type_count();
+ int nn;
+
+ control_write( client, "event <type> can be an integer or one of the following aliases\r\n" );
+ for (nn = 0; nn < count; nn++) {
+ char tmp[16];
+ char* p = tmp;
+ char* end = p + sizeof(tmp);
+ int count2 = android_event_get_code_count( nn );;
+
+ p = android_event_bufprint_type_str( p, end, nn );
+
+ control_write( client, " %-8s", tmp );
+ if (count2 > 0)
+ control_write( client, " (%d code aliases)", count2 );
+
+ control_write( client, "\r\n" );
+ }
+ return 0;
+}
+
+static int
+do_event_codes( ControlClient client, char* args )
+{
+ int count;
+ int nn, type, dummy;
+
+ if (!args) {
+ control_write( client, "KO: argument missing, try 'event codes <type>'\r\n" );
+ return -1;
+ }
+
+ if ( android_event_from_str( args, &type, &dummy, &dummy ) < 0 ) {
+ control_write( client, "KO: bad argument, see 'event types' for valid values\r\n" );
+ return -1;
+ }
+
+ count = android_event_get_code_count( type );
+ if (count == 0) {
+ control_write( client, "no code aliases defined for this type\r\n" );
+ } else {
+ control_write( client, "type '%s' accepts the following <code> aliases:\r\n",
+ args );
+ for (nn = 0; nn < count; nn++) {
+ char temp[20], *p = temp, *end = p + sizeof(temp);
+ android_event_bufprint_code_str( p, end, type, nn );
+ control_write( client, " %-12s\r\n", temp );
+ }
+ }
+
+ return 0;
+}
+
+static __inline__ int
+utf8_next( unsigned char* *pp, unsigned char* end )
+{
+ unsigned char* p = *pp;
+ int result = -1;
+
+ if (p < end) {
+ int c= *p++;
+ if (c >= 128) {
+ if ((c & 0xe0) == 0xc0)
+ c &= 0x1f;
+ else if ((c & 0xf0) == 0xe0)
+ c &= 0x0f;
+ else
+ c &= 0x07;
+
+ while (p < end && (p[0] & 0xc0) == 0x80) {
+ c = (c << 6) | (p[0] & 0x3f);
+ }
+ }
+ result = c;
+ *pp = p;
+ }
+ return result;
+}
+
+static int
+do_event_text( ControlClient client, char* args )
+{
+ SkinKeyboard* keyboard;
+ unsigned char* p = (unsigned char*) args;
+ unsigned char* end = p + strlen(args);
+ int textlen;
+
+ if (!args) {
+ control_write( client, "KO: argument missing, try 'event text <message>'\r\n" );
+ return -1;
+ }
+ keyboard = android_emulator_get_keyboard();
+ if (keyboard == NULL) {
+ control_write( client, "KO: no keyboard active in current device layout/config\r\n" );
+ return -1;
+ }
+
+ /* un-secape message text into proper utf-8 (conversion happens in-site) */
+ textlen = strlen((char*)p);
+ textlen = sms_utf8_from_message_str( args, textlen, (unsigned char*)p, textlen );
+ if (textlen < 0) {
+ control_write( client, "message must be utf8 and can use the following escapes:\r\n"
+ " \\n for a newline\r\n"
+ " \\xNN where NN are two hexadecimal numbers\r\n"
+ " \\uNNNN where NNNN are four hexadecimal numbers\r\n"
+ " \\\\ to send a '\\' character\r\n\r\n"
+ " anything else is an error\r\n"
+ "KO: badly formatted text\r\n" );
+ return -1;
+ }
+
+ end = p + textlen;
+ while (p < end) {
+ int c = utf8_next( &p, end );
+ if (c <= 0)
+ break;
+
+ skin_keyboard_process_unicode_event( keyboard, (unsigned)c, 1 );
+ skin_keyboard_process_unicode_event( keyboard, (unsigned)c, 0 );
+ skin_keyboard_flush( keyboard );
+ }
+
+ return 0;
+}
+
+static const CommandDefRec event_commands[] =
+{
+ { "send", "send a series of events to the kernel",
+ "'event send <type>:<code>:<value> ...' allows your to send one or more hardware events\r\n"
+ "to the Android kernel. you can use text names or integers for <type> and <code>\r\n", NULL,
+ do_event_send, NULL },
+
+ { "types", "list all <type> aliases",
+ "'event types' list all <type> string aliases supported by the 'event' subcommands\r\n",
+ NULL, do_event_types, NULL },
+
+ { "codes", "list all <code> aliases for a given <type>",
+ "'event codes <type>' lists all <code> string aliases for a given event <type>\r\n",
+ NULL, do_event_codes, NULL },
+
+ { "text", "simulate keystrokes from a given text",
+ "'event text <message>' allows you to simulate keypresses to generate a given text\r\n"
+ "message. <message> must be an utf-8 string. Unicode points will be reverse-mapped\r\n"
+ "according to the current device keyboard. unsupported characters will be discarded\r\n"
+ "silently\r\n", NULL, do_event_text, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** V M C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_avd_stop( ControlClient client, char* args )
+{
+ if (!vm_running) {
+ control_write( client, "KO: virtual device already stopped\r\n" );
+ return -1;
+ }
+ vm_stop(EXCP_INTERRUPT);
+ return 0;
+}
+
+static int
+do_avd_start( ControlClient client, char* args )
+{
+ if (vm_running) {
+ control_write( client, "KO: virtual device already running\r\n" );
+ return -1;
+ }
+ vm_start();
+ return 0;
+}
+
+static int
+do_avd_status( ControlClient client, char* args )
+{
+ control_write( client, "virtual device is %s\r\n", vm_running ? "running" : "stopped" );
+ return 0;
+}
+
+static int
+do_avd_name( ControlClient client, char* args )
+{
+ control_write( client, "%s\r\n", avdInfo_getName(android_avdInfo) );
+ return 0;
+}
+
+static const CommandDefRec vm_commands[] =
+{
+ { "stop", "stop the virtual device",
+ "'avd stop' stops the virtual device immediately, use 'avd start' to continue execution\r\n",
+ NULL, do_avd_stop, NULL },
+
+ { "start", "start/restart the virtual device",
+ "'avd start' will start or continue the virtual device, use 'avd stop' to stop it\r\n",
+ NULL, do_avd_start, NULL },
+
+ { "status", "query virtual device status",
+ "'avd status' will indicate wether the virtual device is running or not\r\n",
+ NULL, do_avd_status, NULL },
+
+ { "name", "query virtual device name",
+ "'avd name' will return the name of this virtual device\r\n",
+ NULL, do_avd_name, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** G E O C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_geo_nmea( ControlClient client, char* args )
+{
+ if (!args) {
+ control_write( client, "KO: NMEA sentence missing, try 'help geo nmea'\r\n" );
+ return -1;
+ }
+ if (!android_gps_cs) {
+ control_write( client, "KO: no GPS emulation in this virtual device\r\n" );
+ return -1;
+ }
+ android_gps_send_nmea( args );
+ return 0;
+}
+
+static int
+do_geo_fix( ControlClient client, char* args )
+{
+#define MAX_GEO_PARAMS 3
+ char* p = args;
+ int n_params = 0;
+ double params[ MAX_GEO_PARAMS ];
+
+ static int last_time = 0;
+ static double last_altitude = 0.;
+
+ if (!p)
+ p = "";
+
+ /* tokenize */
+ while (*p) {
+ char* end;
+ double val = strtod( p, &end );
+
+ if (end == p) {
+ control_write( client, "KO: argument '%s' is not a number\n", p );
+ return -1;
+ }
+
+ params[n_params++] = val;
+ if (n_params >= MAX_GEO_PARAMS)
+ break;
+
+ p = end;
+ while (*p && (p[0] == ' ' || p[0] == '\t'))
+ p += 1;
+ }
+
+ /* sanity check */
+ if (n_params < 2) {
+ control_write( client, "KO: not enough arguments: see 'help geo fix' for details\r\n" );
+ return -1;
+ }
+
+ /* generate an NMEA sentence for this fix */
+ {
+ STRALLOC_DEFINE(s);
+ double val;
+ int deg, min;
+ char hemi;
+
+ /* first, the time */
+ stralloc_add_format( s, "$GPGGA,%06d", last_time );
+ last_time ++;
+
+ /* then the latitude */
+ hemi = 'N';
+ val = params[1];
+ if (val < 0) {
+ hemi = 'S';
+ val = -val;
+ }
+ deg = (int) val;
+ min = 60*(val - deg);
+ val = val - min/60.;
+ stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi );
+
+ /* the longitude */
+ hemi = 'E';
+ val = params[0];
+ if (val < 0) {
+ hemi = 'W';
+ val = -val;
+ }
+ deg = (int) val;
+ min = 60*(val - deg);
+ val = val - min/60.;
+ stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi );
+
+ /* bogus fix quality, empty satellite count and dilutions */
+ stralloc_add_str( s, ",1,,,," );
+
+ /* optional altitude */
+ if (n_params >= 3) {
+ stralloc_add_format( s, "%.1g", params[2] );
+ last_altitude = params[2];
+ } else {
+ stralloc_add_str( s, "," );
+ }
+ /* bogus rest and checksum */
+ stralloc_add_str( s, ",,,*47" );
+
+ /* send it, then free */
+ android_gps_send_nmea( stralloc_cstr(s) );
+ stralloc_reset( s );
+ }
+ return 0;
+}
+
+static const CommandDefRec geo_commands[] =
+{
+ { "nmea", "send an GPS NMEA sentence",
+ "'geo nema <sentence>' sends a NMEA 0183 sentence to the emulated device, as\r\n"
+ "if it came from an emulated GPS modem. <sentence> must begin with '$GP'. only\r\n"
+ "'$GPGGA' and '$GPRCM' sentences are supported at the moment.\r\n",
+ NULL, do_geo_nmea, NULL },
+
+ { "fix", "send a simple GPS fix",
+ "'geo fix <longitude> <latitude> [<altitude>]' allows you to send a\r\n"
+ "simple GPS fix to the emulated system. the parameters are:\r\n\r\n"
+ " <longitude> longitude, in decimal degrees\r\n"
+ " <latitude> latitude, in decimal degrees\r\n"
+ " <altitude> optional altitude in meters\r\n"
+ "\r\n",
+ NULL, do_geo_fix, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** M A I N C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+extern void android_emulator_set_window_scale( double, int );
+
+static int
+do_window_scale( ControlClient client, char* args )
+{
+ double scale;
+ int is_dpi = 0;
+ char* end;
+
+ if (!args) {
+ control_write( client, "KO: argument missing, try 'window scale <scale>'\r\n" );
+ return -1;
+ }
+
+ scale = strtol( args, &end, 10 );
+ if (end > args && !memcmp( end, "dpi", 4 )) {
+ is_dpi = 1;
+ }
+ else {
+ scale = strtod( args, &end );
+ if (end == args || end[0]) {
+ control_write( client, "KO: argument <scale> must be a real number, or an integer followed by 'dpi'\r\n" );
+ return -1;
+ }
+ }
+
+ android_emulator_set_window_scale( scale, is_dpi );
+ return 0;
+}
+
+static const CommandDefRec window_commands[] =
+{
+ { "scale", "change the window scale",
+ "'window scale <scale>' allows you to change the scale of the emulator window at runtime\r\n"
+ "<scale> must be either a real number between 0.1 and 3.0, or an integer followed by\r\n"
+ "the 'dpi' prefix (as in '120dpi')\r\n",
+ NULL, do_window_scale, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** M A I N C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_kill( ControlClient client, char* args )
+{
+ control_write( client, "OK: killing emulator, bye bye\r\n" );
+ exit(0);
+}
+
+static const CommandDefRec main_commands[] =
+{
+ { "help|h|?", "print a list of commands", NULL, NULL, do_help, NULL },
+
+ { "event", "simulate hardware events",
+ "allows you to send fake hardware events to the kernel\r\n", NULL,
+ NULL, event_commands },
+
+ { "geo", "Geo-location commands",
+ "allows you to change Geo-related settings, or to send GPS NMEA sentences\r\n", NULL,
+ NULL, geo_commands },
+
+ { "gsm", "GSM related commands",
+ "allows you to change GSM-related settings, or to make a new inbound phone call\r\n", NULL,
+ NULL, gsm_commands },
+
+ { "kill", "kill the emulator instance", NULL, NULL,
+ do_kill, NULL },
+
+ { "network", "manage network settings",
+ "allows you to manage the settings related to the network data connection of the\r\n"
+ "emulated device.\r\n", NULL,
+ NULL, network_commands },
+
+ { "power", "power related commands",
+ "allows to change battery and AC power status\r\n", NULL,
+ NULL, power_commands },
+
+ { "quit|exit", "quit control session", NULL, NULL,
+ do_quit, NULL },
+
+ { "redir", "manage port redirections",
+ "allows you to add, list and remove UDP and/or PORT redirection from the host to the device\r\n"
+ "as an example, 'redir tcp:5000:6000' will route any packet sent to the host's TCP port 5000\r\n"
+ "to TCP port 6000 of the emulated device\r\n", NULL,
+ NULL, redir_commands },
+
+ { "sms", "SMS related commands",
+ "allows you to simulate an inbound SMS\r\n", NULL,
+ NULL, sms_commands },
+
+ { "avd", "manager virtual device state",
+ "allows to change (e.g. start/stop) the virtual device state\r\n", NULL,
+ NULL, vm_commands },
+
+ { "window", "manage emulator window",
+ "allows you to modify the emulator window\r\n", NULL,
+ NULL, window_commands },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static ControlGlobalRec _g_global;
+
+int
+control_console_start( int port )
+{
+ return control_global_init( &_g_global, port );
+}
diff --git a/android/globals.h b/android/globals.h
new file mode 100644
index 0000000..b26663d
--- /dev/null
+++ b/android/globals.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_GLOBALS_H
+#define _ANDROID_GLOBALS_H
+
+#include "android/avd/info.h"
+#include "android/avd/hw-config.h"
+
+/* this structure is setup when loading the virtual device
+ * after that, you can read the 'flags' field to determine
+ * wether a data or cache wipe has been in effect.
+ */
+extern AvdInfoParams android_avdParams[1];
+
+/* a pointer to the android virtual device information
+ * object, which can be queried for the paths of various
+ * image files or the skin
+ */
+extern AvdInfo* android_avdInfo;
+
+/* the hardware configuration for this specific virtual device */
+extern AndroidHwConfig android_hw[1];
+
+#endif /* _ANDROID_GLOBALS_H */
diff --git a/android/gps.c b/android/gps.c
new file mode 100644
index 0000000..be68cfc
--- /dev/null
+++ b/android/gps.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/gps.h"
+#include "android/utils/debug.h"
+#include "qemu-char.h"
+
+CharDriverState* android_gps_cs;
+
+#define D(...) VERBOSE_PRINT(gps,__VA_ARGS__)
+
+void
+android_gps_send_nmea( const char* sentence )
+{
+ if (sentence == NULL)
+ return;
+
+ D("sending '%s'", sentence);
+
+ if (android_gps_cs == NULL) {
+ D("missing GPS channel, ignored");
+ return;
+ }
+
+ qemu_chr_write( android_gps_cs, (const void*)sentence, strlen(sentence) );
+ qemu_chr_write( android_gps_cs, (const void*)"\n", 1 );
+}
+
+
diff --git a/android/gps.h b/android/gps.h
new file mode 100644
index 0000000..33ecece
--- /dev/null
+++ b/android/gps.h
@@ -0,0 +1,23 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _android_gps_h
+#define _android_gps_h
+
+#include "qemu-common.h"
+
+/* this is the internal character driver used to communicate with the
+ * emulated GPS unit. see qemu_chr_open() in vl.c */
+extern CharDriverState* android_gps_cs;
+
+extern void android_gps_send_nmea( const char* sentence );
+
+#endif /* _android_gps_h */
diff --git a/android/help.c b/android/help.c
new file mode 100644
index 0000000..92531d9
--- /dev/null
+++ b/android/help.c
@@ -0,0 +1,1452 @@
+#include "android/help.h"
+#include "android/cmdline-option.h"
+#include "android/utils/path.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+#include "android/utils/misc.h"
+#include "android/skin/keyset.h"
+#include "android/android.h"
+#include <stdint.h>
+#include "audio/audio.h"
+#include <string.h>
+#include <stdlib.h>
+
+/* XXX: TODO: put most of the help stuff in auto-generated files */
+
+#define PRINTF(...) stralloc_add_format(out,__VA_ARGS__)
+
+static void
+help_virtual_device( stralloc_t* out )
+{
+ PRINTF(
+ " An Android Virtual Device (AVD) models a single virtual\n"
+ " device running the Android platform that has, at least, its own\n"
+ " kernel, system image and data partition.\n\n"
+
+ " Only one emulator process can run a given AVD at a time, but\n"
+ " you can create several AVDs and run them concurrently.\n\n"
+
+ " You can invoke a given AVD at startup using either '-avd <name>'\n"
+ " or '@<name>', both forms being equivalent. For example, to launch\n"
+ " the AVD named 'foo', type:\n\n"
+
+ " emulator @foo\n\n"
+
+ " The 'android' helper tool can be used to manage virtual devices.\n"
+ " For example:\n\n"
+
+ " android avd -- creates a new virtual device.\n"
+ " android list -- list all virtual devices available.\n\n"
+
+ " Each AVD really corresponds to a content directory which stores\n"
+ " persistent and writable disk images as well as configuration files.\n"
+
+ " Each AVD must be created against an existing SDK platform or add-on.\n"
+ " For more information on this topic, see -help-sdk-images.\n\n"
+
+ " SPECIAL NOTE: in the case where you are *not* using the emulator\n"
+ " with the Android SDK, but with the Android build system, you will\n"
+ " need to define the ANDROID_PRODUCT_OUT variable in your environment.\n"
+ " See -help-build-images for the details.\n"
+ );
+}
+
+
+static void
+help_sdk_images( stralloc_t* out )
+{
+ PRINTF(
+ " The Android SDK now supports multiple versions of the Android platform.\n"
+ " Each SDK 'platform' corresponds to:\n\n"
+
+ " - a given version of the Android API.\n"
+ " - a set of corresponding system image files.\n"
+ " - build and configuration properties.\n"
+ " - an android.jar file used when building your application.\n"
+ " - skins.\n\n"
+
+ " The Android SDK also supports the concept of 'add-ons'. Each add-on is\n"
+ " based on an existing platform, and provides replacement or additional\n"
+ " image files, android.jar, hardware configuration options and/or skins.\n\n"
+
+ " The purpose of add-ons is to allow vendors to provide their own customized\n"
+ " system images and APIs without needing to package a complete SDK.\n\n"
+
+ " Before using the SDK, you need to create an Android Virtual Device (AVD)\n"
+ " (see -help-virtual-device for details). Each AVD is created in reference\n"
+ " to a given SDK platform *or* add-on, and will search the corresponding\n"
+ " directories for system image files, in the following order:\n\n"
+
+ " - in the AVD's content directory.\n"
+ " - in the AVD's SDK add-on directory, if any.\n"
+ " - in the AVD's SDK platform directory, if any.\n\n"
+
+ " The image files are documented in -help-disk-images. By default, an AVD\n"
+ " content directory will contain the following persistent image files:\n\n"
+
+ " userdata-qemu.img - the /data partition image file\n"
+ " cache.img - the /cache partition image file\n\n"
+
+ " You can use -wipe-data to re-initialize the /data partition to its factory\n"
+ " defaults. This will erase all user settings for the virtual device.\n\n"
+ );
+}
+
+static void
+help_build_images( stralloc_t* out )
+{
+ PRINTF(
+ " The emulator detects that you are working from the Android build system\n"
+ " by looking at the ANDROID_PRODUCT_OUT variable in your environment.\n\n"
+
+ " If it is defined, it should point to the product-specific directory that\n"
+ " contains the generated system images.\n"
+
+ " In this case, the emulator will look by default for the following image\n"
+ " files there:\n\n"
+
+ " - system.img : the *initial* system image.\n"
+ " - ramdisk.img : the ramdisk image used to boot the system.\n"
+ " - userdata.img : the *initial* user data image (see below).\n"
+ " - kernel-qemu : the emulator-specific Linux kernel image.\n\n"
+
+ " If the kernel image is not found in the out directory, then it is searched\n"
+ " in <build-root>/prebuilt/android-arm/kernel/.\n\n"
+
+ " Skins will be looked in <build-root>/development/emulator/skins/\n\n"
+
+ " You can use the -sysdir, -system, -kernel, -ramdisk, -datadir, -data options\n"
+ " to specify different search directories or specific image files. You can\n"
+ " also use the -cache and -sdcard options to indicate specific cache partition\n"
+ " and SD Card image files.\n\n"
+
+ " For more details, see the corresponding -help-<option> section.\n\n"
+
+ " Note that the following behaviour is specific to 'build mode':\n\n"
+
+ " - the *initial* system image is copied to a temporary file which is\n"
+ " automatically removed when the emulator exits. There is thus no way to\n"
+ " make persistent changes to this image through the emulator, even if\n"
+ " you use the '-image <file>' option.\n\n"
+
+ " - unless you use the '-cache <file>' option, the cache partition image\n"
+ " is backed by a temporary file that is initially empty and destroyed on\n"
+ " program exit.\n\n"
+
+ " SPECIAL NOTE: If you are using the emulator with the Android SDK, the\n"
+ " information above doesn't apply. See -help-sdk-images for more details.\n"
+ );
+}
+
+static void
+help_disk_images( stralloc_t* out )
+{
+ char datadir[256];
+
+ bufprint_config_path( datadir, datadir + sizeof(datadir) );
+
+ PRINTF(
+ " The emulator needs several key image files to run appropriately.\n"
+ " Their exact location depends on whether you're using the emulator\n"
+ " from the Android SDK, or not (more details below).\n\n"
+
+ " The minimal required image files are the following:\n\n"
+
+ " kernel-qemu the emulator-specific Linux kernel image\n"
+ " ramdisk.img the ramdisk image used to boot the system\n"
+ " system.img the *initial* system image\n"
+ " userdata.img the *initial* data partition image\n\n"
+
+ " It will also use the following writable image files:\n\n"
+
+ " userdata-qemu.img the persistent data partition image\n"
+ " system-qemu.img an *optional* persistent system image\n"
+ " cache.img an *optional* cache partition image\n"
+ " sdcard.img an *optional* SD Card partition image\n\n"
+
+ " If you use a virtual device, its content directory should store\n"
+ " all writable images, and read-only ones will be found from the\n"
+ " corresponding platform/add-on directories. See -help-sdk-images\n"
+ " for more details.\n\n"
+
+ " If you are building from the Android build system, you should\n"
+ " have ANDROID_PRODUCT_OUT defined in your environment, and the\n"
+ " emulator shall be able to pick-up the right image files automatically.\n"
+ " See -help-build-images for more details.\n\n"
+
+ " If you're neither using the SDK or the Android build system, you\n"
+ " can still run the emulator by explicitely providing the paths to\n"
+ " *all* required disk images through a combination of the following\n"
+ " options: -sysdir, -datadir, -kernel, -ramdisk, -system, -data, -cache\n"
+ " and -sdcard\n\n"
+
+ " The actual logic being that the emulator should be able to find all\n"
+ " images from the options you give it.\n\n"
+
+ " For more detail, see the corresponding -help-<option> entry.\n\n"
+
+ " Other related options are:\n\n"
+
+ " -init-data Specify an alernative *initial* user data image\n\n"
+
+ " -wipe-data Copy the content of the *initial* user data image\n"
+ " (userdata.img) into the writable one (userdata-qemu.img)\n\n"
+
+ " -no-cache do not use a cache partition, even if one is\n"
+ " available.\n\n"
+ ,
+ datadir );
+}
+
+static void
+help_keys(stralloc_t* out)
+{
+ int pass, maxw = 0;
+
+ stralloc_add_str( out, " When running the emulator, use the following keypresses:\n\n");
+
+ if (!android_keyset)
+ android_keyset = skin_keyset_new_from_text( skin_keyset_get_default() );
+
+ for (pass = 0; pass < 2; pass++) {
+ SkinKeyCommand cmd;
+
+ for (cmd = SKIN_KEY_COMMAND_NONE+1; cmd < SKIN_KEY_COMMAND_MAX; cmd++)
+ {
+ SkinKeyBinding bindings[ SKIN_KEY_COMMAND_MAX_BINDINGS ];
+ int n, count, len;
+ char temp[32], *p = temp, *end = p + sizeof(temp);
+
+ count = skin_keyset_get_bindings( android_keyset, cmd, bindings );
+ if (count <= 0)
+ continue;
+
+ for (n = 0; n < count; n++) {
+ p = bufprint(p, end, "%s%s", (n == 0) ? "" : ", ",
+ skin_key_symmod_to_str( bindings[n].sym, bindings[n].mod ) );
+ }
+
+ if (pass == 0) {
+ len = strlen(temp);
+ if (len > maxw)
+ maxw = len;
+ } else {
+ PRINTF( " %-*s %s\n", maxw, temp, skin_key_command_description(cmd) );
+ }
+ }
+ }
+ PRINTF( "\n" );
+ PRINTF( " note that NumLock must be deactivated for keypad keys to work\n\n" );
+}
+
+
+static void
+help_environment(stralloc_t* out)
+{
+ PRINTF(
+ " The Android emulator looks at various environment variables when it starts:\n\n"
+
+ " If ANDROID_LOG_TAGS is defined, it will be used as in '-logcat <tags>'.\n\n"
+
+ " If 'http_proxy' is defined, it will be used as in '-http-proxy <proxy>'.\n\n"
+
+ " If ANDROID_VERBOSE is defined, it can contain a comma-separated list of\n"
+ " verbose items. for example:\n\n"
+
+ " ANDROID_VERBOSE=socket,radio\n\n"
+
+ " is equivalent to using the '-verbose -verbose-socket -verbose-radio'\n"
+ " options together. unsupported items will be ignored.\n\n"
+
+ " If ANDROID_LOG_TAGS is defined, it will be used as in '-logcat <tags>'.\n\n"
+
+ " If ANDROID_SDK_HOME is defined, it indicates the path of the '.android'\n"
+ " directory which contains the SDK user data (Android Virtual Devices,\n"
+ " DDMS preferences, key stores, etc.).\n\n"
+
+ " If ANDROID_SDK_ROOT is defined, it indicates the path of the SDK\n"
+ " installation directory.\n\n"
+
+ );
+}
+
+
+static void
+help_keyset_file(stralloc_t* out)
+{
+ int n, count;
+ const char** strings;
+ char temp[MAX_PATH];
+
+ PRINTF(
+ " on startup, the emulator looks for 'keyset' file that contains the\n"
+ " configuration of key-bindings to use. the default location on this\n"
+ " system is:\n\n"
+ );
+
+ bufprint_config_file( temp, temp+sizeof(temp), KEYSET_FILE );
+ PRINTF( " %s\n\n", temp );
+
+ PRINTF(
+ " if the file doesn't exist, the emulator writes one containing factory\n"
+ " defaults. you are then free to modify it to suit specific needs.\n\n"
+ " this file shall contain a list of text lines in the following format:\n\n"
+
+ " <command> [<modifiers>]<key>\n\n"
+
+ " where <command> is an emulator-specific command name, i.e. one of:\n\n"
+ );
+
+ count = SKIN_KEY_COMMAND_MAX-1;
+ strings = calloc( count, sizeof(char*) );
+ for (n = 0; n < count; n++)
+ strings[n] = skin_key_command_to_str(n+1);
+
+ stralloc_tabular( out, strings, count, " ", 80-8 );
+ free(strings);
+
+ PRINTF(
+ "\n"
+ " <modifers> is an optional list of <modifier> elements (without separators)\n"
+ " which can be one of:\n\n"
+
+ " Ctrl- Left Control Key\n"
+ " Shift- Left Shift Key\n"
+ " Alt- Left Alt key\n"
+ " RCtrl- Right Control Key\n"
+ " RShift- Right Shift Key\n"
+ " RAlt- Right Alt key (a.k.a AltGr)\n"
+ "\n"
+ " finally <key> is a QWERTY-specific keyboard symbol which can be one of:\n\n"
+ );
+ count = skin_keysym_str_count();
+ strings = calloc( count, sizeof(char*) );
+ for (n = 0; n < count; n++)
+ strings[n] = skin_keysym_str(n);
+
+ stralloc_tabular( out, strings, count, " ", 80-8 );
+ free(strings);
+
+ PRINTF(
+ "\n"
+ " case is not significant, and a single command can be associated to up\n"
+ " to %d different keys. to bind a command to multiple keys, use commas to\n"
+ " separate them. here are some examples:\n\n",
+ SKIN_KEY_COMMAND_MAX_BINDINGS );
+
+ PRINTF(
+ " TOGGLE_NETWORK F8 # toggle the network on/off\n"
+ " CHANGE_LAYOUT_PREV Keypad_7,Ctrl-J # switch to a previous skin layout\n"
+ "\n"
+ );
+}
+
+
+static void
+help_debug_tags(stralloc_t* out)
+{
+ int n;
+
+#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
+ static const struct { const char* name; int flag; const char* text; }
+ verbose_options[] = {
+ VERBOSE_TAG_LIST
+ { 0, 0, 0 }
+ };
+#undef _VERBOSE_TAG
+
+ PRINTF(
+ " the '-debug <tags>' option can be used to enable or disable debug\n"
+ " messages from specific parts of the emulator. <tags> must be a list\n"
+ " (separated by space/comma/column) of <component> names, which can be one of:\n\n"
+ );
+
+ for (n = 0; n < VERBOSE_MAX; n++)
+ PRINTF( " %-12s %s\n", verbose_options[n].name, verbose_options[n].text );
+ PRINTF( " %-12s %s\n", "all", "all components together\n" );
+
+ PRINTF(
+ "\n"
+ " each <component> can be prefixed with a single '-' to indicate the disabling\n"
+ " of its debug messages. for example:\n\n"
+
+ " -debug all,-socket,-keys\n\n"
+
+ " enables all debug messages, except the ones related to network sockets\n"
+ " and key bindings/presses\n\n"
+ );
+}
+
+static void
+help_char_devices(stralloc_t* out)
+{
+ PRINTF(
+ " various emulation options take a <device> specification that can be used to\n"
+ " specify something to hook to an emulated device or communication channel.\n"
+ " here is the list of supported <device> specifications:\n\n"
+
+ " stdio\n"
+ " standard input/output. this may be subject to character\n"
+ " translation (e.g. LN <=> CR/LF)\n\n"
+
+ " COM<n> [Windows only]\n"
+ " where <n> is a digit. host serial communication port.\n\n"
+
+ " pipe:<filename>\n"
+ " named pipe <filename>\n\n"
+
+ " file:<filename>\n"
+ " write output to <filename>, no input can be read\n\n"
+
+ " pty [Linux only]\n"
+ " pseudo TTY (a new PTY is automatically allocated)\n\n"
+
+ " /dev/<file> [Unix only]\n"
+ " host char device file, e.g. /dev/ttyS0. may require root access\n\n"
+
+ " /dev/parport<N> [Linux only]\n"
+ " use host parallel port. may require root access\n\n"
+
+ " unix:<path>[,server][,nowait]] [Unix only]\n"
+ " use a Unix domain socket. if you use the 'server' option, then\n"
+ " the emulator will create the socket and wait for a client to\n"
+ " connect before continuing, unless you also use 'nowait'\n\n"
+
+ " tcp:[<host>]:<port>[,server][,nowait][,nodelay]\n"
+ " use a TCP socket. 'host' is set to localhost by default. if you\n"
+ " use the 'server' option will bind the port and wait for a client\n"
+ " to connect before continuing, unless you also use 'nowait'. the\n"
+ " 'nodelay' option disables the TCP Nagle algorithm\n\n"
+
+ " telnet:[<host>]:<port>[,server][,nowait][,nodelay]\n"
+ " similar to 'tcp:' but uses the telnet protocol instead of raw TCP\n\n"
+
+ " udp:[<remote_host>]:<remote_port>[@[<src_ip>]:<src_port>]\n"
+ " send output to a remote UDP server. if 'remote_host' is no\n"
+ " specified it will default to '0.0.0.0'. you can also receive input\n"
+ " through UDP by specifying a source address after the optional '@'.\n\n"
+
+ " fdpair:<fd1>,<fd2> [Unix only]\n"
+ " redirection input and output to a pair of pre-opened file\n"
+ " descriptors. this is mostly useful for scripts and other\n"
+ " programmatic launches of the emulator.\n\n"
+
+ " none\n"
+ " no device connected\n\n"
+
+ " null\n"
+ " the null device (a.k.a /dev/null on Unix, or NUL on Win32)\n\n"
+
+ " NOTE: these correspond to the <device> parameter of the QEMU -serial option\n"
+ " as described on http://bellard.org/qemu/qemu-doc.html#SEC10\n\n"
+ );
+}
+
+static void
+help_avd(stralloc_t* out)
+{
+ PRINTF(
+ " use '-avd <name>' to start the emulator program with a given avd,\n"
+ " where <name> must correspond to the name of one of the\n"
+ " Android Virtual Devices available on your host.\n\n"
+
+ " As a special convenience, using '@<name>' is equivalent to using\n"
+ " '-avd <name>'.\n\n"
+
+ " For more information about virtual devices, see -help-virtual-device.\n"
+ );
+}
+
+static void
+help_sysdir(stralloc_t* out)
+{
+ char systemdir[MAX_PATH];
+ char *p = systemdir, *end = p + sizeof(systemdir);
+
+ p = bufprint_app_dir( p, end );
+ p = bufprint( p, end, PATH_SEP "lib" PATH_SEP "images" );
+
+ PRINTF(
+ " use '-sysdir <dir>' to specify a directory where system read-only\n"
+ " image files will be searched. on this system, the default directory is:\n\n"
+ " %s\n\n", systemdir );
+
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_datadir(stralloc_t* out)
+{
+ char datadir[MAX_PATH];
+
+ bufprint_config_path(datadir, datadir + sizeof(datadir));
+
+ PRINTF(
+ " use '-datadir <dir>' to specify a directory where writable image files\n"
+ " will be searched. on this system, the default directory is:\n\n"
+ " %s\n\n", datadir );
+
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_kernel(stralloc_t* out)
+{
+ PRINTF(
+ " use '-kernel <file>' to specify a Linux kernel image to be run.\n"
+ " the default image is 'kernel-qemu' from the system directory.\n\n"
+
+ " you can use '-debug-kernel' to see debug messages from the kernel\n"
+ " to the terminal\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_ramdisk(stralloc_t* out)
+{
+ PRINTF(
+ " use '-ramdisk <file>' to specify a Linux ramdisk boot image to be run in\n"
+ " the emulator. the default image is 'ramdisk.img' from the system directory.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_system(stralloc_t* out)
+{
+ PRINTF(
+ " use '-system <file>' to specify the intial system image that will be loaded.\n"
+ " the default image is 'system.img' from the system directory.\n\n"
+
+ " NOTE: In previous releases of the Android SDK, this option was named '-image'.\n"
+ " And using '-system <path>' was equivalent to using '-sysdir <path>' now.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_image(stralloc_t* out)
+{
+ PRINTF(
+ " This option is obsolete, you should use '-system <file>' instead to point\n"
+ " to the initial system image.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_init_data(stralloc_t* out)
+{
+ PRINTF(
+ " use '-init-data <file>' to specify an *init* /data partition file.\n"
+ " it is only used when creating a new writable /data image file, or\n"
+ " when you use '-wipe-data' to reset it. the default is 'userdata.img'\n"
+ " from the system directory.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_data(stralloc_t* out)
+{
+ PRINTF(
+ " use '-data <file>' to specify a different /data partition image file.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_wipe_data(stralloc_t* out)
+{
+ PRINTF(
+ " use '-wipe-data' to reset your /data partition image to its factory\n"
+ " defaults. this removes all installed applications and settings.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_cache(stralloc_t* out)
+{
+ PRINTF(
+ " use '-cache <file>' to specify a /cache partition image. if <file> does\n"
+ " not exist, it will be created empty. by default, the cache partition is\n"
+ " backed by a temporary file that is deleted when the emulator exits.\n"
+ " using the -cache option allows it to be persistent.\n\n"
+
+ " the '-no-cache' option can be used to disable the cache partition.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_no_cache(stralloc_t* out)
+{
+ PRINTF(
+ " use '-no-cache' to disable the cache partition in the emulated system.\n"
+ " the cache partition is optional, but when available, is used by the browser\n"
+ " to cache web pages and images\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_sdcard(stralloc_t* out)
+{
+ PRINTF(
+ " use '-sdcard <file>' to specify a SD Card image file that will be attached\n"
+ " to the emulator. By default, the 'sdcard.img' file is searched in the data\n"
+ " directory.\n\n"
+
+ " if the file does not exist, the emulator will still start, but without an\n"
+ " attached SD Card.\n\n"
+
+ " see '-help-disk-images' for more information about disk image files\n\n"
+ );
+}
+
+static void
+help_skindir(stralloc_t* out)
+{
+ PRINTF(
+ " use '-skindir <dir>' to specify a directory that will be used to search\n"
+ " for emulator skins. each skin must be a subdirectory of <dir>. by default\n"
+ " the emulator will look in the 'skins' sub-directory of the system directory\n\n"
+
+ " the '-skin <name>' option is required when -skindir is used.\n"
+ );
+}
+
+static void
+help_skin(stralloc_t* out)
+{
+ PRINTF(
+ " use '-skin <skin>' to specify an emulator skin, each skin corresponds to\n"
+ " the visual appearance of a given device, including buttons and keyboards,\n"
+ " and is stored as subdirectory <skin> of the skin root directory\n"
+ " (see '-help-skindir')\n\n" );
+
+ PRINTF(
+ " note that <skin> can also be '<width>x<height>' (e.g. '320x480') to\n"
+ " specify an exact framebuffer size, without any visual ornaments.\n\n" );
+}
+
+/* default network settings for emulator */
+#define DEFAULT_NETSPEED "full"
+#define DEFAULT_NETDELAY "none"
+
+static void
+help_shaper(stralloc_t* out)
+{
+ int n;
+
+ PRINTF(
+ " the Android emulator supports network throttling, i.e. slower network\n"
+ " bandwidth as well as higher connection latencies. this is done either through\n"
+ " skin configuration, or with '-netspeed <speed>' and '-netdelay <delay>'.\n\n"
+
+ " the format of -netspeed is one of the following (numbers are kbits/s):\n\n" );
+
+ for (n = 0; android_netspeeds[n].name != NULL; n++) {
+ PRINTF( " -netspeed %-12s %-15s (up: %.1f, down: %.1f)\n",
+ android_netspeeds[n].name,
+ android_netspeeds[n].display,
+ android_netspeeds[n].upload/1000.,
+ android_netspeeds[n].download/1000. );
+ }
+ PRINTF( "\n" );
+ PRINTF( " -netspeed %-12s %s", "<num>", "select both upload and download speed\n");
+ PRINTF( " -netspeed %-12s %s", "<up>:<down>", "select individual up and down speed\n");
+
+ PRINTF( "\n The format of -netdelay is one of the following (numbers are msec):\n\n" );
+ for (n = 0; android_netdelays[n].name != NULL; n++) {
+ PRINTF( " -netdelay %-10s %-15s (min %d, max %d)\n",
+ android_netdelays[n].name, android_netdelays[n].display,
+ android_netdelays[n].min_ms, android_netdelays[n].max_ms );
+ }
+ PRINTF( " -netdelay %-10s %s", "<num>", "select exact latency\n");
+ PRINTF( " -netdelay %-10s %s", "<min>:<max>", "select min and max latencies\n\n");
+
+ PRINTF( " the emulator uses the following defaults:\n\n" );
+ PRINTF( " Default network speed is '%s'\n", DEFAULT_NETSPEED);
+ PRINTF( " Default network latency is '%s'\n\n", DEFAULT_NETDELAY);
+}
+
+static void
+help_http_proxy(stralloc_t* out)
+{
+ PRINTF(
+ " the Android emulator allows you to redirect all TCP connections through\n"
+ " a HTTP/HTTPS proxy. this can be enabled by using the '-http-proxy <proxy>'\n"
+ " option, or by defining the 'http_proxy' environment variable.\n\n"
+
+ " <proxy> can be one of the following:\n\n"
+ " http://<server>:<port>\n"
+ " http://<username>:<password>@<server>:<port>\n\n"
+
+ " the 'http://' prefix can be omitted. If '-http-proxy <proxy>' is not used,\n"
+ " the 'http_proxy' environment variable is looked up and any value matching\n"
+ " the <proxy> format will be used automatically\n\n" );
+}
+
+static void
+help_report_console(stralloc_t* out)
+{
+ PRINTF(
+ " the '-report-console <socket>' option can be used to report the\n"
+ " automatically-assigned console port number to a remote third-party\n"
+ " before starting the emulation. <socket> must be in one of these\n"
+ " formats:\n\n"
+
+ " tcp:<port>[,server][,max=<seconds>]\n"
+ " unix:<path>[,server][,max=<seconds>]\n"
+ "\n"
+ " if the 'server' option is used, the emulator opens a server socket\n"
+ " and waits for an incoming connection to it. by default, it will instead\n"
+ " try to make a normal client connection to the socket, and, in case of\n"
+ " failure, will repeat this operation every second for 10 seconds.\n"
+ " the 'max=<seconds>' option can be used to modify the timeout\n\n"
+
+ " when the connection is established, the emulator sends its console port\n"
+ " number as text to the remote third-party, then closes the connection and\n"
+ " starts the emulation as usual. *any* failure in the process described here\n"
+ " will result in the emulator aborting immediately\n\n"
+
+ " as an example, here's a small Unix shell script that starts the emulator in\n"
+ " the background and waits for its port number with the help of the 'netcat'\n"
+ " utility:\n\n"
+
+ " MYPORT=5000\n"
+ " emulator -no-window -report-console tcp:$MYPORT &\n"
+ " CONSOLEPORT=`nc -l localhost $MYPORT`\n"
+ "\n"
+ );
+}
+
+static void
+help_dpi_device(stralloc_t* out)
+{
+ PRINTF(
+ " use '-dpi-device <dpi>' to specify the screen resolution of the emulated\n"
+ " device. <dpi> must be an integer between 72 and 1000. the default is taken\n"
+ " from the skin, if available, or uses the contant value %d (an average of\n"
+ " several prototypes used during Android development).\n\n", DEFAULT_DEVICE_DPI );
+
+ PRINTF(
+ " the device resolution can also used to rescale the emulator window with\n"
+ " the '-scale' option (see -help-scale)\n\n"
+ );
+}
+
+static void
+help_audio(stralloc_t* out)
+{
+ PRINTF(
+ " the '-audio <backend>' option allows you to select a specific backend\n"
+ " to be used to both play and record audio in the Android emulator.\n\n"
+
+ " this is equivalent to calling both '-audio-in <backend>' and\n"
+ " '-audio-out <backend>' at the same time.\n\n"
+
+ " use '-help-audio-out' to see a list of valid output <backend> values.\n"
+ " use '-help-audio-in' to see a list of valid input <backend> values.\n"
+ " use '-audio none' to disable audio completely.\n\n"
+ );
+}
+
+static void
+help_audio_out(stralloc_t* out)
+{
+ int nn;
+
+ PRINTF(
+ " the '-audio-out <backend>' option allows you to select a specific\n"
+ " backend to play audio in the Android emulator. this is mostly useful\n"
+ " on Linux\n\n"
+
+ " on this system, output <backend> can be one of the following:\n\n"
+ );
+ for ( nn = 0; ; nn++ ) {
+ const char* descr;
+ const char* name = audio_get_backend_name( 0, nn, &descr );
+ if (name == NULL)
+ break;
+ PRINTF( " %-10s %s\n", name, descr );
+ }
+ PRINTF( "\n" );
+}
+
+static void
+help_audio_in(stralloc_t* out)
+{
+ int nn;
+
+ PRINTF(
+ " the '-audio-in <backend>' option allows you to select a specific\n"
+ " backend to play audio in the Android emulator. this is mostly useful\n"
+ " on Linux\n\n"
+
+ " IMPORTANT NOTE:\n"
+ " on some Linux systems, broken Esd/ALSA/driver implementations will\n"
+ " make your emulator freeze and become totally unresponsive when\n"
+ " using audio recording. the only way to avoid this is to use\n"
+ " '-audio-in none' to disable it\n\n"
+
+ " on this system, input <backend> can be one of:\n\n"
+ );
+ for ( nn = 0; ; nn++ ) {
+ const char* descr;
+ const char* name = audio_get_backend_name( 1, nn, &descr );
+ if (name == NULL)
+ break;
+ PRINTF( " %-10s %s\n", name, descr );
+ }
+ PRINTF( "\n" );
+}
+
+
+static void
+help_scale(stralloc_t* out)
+{
+ PRINTF(
+ " the '-scale <scale>' option is used to scale the emulator window to\n"
+ " something that better fits the physical dimensions of a real device. this\n"
+ " can be *very* useful to check that your UI isn't too small to be usable\n"
+ " on a real device.\n\n"
+
+ " there are three supported formats for <scale>:\n\n"
+
+ " * if <scale> is a real number (between 0.1 and 3.0) it is used as a\n"
+ " scaling factor for the emulator's window.\n\n"
+
+ " * if <scale> is an integer followed by the suffix 'dpi' (e.g. '110dpi'),\n"
+ " then it is interpreted as the resolution of your monitor screen. this\n"
+ " will be divided by the emulated device's resolution to get an absolute\n"
+ " scale. (see -help-dpi-device for details).\n\n"
+
+ " * finally, if <scale> is the keyword 'auto', the emulator tries to guess\n"
+ " your monitor's resolution and automatically adjusts its window\n"
+ " accordingly\n\n"
+
+ " NOTE: this process is *very* unreliable, depending on your OS, video\n"
+ " driver issues and other random system parameters\n\n"
+
+ " the emulator's scale can be changed anytime at runtime through the control\n"
+ " console. see the help for the 'window scale' command for details\n\n" );
+}
+
+static void
+help_trace(stralloc_t* out)
+{
+ PRINTF(
+ " use '-trace <name>' to start the emulator with runtime code profiling support\n"
+ " profiling itself will not be enabled unless you press F9 to activate it, or\n"
+ " the executed code turns it on programmatically.\n\n"
+
+ " trace information is stored in directory <name>, several files are created\n"
+ " there, that can later be used with the 'traceview' program that comes with\n"
+ " the Android SDK for analysis.\n\n"
+
+ " note that execution will be slightly slower when enabling code profiling,\n"
+ " this is a necessary requirement of the operations being performed to record\n"
+ " the execution trace. this slowdown should not affect your system until you\n"
+ " enable the profiling though...\n\n"
+ );
+}
+
+static void
+help_show_kernel(stralloc_t* out)
+{
+ PRINTF(
+ " use '-show-kernel' to redirect debug messages from the kernel to the current\n"
+ " terminal. this is useful to check that the boot process works correctly.\n\n"
+ );
+}
+
+static void
+help_shell(stralloc_t* out)
+{
+ PRINTF(
+ " use '-shell' to create a root shell console on the current terminal.\n"
+ " this is unlike the 'adb shell' command for the following reasons:\n\n"
+
+ " * this is a *root* shell that allows you to modify many parts of the system\n"
+ " * this works even if the ADB daemon in the emulated system is broken\n"
+ " * pressing Ctrl-C will stop the emulator, instead of the shell.\n\n"
+ " See also '-shell-serial'.\n\n" );
+}
+
+static void
+help_shell_serial(stralloc_t* out)
+{
+ PRINTF(
+ " use '-shell-serial <device>' instead of '-shell' to open a root shell\n"
+ " to the emulated system, while specifying an external communication\n"
+ " channel / host device.\n\n"
+
+ " '-shell-serial stdio' is identical to '-shell', while you can use\n"
+ " '-shell-serial tcp::4444,server,nowait' to talk to the shell over local\n"
+ " TCP port 4444. '-shell-serial fdpair:3:6' would let a parent process\n"
+ " talk to the shell using fds 3 and 6.\n\n"
+
+ " see -help-char-devices for a list of available <device> specifications.\n\n"
+ " NOTE: you can have only one shell per emulator instance at the moment\n\n"
+ );
+}
+
+static void
+help_logcat(stralloc_t* out)
+{
+ PRINTF(
+ " use '-logcat <tags>' to redirect log messages from the emulated system to\n"
+ " the current terminal. <tags> is a list of space/comma-separated log filters\n"
+ " where each filter has the following format:\n\n"
+
+ " <componentName>:<logLevel>\n\n"
+
+ " where <componentName> is either '*' or the name of a given component,\n"
+ " and <logLevel> is one of the following letters:\n\n"
+
+ " v verbose level\n"
+ " d debug level\n"
+ " i informative log level\n"
+ " w warning log level\n"
+ " e error log level\n"
+ " s silent log level\n\n"
+
+ " for example, the following only displays messages from the 'GSM' component\n"
+ " that are at least at the informative level:\n\n"
+
+ " -logcat '*:s GSM:i'\n\n"
+
+ " if '-logcat <tags>' is not used, the emulator looks for ANDROID_LOG_TAGS\n"
+ " in the environment. if it is defined, its value must match the <tags>\n"
+ " format and will be used to redirect log messages to the terminal.\n\n"
+
+ " note that this doesn't prevent you from redirecting the same, or other,\n"
+ " log messages through the ADB or DDMS tools too.\n\n");
+}
+
+static void
+help_no_audio(stralloc_t* out)
+{
+ PRINTF(
+ " use '-no-audio' to disable all audio support in the emulator. this may be\n"
+ " unfortunately be necessary in some cases:\n\n"
+
+ " * at least two users have reported that their Windows machine rebooted\n"
+ " instantly unless they used this option when starting the emulator.\n"
+ " it is very likely that the problem comes from buggy audio drivers.\n\n"
+
+ " * on some Linux machines, the emulator might get stuck at startup with\n"
+ " audio support enabled. this problem is hard to reproduce, but seems to\n"
+ " be related too to flaky ALSA / audio driver support.\n\n"
+
+ " on Linux, another option is to try to change the default audio backend\n"
+ " used by the emulator. you can do that by setting the QEMU_AUDIO_DRV\n"
+ " environment variables to one of the following values:\n\n"
+
+ " alsa (use the ALSA backend)\n"
+ " esd (use the EsounD backend)\n"
+ " sdl (use the SDL audio backend, no audio input supported)\n"
+ " oss (use the OSS backend)\n"
+ " none (do not support audio)\n"
+ "\n"
+ " the very brave can also try to use distinct backends for audio input\n"
+ " and audio outputs, this is possible by selecting one of the above values\n"
+ " into the QEMU_AUDIO_OUT_DRV and QEMU_AUDIO_IN_DRV environment variables.\n\n"
+ );
+}
+
+static void
+help_raw_keys(stralloc_t* out)
+{
+ PRINTF(
+ " this option is deprecated because one can do the same using Ctrl-K\n"
+ " at runtime (this keypress toggles between unicode/raw keyboard modes)\n\n"
+
+ " by default, the emulator tries to reverse-map the characters you type on\n"
+ " your keyboard to device-specific key presses whenever possible. this is\n"
+ " done to make the emulator usable with a non-QWERTY keyboard.\n\n"
+
+ " however, this also means that single keypresses like Shift or Alt are not\n"
+ " passed to the emulated device. the '-raw-keys' option disables the reverse\n"
+ " mapping. it should only be used when using a QWERTY keyboard on your machine\n"
+
+ " (should only be useful to Android system hackers, e.g. when implementing a\n"
+ " new input method).\n\n"
+ );
+}
+
+static void
+help_radio(stralloc_t* out)
+{
+ PRINTF(
+ " use '-radio <device>' to redirect the GSM modem emulation to an external\n"
+ " character device or program. this bypasses the emulator's internal modem\n"
+ " and should only be used for testing.\n\n"
+
+ " see '-help-char-devices' for the format of <device>\n\n"
+
+ " the data exchanged with the external device/program are GSM AT commands\n\n"
+
+ " note that, when running in the emulator, the Android GSM stack only supports\n"
+ " a *very* basic subset of the GSM protocol. trying to link the emulator to\n"
+ " a real GSM modem is very likely to not work properly.\n\n"
+ );
+}
+
+
+static void
+help_port(stralloc_t* out)
+{
+ PRINTF(
+ " at startup, the emulator tries to bind its control console at a free port\n"
+ " starting from 5554, in increments of two (i.e. 5554, then 5556, 5558, etc..)\n"
+ " this allows several emulator instances to run concurrently on the same\n"
+ " machine, each one using a different console port number.\n\n"
+
+ " use '-port <port>' to force an emulator instance to use a given console port\n\n"
+
+ " note that <port> must be an *even* integer between 5554 and 5584 included.\n"
+ " <port>+1 must also be free and will be reserved for ADB. if any of these\n"
+ " ports is already used, the emulator will fail to start.\n\n" );
+}
+
+static void
+help_ports(stralloc_t* out)
+{
+ PRINTF(
+ " the '-ports <consoleport>,<adbport>' option allows you to explicitely set\n"
+ " the TCP ports used by the emulator to implement its control console and\n"
+ " communicate with the ADB tool.\n\n"
+
+ " This is a very special option that should probably *not* be used by typical\n"
+ " developers using the Android SDK (use '-port <port>' instead), because the\n"
+ " corresponding instance is probably not going to be seen from adb/DDMS. Its\n"
+ " purpose is to use the emulator in very specific network configurations.\n\n"
+
+ " <consoleport> is the TCP port used to bind the control console\n"
+ " <adbport> is the TCP port used to bind the ADB local transport/tunnel.\n\n"
+
+ " If both ports aren't available on startup, the emulator will exit.\n\n");
+}
+
+
+static void
+help_onion(stralloc_t* out)
+{
+ PRINTF(
+ " use '-onion <file>' to specify a PNG image file that will be displayed on\n"
+ " top of the emulated framebuffer with translucency. this can be useful to\n"
+ " check that UI elements are correctly positioned with regards to a reference\n"
+ " graphics specification.\n\n"
+
+ " the default translucency is 50%%, but you can use '-onion-alpha <%%age>' to\n"
+ " select a different one, or even use keypresses at runtime to alter it\n"
+ " (see -help-keys for details)\n\n"
+
+ " finally, the onion image can be rotated (see -help-onion-rotate)\n\n"
+ );
+}
+
+static void
+help_onion_alpha(stralloc_t* out)
+{
+ PRINTF(
+ " use '-onion-alpha <percent>' to change the translucency level of the onion\n"
+ " image that is going to be displayed on top of the framebuffer (see also\n"
+ " -help-onion). the default is 50%%.\n\n"
+
+ " <percent> must be an integer between 0 and 100.\n\n"
+
+ " you can also change the translucency dynamically (see -help-keys)\n\n"
+ );
+}
+
+static void
+help_onion_rotation(stralloc_t* out)
+{
+ PRINTF(
+ " use '-onion-rotation <rotation>' to change the rotation of the onion\n"
+ " image loaded through '-onion <file>'. valid values for <rotation> are:\n\n"
+
+ " 0 no rotation\n"
+ " 1 90 degrees clockwise\n"
+ " 2 180 degrees\n"
+ " 3 270 degrees clockwise\n\n"
+ );
+}
+
+
+static void
+help_timezone(stralloc_t* out)
+{
+ PRINTF(
+ " by default, the emulator tries to detect your current timezone to report\n"
+ " it to the emulated system. use the '-timezone <timezone>' option to choose\n"
+ " a different timezone, or if the automatic detection doesn't work correctly.\n\n"
+
+ " VERY IMPORTANT NOTE:\n\n"
+ " the <timezone> value must be in zoneinfo format, i.e. it should look like\n"
+ " Area/Location or even Area/SubArea/Location. valid examples are:\n\n"
+
+ " America/Los_Angeles\n"
+ " Europe/Paris\n\n"
+
+ " using a human-friendly abbreviation like 'PST' or 'CET' will not work, as\n"
+ " well as using values that are not defined by the zoneinfo database.\n\n"
+
+ " NOTE: unfortunately, this will not work on M5 and older SDK releases\n\n"
+ );
+}
+
+
+static void
+help_dns_server(stralloc_t* out)
+{
+ PRINTF(
+ " by default, the emulator tries to detect the DNS servers you're using and\n"
+ " will setup special aliases in the emulated firewall network to allow the\n"
+ " Android system to connect directly to them. use '-dns-server <servers>' to\n"
+ " select a different list of DNS servers to be used.\n\n"
+
+ " <servers> must be a comma-separated list of up to 4 DNS server names or\n"
+ " IP addresses.\n\n"
+
+ " NOTE: on M5 and older SDK releases, only the first server in the list will\n"
+ " be used.\n\n"
+ );
+}
+
+
+static void
+help_cpu_delay(stralloc_t* out)
+{
+ PRINTF(
+ " this option is purely experimental, probably doesn't work as you would\n"
+ " expect, and may even disappear in a later emulator release.\n\n"
+
+ " use '-cpu-delay <delay>' to throttle CPU emulation. this may be useful\n"
+ " to detect weird race conditions that only happen on 'lower' CPUs. note\n"
+ " that <delay> is a unit-less integer that doesn't even scale linearly\n"
+ " to observable slowdowns. use trial and error to find something that\n"
+ " suits you, the 'correct' machine is very probably dependent on your\n"
+ " host CPU and memory anyway...\n\n"
+ );
+}
+
+
+static void
+help_no_boot_anim(stralloc_t* out)
+{
+ PRINTF(
+ " use '-no-boot-anim' to disable the boot animation (red bouncing ball) when\n"
+ " starting the emulator. on slow machines, this can surprisingly speed up the\n"
+ " boot sequence in tremendous ways.\n\n"
+
+ " NOTE: unfortunately, this will not work on M5 and older SDK releases\n\n"
+ );
+}
+
+
+static void
+help_gps(stralloc_t* out)
+{
+ PRINTF(
+ " use '-gps <device>' to emulate an NMEA-compatible GPS unit connected to\n"
+ " an external character device or socket. the format of <device> is the same\n"
+ " than the one used for '-radio <device>' (see -help-char-devices for details)\n\n"
+ );
+}
+
+
+static void
+help_keyset(stralloc_t* out)
+{
+ char temp[256];
+
+ PRINTF(
+ " use '-keyset <name>' to specify a different keyset file name to use when\n"
+ " starting the emulator. a keyset file contains a list of key bindings used\n"
+ " to control the emulator with the host keyboard.\n\n"
+
+ " by default, the emulator looks for the following file:\n\n"
+ );
+
+ bufprint_config_file(temp, temp+sizeof(temp), KEYSET_FILE);
+ PRINTF(
+ " %s\n\n", temp );
+
+ bufprint_config_path(temp, temp+sizeof(temp));
+ PRINTF(
+ " however, if -keyset is used, then the emulator does the following:\n\n"
+
+ " - first, if <name> doesn't have an extension, then the '.keyset' suffix\n"
+ " is appended to it (e.g. \"foo\" => \"foo.keyset\"),\n\n"
+
+ " - then, the emulator searches for a file named <name> in the following\n"
+ " directories:\n\n"
+
+ " * the emulator configuration directory: %s\n"
+ " * the 'keysets' subdirectory of <systemdir>, if any\n"
+ " * the 'keysets' subdirectory of the program location, if any\n\n",
+ temp );
+
+ PRINTF(
+ " if no corresponding file is found, a default set of key bindings is used.\n\n"
+ " use '-help-keys' to list the default key bindings.\n"
+ " use '-help-keyset-file' to learn more about the format of keyset files.\n"
+ "\n"
+ );
+}
+
+static void
+help_old_system(stralloc_t* out)
+{
+ PRINTF(
+ " use '-old-system' if you want to use a recent emulator binary to run\n"
+ " an old version of the Android SDK system images. Here, 'old' means anything\n"
+ " older than version 1.4 of the emulator.\n\n"
+
+ " NOTE: using '-old-system' with recent system images is likely to not work\n"
+ " properly, though you may not notice it immediately (e.g. failure to\n"
+ " start the emulated GPS hardware)\n\n"
+ );
+}
+
+#ifdef CONFIG_NAND_LIMITS
+static void
+help_nand_limits(stralloc_t* out)
+{
+ PRINTF(
+ " use '-nand-limits <limits>' to enable a debugging feature that sends a\n"
+ " signal to an external process once a read and/or write limit is achieved\n"
+ " in the emulated system. the format of <limits> is the following:\n\n"
+
+ " pid=<number>,signal=<number>,[reads=<threshold>][,writes=<threshold>]\n\n"
+
+ " where 'pid' is the target process identifier, 'signal' the number of the\n"
+ " target signal. the read and/or write threshold'reads' are a number optionally\n"
+ " followed by a K, M or G suffix, corresponding to the number of bytes to be\n"
+ " read or written before the signal is sent.\n\n"
+ );
+}
+#endif /* CONFIG_NAND_LIMITS */
+
+static void
+help_bootchart(stralloc_t *out)
+{
+ PRINTF(
+ " some Android system images have a modified 'init' system that integrates\n"
+ " a bootcharting facility (see http://www.bootchart.org/). You can pass a\n"
+ " bootcharting period to the system with the following:\n\n"
+
+ " -bootchart <timeout>\n\n"
+
+ " where 'timeout' is a period expressed in seconds. Note that this won't do\n"
+ " anything if your init doesn't have bootcharting activated.\n\n"
+ );
+}
+
+static void
+help_tcpdump(stralloc_t *out)
+{
+ PRINTF(
+ " use the -tcpdump <file> option to start capturing all network packets\n"
+ " that are sent through the emulator's virtual Ethernet LAN. You can later\n"
+ " use tools like WireShark to analyze the traffic and understand what\n"
+ " really happens.\n\n"
+
+ " note that this captures all Ethernet packets, and is not limited to TCP\n"
+ " connections.\n\n"
+
+ " you can also start/stop the packet capture dynamically through the console;\n"
+ " see the 'network capture start' and 'network capture stop' commands for\n"
+ " details.\n\n"
+ );
+}
+
+#define help_no_skin NULL
+#define help_netspeed help_shaper
+#define help_netdelay help_shaper
+#define help_netfast help_shaper
+
+#define help_noaudio NULL
+#define help_noskin NULL
+#define help_nocache NULL
+#define help_no_jni NULL
+#define help_nojni NULL
+#define help_initdata NULL
+#define help_no_window NULL
+#define help_version NULL
+#define help_memory NULL
+
+typedef struct {
+ const char* name;
+ const char* template;
+ const char* descr;
+ void (*func)(stralloc_t*);
+} OptionHelp;
+
+static const OptionHelp option_help[] = {
+#define OPT_FLAG(_name,_descr) { STRINGIFY(_name), NULL, _descr, help_##_name },
+#define OPT_PARAM(_name,_template,_descr) { STRINGIFY(_name), _template, _descr, help_##_name },
+#include "android/cmdline-options.h"
+ { NULL, NULL, NULL, NULL }
+};
+
+typedef struct {
+ const char* name;
+ const char* desc;
+ void (*func)(stralloc_t*);
+} TopicHelp;
+
+
+static const TopicHelp topic_help[] = {
+ { "disk-images", "about disk images", help_disk_images },
+ { "keys", "supported key bindings", help_keys },
+ { "debug-tags", "debug tags for -debug <tags>", help_debug_tags },
+ { "char-devices", "character <device> specification", help_char_devices },
+ { "environment", "environment variables", help_environment },
+ { "keyset-file", "key bindings configuration file", help_keyset_file },
+ { "virtual-device", "virtual device management", help_virtual_device },
+ { "sdk-images", "about disk images when using the SDK", help_sdk_images },
+ { "build-images", "about disk images when building Android", help_build_images },
+ { NULL, NULL, NULL }
+};
+
+int
+android_help_for_option( const char* option, stralloc_t* out )
+{
+ OptionHelp const* oo;
+ char temp[32];
+
+ /* the names in the option_help table use underscore instead
+ * of dashes, so create a tranlated copy of the option name
+ * before scanning the table for matches
+ */
+ buffer_translate_char( temp, sizeof temp, option, '-', '_' );
+
+ for ( oo = option_help; oo->name != NULL; oo++ ) {
+ if ( !strcmp(oo->name, temp) ) {
+ if (oo->func)
+ oo->func(out);
+ else
+ stralloc_add_str(out, oo->descr);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+int
+android_help_for_topic( const char* topic, stralloc_t* out )
+{
+ const TopicHelp* tt;
+
+ for ( tt = topic_help; tt->name != NULL; tt++ ) {
+ if ( !strcmp(tt->name, topic) ) {
+ tt->func(out);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+extern void
+android_help_list_options( stralloc_t* out )
+{
+ const OptionHelp* oo;
+ const TopicHelp* tt;
+ int maxwidth = 0;
+
+ for ( oo = option_help; oo->name != NULL; oo++ ) {
+ int width = strlen(oo->name);
+ if (oo->template != NULL)
+ width += strlen(oo->template);
+ if (width > maxwidth)
+ maxwidth = width;
+ }
+
+ for (oo = option_help; oo->name != NULL; oo++) {
+ char temp[32];
+ /* the names in the option_help table use underscores instead
+ * of dashes, so create a translated copy of the option's name
+ */
+ buffer_translate_char(temp, sizeof temp, oo->name, '_', '-');
+
+ stralloc_add_format( out, " -%s %-*s %s\n",
+ temp,
+ (int)(maxwidth - strlen(oo->name)),
+ oo->template ? oo->template : "",
+ oo->descr );
+ }
+
+ PRINTF( "\n" );
+ PRINTF( " %-*s %s\n", maxwidth, "-qemu args...", "pass arguments to qemu");
+ PRINTF( " %-*s %s\n", maxwidth, "-qemu -h", "display qemu help");
+ PRINTF( "\n" );
+ PRINTF( " %-*s %s\n", maxwidth, "-verbose", "same as '-debug-init'");
+ PRINTF( " %-*s %s\n", maxwidth, "-debug <tags>", "enable/disable debug messages");
+ PRINTF( " %-*s %s\n", maxwidth, "-debug-<tag>", "enable specific debug messages");
+ PRINTF( " %-*s %s\n", maxwidth, "-debug-no-<tag>","disable specific debug messages");
+ PRINTF( "\n" );
+ PRINTF( " %-*s %s\n", maxwidth, "-help", "print this help");
+ PRINTF( " %-*s %s\n", maxwidth, "-help-<option>", "print option-specific help");
+ PRINTF( "\n" );
+
+ for (tt = topic_help; tt->name != NULL; tt += 1) {
+ char help[32];
+ snprintf(help, sizeof(help), "-help-%s", tt->name);
+ PRINTF( " %-*s %s\n", maxwidth, help, tt->desc );
+ }
+ PRINTF( " %-*s %s\n", maxwidth, "-help-all", "prints all help content");
+ PRINTF( "\n");
+}
+
+
+void
+android_help_main( stralloc_t* out )
+{
+ stralloc_add_str(out, "Android Emulator usage: emulator [options] [-qemu args]\n");
+ stralloc_add_str(out, " options:\n" );
+
+ android_help_list_options(out);
+
+ /*printf( "%.*s", out->n, out->s );*/
+}
+
+
+void
+android_help_all( stralloc_t* out )
+{
+ const OptionHelp* oo;
+ const TopicHelp* tt;
+
+ for (oo = option_help; oo->name != NULL; oo++) {
+ PRINTF( "========= help for option -%s:\n\n", oo->name );
+ android_help_for_option( oo->name, out );
+ }
+
+ for (tt = topic_help; tt->name != NULL; tt++) {
+ PRINTF( "========= help for -help-%s\n\n", tt->name );
+ android_help_for_topic( tt->name, out );
+ }
+ PRINTF( "========= top-level help\n\n" );
+ android_help_main(out);
+}
diff --git a/android/help.h b/android/help.h
new file mode 100644
index 0000000..94feca1
--- /dev/null
+++ b/android/help.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_HELP_H
+#define _ANDROID_HELP_H
+
+#include "android/utils/stralloc.h"
+
+/* appends the list of options with a small description to a dynamic string */
+extern void android_help_list_options( stralloc_t* out );
+
+/* output main help screen into a single dynamic string */
+extern void android_help_main( stralloc_t* out );
+
+/* output all help into a single dynamic string */
+extern void android_help_all( stralloc_t* out );
+
+/* appends the help for a given command-line option into a dynamic string
+ * returns 0 on success, or -1 on error (i.e. unknown option)
+ */
+extern int android_help_for_option( const char* option, stralloc_t* out );
+
+/* appends the help for a given help topic into a dynamic string
+ * returns 0 on success, or -1 on error (i.e. unknown topic)
+ */
+extern int android_help_for_topic( const char* topic, stralloc_t* out );
+
+#endif /* _ANDROID_HELP_H */
diff --git a/android/hw-control.c b/android/hw-control.c
new file mode 100644
index 0000000..681e85b
--- /dev/null
+++ b/android/hw-control.c
@@ -0,0 +1,204 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+/* this file implements the support of the new 'hardware control'
+ * qemud communication channel, which is used by libs/hardware on
+ * the system image to communicate with the emulator program for
+ * emulating the following:
+ *
+ * - power management
+ * - led(s) brightness
+ * - vibrator
+ * - flashlight
+ */
+#include "android/hw-control.h"
+#include "cbuffer.h"
+#include "android/qemud.h"
+#include "android/utils/misc.h"
+#include "android/utils/debug.h"
+#include "qemu-char.h"
+#include <stdio.h>
+#include <string.h>
+
+#define D(...) VERBOSE_PRINT(hw_control,__VA_ARGS__)
+
+/* define T_ACTIVE to 1 to debug transport communications */
+#define T_ACTIVE 0
+
+#if T_ACTIVE
+#define T(...) VERBOSE_PRINT(hw_control,__VA_ARGS__)
+#else
+#define T(...) ((void)0)
+#endif
+
+static void* hw_control_client;
+static AndroidHwControlFuncs hw_control_funcs;
+
+#define BUFFER_SIZE 512
+
+typedef struct {
+ CharDriverState* cs;
+ int overflow;
+ int wanted;
+ CBuffer input[1];
+ char input_0[ BUFFER_SIZE ];
+ /* note: 1 more byte to zero-terminate the query */
+ char query[ BUFFER_SIZE+1 ];
+} HwControl;
+
+/* forward */
+static void hw_control_do_query( HwControl* h,
+ uint8_t* query,
+ int querylen );
+
+static void
+hw_control_init( HwControl* h, CharDriverState* cs )
+{
+ h->cs = cs;
+ h->overflow = 0;
+ h->wanted = 0;
+ cbuffer_reset( h->input, h->input_0, sizeof h->input_0 );
+}
+
+static int
+hw_control_can_read( void* _hw )
+{
+ HwControl* h = _hw;
+ return cbuffer_write_avail( h->input );
+}
+
+static void
+hw_control_read( void* _hw, const uint8_t* data, int len )
+{
+ HwControl* h = _hw;
+ CBuffer* input = h->input;
+
+ T("%s: %4d '%.*s'", __FUNCTION__, len, len, data);
+
+ cbuffer_write( input, data, len );
+
+ while ( input->count > 0 )
+ {
+ /* skip over unwanted data, if any */
+ while (h->overflow > 0) {
+ uint8_t* dummy;
+ int avail = cbuffer_read_peek( input, &dummy );
+
+ if (avail == 0)
+ return;
+
+ if (avail > h->overflow)
+ avail = h->overflow;
+
+ cbuffer_read_step( input, avail );
+ h->overflow -= avail;
+ }
+
+ /* all incoming messages are made of a 4-byte hexchar sequence giving */
+ /* the length of the following payload */
+ if (h->wanted == 0)
+ {
+ char header[4];
+ int len;
+
+ if (input->count < 4)
+ return;
+
+ cbuffer_read( input, header, 4 );
+ len = hex2int( (uint8_t*)header, 4 );
+ if (len >= 0) {
+ /* if the message is too long, skip it */
+ if (len > input->size) {
+ T("%s: skipping oversized message (%d > %d)",
+ __FUNCTION__, len, input->size);
+ h->overflow = len;
+ } else {
+ T("%s: waiting for %d bytes", __FUNCTION__, len);
+ h->wanted = len;
+ }
+ }
+ }
+ else
+ {
+ if (input->count < h->wanted)
+ break;
+
+ cbuffer_read( input, h->query, h->wanted );
+ h->query[h->wanted] = 0;
+ hw_control_do_query( h, (uint8_t*)h->query, h->wanted );
+ h->wanted = 0;
+ }
+ }
+}
+
+
+static uint8_t*
+if_starts_with( uint8_t* buf, int buflen, const char* prefix )
+{
+ int prefixlen = strlen(prefix);
+
+ if (buflen < prefixlen || memcmp(buf, prefix, prefixlen))
+ return NULL;
+
+ return (uint8_t*)buf + prefixlen;
+}
+
+
+static void
+hw_control_do_query( HwControl* h,
+ uint8_t* query,
+ int querylen )
+{
+ uint8_t* q;
+
+ D("%s: query %4d '%.*s'", __FUNCTION__, querylen, querylen, query );
+
+ q = if_starts_with( query, querylen, "power:light:brightness:" );
+ if (q != NULL) {
+ if (hw_control_funcs.light_brightness) {
+ char* qq = strchr((const char*)q, ':');
+ int value;
+ if (qq == NULL) {
+ D("%s: badly formatted", __FUNCTION__ );
+ return;
+ }
+ *qq++ = 0;
+ value = atoi(qq);
+ hw_control_funcs.light_brightness( hw_control_client, (char*)q, value );
+ }
+ return;
+ }
+}
+
+
+void
+android_hw_control_init( void* opaque, const AndroidHwControlFuncs* funcs )
+{
+ static CharDriverState* hw_control_cs;
+ static HwControl hwstate[1];
+
+ if (hw_control_cs == NULL) {
+ CharDriverState* cs;
+ if ( android_qemud_get_channel( ANDROID_QEMUD_CONTROL, &cs ) < 0 ) {
+ derror( "could not create hardware control charpipe" );
+ exit(1);
+ }
+
+ hw_control_cs = cs;
+ hw_control_init( hwstate, cs );
+ qemu_chr_add_handlers( cs, hw_control_can_read, hw_control_read, NULL, hwstate );
+
+ D("%s: hw-control char pipe initialized", __FUNCTION__);
+ }
+ hw_control_client = opaque;
+ hw_control_funcs = funcs[0];
+}
diff --git a/android/hw-control.h b/android/hw-control.h
new file mode 100644
index 0000000..6e9874e
--- /dev/null
+++ b/android/hw-control.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _android_hw_control_h
+#define _android_hw_control_h
+
+#include "qemu-common.h"
+
+/* a callback function called when the system wants to change the brightness
+ * of a given light. 'light' is a string which can be one of:
+ * 'lcd_backlight', 'button_backlight' or 'Keyboard_backlight'
+ *
+ * brightness is an integer (acceptable range are 0..255), however the
+ * default is around 105, and we probably don't want to dim the emulator's
+ * output at that level.
+ */
+typedef void (*AndroidHwLightBrightnessFunc)( void* opaque,
+ const char* light,
+ int brightness );
+
+/* used to record a hw control 'client' */
+typedef struct {
+ AndroidHwLightBrightnessFunc light_brightness;
+} AndroidHwControlFuncs;
+
+/* used to initialize the hardware control support */
+extern void android_hw_control_init( void* opaque,
+ const AndroidHwControlFuncs* funcs );
+
+#endif /* _android_hw_control_h */
diff --git a/android/hw-events.c b/android/hw-events.c
new file mode 100644
index 0000000..e72440c
--- /dev/null
+++ b/android/hw-events.c
@@ -0,0 +1,223 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/hw-events.h"
+#include "android/utils/bufprint.h"
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ const char* name;
+ int value;
+} PairRec;
+
+#define EV_TYPE(n,v) { STRINGIFY(n), (v) },
+#define BTN_CODE(n,v) { STRINGIFY(n), (v) },
+#define REL_CODE(n,v) { STRINGIFY(n), (v) },
+#define ABS_CODE(n,v) { STRINGIFY(n), (v) },
+
+static const PairRec _ev_types_tab[] =
+{
+ EVENT_TYPE_LIST
+ { NULL, 0 }
+};
+
+static const PairRec _btn_codes_list[] =
+{
+ EVENT_BTN_LIST
+ { NULL, 0 }
+};
+
+static const PairRec _rel_codes_list[] =
+{
+ EVENT_REL_LIST
+ { NULL, 0 }
+};
+
+static const PairRec _abs_codes_list[] =
+{
+ EVENT_ABS_LIST
+ { NULL, 0 }
+};
+
+#undef EV_TYPE
+#undef BTN_CODE
+#undef REL_CODE
+#undef ABS_CODE
+
+static int
+count_list( const PairRec* list )
+{
+ int nn = 0;
+ while (list[nn].name != NULL)
+ nn += 1;
+
+ return nn;
+}
+
+static int
+scan_list( const PairRec* list,
+ const char* prefix,
+ const char* name,
+ int namelen )
+{
+ int len;
+
+ if (namelen <= 0)
+ return -1;
+
+ len = strlen(prefix);
+ if (namelen <= len)
+ return -1;
+ if ( memcmp( name, prefix, len ) != 0 )
+ return -1;
+
+ name += len;
+ namelen -= len;
+
+ for ( ; list->name != NULL; list += 1 )
+ {
+ if ( memcmp( list->name, name, namelen ) == 0 && list->name[namelen] == 0 )
+ return list->value;
+ }
+ return -1;
+}
+
+
+typedef struct {
+ int type;
+ const char* prefix;
+ const PairRec* pairs;
+} TypeListRec;
+
+typedef const TypeListRec* TypeList;
+
+static const TypeListRec _types_list[] =
+{
+ { EV_KEY, "BTN_", _btn_codes_list },
+ { EV_REL, "REL_", _rel_codes_list },
+ { EV_ABS, "ABS_", _abs_codes_list },
+ { -1, NULL, NULL }
+};
+
+
+static TypeList
+find_type_list( int type )
+{
+ TypeList list = _types_list;
+
+ for ( ; list->type >= 0; list += 1 )
+ if (list->type == type)
+ return list;
+
+ return NULL;
+}
+
+
+int
+android_event_from_str( const char* name,
+ int *ptype,
+ int *pcode,
+ int *pvalue )
+{
+ const char* p;
+ const char* pend;
+ const char* q;
+ TypeList list;
+ char* end;
+
+ *ptype = 0;
+ *pcode = 0;
+ *pvalue = 0;
+
+ p = name;
+ pend = p + strcspn(p, " \t");
+ q = strchr(p, ':');
+ if (q == NULL || q > pend)
+ q = pend;
+
+ *ptype = scan_list( _ev_types_tab, "EV_", p, q-p );
+ if (*ptype < 0) {
+ *ptype = (int) strtol( p, &end, 0 );
+ if (end != q)
+ return -1;
+ }
+
+ if (*q != ':')
+ return 0;
+
+ p = q + 1;
+ q = strchr(p, ':');
+ if (q == NULL || q > pend)
+ q = pend;
+
+ list = find_type_list( *ptype );
+
+ *pcode = -1;
+ if (list != NULL) {
+ *pcode = scan_list( list->pairs, list->prefix, p, q-p );
+ }
+ if (*pcode < 0) {
+ *pcode = (int) strtol( p, &end, 0 );
+ if (end != q)
+ return -2;
+ }
+
+ if (*q != ':')
+ return 0;
+
+ p = q + 1;
+ q = strchr(p, ':');
+ if (q == NULL || q > pend)
+ q = pend;
+
+ *pvalue = (int)strtol( p, &end, 0 );
+ if (end != q)
+ return -3;
+
+ return 0;
+}
+
+int
+android_event_get_type_count( void )
+{
+ return count_list( _ev_types_tab );
+}
+
+char*
+android_event_bufprint_type_str( char* buff, char* end, int type_index )
+{
+ return bufprint( buff, end, "EV_%s", _ev_types_tab[type_index].name );
+}
+
+/* returns the list of valid event code string aliases for a given event type */
+int
+android_event_get_code_count( int type )
+{
+ TypeList list = find_type_list(type);
+
+ if (list == NULL)
+ return 0;
+
+ return count_list( list->pairs );
+}
+
+char*
+android_event_bufprint_code_str( char* buff, char* end, int type, int code_index )
+{
+ TypeList list = find_type_list(type);
+
+ if (list == NULL)
+ return buff;
+
+ return bufprint( buff, end, "%s%s", list->prefix, list->pairs[code_index].name );
+}
+
diff --git a/android/hw-events.h b/android/hw-events.h
new file mode 100644
index 0000000..74100b8
--- /dev/null
+++ b/android/hw-events.h
@@ -0,0 +1,184 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_HW_EVENTS_H
+#define _ANDROID_HW_EVENTS_H
+
+#include "android/utils/system.h"
+
+/* from the Linux kernel */
+
+#define EVENT_TYPE_LIST \
+ EV_TYPE(SYN,0x00) \
+ EV_TYPE(KEY,0x01) \
+ EV_TYPE(REL,0x02) \
+ EV_TYPE(ABS,0x03) \
+ EV_TYPE(MSC,0x04) \
+ EV_TYPE(SW, 0x05) \
+ EV_TYPE(LED,0x11) \
+ EV_TYPE(SND,0x12) \
+ EV_TYPE(REP,0x14) \
+ EV_TYPE(FF, 0x15) \
+ EV_TYPE(PWR,0x16) \
+ EV_TYPE(FF_STATUS,0x17) \
+ EV_TYPE(MAX,0x1f)
+
+#undef EV_TYPE
+#define EV_TYPE(n,v) GLUE(EV_,n) = v,
+typedef enum {
+ EVENT_TYPE_LIST
+} EventType;
+#undef EV_TYPE
+
+#define EVENT_BTN_LIST \
+ BTN_CODE(MISC,0x100) \
+ BTN_CODE(0,0x100) \
+ BTN_CODE(1,0x101) \
+ BTN_CODE(2,0x102) \
+ BTN_CODE(3,0x103) \
+ BTN_CODE(4,0x104) \
+ BTN_CODE(5,0x105) \
+ BTN_CODE(6,0x106) \
+ BTN_CODE(7,0x107) \
+ BTN_CODE(8,0x108) \
+ BTN_CODE(9,0x109) \
+ \
+ BTN_CODE(MOUSE, 0x110) \
+ BTN_CODE(LEFT, 0x110) \
+ BTN_CODE(RIGHT, 0x111) \
+ BTN_CODE(MIDDLE, 0x112) \
+ BTN_CODE(SIDE, 0x113) \
+ BTN_CODE(EXTRA, 0x114) \
+ BTN_CODE(FORWARD,0x115) \
+ BTN_CODE(BACK, 0x116) \
+ BTN_CODE(TASK, 0x117) \
+ \
+ BTN_CODE(JOYSTICK,0x120) \
+ BTN_CODE(TRIGGER, 0x120) \
+ BTN_CODE(THUMB, 0x121) \
+ BTN_CODE(THUMB2, 0x122) \
+ BTN_CODE(TOP, 0x123) \
+ BTN_CODE(TOP2, 0x124) \
+ BTN_CODE(PINKIE, 0x125) \
+ BTN_CODE(BASE, 0x126) \
+ BTN_CODE(BASE2, 0x127) \
+ BTN_CODE(BASE3, 0x128) \
+ BTN_CODE(BASE4, 0x129) \
+ BTN_CODE(BASE5, 0x12a) \
+ BTN_CODE(BASE6, 0x12b) \
+ BTN_CODE(DEAD, 0x12f) \
+ \
+ BTN_CODE(GAMEPAD, 0x130) \
+ BTN_CODE(A, 0x130) \
+ BTN_CODE(B, 0x131) \
+ BTN_CODE(C, 0x132) \
+ BTN_CODE(X, 0x133) \
+ BTN_CODE(Y, 0x134) \
+ BTN_CODE(Z, 0x135) \
+ BTN_CODE(TL, 0x136) \
+ BTN_CODE(TR, 0x137) \
+ BTN_CODE(TL2, 0x138) \
+ BTN_CODE(TR2, 0x139) \
+ BTN_CODE(SELECT, 0x13a) \
+ BTN_CODE(START, 0x13b) \
+ BTN_CODE(MODE, 0x13c) \
+ BTN_CODE(THUMBL, 0x13d) \
+ BTN_CODE(THUMBR, 0x13e) \
+ \
+ BTN_CODE(DIGI, 0x140) \
+ BTN_CODE(TOOL_PEN, 0x140) \
+ BTN_CODE(TOOL_RUBBER, 0x141) \
+ BTN_CODE(TOOL_BRUSH, 0x142) \
+ BTN_CODE(TOOL_PENCIL, 0x143) \
+ BTN_CODE(TOOL_AIRBRUSH, 0x144) \
+ BTN_CODE(TOOL_FINGER, 0x145) \
+ BTN_CODE(TOOL_MOUSE, 0x146) \
+ BTN_CODE(TOOL_LENS, 0x147) \
+ BTN_CODE(TOUCH, 0x14a) \
+ BTN_CODE(STYLUS, 0x14b) \
+ BTN_CODE(STYLUS2, 0x14c) \
+ BTN_CODE(TOOL_DOUBLETAP, 0x14d) \
+ BTN_CODE(TOOL_TRIPLETAP, 0x14e) \
+ \
+ BTN_CODE(WHEEL, 0x150) \
+ BTN_CODE(GEAR_DOWN, 0x150) \
+ BTN_CODE(GEAR_UP, 0x150)
+
+#undef BTN_CODE
+#define BTN_CODE(n,v) GLUE(BTN_,n) = v,
+typedef enum {
+ EVENT_BTN_LIST
+} EventBtnCode;
+#undef BTN_CODE
+
+#define EVENT_REL_LIST \
+ REL_CODE(X, 0x00) \
+ REL_CODE(Y, 0x01)
+
+#define REL_CODE(n,v) GLUE(REL_,n) = v,
+typedef enum {
+ EVENT_REL_LIST
+} EventRelCode;
+#undef REL_CODE
+
+#define EVENT_ABS_LIST \
+ ABS_CODE(X, 0x00) \
+ ABS_CODE(Y, 0x01) \
+ ABS_CODE(Z, 0x02) \
+ ABS_CODE(RX, 0x03) \
+ ABS_CODE(RY, 0x04) \
+ ABS_CODE(RZ, 0x05) \
+ ABS_CODE(THROTTLE, 0x06) \
+ ABS_CODE(RUDDER, 0x07) \
+ ABS_CODE(WHEEL, 0x08) \
+ ABS_CODE(GAS, 0x09) \
+ ABS_CODE(BRAKE, 0x0a) \
+ ABS_CODE(HAT0X, 0x10) \
+ ABS_CODE(HAT0Y, 0x11) \
+ ABS_CODE(HAT1X, 0x12) \
+ ABS_CODE(HAT1Y, 0x13) \
+ ABS_CODE(HAT2X, 0x14) \
+ ABS_CODE(HAT2Y, 0x15) \
+ ABS_CODE(HAT3X, 0x16) \
+ ABS_CODE(HAT3Y, 0x17) \
+ ABS_CODE(PRESSURE, 0x18) \
+ ABS_CODE(DISTANCE, 0x19) \
+ ABS_CODE(TILT_X, 0x1a) \
+ ABS_CODE(TILT_Y, 0x1b) \
+ ABS_CODE(TOOL_WIDTH, 0x1c) \
+ ABS_CODE(VOLUME, 0x20) \
+ ABS_CODE(MISC, 0x28) \
+ ABS_CODE(MAX, 0x3f)
+
+#define ABS_CODE(n,v) GLUE(ABS_,n) = v,
+
+typedef enum {
+ EVENT_ABS_LIST
+} EventAbsCode;
+#undef ABS_CODE
+
+/* convert an event string specification like <type>:<code>:<value>
+ * into three integers. returns 0 on success, or -1 in case of error
+ */
+extern int android_event_from_str( const char* name,
+ int *ptype,
+ int *pcode,
+ int *pvalue );
+
+/* returns the list of valid event type string aliases */
+extern int android_event_get_type_count( void );
+extern char* android_event_bufprint_type_str( char* buff, char* end, int type_index );
+
+/* returns the list of valid event code string aliases for a given event type */
+extern int android_event_get_code_count( int type );
+extern char* android_event_bufprint_code_str( char* buff, char* end, int type, int code_index );
+
+#endif /* _ANDROID_HW_EVENTS_H */
diff --git a/android/hw-kmsg.c b/android/hw-kmsg.c
new file mode 100644
index 0000000..987943b
--- /dev/null
+++ b/android/hw-kmsg.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/hw-kmsg.h"
+#include "qemu-char.h"
+#include "charpipe.h"
+#include "android/utils/debug.h"
+
+static CharDriverState* android_kmsg_cs;
+
+typedef struct {
+ CharDriverState* cs;
+ AndroidKmsgFlags flags;
+} KernelLog;
+
+static int
+kernel_log_can_read( void* opaque )
+{
+ return 1024;
+}
+
+static void
+kernel_log_read( void* opaque, const uint8_t* from, int len )
+{
+ KernelLog* k = opaque;
+
+ if (k->flags & ANDROID_KMSG_PRINT_MESSAGES)
+ printf( "%.*s", len, (const char*)from );
+
+ /* XXXX: TODO: save messages into in-memory buffer for later retrieval */
+}
+
+static void
+kernel_log_init( KernelLog* k, AndroidKmsgFlags flags )
+{
+ if ( qemu_chr_open_charpipe( &k->cs, &android_kmsg_cs ) < 0 ) {
+ derror( "could not create kernel log charpipe" );
+ exit(1);
+ }
+
+ qemu_chr_add_handlers( k->cs, kernel_log_can_read, kernel_log_read, NULL, k );
+
+ k->flags = flags;
+}
+
+static KernelLog _kernel_log[1];
+
+void
+android_kmsg_init( AndroidKmsgFlags flags )
+{
+ if (_kernel_log->cs == NULL)
+ kernel_log_init( _kernel_log, flags );
+}
+
+
+CharDriverState* android_kmsg_get_cs( void )
+{
+ if (android_kmsg_cs == NULL) {
+ android_kmsg_init(0);
+ }
+ return android_kmsg_cs;
+}
diff --git a/android/hw-kmsg.h b/android/hw-kmsg.h
new file mode 100644
index 0000000..51d6731
--- /dev/null
+++ b/android/hw-kmsg.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _android_kmsg_h
+#define _android_kmsg_h
+
+#include "qemu-common.h"
+
+/* this chardriver is used to read the kernel messages coming
+ * from the first serial port (i.e. /dev/ttyS0) and store them
+ * in memory for later...
+ */
+
+typedef enum {
+ ANDROID_KMSG_SAVE_MESSAGES = (1 << 0),
+ ANDROID_KMSG_PRINT_MESSAGES = (1 << 1),
+} AndroidKmsgFlags;
+
+extern void android_kmsg_init( AndroidKmsgFlags flags );
+
+extern CharDriverState* android_kmsg_get_cs( void );
+
+#endif /* _android_kmsg_h */
diff --git a/android/icons.h b/android/icons.h
new file mode 100644
index 0000000..e4ec861
--- /dev/null
+++ b/android/icons.h
@@ -0,0 +1,984 @@
+/* Copyright (C) 2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+/* automatically generated, do not touch */
+
+static const unsigned char _data_android_icon_16_png[460] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 16, 0, 0, 0, 16, 8, 6, 0, 0, 0, 31,243,255,
+ 97, 0, 0, 1,147, 73, 68, 65, 84, 56,141,173, 82, 77, 75, 66,
+ 65, 20, 61, 79,173,199,148,125, 64,209, 35,112, 97,145, 84,219,
+ 30,210, 7,173,162, 64,168, 77,235, 8,132, 86,110,251, 39,109,
+ 94,109, 10,177, 40,104, 47, 73, 59,169, 80,136, 90, 68,144,182,
+ 8, 18,162, 44, 42,165,184,111, 20,229,182,200, 39,126,188,146,
+ 160, 3, 3,119,152,115,207, 61, 51,115,192,204,104, 92, 68, 82,
+ 39,146, 61, 53,123, 65, 36,167,237,184,182,205,145,228, 12,231,
+ 62, 94,152, 72,222, 17,201,251,143,207, 28, 71,146, 51,108, 39,
+ 226, 66, 51, 2,139,227,135, 56, 78,175, 65,150,222,134,152,203,
+ 80, 93,189, 8,140, 70, 0, 32, 0, 32, 81,199,110,152, 62,250,
+ 244,126,203,225,196, 36, 19, 73, 54,226, 94, 54,226, 94, 38,146,
+ 188,115, 54,193, 15,175, 87, 77, 46, 28,150,144,105, 22,102, 1,
+ 132, 82,217, 61, 80, 49,139,240,249, 88,117, 72,248,124, 12,178,
+ 244,134,235,199,109, 0, 8,153,102, 97,193, 58, 83,152, 25,166,
+ 89,152,205,126, 94,156,104,110,221,230, 70, 63, 98, 73, 8, 53,
+ 106,189, 65, 40,253,124,128,163,155, 21, 4,253,169,186,233,181,
+ 8,250, 83,216,191,244, 99,160, 75,199,188,111, 43, 4, 32,234,
+ 176,101,254, 1,255, 38, 80, 86,224,132,162, 56, 91, 54, 40,138,
+ 3,202,119, 91, 25, 64, 53, 7,155,186,103,125,117,164,127,185,
+ 165,192,156,207, 64,103,155, 6, 0,155, 85, 7, 66,168,137,142,
+ 118,205, 51,216, 61,181,209, 74, 64,115,235,187,110,213, 51, 44,
+ 132, 26, 3,208, 28, 36, 34,105,228,205, 12, 27,113, 47,231,205,
+ 12,215,214, 68, 50,242, 99,144, 42, 78,210, 0,162,191, 24,136,
+ 9,161,214, 69,217,238, 23, 46, 74, 69, 7,134,251,150, 80,144,
+ 69, 0,168,173, 19,141,100,133,153,155, 20,172, 88,163,242, 80,
+ 86, 45,132,122,218,200,253, 2, 34,145, 32,131,249,218,106,138,
+ 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+#ifdef CONFIG_DARWIN
+static const unsigned char _data_android_icon_256_png[13369] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 1, 0, 0, 0, 1, 0, 8, 6, 0, 0, 0, 92,114,168,
+ 102, 0, 0, 32, 0, 73, 68, 65, 84,120,156,237,157,119,124, 84,
+ 85,222,255, 63, 51,119,122, 50,105, 36,164,144, 10, 36, 4,144,
+ 162, 16, 69, 17, 68, 4, 17, 69,220, 93, 5,101,125,118,117,197,
+ 125, 22,244,121, 30, 93, 86,244,167,235,174,143,186,174,171,176,
+ 214, 69,121,118,215,222,176, 23,176, 32,138, 65,164, 8, 2, 73,
+ 32, 16,106,122, 47,147, 73,153,126,231,254,254,184,153,100,106,
+ 114,238,100,250, 61,239,215,107, 94, 19,134,115,238, 57,183,124,
+ 63,247,123,234, 87,194,113, 28, 40, 20,138, 56,145,134,187, 2,
+ 20, 10, 37,124, 80, 1,160, 80, 68,140, 44,208, 7, 52, 26,205,
+ 129, 62,100,196,163,209,168, 36,129, 56,142,193, 96, 18, 85,123,
+ 140, 94, 55,255, 81,171,149, 1, 57,142, 36,208,125, 0, 98, 18,
+ 128, 97, 30, 96, 41,120,113,101, 6,190, 37, 0,216,129,143, 13,
+ 128, 29, 0, 55,240,241, 74,172, 62,212,195, 92, 51, 9,134,174,
+ 23, 51,240,225,192, 95, 47,199,181,115, 92, 55,175,196,234, 53,
+ 243, 70,160, 4,128, 54, 1,252, 64,163, 81, 73,188, 60,200, 12,
+ 0, 21,128,132, 39,159,220, 48,169,186,186,230,209,174, 46,221,
+ 238,254,126, 67,131,193, 96,234,236,233,233, 61,209,210,210,250,
+ 246,161, 67,135, 86, 1, 72, 4,160, 1, 32, 7,127, 15, 36, 3,
+ 31,151, 50, 66,112, 42, 33,197,203, 57, 73,193, 95, 3, 13,128,
+ 196, 67,135, 14,173,106,105,105,125,187,167,167,247,132,193, 96,
+ 234,236,239, 55, 52,116,117,233,118, 87, 87,215, 60,250,228,147,
+ 27,138, 0, 36, 0, 80,131,191,214, 94,175, 89, 44, 94,183, 96,
+ 66, 61, 0,129,120,121,192, 36,224,223, 90,154,150,150,214,151,
+ 180,218,132,107, 36, 18,201, 72,242,204,153,205,166,170,147, 39,
+ 79, 62, 60,103,206, 69,219, 0, 88,192,191,225, 6,255,223,241,
+ 71,172,188,213,220,174,155, 4,188,241, 43,203,202,202, 87,228,
+ 231, 23, 60,160, 80, 40, 38,194,205,160,221,225, 56,206,220,219,
+ 219,243,121, 70, 70,250,237, 0, 12,224,189, 3,199,245,113,185,
+ 78,177,114,221,124, 65,155, 0, 97,192,199, 27, 76,249,209, 71,
+ 31, 95,176,120,241,226, 15, 25, 70, 54, 86,232, 49,219,219,219,
+ 62,202,203,203, 93, 13,192, 8, 31, 15,116,180, 63,204, 94,140,
+ 159, 1,160,105,110,110,125, 45, 49, 49,241, 58,161,199,179, 90,
+ 45,237, 95,127,189,253,250, 21, 43, 86, 28, 6, 96,198, 80,115,
+ 74, 52, 34, 64, 5, 32, 12,184, 61,200, 82, 0,170,250,250,134,
+ 39,198,140, 73, 93,139, 81, 52,167,140, 70, 99,237,152, 49,201,
+ 179, 0,244,129, 23, 1,192,237,129,142,214,135,217,139,241,203,
+ 0,196,245,244,244,150,203,100,242, 28,255,143,204,217, 91, 90,
+ 90,254, 57,126,124,193,122, 0, 38,120, 17,129,104,189,102, 36,
+ 208, 62,128, 16,227,229, 65,150,151,151, 87,220, 54,102, 76,234,
+ 157, 24,229,117, 84,171,213,121,157,157, 93, 21, 0,226,192,191,
+ 29, 29,101, 12,150, 25,141,109, 91, 31,111,126,245,232,141, 31,
+ 0, 36,210,140,140,204, 53,223,125, 87,122, 39, 0, 5,134,174,
+ 87, 84, 95,179, 80, 67, 5, 64, 56,142,246,107,220,196,137,133,
+ 79, 4,234,160,106,181, 38,235,228,201, 83,239, 98,168,147,203,
+ 81, 86, 44, 60,196,131,109,254,166,166,230,215, 71,111,252, 67,
+ 204,158, 61,251, 97, 0,169,112,125,150, 99,225,154,133, 4, 42,
+ 0,194,145, 0, 80,233,116,221,223, 75, 36, 18,117, 32, 15,156,
+ 147,147,187,232,163,143, 62, 94, 13,222, 77,246,120,160,163,233,
+ 141,230, 84, 87,199, 55,115,224,192,193, 27,147,146,146,151, 7,
+ 178, 28,134,145, 41,155,155, 91,118,130, 31,129,113,140,168, 80,
+ 8,161, 2, 32, 28,201,182,109,159,207, 82, 42, 85, 83,130,113,
+ 240,203, 47,191,252,127,193,191,209,124, 14,117, 5,163,220, 64,
+ 226, 99,136, 52,110,242,228, 41, 27,131, 81, 94, 98, 98,210,132,
+ 135, 31,126,100, 41,232,243, 44,152,128,207, 4, 20,202,171, 7,
+ 139,195, 93, 5, 33, 72, 0,200,166, 79,159,113,115,176, 10, 80,
+ 42, 85,218,234,234,154,207, 10, 10,242, 47, 7, 63,212,229, 49,
+ 60, 24, 69,215,204,225,250,171,218,219, 59,183, 49, 12,147, 20,
+ 172,130, 22, 45, 90,180,234,161,135,254,188, 29,124, 71,170, 3,
+ 46,210,175,213,173, 37, 85, 97, 45,159, 42,166,112,100, 90,109,
+ 252,165,193, 44, 32, 61, 61, 99,198, 7, 31,124,176, 22, 67,179,
+ 8, 93, 58,184,238,184,172, 38, 98,189, 0,167,186, 57,234, 43,
+ 59,120,240,167,155,227,226,226, 46, 14,102,185,121,121,249, 51,
+ 192, 79,176,138,216,107, 19,137, 80, 1, 16,142, 76,161, 80, 20,
+ 144, 36,236,232,175,192, 87, 85,191,194, 7, 21,139,112,164,241,
+ 121, 65,133, 44, 92,184,232,255,129,111, 10, 56, 68,192,133, 72,
+ 20, 1, 47,117,146, 2,136, 47, 46, 46,126, 92,200,113, 14, 53,
+ 60,133, 15, 42, 22,225,171,170, 95,161,163,191,130, 40, 79, 66,
+ 66, 66, 38,128,160,121, 24,177, 74,216,155, 0,209,128,243, 91,
+ 237, 79,127,250, 83,186, 68, 34, 85,141,148,135,181,155,240,205,
+ 169, 53, 48,217,186, 0, 0,229, 77,155, 96,231,172,152,149,189,
+ 142,168, 76,149, 74,165,173,174,174,249,180, 96,168, 41,224, 60,
+ 166,205, 57,234,245,194,174,252,193,223, 67, 45, 10,195,148,237,
+ 236,250,127,198, 48, 50, 98,195, 60,212,240, 20,142, 54,255, 19,
+ 0,208,103,110,192, 55,167,214, 96,197,140,157, 96, 70,184,228,
+ 50,153, 76,185, 96,193,130,156,210,210,210, 42, 56,205, 7,112,
+ 191, 70, 20, 87,168, 0, 8, 67,114,227,141, 55, 93, 78,146, 80,
+ 111,170, 30, 52,126, 7,199, 90, 94, 66,110,210, 66,164,197,207,
+ 36, 42,204,209, 20,184,225,134, 27,158, 3,255, 64,219,157,254,
+ 123,240, 1,119,175,163,151,127, 15,247,113, 28,203,125, 34,141,
+ 163, 60, 95,198,195,249, 16, 28,191, 93,255,246,190, 50, 28,107,
+ 121,201,229, 55,147,173, 11,122, 83, 53, 82, 52,147, 71,204,127,
+ 235,173,183, 94, 90, 90, 90,186, 19,174,253, 38,148, 97,160, 2,
+ 32, 12,238,221,119,183,124,119,255,253,127, 28, 49, 97,162,170,
+ 0, 10, 70, 11, 11,219, 59,148,153, 99,241, 67,245,253,184,238,
+ 188,207, 32,149,200,137, 10, 28,104, 10,188, 13,160, 13, 67, 43,
+ 9, 1,222,200, 56,167,191, 25,240,111, 93, 41,134, 86,211, 73,
+ 211,210,210,228,159,127,254,197, 34,133, 66,145,234, 56,102,124,
+ 124,124,102, 92, 92,156, 75,239, 88,127,127,127, 85, 95, 95, 95,
+ 179,227,223, 70,163,177, 99,249,242,107,191,109,111,111,183, 12,
+ 148,105,135,235,170, 60,111, 43, 26, 7,135,252, 0,104, 39, 77,
+ 34,119,253,237,156, 21, 63, 84,223, 15,142,115,181, 93, 5,163,
+ 69,162,138,168,197,133,205,155,255,239, 16, 0, 37,248,181, 21,
+ 20, 2,168, 0, 8,131,123,244,209, 71,219,238,187,239,126,147,
+ 84, 58,188, 79,202, 72, 85,152,157,179, 30,123,107,254,236,242,
+ 187,222, 84,141,195, 13,207, 96,118,206,122,162, 2, 85, 42,149,
+ 246,220,185,234, 79,198,143, 47,184, 2,124, 83, 96,176, 8,167,
+ 143,124,223,190,125, 87,101,103,231, 92,166, 80, 40,115,149, 74,
+ 197, 68,153, 76,150, 42,145, 72, 53, 18,137,132,232, 30, 39, 38,
+ 38,121,204,201,175,173,173, 7,199,113, 54,187,221,110, 96, 89,
+ 91,135,201,100, 58,107, 54,155,235,154,154, 26, 75, 47,190,248,
+ 226,237, 0,172,224, 69,201,177,100, 23,224, 69, 64,221,214,214,
+ 254,153, 76, 70,238,250, 31,110,120, 6,122, 83,181,199,239,179,
+ 115,214,143,232,254, 3,128,213,106,181,236,223,191, 79, 7,126,
+ 77, 5,133, 16, 42, 0,194,177, 89,173,150,106,165, 82, 53,162,
+ 79, 90,148,182, 18, 53, 93, 95,161,169,103,175,203,239,149,173,
+ 175, 34, 47,121, 49,113, 83, 32, 35, 35,115,198,150, 45,239,174,
+ 189,233,166, 27,255, 9, 0,119,223,253,251,180,223,253,238,119,
+ 191, 76, 77, 77, 93,160, 84,170,138,101, 50, 89, 50,130,212,251,
+ 45,145, 72,100, 12,195, 36, 48, 12,147,160, 80, 40,199, 3, 64,
+ 90,218,216,213, 6,131,137,179,217,108, 58,179,217, 84,213,209,
+ 209, 81,250,210, 75,255,126,107,227,198,141,109, 0,240,195, 15,
+ 123,110,140,143,215,206, 33, 45,163,189,175, 12,149,173,175,122,
+ 252,158,149,112, 9,138,210, 86, 18, 29, 67,175,215, 55,129, 31,
+ 2,180,143,148,150, 50, 68,216, 23, 3, 69,250, 56, 45,224, 49,
+ 180,165,172,169,169,125,110,236,216,244,219, 73,242,246, 91,154,
+ 241,201,209,107, 96,181, 27, 92,126, 79, 84, 21, 8,106, 10, 24,
+ 141,134, 62,171,213,218, 28, 23, 23,159,195, 48,204,200,175,196,
+ 48,192,178,172,201,100, 50,214,202,229,138, 12,133, 66,145, 72,
+ 146,199,206, 89,241,233,177,229, 30,111,127,185, 84,131,159, 77,
+ 251, 28,113,138, 76,162,178, 15, 30, 60,240,217,101,151,205,255,
+ 127, 0,206,194,181,137,130, 72,238, 4,244,119, 30, 0, 93, 12,
+ 20, 62,216,159,126, 58,248, 14,105,226, 56, 69, 38, 46,204,125,
+ 192,227,119, 71, 83,128, 20,181, 90, 19,159,144,144, 88, 24,169,
+ 198, 15, 0, 12,195,168,226,226,226, 39,145, 26, 63,224,219,245,
+ 191, 48,247, 1, 98,227, 7,128, 45, 91,222,249, 26, 64, 15,113,
+ 6, 10, 0, 42, 0, 68,184,189, 65,236, 55,220,112,195, 97,163,
+ 209,120,134, 52,127, 97,218, 13,200, 74,184,196,227,247,202,214,
+ 87,209,222, 87, 22,136, 42, 70, 37, 29,253, 21, 62, 93,255,194,
+ 180, 27,136,143,211,213,213, 89,255,226,139, 47, 86, 1,112,244,
+ 184, 14,222,175, 72,126,251, 71, 2, 84, 0,132,195, 1, 48,109,
+ 216,240,228,207,237,118, 59,241,112,211,220,130,199,160, 96,180,
+ 174, 7, 26, 24, 21,176,115,214, 64,215, 49,226,177,115, 86,236,
+ 62,119,159,215, 94,255,185, 5,143, 17, 31,135,101, 89,118,197,
+ 138, 27,238, 7,208, 2,190,247,159, 26,188, 0,168, 0,248, 7,
+ 251,183,191, 61, 94,215,209,209,254, 17,105,134, 56, 69, 38, 74,
+ 114,238,243,248, 93,104, 83, 32, 86,240,229,250,151,228,220, 39,
+ 200,245, 63,118,236,104,233,190,125,251,106, 1,212,130, 26,191,
+ 96,168, 0, 8,195,121,178,140, 37, 63, 63,239,206,254,254,190,
+ 58,210,204,180, 41,192, 19, 40,215,191,179,179,179,249,226,139,
+ 231,252, 29, 64, 3,248, 97, 72,111, 19,154, 40,195, 64, 5,192,
+ 63, 56,240, 15,156, 97,221,186,223, 47,181,219,237,182,145, 50,
+ 56,184,180,224,113, 81, 55, 5, 2,229,250,219,108, 54,246,170,
+ 171,174,188, 7, 64, 35,128,118, 80,195,247, 11, 58, 15, 96,116,
+ 216,222,120,227,141,166,135, 31,126,228,227,140,140,204, 21, 36,
+ 25, 52,138,116,148,228,220,135, 61, 53, 15,186,252, 46,116,130,
+ 144, 16,244,166,106,216,216,161, 97, 72, 51,171, 71,159,185,193,
+ 37, 77,188, 50, 27, 74,102,168,243, 94,198,104,136,103,224, 9,
+ 33, 80,174,255,209,163, 21,223, 87, 86, 86, 54,129,119,253,135,
+ 141, 23, 64,241, 13, 21, 0,255,112,105, 10,140, 31, 95,240, 95,
+ 109,109,237, 23,197,199,107,115, 73, 50, 23,166,221,128, 26,221,
+ 118, 52,234,119,187,252, 46,116,130,144, 51,122, 83, 53,116,198,
+ 83, 48, 88, 90,209,109, 60,131, 94,115, 29, 12,150, 86,175,198,
+ 38,132, 68, 85, 1, 52,138,116,104,149,185, 72, 82, 79,132, 70,
+ 145,142,100,117,145, 95,226, 16, 40,215,191,163,163,189,121,238,
+ 220, 75,158, 2, 80,143,161,157,148,169, 7,224, 7,116, 34,144,
+ 0,188,172,117,119,204,189, 87,172, 88,177, 50,255,229,151, 95,
+ 57,204, 48, 12,145,168, 26, 44,173,248,228,216, 50,151,181, 2,
+ 0,217, 4, 33,214,110, 66, 91, 95, 25,218,251,202,208,214, 95,
+ 134,246,190, 35, 48,219,244,126,157,147,191, 40,101,137, 72,139,
+ 63, 31, 99,227,102, 34, 45,126, 38,198,198,207, 28,118,202,174,
+ 175, 9, 63, 10, 70,139,159,157,183, 13, 26, 69, 58, 81,185, 86,
+ 171,149,189,232,162, 11,127, 83, 85,117,162, 18,192, 25, 12, 77,
+ 67,246, 88,159, 16, 13, 67,128,225,158, 8, 68, 61,128,192,192,
+ 189,255,254,123,157, 15, 61,244,208, 23,227,199, 79, 32,218,243,
+ 78,163, 72,199,133,185, 15,224,135,234,251, 93,126,247,213, 20,
+ 232, 50,156, 64,125,247, 78, 52,232,119, 71, 68,135,161,217,166,
+ 71, 67,119, 41, 26,186, 75, 7,127, 75,139,159,137,236,196,121,
+ 200, 73, 90,232,177,122,111, 56,215,159,212,248, 1,224,208,161,
+ 159,246, 86, 85,157,232, 4,223,241, 23,241, 6, 30,233, 80, 15,
+ 128, 16, 47,235,221, 29, 30,128, 28, 64,252,185,115,213,255, 72,
+ 79,207,184, 65, 34,145, 8,154,147,191,227,212,111, 61,154, 2,
+ 18, 9,131,107, 38,191, 3,169, 68,142,234,174, 47,113,182,243,
+ 83, 24, 44,173,163, 61,133,144,162, 81,164, 99,194,152,235, 80,
+ 144,178, 20, 28,103,199,182, 19, 43, 61, 58,254,198, 37,206,195,
+ 226,162,127, 9, 58, 46,199,113, 56,115,230,244, 87, 51,102, 76,
+ 255, 45,248,185,255,142,168, 74, 94, 87, 40, 70,186, 23, 16,110,
+ 15,128, 10, 0, 1, 94,140, 31, 24, 88,133,119,193, 5, 23,140,
+ 249,230,155,157,187, 84, 42,255,122,204,124, 53, 5, 24,169, 10,
+ 172,221,228, 95,133, 35, 12,111,231, 34,212,245,119,167,183,183,
+ 167,225,150, 91,110, 89,252,213, 87, 95, 54,131,143, 14,228, 24,
+ 6,116, 44, 6,138, 10, 17, 8,183, 0,208, 97,192, 17, 24,198,
+ 248, 85, 71,142,148,221,182,123,247,158, 51,254, 26, 63, 48,212,
+ 20,112, 39, 86,140, 31,240,126, 46, 23,230, 62,224,183,241, 3,
+ 128, 86,155,144,253,254,251, 31, 28,221,187,119,223,111,224, 25,
+ 75,193,249, 59, 34,183, 79,139, 20,168, 0, 12,195, 48,198,175,
+ 169,171,171,223, 60,105, 82,241,243, 18,137, 68, 49,154, 50,186,
+ 12, 39, 80,215,189,115, 52,135,136, 74,234,186,119,162,203,112,
+ 98, 84,199, 96, 24, 70, 54,115,230,249, 79,159, 62,125,102, 51,
+ 248, 8,195,206,155,168, 2, 84, 4, 70,132, 54, 1,124,224,195,
+ 248,101, 0,226, 58, 59,117,223,170,213,234,243, 71,115,252, 46,
+ 195, 9,148, 53,189,128, 58,221,142,209, 28, 38,234,201, 77, 94,
+ 140,153, 89,119, 16,109,249, 53, 28, 61, 61,250,163, 25, 25,233,
+ 87,128,239, 23,176,194,115,123, 51, 0,145,215, 28, 8,119, 19,
+ 128, 10,128, 23,124,116,248,201, 0,104,245,250,222, 50,185, 92,
+ 62,206,223, 99,155,109,122,252,212,176, 1,167,219, 63, 24,109,
+ 53, 99,138,194,180, 27, 48, 59,123, 61,148, 50,226,149,196, 30,
+ 152, 76,198,214,148,148,228, 25,224, 87, 5, 90,225, 58, 65, 40,
+ 34, 69, 32,220, 2, 64,155, 0,110,248, 48,126,121,105,233,174,
+ 43,251,250, 12,213,254, 26, 63,199,177,168,108,121, 5, 31, 86,
+ 44,162,198,239,133,211,237, 31,224,195,138, 69,168,108,121,197,
+ 99,180,128, 20,149, 74,157,222,211,211,123,110,251,246,175,175,
+ 4, 31, 48,212, 57, 84, 24,109, 14,120,129, 10,128, 19,195, 24,
+ 255,226,217,179, 75,182, 72,165,210,120,127,142,171, 55, 85,227,
+ 243, 19,171,112,176,254, 9,143,222,126,202, 16, 22,182, 23, 7,
+ 235,159,192,231, 39, 86,249, 61,131, 81, 38,147,107, 46,185,228,
+ 146, 45, 31,126,248,209,213,160, 34, 48, 34, 84, 0, 6,240,213,
+ 230, 47, 45,221,181,184,164,164,228, 93,169, 84,170,241,231,184,
+ 21, 77,155,241,233,177,229,196, 1, 46, 40,252,148,225, 79,143,
+ 45, 71, 69,211,102,191,242, 51,140, 76,121,229,149, 75,222,252,
+ 248,227, 79,150,130,159,167, 65, 59, 6,125, 64, 5,192, 19,231,
+ 14, 63,237,236,217,179,223,146, 72,164,130,163, 0, 27,173, 29,
+ 248,250,228,109, 56,220,248,140, 40, 86,249, 5, 26, 59,103,197,
+ 225,198,103,176,253,228,173, 48, 90, 59, 4,231,103, 24, 70,177,
+ 112,225,194, 87, 1,140,193, 48, 34, 32,118,168, 0,192,235,155,
+ 128, 1, 16,175,215,247,150, 75,165,110,107,119, 9,104,238,217,
+ 143,207, 42,127,230,177, 27, 48, 69, 56,142,107,217,220,179, 95,
+ 112, 94,185, 92, 17,215,209,209,121, 8,128, 22,158, 67,132, 0,
+ 168, 23, 32,122, 1,240, 17,210, 74,211,213,165,219, 41,151,203,
+ 179,132, 30,239, 68,219, 91,248,250,212,106,191,222, 90, 20,239,
+ 24,173, 29,248,250,212,106,156,104,123, 75,112, 94,141, 38, 46,
+ 173,161,161,105, 23,128, 56,184,134, 92,167, 77, 1,136, 92, 0,
+ 124,197,179,171,173,173,123, 90,165, 82,207, 16,122,188,159,234,
+ 55,224,199,218, 71,253,238,197,166,248,134,227, 88,252, 88,251,
+ 40, 14,214, 63, 33, 56,111, 74, 74, 74,113, 89, 89,249, 11, 0,
+ 84, 24,234, 20,164, 34, 0,145, 11,128, 19,142,155, 47, 63,114,
+ 164,236,214,180,180,177,191, 17,146,217,206, 89,177,235,236, 58,
+ 143,184,118,148,192, 83,217,242, 10,118,157, 93, 39,184, 95,165,
+ 168,104,210,202,175,190,218,190, 22,252,200, 0,237, 15, 24, 64,
+ 180, 2,224,171,221, 95, 84, 52,105,163,144,227,216, 57, 43, 74,
+ 207,174, 67,117,215, 23,129,171, 28,101, 88,170,187,190,192,119,
+ 103,238, 18, 44, 2,115,231, 94,250, 72, 97, 97, 97, 54, 60, 59,
+ 5, 1,136,211, 11, 16,165, 0,120,113,253, 25, 0,113, 58,157,
+ 126,175, 68, 34, 33,158, 98,101,231,172,248,238,204, 93, 1,157,
+ 206, 27,175,204, 70,126,242, 18,140,137,155, 26,176, 99,134,155,
+ 49,113, 83,145,159,188, 4,241,202,236,128, 29,179,190,123, 39,
+ 190, 61,125,135, 32, 17, 96, 24, 70,190,123,247,158, 29,160,253,
+ 1,131,136,125, 67, 16,199,205, 87, 52, 52, 52,254, 67,169, 84,
+ 78, 20,146,249,135,234,251, 81, 31,160,133, 60, 83, 51,126,131,
+ 233,153,107, 60,166,194,158,235,220,134, 3,117,127,245, 8, 53,
+ 30,233,168,100, 41,184, 48,247, 1,140, 31,179,204,229,119,179,
+ 77,143,138,230,205,168,108,121,101,212,101, 52,234,119,227,135,
+ 234,251, 49,127, 60,185,211,150,144,144,144,125,236, 88,229, 43,
+ 231,157, 55,245,102,120,134, 17,143,152, 41,194,161, 66,116, 30,
+ 128, 55,215,255,142, 59,238,200, 74, 78, 78,185, 81,200,113, 14,
+ 214, 63,129,115,157,219, 70, 93, 31,149, 44, 5,215, 76,222,130,
+ 146,156,251,188,206,131, 31, 63,102, 25,126, 62,237, 75,140, 75,
+ 156, 55,234,178, 66,197,184,196,121,248,217,180,109, 30,198, 15,
+ 240, 91,137,149,228,220,135,107, 38,111,129, 74,150, 50,234,178,
+ 206,117,110, 19,220, 49,152,159, 95,112,213,162, 69,139, 39, 99,
+ 168, 41,224,130,152,188, 0,209, 9,128, 19, 14,215, 95,243,216,
+ 99,143,127, 73, 26, 70, 27, 0,142,183,190, 30,144, 55, 24, 0,
+ 44,152,248,236,136,155,128, 42,101,137, 88, 56,241,121, 36, 40,
+ 137,246, 28, 13, 43, 9,202, 92, 44,152,248,236,136,198,157, 22,
+ 63, 19,151, 23, 62, 31,144, 50, 43, 91, 94,193,241,214,215,137,
+ 211, 75,165, 82,230,205, 55,223,124, 15,252,252, 0,175, 77, 1,
+ 177, 32, 42, 1,112,219,212, 19, 0,228,245,245,141,207, 40,149,
+ 202, 9,164,199,104,237, 59,132,159,234, 55, 4,164, 62, 5, 41,
+ 87, 35, 67, 91, 66,148,150,145,170,130,178,101,120,160,153,157,
+ 179, 30,114,194, 89,211,233,241,179, 80,144,114,117, 64,202,253,
+ 169,126, 3, 90,251, 14, 17,167, 79, 72, 72,204, 41, 47,175,120,
+ 1, 62, 70, 5,196,226, 5,136, 74, 0,220, 96, 0,104,146,147,
+ 147,174, 39,205, 96,180,118,160,212,143,222,103, 95, 76, 24, 67,
+ 180,127,232, 32, 57, 73, 11, 71,181, 92, 54,216, 40,101,137,200,
+ 73, 90, 40, 40,143,208,107,224, 11, 59,103, 69,233,153,187, 4,
+ 77,192,202,203,203, 95, 10, 32, 11, 62,102, 9,138, 1,209, 8,
+ 128,151, 45,189,149,237,237, 29,159, 72,165, 12,241, 10,191, 31,
+ 170,239, 15,232, 12,191,100,205, 36, 65,233, 37, 18, 6, 73, 42,
+ 65,253,148, 33, 37, 73, 53, 17, 18, 9, 51,114, 66, 39,132, 94,
+ 131,225, 48, 90, 59,176,251,220,189,196,233, 21, 10,133,250,220,
+ 185,234,183, 0, 40,225,218, 12, 16,141, 23, 32, 26, 1,112,131,
+ 249,247,191,255, 61, 53, 46, 46,126, 46,105,134,211,237, 31,120,
+ 236,222, 59, 90,100,126, 44, 48,148, 49,126, 45, 74, 12, 9,254,
+ 212,205,159,107, 48, 28, 77, 61,123, 5,237,183,144,145,145,121,
+ 193, 93,119,221, 53, 15, 67, 94,128,168, 16,133, 0,120,121,251,
+ 43,174,189,118,249,227,164,249,251, 45,205, 56, 80,247,215,128,
+ 215,203,104,109,247, 35, 79,228,174, 49,240,167,110,254, 92,131,
+ 145, 56, 80,247, 87,244, 91,154,137,211,175, 89,179,246, 33,240,
+ 115, 3, 68,231, 5,136, 66, 0,220,144, 2, 80,199,199,107,231,
+ 147,102,216, 87,251, 48,172,118,195,200, 9, 5, 34,116,181, 96,
+ 191,165,121,212, 27,105, 6,147, 46,195, 9, 65,134, 7, 8,191,
+ 6, 36, 88,237, 6,236,171,125,152, 56,125, 78, 78,238, 76,240,
+ 125, 1,142, 17, 1,209, 32, 70, 1,144,215,215, 55,108,148, 16,
+ 54, 86,221,163,223, 4,146,227,173,175, 11,234, 80, 20, 50,212,
+ 21, 46,132,212,209,206, 89,131,118, 78, 66,238,155, 84, 42,101,
+ 14, 28, 56,248, 24, 60, 71, 4, 98,158,152, 23, 0, 55,247, 95,
+ 10, 64,149,156,156,242, 11,146,188, 28,199,226,112,227,179, 65,
+ 171, 91,159,185,129,184,105,209,220,179, 31, 39, 90,223, 12, 90,
+ 93, 2,197,137,214, 55,137,215,238, 31,168,251,171, 71,148,226,
+ 64,114,184,241, 89,226,149,153, 69, 69, 69, 11, 1,100,192,203,
+ 106,193, 88,110, 6,196,188, 0,184, 33,219,187,119,223,114,210,
+ 189,253,106,187,191, 9,186,203, 93,213,246, 14,246,214,252,121,
+ 216, 64, 32, 53,186,237,216, 41,112,222,123,184,176,115, 86,236,
+ 60,125,199,176,139,163, 88,187, 9,123,107,254,140,170,182,119,
+ 130, 90,151, 46,195, 9,212,118,127, 67,148, 86,161, 80,170, 55,
+ 111,254,191, 21, 16,217,144,160, 88,214, 2, 12,110,240, 89, 84,
+ 52,233, 46,210, 76,254,238, 73, 39,148, 83,237,239,161, 81,191,
+ 27, 69,105, 55, 32, 43, 97, 46,100,140, 6,118,187, 21,221,166,
+ 51, 56,219,241,105,212,237, 44,100,181, 27,176,235,236, 58,156,
+ 110,255, 0, 19, 82,175, 67,146,106, 34,164, 82, 57,108,172, 1,
+ 77, 61,123,112,170,253, 3,193,125, 5,254, 82,209,180, 25,249,
+ 201, 75,136,210, 46, 93,186,244, 22, 0, 47, 3,232, 28,248,201,
+ 33, 2, 49,187, 70, 32,166,227, 2,120,113,255,147,250,251,141,
+ 45, 36,237,255,134,238, 82,124,115,122, 77,208,234, 70, 9, 29,
+ 139, 10, 55, 35, 59,105,193,136,233,236,118,187, 61, 62, 94, 83,
+ 2,224, 4,248,176,227, 65, 15, 55, 78,227, 2,132, 14, 89, 89,
+ 89,249, 42,210,206,191,170,246, 45,193,174, 15, 37, 68,144,222,
+ 75,169, 84, 42,125,227,141, 55,110,130,136,154, 1, 98, 17, 0,
+ 9, 0, 89, 86, 86,214, 10,146,196, 6, 75,107,192, 39,253, 80,
+ 194, 71,163,126, 55,113,120,245,146,146, 11, 23, 3, 72,128, 72,
+ 118, 12, 18,131, 0, 12, 46,252, 81,171,201,246,249, 59,219,249,
+ 41,221,215, 47,134,224, 56, 22,103, 58, 62, 38, 74,155,158,158,
+ 94, 8, 32, 25, 34,217, 54, 76, 12, 2, 0,240,231,169, 96, 24,
+ 89, 2, 73,226, 64,172,243,167, 68, 22,164, 91,182, 41,149,170,
+ 56, 0, 41,112, 29, 14,140, 89, 98, 86, 0,220,198,110,153,178,
+ 178,242,255, 32,201,215, 99,174,131,206,120, 42, 72,181,162,132,
+ 11,157,241, 20,122,204,117, 68,105, 95,127,253,141,235,225,101,
+ 109, 64, 44,206, 7,136, 89, 1,112, 66, 2, 64,150,153,153, 73,
+ 180,240,188, 73,191, 39,200,213,161,132, 11,210,123, 59,107,214,
+ 172,185,224,251, 1,128, 24,247, 2, 98, 93, 0, 6,195,124,169,
+ 213,234,105, 36, 25,162,109,204,157, 66, 14,233,189, 29, 59, 54,
+ 125, 2,128, 68,184, 26,126, 76,138, 64,172, 11, 0,192,159,163,
+ 92, 38,147,141, 33, 73,220,222,119, 36,200,213,161,132, 11,210,
+ 123,171,209,168, 19, 1, 36, 65, 4,253, 0, 98, 16, 0,201,103,
+ 159,109,157, 13, 72, 70, 60, 87,131,165, 53,162,151,219, 82, 70,
+ 135,209,218, 65, 52, 28, 40,145, 72, 37,235,215,223, 59, 11, 34,
+ 176,143,168,154, 10,236,103, 39, 12,115,222,121,231,121,110, 79,
+ 235,133, 78, 67,165, 31,135,167, 68, 19,157,134, 74,104, 20,233,
+ 35,166, 91,178,100,201,101, 27, 54, 60,249, 14, 0,151, 5, 24,
+ 66,158,193, 96,204, 28, 12, 52, 17, 41, 0, 2, 46,178,123, 58,
+ 206,237,255, 36, 0, 24,141, 70,115, 30,201,193,244,166,106,194,
+ 98, 41,209,138,222, 84,141, 28,130,116, 89, 89, 89,227, 1,196,
+ 3,232,133,107, 51,192,253, 25,115,198,197,224,125, 61,199,145,
+ 36, 12, 17, 35, 0,195, 24,189,227,226, 75,193,215, 87, 6,126,
+ 227, 6,105, 70, 70, 6, 3, 0, 45, 45, 45,142,121,219, 54,240,
+ 193, 30,216,129,127, 75, 1, 48, 10,133, 34,147,164, 14,253,230,
+ 166,209,156, 2, 37, 10, 32,189,199, 90,173,118, 12, 0, 13,134,
+ 158, 63,199,176, 32, 51,240,183, 52, 35, 35, 67, 6, 0, 45, 45,
+ 45,142,231,205,241,236, 57,158, 67,103, 67, 31,252,219,249, 89,
+ 191,213, 16,222,133, 70, 97, 23, 0, 47,134,239,188, 22, 91, 62,
+ 240, 81, 28, 57, 82,118,195,184,113,227,150,171, 84,234,153, 12,
+ 35, 77,150, 72,164,170,161, 44,156,205,110,231,140,102,179,233,
+ 116,119,119,247,206,119,223,125,247,213, 7, 30,184,191, 25,252,
+ 77, 80, 49,140, 44,149,164, 46,189,150,198, 64,156, 18, 37,130,
+ 33,189,199,106,181, 58, 9,188, 7, 16, 7, 64,242,151,191, 60,
+ 150,190,106,213,170, 91,146,146,146, 22, 42,149,170, 66,169, 84,
+ 162, 6,134, 98, 73,112,156,221,196,178,108,151,193, 96, 56, 82,
+ 95, 95,255, 73, 73,201,236, 79,192, 55, 31, 28, 31, 14,188, 72,
+ 12,102, 1, 0,141, 70, 37, 1, 0,131,193, 20, 22, 33, 8,219,
+ 106, 64,199,137, 59,215, 5, 67, 10,171,250,234,171,237, 23, 77,
+ 159, 62,125,181, 86,155,112, 37,195, 48,201, 66,235,193,113,118,
+ 179,209,104, 60,117,252,248,241, 45,231,159,127,254, 31, 25, 70,
+ 54,226,238,147,159,159,184, 9,237,125,101, 66,139,162, 68, 17,
+ 105,241, 51,113,205,228,145, 23, 7,153,205,102,243,231,159,111,
+ 125,241,202, 43,151, 92,161,209,196, 21, 73,165, 82,161,203,239,
+ 56,155,205,166,235,233,209,127, 83, 94, 94,254,210, 53,215, 92,
+ 253, 35, 0, 51,134, 86, 25, 14,166,115,206, 68, 42, 4,129, 90,
+ 13, 24, 22, 1,112, 51,126,199,223, 12, 0, 85,101,229,241,223,
+ 101,103,103,223, 37,151, 43, 2, 22, 73,146,101, 89, 43,195, 48,
+ 242,145,210,125,122,108, 57,157, 5, 24,227, 36,171,139,112,221,
+ 121,159,141,152,206,106,181,218,228,114,121,192, 60,100,139,197,
+ 220, 80, 95, 95,247,220,180,105,211,254, 9,192,136,161,184,132,
+ 156,219, 55,145, 8, 4, 74, 0, 66,222, 4,240, 98,252, 14, 87,
+ 63, 94,167,211,239, 86, 42,149, 1,223, 32,128,196,248, 1, 4,
+ 101,227, 79, 74,100, 65,122,143, 3,105,252, 0,160, 80, 40,179,
+ 39, 76, 40,124,178,179,179,235,246, 49, 99, 82,230, 1,232, 3,
+ 223, 52,112,236, 57, 32,129, 83,179, 32, 84, 77,130,144,142,115,
+ 122, 49,126, 6,128,250,216,177,202,181,253,253,134,250, 96, 24,
+ 191, 16,130,185, 63, 29, 37, 50, 8,247, 61, 86,171, 53, 69,189,
+ 189,253,117,101,101,229,107, 1,168,225, 35, 54,161,151, 38,114,
+ 80, 8, 89, 19,192,139,241,203, 0,104,154,154,154, 95, 79, 74,
+ 74,190, 54,160,149,160, 80,162,128,246,246,182, 47,243,242,114,
+ 255, 3,128, 1,124,223, 0,231,244, 1,224,187, 57, 16, 85,125,
+ 0, 62,222,252,241,221,221, 61, 7, 20, 10, 69,228,198,186,162,
+ 80,130,140,193,208, 95,147,154, 58,166, 4,252,124, 3,199,208,
+ 225,136, 34, 16, 53, 91,130,249, 48,254, 56,157,174,251, 7,106,
+ 252, 20,177,163,209,196,229,183,182,182, 31, 4, 63,220, 24,242,
+ 230, 64, 40,251, 0, 6,247,229,111,108,108,126, 69,169, 84, 77,
+ 9, 97,217, 20, 74,196,162,213,106,243, 79,159, 62,243, 33, 0,
+ 21,188,196, 37, 8, 38, 65, 21, 0, 39,229, 26, 92,150, 91, 81,
+ 113,244,183,201,201,201, 63, 11,102,185, 20, 74,180, 49,110, 92,
+ 246,130, 29, 59,118,220, 13,126, 68,204, 99,152, 60, 88, 94, 64,
+ 80,251, 0,220, 4,128, 1,144,216,223,111,168,119,157,197, 71,
+ 134,213,110, 64,179,126, 15,170,187,190, 68,143,185, 22, 58,195,
+ 169,193, 64, 25, 9,202, 92,104, 20,233,200, 74,152,139,188,148,
+ 37, 72, 84, 21,248, 85,247, 96,110, 81, 78,137, 28,252,221,138,
+ 91,111,170, 70,109,215,118, 52,245,236,129,193,210, 58,184,195,
+ 144, 84, 34, 71,178,166, 8,137,170, 2,228, 39, 47, 65,102,226,
+ 92,200,253,136,122,204,178, 54,139, 86, 27, 95, 12,160, 25, 94,
+ 58, 5,157,251, 2, 34,190, 19,208,205,248,165, 0, 52, 58,157,
+ 254, 71,161, 67,125, 22,182, 23, 71, 26,158,193,169,142, 15,135,
+ 141,158,227, 76, 90,252, 76, 92, 48,238,110,100, 38,204, 17, 82,
+ 20, 21, 0,145, 32, 84, 0,154,123,246,227,112,227, 51,196,179,
+ 68, 25,169, 10, 69,169,215,227,252,236,187,161, 96,180,130,202,
+ 210,235,187,171, 51, 51, 51,102, 1,232,135,107, 92, 2, 23, 17,
+ 136,154, 78,192, 1,152,242,242,138,219,132, 26,127,125,247, 78,
+ 124, 88,177, 8, 39,218,222, 34, 54,126, 0,104,239, 43,195,246,
+ 147,183,226,251,115,247,208,201, 61, 20,191,177,218, 13,248,254,
+ 220, 61,216,126,242, 86, 65, 83,196, 89,187, 9, 39,218,222,194,
+ 135, 21,139, 80,223,189, 83, 80,153,137,137, 73, 5, 91,183,110,
+ 93, 7,207,166, 64, 80, 8,182, 0, 12,118,252,229,229,229,253,
+ 94, 72,198,242,166, 77,248,246,244, 29, 48,219,244,126, 23,126,
+ 174,115, 27,182, 85, 94, 31,178, 48, 84,148,216,161,223,210,140,
+ 109,149,215,143,106,135,104,179, 77,143,111, 79,223,129,242,166,
+ 77,130,242, 93,120,225, 69,183,195,115,103,226,160,136, 65, 80,
+ 4,192,173,195, 66,250,221,119,165,151, 43, 20,202, 92,210,252,
+ 199, 90, 94,194,145,198,231, 3, 82, 23,189,169, 26,219,171,110,
+ 129,133,237, 13,200,241, 40,177,143,133,237,197,246,170, 91, 2,
+ 182, 63,196,145,198,231, 5,197,153,212,106, 19, 50,158,121,230,
+ 217,101, 24, 26, 22, 28, 36,208,157,129,161,104, 2,200,167, 78,
+ 157, 74, 28,144,179,161,187, 20,135, 26,158, 10,104, 5,122,204,
+ 117, 40, 61,115, 23, 13,246, 65, 25, 17,142, 99, 81,122,230, 46,
+ 226, 45,196, 73, 57,220,248, 12,234,116, 59,136,211, 47, 93,186,
+ 244,118,240,203,145,131, 58, 28, 24, 76, 1, 24, 92,232,163, 86,
+ 107, 46, 32,201, 96,182,233,177,187,250,190,160, 24,106, 83,207,
+ 94, 28,107,121, 41,224,199,165,196, 22,199, 90, 94, 10,218,206,
+ 208,123,106, 30, 36,110,210,166,167,167, 23, 3, 72,133,107,116,
+ 162,128, 11, 65, 40,250, 0, 20, 12,195, 16, 69,228, 41,111,218,
+ 52,170, 54,255, 72, 84, 52,109,134,201,214, 21,180,227, 83,162,
+ 27,147,173, 43,168, 33,225,205, 54, 61,113,127,128, 66,161,212,
+ 0, 24,131,161,126,128,160, 16,108, 1,144, 85, 84, 28, 37,138,
+ 200, 99,182,233,113,178,253,189,160, 86,198,106, 55,224, 68,235,
+ 91, 65, 45,131, 18,189,156,104,125, 43,232,163, 70, 39,219,223,
+ 35,126,201,109,217,242,238,141, 8,114,164,226,128, 11,128, 91,
+ 39, 5,147,158,158,126, 13, 73,190, 90,221,118, 65, 67,125,254,
+ 114,182,243,211,160,151, 65,137, 78, 66,241,108,176,118, 19,106,
+ 117,219,137,210,206,152, 49,227, 18,184, 70, 42, 6, 16,216,142,
+ 192, 96,247, 1,200, 73, 35,242, 52,132, 40, 28,119,159,185,129,
+ 238,254, 75,241,160,219,120, 38,100,123, 5,212,119,151, 18,165,
+ 75, 75, 27, 59, 30,124,164, 98, 32,202,250, 0, 6,183,249, 34,
+ 141,200,211,209, 95, 17,164,170,132,183, 44, 74,116, 16,202,152,
+ 16,164,101,169, 84, 42, 45, 60, 61,128,168, 25, 6,148,252,230,
+ 55,183, 37,145, 68,228,177,115, 86,162,136, 45,129, 34,220,187,
+ 194, 80, 34,143, 80, 62, 19, 6, 75,235,224, 58,150,225,144, 74,
+ 165,210,169, 83,167,166, 33,136, 29,129, 65, 21,128, 37, 75,174,
+ 28, 71,146, 48,212,147,116, 44,108, 95, 72,203,163, 68, 62, 86,
+ 54,180, 83,198, 73,159,249,139, 46,186, 40, 11,174, 67,129, 1,
+ 37,168, 2,144,144,144, 64,180,157, 55,107, 39,219, 74, 60, 80,
+ 132,162,179,145, 18, 93,216, 66,188,102,132,244,153, 79, 79, 79,
+ 215, 34,136,235, 2, 98, 62,248, 33,133, 18,205,216,237,156, 99,
+ 61, 77, 80,160, 2, 64,161, 68, 62, 81, 57, 17, 40,102, 99,170,
+ 83, 40,161,195,101,191,142,168,234, 3, 64,128,247, 26,161, 80,
+ 196, 76, 84,245, 1,208,183, 63,133, 18, 56,162,114, 30, 0,133,
+ 66,137,112,168, 0, 80, 40, 34,134, 10, 0,133, 18,193,112, 28,
+ 23,212,230, 52, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21,
+ 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80,
+ 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12,
+ 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196,
+ 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68,
+ 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,
+ 196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80,
+ 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10,
+ 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160,
+ 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0,
+ 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,
+ 160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21,
+ 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80,
+ 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12,
+ 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 37,130,
+ 145, 72, 36, 92, 48,143, 79, 5,128, 66, 17, 49, 84, 0, 40, 20,
+ 17, 19, 44, 1, 8,170,219, 66,161,136, 12,206,199,223,163, 38,
+ 152, 30, 0,215,210,210,220, 78,146, 80, 38,213, 4,177, 26,225,
+ 47,143, 18,249, 68,234, 51, 88, 91, 91,219, 5,222,232,131,242,
+ 82, 13,170, 0,124,255,253,247,109, 36, 9,229, 76,104, 47,190,
+ 130,209,134,180, 60, 74,228, 19,234,103,144,180,188,178,178, 50,
+ 61, 0,251,192, 63, 3, 46, 2, 65, 21,128,215, 94,123, 77,207,
+ 113, 28, 59, 98, 37, 36,114,196, 43,179,131, 88, 21, 87,180,170,
+ 220,144,149, 69,137, 14, 18, 84, 5, 33, 43, 43, 94,153, 13,169,
+ 68, 62, 98, 58,150,101,237, 85, 85, 85,189, 0,172,193,170, 75,
+ 176, 59, 1,109, 86,171,181,147, 36, 97,170,102,106,144,171, 50,
+ 68, 90,220,244,144,149, 69,137, 14, 66,249, 76,144, 62,235, 6,
+ 131, 65, 15,192,132, 40,109, 2, 0,128,205, 96,232,175, 32, 73,
+ 56, 46,113, 94,144,171,194,147,160,204, 13,169,183, 65,137, 14,
+ 226,149,217, 72, 80,134,198, 51, 36,125,214, 91, 91, 91,206, 0,
+ 232, 65, 16, 59,213,131,218, 4, 0, 96,107,104,104,248,156, 36,
+ 113, 94,202, 18,200, 67,208, 17, 51, 49,245, 23, 65, 47,131, 18,
+ 157,132,226,217,144, 75, 53,200, 75, 89, 66,148,246,199, 31,247,
+ 239, 5,160,119,250, 41,170,250, 0, 0,128,189,240,194,146,119,
+ 72, 18, 42, 24, 45,166,101,254,103, 80, 43,163, 81,164, 99,114,
+ 198,175,131, 90, 6, 37,122,153,156,241,107,104, 20,233, 65, 45,
+ 99, 90,230,127, 18,117, 66,115, 28,135,223,254,246,183,223, 96,
+ 200, 3,136,170, 38, 0,231,244,109,179,217,172,250,225, 18, 59,
+ 8,246, 13,152,158,185, 38, 36, 94, 6, 37, 58,145, 75, 53,152,
+ 158,185, 38,104,199, 23,242, 2, 50,153,140,125,224, 59,255,250,
+ 17,173,243, 0, 6, 62,214,190,190,190, 67, 36, 25,228, 82, 13,
+ 230,143,223, 72,212, 67, 42,148,156,164,133, 40, 30,187, 42,224,
+ 199,165,196, 22,197, 99, 87, 33, 39,105, 97,192,143, 43,145, 48,
+ 152,155,255, 23,226, 23, 80, 83, 83,211, 73, 0, 58,184,190, 76,
+ 35,191, 9, 96, 48,152,220, 43,105, 61,120,240,192,115,164,249,
+ 51,180, 37,152,147,247,167,128,214, 41, 89, 93,132,249, 19, 54,
+ 6,244,152,148,216,101,254,132,141, 72, 86, 23, 5,244,152, 37,
+ 57,247, 9,234,232,126,253,245,215,223,197,144, 0,184,216,148,
+ 23, 27,243,155, 96,247, 1,112, 0,216,235,174,187,110,183,209,
+ 104, 56, 71,154,169, 40,109, 37, 46, 45,120, 60, 32,158, 64,134,
+ 182, 4, 87, 21,191, 65, 93,127, 10, 49,114,169, 6, 87, 21,191,
+ 129, 12,109,201,168,143, 37,149,200,113,105,193,227,152,146, 78,
+ 222,247,212,217,217,217,184, 97,195,147,229, 0, 58, 49, 36, 0,
+ 81,213, 7,224,140, 29,128,121,223,190,125,235,133,100,154,152,
+ 250,115, 44, 41,126,213,239, 33, 59,137,132,193,121, 25,171,113,
+ 229,164,151,161,148, 37,250,117, 12,138,120, 81,202, 18,113,229,
+ 164,151,113, 94,198,106, 72, 36,140, 95,199,136, 87,102,227,202,
+ 73, 47, 99, 98,234,207, 5,229,219,180,233,249, 77, 0,154, 1,
+ 24, 17, 68,227, 7, 0, 9,199, 5,246,216, 70,163, 25, 26,141,
+ 74,226, 56, 62,120,145, 97, 0,104,218,218,218,119,197,199,107,
+ 167, 9, 57,158,157,179,226,100,251,123, 40,107,124, 14,102, 27,
+ 81, 95, 34,114,147, 23,227,130,113,119, 33, 73, 61, 81, 80,221,
+ 95, 61, 88, 44, 40, 61, 37, 58,185,181,164, 74, 80,122,189,169,
+ 26,135, 26,158, 66,157,110, 7, 81,122,165, 44, 17, 51,199,253,
+ 15, 38,165,173, 20,236,197, 54, 55, 55,157,157, 48, 97,252, 29,
+ 0,126, 2, 96, 0,255, 2,117,124, 56,128,111, 2,168,213, 74,
+ 65,199,245, 69, 40, 4,192, 33, 2, 50, 0, 9,122,125,239, 57,
+ 185, 92,238,151, 63,222,212,179, 23, 77,250, 61,104,238,221, 15,
+ 0,232,236,175, 68,156, 34, 19, 42,121, 10, 52,242,116,228, 37,
+ 47,198,184,196,121, 80,203, 83,253, 92,168,210,238, 0, 0, 19,
+ 244, 73, 68, 65, 84,170, 59, 21, 0,113, 32, 84, 0, 28,152,108,
+ 93,104,232,222,133, 90,221, 14, 24,172,173, 48, 89,187,208,111,
+ 105,198,152, 56,126,102, 95,166,118, 14,178, 18,231, 34, 43,225,
+ 18,191,142,111, 54,155,140,201,201, 73, 43, 0,156, 3, 80, 3,
+ 79,227, 15,184, 0,200, 2,114, 20, 55, 12, 6, 19,231, 36, 2,
+ 142,138,179, 0, 12,229,229,101,235,102,207, 46,217,236,207,113,
+ 179, 18, 46,241,251,226, 82, 40,163, 69, 37, 75,193,196,212,159,
+ 11,118,233, 73,121,237,181,215,254, 1,160, 3, 64, 29,124,180,
+ 253, 3,217, 1, 8,132,166, 19,208,241,205, 1,176,206,159, 63,
+ 239,189,186,186, 90,162,201, 65, 20,138, 88,168,168, 40,223,117,
+ 247,221,119,125, 3,160, 26,174,111,252,168,239, 4, 4, 92,189,
+ 0, 83,113,241,164,187,116,186,174, 35, 33, 42,155, 66,137,104,
+ 154,155,155,206,206,153,115,209,223, 0,156, 6,208, 7, 47,110,
+ 127,176, 8,154, 0, 56,185, 42,238, 94, 0, 11,160,127,220,184,
+ 172,171,218,218, 90,127, 10, 86,249, 20, 74, 52, 80, 83, 83,125,
+ 116,194,132,241,255, 13,160, 22, 64, 43, 60,223,254,128, 83,219,
+ 63,208,229,135,218, 3,112,124,108, 0,250,242,243,243,174, 62,
+ 121,178,234,189, 16,213,129, 66,137, 40, 14, 30, 60,176,125,202,
+ 148,201,247, 2, 56, 11, 94, 0,220,223,252,209,235, 1, 0, 94,
+ 21,203, 67, 4,206, 63,127,230,218,143, 63,254,240,191,204,102,
+ 147, 33,152,117,161, 80, 34, 5,163,209,104,120,250,233,167,254,
+ 114,217,101,243, 55, 2,168, 2,208, 0,239,198, 63, 72, 48,222,
+ 254, 64,144, 70, 1,124,192,129, 31, 18,116, 62, 17, 22,128,241,
+ 230,155,111,126, 3,192,151,213,213,181, 91,211,211,211,167,132,
+ 176, 78, 20, 74, 72,105,108,108, 56, 89, 88, 56,113, 61,120,119,
+ 191, 26,252, 98, 31, 95,198, 31,244,205,117,131,222, 4,112, 83,
+ 46,111, 61,155, 44, 0, 11,128,182,130,130,188, 5,127,252,227,
+ 253, 55,117,116,116,212, 5,178, 14, 54,155,205, 62,114, 42, 10,
+ 101, 8,155,205, 26,208,103,166,173,173,173,238,246,219,111,251,
+ 239,194,194,137,255, 3,190,179,239, 56,124, 27,191,139, 7, 16,
+ 172,183, 63, 16,162, 62,128, 97, 68,192,238,244,109, 5,208,247,
+ 244,211, 79,127,153,155,155,125,145, 70,163,186,248,199, 31,247,
+ 111,237,234,234,108, 98, 89,118,196,125, 5,221, 49, 26,141,134,
+ 170,170, 19, 63, 61,246,216,163,127,151, 72, 36, 35,103,160, 80,
+ 92,144,224,207,127,254,211, 19,199,143, 87, 30, 50, 26, 13,130,
+ 155,167, 54,155,141,237,232,232,104,218,183,111,239, 54,141, 70,
+ 117, 93,126,126,238,237,111,191,253,118, 41,128, 3, 0,234,193,
+ 191,248, 88,184,218, 64, 72,141, 31, 8,210, 76, 64, 95, 56, 77,
+ 14, 2,248,230,128,227,219,249, 35, 29,248,102, 0,200, 1,140,
+ 5,144,188,102,205,154, 11, 86,174,188,113,233,132, 9, 19,166,
+ 39, 37, 37,101,112, 28,160, 80, 40, 20, 44,203,218, 89,150,181,
+ 89,173, 22, 99, 75, 75, 75,205,225,195,135,247,223,114,203,175,
+ 191, 2, 47, 40, 61, 0,108,125,125,253, 63, 72,165,204,136, 98,
+ 71,103, 2,138, 3,146,153,128, 44,107,179,107,181,241,215, 3,
+ 168, 4,144, 8, 32,233,245,215,223,184,254,130, 11, 46,152,147,
+ 158,158, 94, 32,151, 43,212, 12,195,200, 24,134,145, 90, 44, 22,
+ 11, 0,116,119,235, 90,206,156, 57,115,244,237,183,223,250,246,
+ 229,151, 95, 62, 13,126, 42,175, 14, 64, 23,134, 22,246,248, 50,
+ 120, 15,183,127, 56,227,143,232,169,192,195, 65, 40, 2,238, 31,
+ 6,188, 48,168, 0, 36, 1, 72, 0,160, 85,169, 84,140,201,100,
+ 82,128,111, 66, 88,192,111,160,216, 3,126, 27,165,254,129,188,
+ 137,125,125,134,179, 82,169,116,196, 21, 29, 84, 0,196, 1,153,
+ 0,176,118,173, 54,238, 58, 0,251, 49,100,172, 82, 0, 90,240,
+ 130,160, 5,160, 80, 42,149, 10,179,217,204, 96,200,157,239, 6,
+ 208, 59,240, 49,195,183,177,251,109,252, 64,224, 4, 32,148,157,
+ 128, 0,188, 78, 19,134,211,223,206, 70, 15,167,191,237, 3,223,
+ 86,240, 19, 37, 0, 64, 98, 50,153,220, 15,239,126,209,164,224,
+ 221, 44, 10,197, 31, 28, 46,186,227,219, 14,254, 37,227, 8,120,
+ 35, 49,155, 61, 94,120,238,243, 94,124, 25,186,207,206,190, 96,
+ 187,253,206,132, 92, 0, 0, 15, 17, 0, 92, 71, 8,156,133,192,
+ 241, 55,224, 41, 12,190,112,206,195, 1, 96,105, 23, 0,197, 79,
+ 28,157,212,206, 2,224,248,125,164,103,208,241,237,107, 66,156,
+ 123, 90, 0,161, 53,126, 32, 76, 2, 0, 12,157,168, 15,111,192,
+ 241,111,231, 97, 67, 18,227,119,198,145,206, 78,158,133, 66,113,
+ 193,238,229, 67,106,160,222,222,238, 62,135,247, 66,109,248, 14,
+ 194, 38, 0, 14, 94,216,149,207, 1,192, 29,151,213,184,123, 4,
+ 142,111,119,129, 16, 42, 0, 20,138,191,184,143, 88,249, 35, 0,
+ 190,254, 13, 32,124,134,239, 32,236, 2,224,192, 33, 4,128, 79,
+ 49,240,245,111,111,184, 47, 69,166, 80, 0, 0,113,138, 76,162,
+ 116, 78,205,198,225,218,242,126,225,252,172,135,155,136, 17, 0,
+ 103,134,187, 64,110,226,224, 11, 95,237, 45, 10,133,144,193,199,
+ 204, 47,227,143, 36, 35, 31,142,136, 20,128,225, 32,185,176,110,
+ 34, 65,236,182, 37, 40,115,209, 99, 14,232, 36, 68, 74,132,193,
+ 16,110,209,197,241,227,227, 94,163,242, 70,139,113,147, 16,170,
+ 213,128,225,196,206,178,108,223,200,201, 0,173, 42, 47,216,117,
+ 161,132, 25,210,123,108,177,152, 13,224, 23,172,197,140,177,123,
+ 35,214, 5,128, 3,192,154, 76,198,179, 36,137, 83,105,212,224,
+ 152,135,244, 30,119,117,117, 53,130, 31,243,119, 16,147, 66, 16,
+ 235, 2, 0, 0, 86,157, 78,247, 45, 73,194,188,228, 69,193,174,
+ 11, 37,204,144,222,227,227,199,143, 31, 70,144,227,242, 69, 2,
+ 177, 44, 0,142,155,102,127,246,217,103, 95, 37,201,144,162,153,
+ 140,236,164, 5, 65,171, 16, 37,188,100, 39, 45, 64,138,102, 50,
+ 81,218,135, 30,122,104, 27, 92, 35,243, 2, 49, 40, 4,177, 44,
+ 0, 14,236, 47,188,176,169,157,101, 89,143,121,195,222,152,149,
+ 189,206,239, 64, 16,148,200, 69, 34, 97, 48, 43,123, 29, 81, 90,
+ 139,197, 98, 41, 43, 59,162, 3, 63,159, 63,230,140,222,153,152,
+ 20, 0,167, 94, 90,135,251,102,179, 88,204, 53, 36,121,147,213,
+ 69,184, 40,247,193, 96, 85,141, 18, 38, 46,202,125,144, 56,222,
+ 159, 94,223,221, 12,126,205,137, 99, 29,201, 96, 51, 32,150, 70,
+ 0,128, 24, 21, 0, 47, 88,154,154,154,136,247, 30, 44, 30,187,
+ 10,211, 50,255, 51,152,245,161,132,144,233, 89,107, 4, 69,134,
+ 254,241,199, 31,191,133,143,192,156,177,134, 24, 4,128, 3, 96,
+ 155, 54,237,188, 77, 54,155,173,159, 52,211,172,236,117,184,180,
+ 224,113, 26, 84, 52,138,145, 75, 53,184,180,224,113, 92, 48,238,
+ 110,226, 60,102,179,201,184,114,229,138, 15, 16,130,192,156,145,
+ 128, 24, 4, 0,224, 39,116, 24,187,186, 58, 63, 20,146,105, 98,
+ 234,207,241,139,233, 95,163,120,236, 42, 42, 4, 81,132, 92,170,
+ 65,241,216, 85,248,197,244,175, 5, 71,241, 57,118,236,216, 46,
+ 240, 27,120,232, 17,227,198, 15, 68,225, 76, 64,129, 56, 47, 32,
+ 178,230,231,231,253,161,171, 75,183, 88,165, 82,147, 77, 8, 7,
+ 160,150,167, 98, 78,222, 67,184, 48,247, 1, 52,233,247, 64,103,
+ 60,133, 67, 13, 79, 5,167,182,148, 81, 49, 43,123, 29,146,213,
+ 69,200, 74,156,235, 87,104,121,189,190,187, 99,222,188, 75,159,
+ 5, 31,153,215,219,250,253,152, 35,214, 5,192,129, 99, 93,183,
+ 225,249,231,159, 91,254,135, 63,172,223, 79,178, 67,144, 51, 82,
+ 137, 28,217, 73, 11,144,157,180, 64,112,255, 64,168,119, 26,242,
+ 55,248,229, 72,196,202,121,120,131,101, 89,251,175,127,253,171,
+ 245,224,141,191, 3, 34,112,255, 1,241, 52, 1,128,129,190,128,
+ 135, 30,122,232, 84,117,245,185, 77,225,174, 12, 37,178,216,181,
+ 171,244,253, 29, 59,118,156,133,103,108,190,152, 38,102, 5,192,
+ 203, 80,160,227, 99,153, 54,237,188, 71,116, 58, 93,121,216, 42,
+ 71,137, 40, 26, 27, 27, 79, 46, 91,118,205, 43,224,195,114, 91,
+ 225, 99, 5, 96,172, 13, 1, 2, 49, 44, 0, 62, 24,108, 10,140,
+ 27,151,121,165,193,208,223, 20,238, 10, 81,194,139, 78,167,107,
+ 41, 44,156,240,123, 0, 53,224,135,254,132,110,252, 17,213,196,
+ 180, 0, 12,227, 5,176, 0,250, 83, 83,199,156,223,210,210,114,
+ 40, 92,245,163,132,151,154,154,234,163,227,198,101,222, 6,160,
+ 17,252, 94,253, 62, 3,116,196,226,219, 31,136,113, 1,240,130,
+ 243, 77,181, 2,232, 27, 63, 62,255,170,253,251,247, 61,203,178,
+ 54, 91,120,171, 70, 9, 21, 54,155,205,182,109,219,214, 87,167,
+ 76,153,188, 30,124, 96,206, 51, 24, 33, 54, 95,172, 34, 38, 1,
+ 112,223,156,145, 3,191,222,187,127,225,194,203,255,119,193,130,
+ 203,102,119,119,235, 26,194, 83, 53, 74,168,232,232,232,104,154,
+ 50,165,248,151, 43, 87,174,120, 9, 64, 5,188, 7,230,116, 16,
+ 243, 34, 16,243, 2,224,230,186,121,115,239, 88, 0,166, 67,135,
+ 14,157,203,202,202,156,189,115,231,183,127,239,233,209,119,132,
+ 161,170,148, 32,162,215,119,119,124,252,241, 71,255,204,205,205,
+ 94,221,208,208, 80, 5,160, 28,252,100,159, 17, 99,243,197,170,
+ 251, 15,136,100, 30,192, 11,187,242, 57,167,109,194,188,221, 76,
+ 59,248,200, 66,236,178,101,215,252, 5,192,166, 59,239,188,115,
+ 238, 47,127,121,243,205,185,185,185,231, 37, 36, 36,166,203,229,
+ 114,225, 51, 75, 40, 97,195,106,181, 88,187,187,245,109,117,117,
+ 53,199, 94,124,241,197,173,111,191,253,246, 89,240, 17,121,155,
+ 193,175,242, 27,206,240, 69, 97,252,128, 72, 4, 0, 24, 86, 4,
+ 56,184, 6, 34,177, 3,104,217,180,105,211,167,155, 54,109,250,
+ 26, 64, 10,128,132,107,175, 93, 94,116,199, 29,107,175,203,205,
+ 205,155,164,213,106, 83,237,118, 78, 18, 31, 31,151,164,209,196,
+ 169, 66,122, 34, 1,194,110,183,163,185,185,169, 13, 0, 50, 51,
+ 179,198, 74,165,209,233, 12,246,245,245,153,123,123,123,186,165,
+ 82, 41,215,219,219,219, 81, 87, 87,119,234,217,103,159,217,190,
+ 99,199,142, 70,240,225,186,186,193,191,233,117,224,251,125,134,
+ 11,198, 41, 42,227, 7, 68, 36, 0, 0,145, 39, 0,184,134, 33,
+ 179,129, 95, 22, 42,217,186,245,179,147, 91,183,126,246, 53,248,
+ 216,132,113, 0, 82,186,186,186,183, 6,187,206,193,164,176,112,
+ 226, 61, 0,244,125,125,134, 79,195, 93, 23,127,145, 72, 36,220,
+ 132, 9,227,127, 7,126,254,190, 13,188,209, 59,226, 67,218, 64,
+ 22,151,207, 89, 0, 0,136,195,248, 1, 17,244, 1,184,227,165,
+ 79,192,241,237, 30, 1,134,117,251, 88,192,139, 65, 19,248, 9,
+ 35,167, 24, 70, 26,208, 24,242, 97,192, 8,224,156, 68, 34,137,
+ 218,135,125, 32,244,187, 17,192,201,129, 79, 45,248,169,188,102,
+ 240, 2,224,126, 31,125, 69,250, 17,157,241, 3, 34, 20, 0,192,
+ 103,199,160,227,111,231, 7,195,151, 24,216,248, 79,244, 6, 31,
+ 26, 8,124,225, 56,151,168,101, 64, 0,236, 24,188, 39,195, 26,
+ 189,251,253, 5, 68,232,246, 59, 35,170, 38,128, 51, 94, 66,146,
+ 185,223,120,231,149,132,142,111,231, 88,133,118, 73, 84, 71, 29,
+ 149, 0, 67, 6, 17,237,184, 27, 58,139, 97,220,123,120,222,107,
+ 209, 25,190, 3,209, 10,128,131, 17, 98, 19,194,237, 55,231,240,
+ 229,177,240,192, 56, 71,188,141, 74, 6, 52,216, 91, 19,142,104,
+ 76, 95,172,134,239, 64,244, 2,224,224,133, 93,249,220,218,249,
+ 213, 0, 0,137,235,171,221,215,176, 97,148,123, 0, 0, 98,192,
+ 3, 24,232,191,240,230,222,251,156,205, 39,118,163,119, 70,148,
+ 125, 0, 35,193,249, 0, 62,198,138,163,152, 88, 59, 15,151,207,
+ 48,247,145, 50, 0, 21, 0,113, 67,141, 65,228, 80, 1,160, 80,
+ 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10,
+ 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160,
+ 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160,196,202,100,160, 88,
+ 57,143,144, 66, 5,128, 66, 17, 49, 84, 0, 40, 81,206,224,178,
+ 102,138, 31, 80, 1,160, 80,227, 17, 49, 84, 0,252,135,227, 56,
+ 46,138,119,211,137,141, 85,113,118,187,221,121, 57,115, 76,156,
+ 83, 40,161,251, 1, 56,241,226,247, 5, 66,146,115, 28,199, 89,
+ 72, 18,230, 38, 47, 70,157,110,135,127,149, 18, 72,130, 50,151,
+ 40,221,128,225,176, 0,236, 28,199,177, 18,137,100,196,103, 33,
+ 65,153,139, 30,115,221, 40,107, 72, 70,110,242, 98,162,116,118,
+ 59,107,197,208, 14, 64, 46, 8,188,159,162,132,122, 0,254,193,
+ 1, 96,173, 86, 11, 81,112,209, 68, 85,232, 30, 68,173, 42,143,
+ 40,157,217,108, 49, 98, 32, 22,130,205,102,235, 11,228,177, 3,
+ 65,146,122, 2, 81, 58,189, 94,223, 6,215,125, 13,169, 23, 32,
+ 0, 42, 0,254, 99,211,233,116,123, 73, 18,142,141,159, 25,236,
+ 186, 8, 46,171,163,163,189, 30,252,110,186,172,193,208,127, 58,
+ 144,199, 14, 4,105,113,211,137,210, 85, 87,159,171, 4,191, 21,
+ 56, 64,141, 95, 48, 84, 0,132,227,120,200,216,111,190,249,230,
+ 109,146, 12,233,218, 18, 48,210,208,196, 15, 25,151, 56,143, 40,
+ 221,241,227,149, 63,129,223, 59,223,218,222,222,190, 51,144,199,
+ 30, 45,140, 84,133,116,109, 9, 81,218,127,253,235, 95,219,193,
+ 71,250, 17, 85, 76,191, 64, 65, 5,192,127,236,107,215,174, 57,
+ 105,183,219,173, 35, 37, 84, 48, 90,228, 39, 47, 9,122,133,146,
+ 213, 69, 72, 37,124,115,222,115,207, 61, 91, 49, 16, 60,227,222,
+ 123,215,191, 70,146, 39, 53,110, 58,146,213, 69,163,168, 33, 25,
+ 249,201, 75,160, 96,180, 35,166,179,217,172,182,247,222,123,175,
+ 14,124, 32, 16,106,244,126, 64, 5, 64, 0, 78,155, 73, 14, 70,
+ 23,182, 88, 44,245, 36,121,103,140,187, 19, 82, 73,112,195, 11,
+ 206,202, 94, 71,148,206, 98, 49,155,207,157, 59,215,135,129, 24,
+ 121,219,183,111,215,177, 44,107, 12,100, 25,254, 34,149,200, 49,
+ 99,220,157, 68,105,245,250,158, 54,240,238,191, 67,132, 7,247,
+ 56,164, 27,127,146, 65, 5, 96,116, 88,123,122,244, 7, 72, 18,
+ 38, 40,115, 49, 41,109,101,208, 42,146, 30, 63, 11,217, 73, 11,
+ 136,210,234,116,221, 77, 24, 10,144,201, 1,176,153, 76,198,106,
+ 146,188,217, 73, 11,144, 65,232,158,251,195,164,180,149,196, 35,
+ 25, 13, 13,245,149,224,189,152, 88,217,220, 52,228, 80, 1,240,
+ 31, 14, 0,123,244,232,209,119, 72, 51,204,206, 89,143, 20,205,
+ 228,128, 87, 68, 37, 75,193,101, 19,158, 34, 78, 95, 81, 81,190,
+ 7,124,176, 76,135,225, 88,218,218,218, 62, 39,205, 63,127,252,
+ 70,168,100, 41,130,235, 57, 18, 41,154,201,152,157,179,158, 56,
+ 253, 71, 31,125,180, 3,174,238, 63, 21, 1,129, 80, 1, 24, 29,
+ 236,181,215, 46,219, 99,177, 88, 58, 73, 18, 51, 82, 21, 22, 21,
+ 110, 14,168,241, 72, 37,114, 92, 81,248, 2, 52,138,116,162,244,
+ 44,203,218,175,187,110,249, 59, 24, 18, 0, 59, 0,235,212,169,
+ 83,158,226, 56,142, 37, 57,134, 70,145,142, 43, 10, 95, 8,104,
+ 147, 70, 37, 75,193,162,194,205,196,157,165,125,125,125,250, 13,
+ 27,158, 60, 10,234, 1,140, 10, 42, 0,254, 49, 24, 30, 12,128,
+ 185,185,185,233, 85,210,140, 26, 69, 58,150, 77,121, 47, 32,157,
+ 105,106,121, 42,150, 20,191,138, 52, 1,195,115,245,245,117, 71,
+ 193, 7, 57,213,195, 53,160,134,177,167, 71, 79, 52,172, 9, 0,
+ 105,241, 51,177,180,248, 13,168,229,169, 2,107,237, 73,178,186,
+ 8, 87, 79,217, 66, 44, 98, 0,176,127,255,190, 47, 0,180,129,
+ 31,202, 4,168, 23,224, 23, 84, 0,252,199,241,160, 89, 39, 79,
+ 46,254,155,209,104, 36,154, 20, 4, 0,241,202,108, 92, 61,101,
+ 11,198,143, 89,230,119,225, 25,218, 18, 44,155,242, 62,210,227,
+ 103, 17,231,177, 90,173,214, 41, 83, 38, 63, 8,160, 25,158, 17,
+ 116, 44,153,153, 25, 43, 89,150, 37,154,221, 8,240, 34,176,108,
+ 202,251,163,234, 19, 24, 63,102, 25,174,158,178,133,184,221, 15,
+ 0,221,221,186,246,229,203,175,125, 29,252,121,248,138,255, 71,
+ 33,128, 10,192,232, 24,124,123,214,212, 84, 63, 39, 36,163, 92,
+ 170,193,252,241, 27,113,237,148, 15,145,153, 48,135, 56, 95,178,
+ 186, 8,139, 10, 55,227,170,226, 55, 16,167,200, 20, 84,217, 51,
+ 103, 78, 31, 0,239,250, 55,193, 51,146, 14, 11,192,168,215,119,
+ 127, 33,228,152,113,138, 76, 92, 85,252, 6, 22, 21,110, 22,228,
+ 213,100, 38,204,193,178, 41,239, 97,254,248,141,144, 75, 53, 66,
+ 138,196,142, 29, 59, 62, 0,127, 14,206,238, 63, 53,126, 63,144,
+ 4, 58, 82,146,209,104, 22,148,254,213,131,197, 1, 45, 63, 20,
+ 12, 4, 18,117,254, 48, 0,226,154,154,154,119, 36, 37, 37, 95,
+ 224,207, 49, 13,150, 86,212,117,239, 68,107,239, 65,244,152,107,
+ 97,182,233,193,218, 77,208, 40,210,161,145,167, 35, 45,110, 58,
+ 242, 82,150,248, 61,173,184,187,187,187, 61, 43, 43,227, 22, 0,
+ 39, 49,228, 1, 56,135,201,150,128, 95, 27, 18,223,209,209,121,
+ 68,163,137, 27,231, 79, 57,122, 83, 53,106,187,182,163,189,191,
+ 2, 6,107, 43, 12,150, 86, 48, 82, 21,148,178, 68, 36, 40,243,
+ 48, 86, 59, 11,121, 73,139, 4,185,251,206, 52, 52,212,159, 40,
+ 42, 42,252, 61,128, 35,224, 59, 0, 61,226, 1, 70,211, 16,224,
+ 173, 37, 85,126,229, 83,171,149, 1, 41,159, 46, 6,242, 31,231,
+ 135,204, 14,192,152,149,149,121,117,119,119,207, 41,133, 66,145,
+ 32,244, 96, 26, 69, 58,138,199,174, 66,241,216, 85,129,171,225,
+ 0, 44,203,178, 55,222,184,226, 30,240,111,205, 22,248,142,160,
+ 107, 3,208,255,224,131,127,188,114,227,198,167,202,165, 82,169,
+ 224,231, 35, 81, 85,128,233, 89,107, 2, 81,109, 15,140, 70, 67,
+ 95, 81, 81,225, 61, 0,106,193,247, 99,196, 98,188,198,144, 18,
+ 118, 15, 32, 26,209,104, 84,142,176,192,206, 94,128, 20,128,226,
+ 139, 47,190, 92,118,217,101, 11,222,150, 68, 80,232,224,119,222,
+ 121,251,249,213,171,111,123, 15, 64, 57,248, 73, 51,238,111,127,
+ 7,142,243, 80,238,221,187,111,237,204,153,231, 63, 17,218,154,
+ 250,198,110,183,115, 79, 62,249,196, 67,143, 60,242,240,151, 0,
+ 78, 96, 96, 37, 35,188, 68, 3, 54, 24, 76, 49, 47, 4,129,242,
+ 0,168, 0,248,137, 23, 17,144, 14,124,212,223,127,191,123,205,
+ 236,217, 37,143,135,173,114, 78,236,219,183,119,235, 21, 87, 44,
+ 124, 30, 64, 5,124,184,204, 3, 73,221,155, 52,234,163, 71, 43,
+ 159,153, 48, 97,194,175, 67, 95,107, 79, 6, 68,236, 35, 0, 71,
+ 1, 24, 48,180, 4,216,197,147, 17,131,241, 3,129, 19, 0,218,
+ 9, 24, 56, 28, 15,163,105,254,252,121,255,119,232,208, 79,127,
+ 9,119, 40,234, 31,127,220,255,197, 21, 87, 44,252, 7,128, 42,
+ 12,205,252,243,102,252,112,251,141, 5, 96,156, 54,109,234,186,
+ 211,167, 79,189, 25,218, 90,187,194,113, 28,247,233,167,159,188,
+ 188,122,245,109, 91,193,191,249, 13,240,222,124,161,248, 1, 21,
+ 0, 63,113,122,211,184,183, 65,237, 0,140,243,230, 93,250,247,
+ 47,190,216,246, 59,179,217,108, 8,117,221,108, 54, 27,251,238,
+ 187, 91, 54, 95,126,249,130,103,193, 27, 77, 39, 60, 13,127,164,
+ 143, 29,128, 97,198,140,233,119,237,221,187,231, 17,150,101,137,
+ 38, 9, 5, 18,163,209,104,120,250,233,191, 63,186,106,213, 77,
+ 111,130,127,243, 59, 60, 24,175,109,127,177,188,253, 3, 9,109,
+ 2,140, 2,167,102, 0,224,217, 31, 32, 5, 32, 7,144, 86, 83,
+ 83,187,109,236,216,244,192,207, 1,246, 66,119,183,174,117,233,
+ 210,171,254, 80, 94, 94, 94, 7,224, 20, 60,223,252,206,109,127,
+ 111,125, 0,142,111, 41,134,154, 3,202,235,175,191,126,226,166,
+ 77, 47,110, 77, 72, 72,200, 8,246, 57, 0, 64, 99, 99,195,233,
+ 194,194,137,235,192, 79,246,169, 6,191,232,199,155,219, 63,120,
+ 14, 98, 18, 0,218, 7, 16, 33,184,245, 5, 56,190,157, 13, 72,
+ 6, 32,110,207,158,189,127,157, 52,169,120,133, 70,163, 17, 60,
+ 66, 64,130,197, 98,177,158, 58,117,114,255,133, 23,150,252, 13,
+ 64, 35,120,163,177,129,220,248, 29,120, 19, 1,135,152,197, 31,
+ 59, 86,249,122, 78, 78,238,124,185, 92,174, 8,198,121,244,247,
+ 247,245, 28, 56,112,224,171,107,174,185,250, 21,240,189,253,117,
+ 62,206,193,229, 60,196,100,252, 0, 21,128,136,193,139, 23,224,
+ 248,118,127,139, 42, 0,100,148,149,149, 63, 91, 80, 80,176, 64,
+ 46, 87, 4,196,128, 88,150,181,215,213,213, 30,157, 58,117,202,
+ 159, 48, 52,201,167, 21,158,237,125,199,230,153, 94,223,154, 62,
+ 188, 25, 56,157,131, 67,204,148, 0,178, 79,157, 58,253,114, 86,
+ 214,184,243,165, 82,105, 64,154,145, 22,139,197, 82, 85,117, 98,
+ 223,156, 57, 23,109, 0,255,214,111, 30, 56,159, 17,141,223,249,
+ 60,196, 2, 21,128, 8, 98, 4, 17,112,247, 6, 20, 0, 50, 55,
+ 109,218,116,253,194,133, 87,252, 34, 45,109,236,120,181, 90,173,
+ 21, 50,106,104, 54,155, 76, 93, 93, 93, 77,165,165,223,125,181,
+ 122,245,234,175,192,187,249,205,224,223,252,190, 12,102, 68,163,
+ 17,120, 30, 74, 0,121,111,190,249,230,175, 46,185,100,238,181,
+ 201,201, 41,227,148, 74, 37,241,182, 71, 28,199,193,104, 52,244,
+ 182,181,181,215,110,219,246,217,231,247,222,123,239,247, 0,186,
+ 193,207, 83,104, 27,205,121,136, 1, 42, 0, 17, 6,129,241,184,
+ 247, 15,200, 0,196, 3, 72, 3,144,244,194, 11, 47, 46,187,248,
+ 226,139,231,101,102,102, 77, 84,169, 84,241, 12,195,200, 36, 18,
+ 137,196,102,179, 89,173, 86,139,177,189,189,163,161,188,188,236,
+ 224,218,181,107,182,117,119,119,155,192,119,136,117, 3,232,128,
+ 235,218,126,159,157,100, 32, 48, 26, 63,206, 67, 14, 32, 9, 64,
+ 90, 90, 90, 90,202, 63,254,177,233,198, 25, 51,102,148,140, 25,
+ 51, 38, 71, 46, 87,168,101, 50,153,156,227, 56,142,101, 89,155,
+ 201,100,236,107,106,106, 58,179,111,223,190,125,119,222,121,199,
+ 78,240,115, 18,116,224,167,244,118,194,181,135,127, 84,231, 17,
+ 235, 80, 1,136, 64,220,140, 7,112,117,165,125, 25,145,227,155,
+ 1,144,224,244, 81, 13,252, 6,240,187,247,154,193, 27,189, 30,
+ 174, 6,239,236,226, 15,103, 44,196, 70, 51,140, 8,120, 59, 15,
+ 169,219,223, 14, 65, 72, 0, 47,112,138,129,243,224, 6,206,195,
+ 232,116, 30,253, 4,231,224,247,121,196, 50, 84, 0, 34, 20, 31,
+ 34,224,254,237,237, 3, 47,127, 59,227,205, 16,134, 51, 22,175,
+ 157,125,164, 70, 51,194,121,144,158,203, 72,231, 65,122, 46,126,
+ 159, 71,172, 66, 5, 32,194, 33, 20, 2,199,247, 72, 70,227,192,
+ 151, 81,140,104, 48,128,112,163,241,114, 14,222,234, 56, 92,253,
+ 133,156,199,112,231, 54,136,216, 13,223, 1, 21,128, 40, 96, 4,
+ 3,114,254,219,219,111,190,224,188,252,237,237,183, 65, 70,107,
+ 52,177,114, 30,177, 4, 21,128, 40,131,192,136,134,251,205, 25,
+ 111, 55,204,235, 77, 12,180,193,248, 56, 7, 32,136,231, 65,141,
+ 222, 59, 84, 0,162,152, 97, 12,105,212,132,202, 96, 98,225, 28,
+ 162, 25, 42, 0, 49,202, 72,134, 21, 45,198, 17, 43,231, 17,169,
+ 4, 74, 0,254, 63, 34, 58,182, 52, 79,174,223,189, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+#endif /* CONFIG_DARWIN */
+
+static const unsigned char _data_android_icon_32_png[1321] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 32, 0, 0, 0, 32, 8, 6, 0, 0, 0,115,122,122,
+ 244, 0, 0, 4,240, 73, 68, 65, 84, 88,133,237, 87, 91,108, 20,
+ 85, 24,254,102,167, 51,237,238, 78,183,237,178,180,182,213,165,
+ 110, 98, 35, 18,181, 41, 41, 18,185, 52, 1,251,162, 4, 98,212,
+ 180, 38, 74,170,132, 7,170, 38, 26, 31, 20,130, 24,130,196,128,
+ 190, 24,181, 38,120, 71,177, 82,110,106,212, 4,154, 0, 69,170,
+ 98, 85,104,161, 8,180,118,183, 40,236,165,179,219,153,189,204,
+ 206,238,204,244,248, 80,102,178,211,237,110,161, 53,242,226,151,
+ 76,246, 59,255,249,207,255,127,123,230,159,115,161, 8, 33, 0,
+ 0,138,162,144, 7, 84, 40,196, 47,103, 89,118,105, 58,157, 62,
+ 89, 94,238, 58, 33, 73, 50,201,116,176,217,138, 44, 60, 31,121,
+ 154, 97,152, 37,138,162,244,184, 92,206,143, 36, 73, 30,159, 28,
+ 200,102, 43, 50, 56, 33, 4,212,117, 8,160, 68, 49,246, 5,195,
+ 48, 45, 25, 3,131,137, 68,226, 89,139,197, 82, 14, 0,170,170,
+ 122,237,118,251, 86,154,166, 27,116, 31, 77,211,122,139,139,237,
+ 139,219,187,107, 76, 34,218, 26,125, 55, 38, 32, 20,226, 27, 57,
+ 142, 59,158, 75, 93, 62, 72,146,180,190,115,160,254,131,124, 2,
+ 44,211, 5, 97, 89,118,169,206,207,250,119, 33,154,186,156,215,
+ 191,199,183,217,224,170,170,172,152, 46,254,180, 2,100, 89,246,
+ 233,252,206,138, 39,208,119,229, 93, 16,162,129, 79,244,227,210,
+ 104, 39, 46,141,118,226,106,244, 71,164, 84, 17,231,131,187,225,
+ 113,174, 50,198,198,227, 9,170,173,209,151,183,184, 10,242,117,
+ 242,124,228, 65,155,205,246,185,222, 38, 68, 67, 74, 19,241,217,
+ 111,117, 24, 39, 74,150, 63, 87,120, 43, 86,222,209,110,180,171,
+ 170,170, 90, 4, 33, 58, 84, 90,234,216,210,222, 93, 67,178, 6,
+ 32,255, 12, 80, 69, 69, 69, 70, 52, 33, 57,132,175,206,173,194,
+ 85,177, 7, 52,197, 76, 57, 64,213, 36,124, 51,240, 48, 46,132,
+ 58, 12, 27,203,178,155, 71, 71,195, 15,228, 74, 50,165, 0, 66,
+ 8, 34, 17,225,113,139,197, 50, 15, 0,164,116, 16,135, 47,182,
+ 66, 74, 7,177,110, 73, 63,230, 87, 54,103,141,185,171, 98, 45,
+ 30,187,247, 40, 8,209,240,243,200, 86,248,198, 14, 27,125,133,
+ 133,133,175,111, 88,238,197,134,229,222,172,113, 89,175, 96,120,
+ 216,231, 22,132,104, 27, 77,211,166,226, 75, 42, 60, 0,224,148,
+ 119, 39, 46, 6, 15,101, 5,250, 51,252, 53, 34,210, 31, 70,251,
+ 212,200, 54,184, 75, 87,192, 66, 49, 40, 40, 40, 88, 40, 8,209,
+ 183,210,233,116, 23,128,239, 0, 24,175,195,244, 25, 10, 66,116,
+ 19,203,178,219, 39, 7,239,236,107,132,148, 14, 78, 53, 89,121,
+ 241,208,252, 47, 49,151,171, 51,217, 84, 85,253,214,225,224, 86,
+ 3, 32,166,117, 32, 28, 30,107,176,217,108,191,220,112,150, 25,
+ 64,150,229, 86,167,179,244, 83,147,128,104, 52,254, 49,195, 48,
+ 173, 0,240,183,112, 28,231, 2, 31,162,204, 90,139, 6,247,203,
+ 216,253,235,221, 51, 74,212,218,112, 1,222,200,247, 24, 8,124,
+ 130,170,146,251, 81, 95,253, 60, 0,128, 16,146,176,219,173,197,
+ 132, 16, 98, 20, 33, 77,211, 75,116,222,251,215, 14, 4, 98,189,
+ 240,199,126,130, 37, 71,197, 95, 47,250,174,190, 3, 62,209,143,
+ 203, 99, 71, 12, 27, 69, 81,246, 64, 32, 88, 15,152,191, 2,171,
+ 78, 68,121,162, 90,133,228,240,172,146,103,198,152, 28,203,239,
+ 15,184, 38, 11,248, 79,145, 74,201,244, 77, 21,160,105, 26,117,
+ 83, 5,232,248, 95, 64,166,128,164, 78, 74,173, 30,211,239,108,
+ 144, 43,150, 36, 37,227, 38, 1,154,166,245,232,188,225,182,141,
+ 168,116, 44, 70,117, 73, 35, 8,209,102, 37,160,190,250, 5, 84,
+ 112, 11,225,113,174, 54,108,170,170,202, 77, 77, 43, 79, 3, 25,
+ 155,145,162, 40,237,250, 74, 88, 93,178, 12,213, 37,203,102,149,
+ 88,135,187,172, 9,238,178, 38,147,237,216,177,163, 59, 0,152,
+ 103,192,229,114,246,170,170,250,210,191,146, 53, 15,188, 94,239,
+ 137, 53,107, 86,191,135,107, 59,162,169, 8, 29, 14,110,231,249,
+ 243, 3,110, 65, 24,123, 67, 16,198,250,117,251, 76,102,195,237,
+ 108, 52,181,207,156, 57,189,119,207,158, 61,235, 23, 44,152,223,
+ 12, 32,172,219,167, 58, 21, 83,152,184, 7,188,202,113,220, 22,
+ 221, 40,202, 94, 12,241,135,112,214,191, 11, 0, 96,101, 92,104,
+ 174, 59, 9, 0, 56,233,221,136, 33,126,226,140, 80,193, 45,196,
+ 34,247, 38,148,217,106,141,125, 36,153, 76,134,231,204, 41,171,
+ 5, 16, 3, 48,126,237, 33,185, 78,197, 4,192,120, 60, 30,127,
+ 155, 16,114, 69, 55,150, 20,221, 14, 59, 91,105, 56,101,110, 82,
+ 86,102,174,193,153,130, 98,204,177, 47, 48,245,119,117, 29,217,
+ 14, 64,108,239,174, 81, 0,104,200, 56,144,228, 92, 7, 60,158,
+ 26, 62, 24, 12,214,137,162,240, 90, 46,159,233, 16, 10,133,134,
+ 59, 58, 58,158,107,105,105,126, 31, 19,255, 58, 11,121, 23, 34,
+ 143,167,134,103, 24,214,111, 56, 83,180,209, 71,153,120,206, 48,
+ 193,117,235,158,218, 5, 64,154,201,169, 24, 0, 64, 8, 49,214,
+ 135,185, 92, 29,104,203,196,221,174,210,177,216,240,185,165,120,
+ 145,193, 43,139,239, 51,120, 32,224,255, 29,128, 50,249,122,150,
+ 137,235,186, 27, 38, 18, 73,129,162, 40, 7, 0,164, 84, 17,177,
+ 212, 8, 92,246,123, 76, 78, 73,133,135,172, 70, 80,102,173, 53,
+ 108,251,247,239,123, 36, 62,239,149,131,153,126, 55,124, 53, 3,
+ 64, 82,169,212, 51,122,163,176,160, 36, 43, 57, 48,241, 85,100,
+ 38, 31, 28, 28,236, 90,187,246,201,227,211, 71, 39, 4,250, 44,
+ 228, 1, 21, 14,143, 61, 42,138,177,139,146, 36, 19, 73,146, 73,
+ 60, 46, 41, 7, 14, 28,124,179,187,251,135, 23, 5, 33,234,211,
+ 237,162, 24, 75,236,221,219,185, 13, 64, 57, 0, 90,146,100,100,
+ 62,147,115,255, 3, 56,204, 60,122,104, 43, 57,236, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+
+static const FileEntry _file_entries[] =
+{
+
+ { "android_icon_16.png", _data_android_icon_16_png, 460 },
+#ifdef CONFIG_DARWIN
+ { "android_icon_256.png", _data_android_icon_256_png, 13369 },
+#endif
+ { "android_icon_32.png", _data_android_icon_32_png, 1321 },
+ { NULL, NULL, 0 }
+};
diff --git a/android/main.c b/android/main.c
new file mode 100644
index 0000000..c366a9e
--- /dev/null
+++ b/android/main.c
@@ -0,0 +1,2836 @@
+/* Copyright (C) 2006-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#ifdef _WIN32
+#include <process.h>
+#endif
+#include "libslirp.h"
+#include "sockets.h"
+
+#include "android/android.h"
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "console.h"
+
+#include <SDL.h>
+#include <SDL_syswm.h>
+
+#include "math.h"
+
+#include "android/charmap.h"
+#include "modem_driver.h"
+#include "shaper.h"
+#include "proxy_http.h"
+
+#include "android/utils/debug.h"
+#include "android/resource.h"
+#include "android/config.h"
+#include "android/config/config.h"
+
+#include "android/skin/image.h"
+#include "android/skin/trackball.h"
+#include "android/skin/keyboard.h"
+#include "android/skin/file.h"
+#include "android/skin/window.h"
+#include "android/skin/keyset.h"
+
+#include "android/gps.h"
+#include "android/qemud.h"
+#include "android/hw-kmsg.h"
+#include "android/hw-control.h"
+#include "android/user-config.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/dirscanner.h"
+#include "android/utils/path.h"
+#include "android/utils/timezone.h"
+#include "android/utils/display.h"
+
+#include "android/cmdline-option.h"
+#include "android/help.h"
+#include "hw/goldfish_nand.h"
+
+#include "android/globals.h"
+#include "tcpdump.h"
+
+/* in vl.c */
+extern void qemu_help(int code);
+
+#include "framebuffer.h"
+AndroidRotation android_framebuffer_rotation;
+
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define VERSION_STRING STRINGIFY(ANDROID_VERSION_MAJOR)"."STRINGIFY(ANDROID_VERSION_MINOR)
+
+#define KEYSET_FILE "default.keyset"
+SkinKeyset* android_keyset;
+
+#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
+
+extern int control_console_start( int port ); /* in control.c */
+
+extern int qemu_milli_needed;
+
+/* the default device DPI if none is specified by the skin
+ */
+#define DEFAULT_DEVICE_DPI 165
+
+static const AKeyCharmap* android_charmap;
+
+int android_base_port;
+
+#if 0
+static int opts->flashkeys; /* forward */
+#endif
+
+static void handle_key_command( void* opaque, SkinKeyCommand command, int param );
+
+#ifdef CONFIG_TRACE
+extern void start_tracing(void);
+extern void stop_tracing(void);
+#endif
+
+unsigned long android_verbose;
+
+int qemu_cpu_delay = 0;
+int qemu_cpu_delay_count;
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** U T I L I T Y R O U T I N E S *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+/*** APPLICATION DIRECTORY
+ *** Where are we ?
+ ***/
+
+const char* get_app_dir(void)
+{
+ char buffer[1024];
+ char* p = buffer;
+ char* end = p + sizeof(buffer);
+ p = bufprint_app_dir(p, end);
+ if (p >= end)
+ return NULL;
+
+ return strdup(buffer);
+}
+
+/*** CONFIGURATION
+ ***/
+
+static AUserConfig* userConfig;
+
+void
+emulator_config_init( void )
+{
+ userConfig = auserConfig_new( android_avdInfo );
+}
+
+/* only call this function on normal exits, so that ^C doesn't save the configuration */
+void
+emulator_config_done( void )
+{
+ int win_x, win_y;
+
+ if (!userConfig) {
+ D("no user configuration?");
+ return;
+ }
+
+ SDL_WM_GetPos( &win_x, &win_y );
+ auserConfig_setWindowPos(userConfig, win_x, win_y);
+ auserConfig_save(userConfig);
+}
+
+void *loadpng(const char *fn, unsigned *_width, unsigned *_height);
+void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height);
+
+#ifdef CONFIG_DARWIN
+# define ANDROID_ICON_PNG "android_icon_256.png"
+#else
+# define ANDROID_ICON_PNG "android_icon_16.png"
+#endif
+
+static void
+sdl_set_window_icon( void )
+{
+ static int window_icon_set;
+
+ if (!window_icon_set)
+ {
+#ifdef _WIN32
+ HANDLE handle = GetModuleHandle( NULL );
+ HICON icon = LoadIcon( handle, MAKEINTRESOURCE(1) );
+ SDL_SysWMinfo wminfo;
+
+ SDL_GetWMInfo(&wminfo);
+
+ SetClassLong( wminfo.window, GCL_HICON, (LONG)icon );
+#else /* !_WIN32 */
+ unsigned icon_w, icon_h;
+ size_t icon_bytes;
+ const unsigned char* icon_data;
+ void* icon_pixels;
+
+ window_icon_set = 1;
+
+ icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes );
+ if ( !icon_data )
+ return;
+
+ icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h );
+ if ( !icon_pixels )
+ return;
+
+ /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
+ * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
+ * on our CPU endianess
+ */
+ {
+ unsigned* d = icon_pixels;
+ unsigned* d_end = d + icon_w*icon_h;
+
+ for ( ; d < d_end; d++ ) {
+ unsigned pix = d[0];
+#if WORDS_BIGENDIAN
+ /* R,G,B,A read as RGBA => ARGB */
+ pix = ((pix >> 8) & 0xffffff) | (pix << 24);
+#else
+ /* R,G,B,A read as ABGR => ARGB */
+ pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
+#endif
+ d[0] = pix;
+ }
+ }
+
+ SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h );
+ if (icon != NULL) {
+ SDL_WM_SetIcon(icon, NULL);
+ SDL_FreeSurface(icon);
+ free( icon_pixels );
+ }
+#endif /* !_WIN32 */
+ }
+}
+
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** S K I N I M A G E S *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+void send_key_event(unsigned code, unsigned down)
+{
+ if(code == 0) {
+ return;
+ }
+ if (VERBOSE_CHECK(keys))
+ printf(">> KEY [0x%03x,%s]\n", (code & 0x1ff), down ? "down" : " up " );
+ kbd_put_keycode((code & 0x1ff) | (down ? 0x200 : 0));
+}
+
+
+
+typedef struct {
+ AConfig* aconfig;
+ SkinFile* layout_file;
+ SkinLayout* layout;
+ SkinKeyboard* keyboard;
+ SkinWindow* window;
+ int win_x;
+ int win_y;
+ int show_trackball;
+ SkinTrackBall* trackball;
+ int lcd_brightness;
+ SkinImage* onion;
+ SkinRotation onion_rotation;
+ int onion_alpha;
+
+ AndroidOptions opts[1]; /* copy of options */
+} QEmulator;
+
+static QEmulator qemulator[1];
+
+static void
+qemulator_done( QEmulator* emulator )
+{
+ if (emulator->window) {
+ skin_window_free(emulator->window);
+ emulator->window = NULL;
+ }
+ if (emulator->trackball) {
+ skin_trackball_destroy(emulator->trackball);
+ emulator->trackball = NULL;
+ }
+ if (emulator->keyboard) {
+ skin_keyboard_free(emulator->keyboard);
+ emulator->keyboard = NULL;
+ }
+ emulator->layout = NULL;
+ if (emulator->layout_file) {
+ skin_file_free(emulator->layout_file);
+ emulator->layout_file = NULL;
+ }
+}
+
+
+static void
+qemulator_setup( QEmulator* emulator );
+
+static void
+qemulator_fb_update( void* _emulator, int x, int y, int w, int h )
+{
+ QEmulator* emulator = _emulator;
+
+ if (emulator->window)
+ skin_window_update_display( emulator->window, x, y, w, h );
+}
+
+static void
+qemulator_fb_rotate( void* _emulator, int rotation )
+{
+ QEmulator* emulator = _emulator;
+
+ qemulator_setup( emulator );
+}
+
+
+
+static int
+qemulator_init( QEmulator* emulator,
+ AConfig* aconfig,
+ const char* basepath,
+ int x,
+ int y,
+ AndroidOptions* opts )
+{
+ emulator->aconfig = aconfig;
+ emulator->layout_file = skin_file_create_from_aconfig(aconfig, basepath);
+ emulator->layout = emulator->layout_file->layouts;
+ emulator->keyboard = skin_keyboard_create_from_aconfig(aconfig, opts->raw_keys);
+ emulator->window = NULL;
+ emulator->win_x = x;
+ emulator->win_y = y;
+ emulator->opts[0] = opts[0];
+
+ /* register as a framebuffer clients for all displays defined in the skin file */
+ SKIN_FILE_LOOP_PARTS( emulator->layout_file, part )
+ SkinDisplay* disp = part->display;
+ if (disp->valid) {
+ qframebuffer_add_client( disp->qfbuff,
+ emulator,
+ qemulator_fb_update,
+ qemulator_fb_rotate,
+ NULL );
+ }
+ SKIN_FILE_LOOP_END_PARTS
+ return 0;
+}
+
+
+static AndroidKeyCode
+qemulator_rotate_keycode( QEmulator* emulator,
+ AndroidKeyCode sym )
+{
+ switch (skin_layout_get_dpad_rotation(emulator->layout)) {
+ case SKIN_ROTATION_90:
+ switch (sym) {
+ case kKeyCodeDpadLeft: sym = kKeyCodeDpadDown; break;
+ case kKeyCodeDpadRight: sym = kKeyCodeDpadUp; break;
+ case kKeyCodeDpadUp: sym = kKeyCodeDpadLeft; break;
+ case kKeyCodeDpadDown: sym = kKeyCodeDpadRight; break;
+ default: ;
+ }
+ break;
+
+ case SKIN_ROTATION_180:
+ switch (sym) {
+ case kKeyCodeDpadLeft: sym = kKeyCodeDpadRight; break;
+ case kKeyCodeDpadRight: sym = kKeyCodeDpadLeft; break;
+ case kKeyCodeDpadUp: sym = kKeyCodeDpadDown; break;
+ case kKeyCodeDpadDown: sym = kKeyCodeDpadUp; break;
+ default: ;
+ }
+ break;
+
+ case SKIN_ROTATION_270:
+ switch (sym) {
+ case kKeyCodeDpadLeft: sym = kKeyCodeDpadUp; break;
+ case kKeyCodeDpadRight: sym = kKeyCodeDpadDown; break;
+ case kKeyCodeDpadUp: sym = kKeyCodeDpadRight; break;
+ case kKeyCodeDpadDown: sym = kKeyCodeDpadLeft; break;
+ default: ;
+ }
+ break;
+
+ default: ;
+ }
+ return sym;
+}
+
+static int
+get_device_dpi( AndroidOptions* opts )
+{
+ int dpi_device = DEFAULT_DEVICE_DPI;
+
+ if (opts->dpi_device != NULL) {
+ char* end;
+ dpi_device = strtol( opts->dpi_device, &end, 0 );
+ if (end == NULL || *end != 0 || dpi_device <= 0) {
+ fprintf(stderr, "argument for -dpi-device must be a positive integer. Aborting\n" );
+ exit(1);
+ }
+ }
+ return dpi_device;
+}
+
+static double
+get_default_scale( AndroidOptions* opts )
+{
+ int dpi_device = get_device_dpi( opts );
+ int dpi_monitor = -1;
+ double scale = 0.0;
+
+ /* possible values for the 'scale' option are
+ * 'auto' : try to determine the scale automatically
+ * '<number>dpi' : indicates the host monitor dpi, compute scale accordingly
+ * '<fraction>' : use direct scale coefficient
+ */
+
+ if (opts->scale) {
+ if (!strcmp(opts->scale, "auto"))
+ {
+ /* we need to get the host dpi resolution ? */
+ int xdpi, ydpi;
+
+ if ( get_monitor_resolution( &xdpi, &ydpi ) < 0 ) {
+ fprintf(stderr, "could not get monitor DPI resolution from system. please use -dpi-monitor to specify one\n" );
+ exit(1);
+ }
+ D( "system reported monitor resolutions: xdpi=%d ydpi=%d\n", xdpi, ydpi);
+ dpi_monitor = (xdpi + ydpi+1)/2;
+ }
+ else
+ {
+ char* end;
+ scale = strtod( opts->scale, &end );
+
+ if (end && end[0] == 'd' && end[1] == 'p' && end[2] == 'i' && end[3] == 0) {
+ if ( scale < 20 || scale > 1000 ) {
+ fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale,
+ "host dpi number must be between 20 and 1000" );
+ exit(1);
+ }
+ dpi_monitor = scale;
+ scale = 0.0;
+ }
+ else if (end == NULL || *end != 0) {
+ fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale,
+ "not a number or the 'auto' keyword" );
+ exit(1);
+ }
+ else if ( scale < 0.1 || scale > 3. ) {
+ fprintf(stderr, "emulator: ignoring bad -window-scale argument '%s': %s\n", opts->scale,
+ "must be between 0.1 and 3.0" );
+ exit(1);
+ }
+ }
+ }
+
+ if (scale == 0.0 && dpi_monitor > 0)
+ scale = dpi_monitor*1.0/dpi_device;
+
+ if (scale == 0.0)
+ scale = 1.0;
+
+ return scale;
+}
+
+void
+android_emulator_set_window_scale( double scale, int is_dpi )
+{
+ QEmulator* emulator = qemulator;
+
+ if (is_dpi)
+ scale /= get_device_dpi( emulator->opts );
+
+ if (emulator->window)
+ skin_window_set_scale( emulator->window, scale );
+}
+
+
+static void
+qemulator_set_title( QEmulator* emulator )
+{
+ char temp[64];
+
+ if (emulator->window == NULL)
+ return;
+
+ snprintf( temp, sizeof(temp), "Android Emulator (%s:%d)",
+ avdInfo_getName( android_avdInfo ),
+ android_base_port );
+
+ skin_window_set_title( emulator->window, temp );
+}
+
+/* called by the emulated framebuffer device each time the content of the
+ * framebuffer has changed. the rectangle is the bounding box of all changes
+ */
+static void
+sdl_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ /* this function is being called from the console code that is currently inactive
+ ** simple totally ignore it...
+ */
+ (void)ds;
+ (void)x;
+ (void)y;
+ (void)w;
+ (void)h;
+}
+
+
+
+static void
+qemulator_light_brightness( void* opaque, const char* light, int value )
+{
+ QEmulator* emulator = opaque;
+
+ VERBOSE_PRINT(hw_control,"%s: light='%s' value=%d window=%p", __FUNCTION__, light, value, emulator->window);
+ if ( !strcmp(light, "lcd_backlight") ) {
+ emulator->lcd_brightness = value;
+ if (emulator->window)
+ skin_window_set_lcd_brightness( emulator->window, value );
+ return;
+ }
+}
+
+
+static void
+qemulator_setup( QEmulator* emulator )
+{
+ AndroidOptions* opts = emulator->opts;
+
+ if ( !emulator->window && !opts->no_window ) {
+ SkinLayout* layout = emulator->layout;
+ double scale = get_default_scale(emulator->opts);
+
+ emulator->window = skin_window_create( layout, emulator->win_x, emulator->win_y, scale, 0);
+ if (emulator->window == NULL)
+ return;
+
+ {
+ SkinTrackBall* ball;
+ SkinTrackBallParameters params;
+
+ params.diameter = 30;
+ params.ring = 2;
+ params.ball_color = 0xffe0e0e0;
+ params.dot_color = 0xff202020;
+ params.ring_color = 0xff000000;
+
+ ball = skin_trackball_create( &params );
+ emulator->trackball = ball;
+ skin_window_set_trackball( emulator->window, ball );
+
+ emulator->lcd_brightness = 128; /* 50% */
+ skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
+ }
+
+ if ( emulator->onion != NULL )
+ skin_window_set_onion( emulator->window,
+ emulator->onion,
+ emulator->onion_rotation,
+ emulator->onion_alpha );
+
+ qemulator_set_title( emulator );
+
+ skin_window_enable_touch ( emulator->window, android_hw->hw_touchScreen != 0 );
+ skin_window_enable_dpad ( emulator->window, android_hw->hw_dPad != 0 );
+ skin_window_enable_qwerty( emulator->window, android_hw->hw_keyboard != 0 );
+ skin_window_enable_trackball( emulator->window, android_hw->hw_trackBall != 0 );
+ }
+
+ /* initialize hardware control support */
+ {
+ AndroidHwControlFuncs funcs;
+
+ funcs.light_brightness = qemulator_light_brightness;
+ android_hw_control_init( emulator, &funcs );
+ }
+}
+
+
+/* called by the emulated framebuffer device each time the framebuffer
+ * is resized or rotated */
+static void
+sdl_resize(DisplayState *ds, int w, int h)
+{
+ fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n");
+ exit(1);
+}
+
+
+static void sdl_refresh(DisplayState *ds)
+{
+ QEmulator* emulator = ds->opaque;
+ SDL_Event ev;
+ SkinWindow* window = emulator->window;
+ SkinKeyboard* keyboard = emulator->keyboard;
+
+ /* this will eventually call sdl_update if the content of the VGA framebuffer
+ * has changed */
+ qframebuffer_check_updates();
+
+ if (window == NULL)
+ return;
+
+ while(SDL_PollEvent(&ev)){
+ switch(ev.type){
+ case SDL_VIDEOEXPOSE:
+ skin_window_redraw( window, NULL );
+ break;
+
+ case SDL_KEYDOWN:
+#ifdef _WIN32
+ /* special code to deal with Alt-F4 properly */
+ if (ev.key.keysym.sym == SDLK_F4 &&
+ ev.key.keysym.mod & KMOD_ALT) {
+ goto CleanExit;
+ }
+#endif
+#ifdef __APPLE__
+ /* special code to deal with Command-Q properly */
+ if (ev.key.keysym.sym == SDLK_q &&
+ ev.key.keysym.mod & KMOD_META) {
+ goto CleanExit;
+ }
+#endif
+ skin_keyboard_process_event( keyboard, &ev, 1 );
+ break;
+
+ case SDL_KEYUP:
+ skin_keyboard_process_event( keyboard, &ev, 0 );
+ break;
+
+ case SDL_MOUSEMOTION:
+ skin_window_process_event( window, &ev );
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ {
+ int down = (ev.type == SDL_MOUSEBUTTONDOWN);
+ if (ev.button.button == 4)
+ {
+ /* scroll-wheel simulates DPad up */
+ AndroidKeyCode kcode;
+
+ kcode = qemulator_rotate_keycode(emulator, kKeyCodeDpadUp);
+ send_key_event( kcode, down );
+ }
+ else if (ev.button.button == 5)
+ {
+ /* scroll-wheel simulates DPad down */
+ AndroidKeyCode kcode;
+
+ kcode = qemulator_rotate_keycode(emulator, kKeyCodeDpadDown);
+ send_key_event( kcode, down );
+ }
+ else if (ev.button.button == SDL_BUTTON_LEFT) {
+ skin_window_process_event( window, &ev );
+ }
+#if 0
+ else {
+ fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
+ down ? "down" : "up ",
+ ev.button.button, ev.button.state, ev.button.x, ev.button.y);
+ }
+#endif
+ }
+ break;
+
+ case SDL_QUIT:
+#if defined _WIN32 || defined __APPLE__
+ CleanExit:
+#endif
+ /* only save emulator config through clean exit */
+ qemulator_done( emulator );
+ qemu_system_shutdown_request();
+ return;
+ }
+ }
+
+ skin_keyboard_flush( keyboard );
+}
+
+
+/* used to respond to a given keyboard command shortcut
+ */
+static void
+handle_key_command( void* opaque, SkinKeyCommand command, int down )
+{
+ static const struct { SkinKeyCommand cmd; AndroidKeyCode kcode; } keycodes[] =
+ {
+ { SKIN_KEY_COMMAND_BUTTON_CALL, kKeyCodeCall },
+ { SKIN_KEY_COMMAND_BUTTON_HOME, kKeyCodeHome },
+ { SKIN_KEY_COMMAND_BUTTON_BACK, kKeyCodeBack },
+ { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall },
+ { SKIN_KEY_COMMAND_BUTTON_POWER, kKeyCodePower },
+ { SKIN_KEY_COMMAND_BUTTON_SEARCH, kKeyCodeSearch },
+ { SKIN_KEY_COMMAND_BUTTON_MENU, kKeyCodeMenu },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_UP, kKeyCodeDpadUp },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT, kKeyCodeDpadLeft },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT, kKeyCodeDpadRight },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN, kKeyCodeDpadDown },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
+ { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP, kKeyCodeVolumeUp },
+ { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
+ { SKIN_KEY_COMMAND_NONE, 0 }
+ };
+ int nn;
+#ifdef CONFIG_TRACE
+ static int tracing = 0;
+#endif
+ QEmulator* emulator = opaque;
+
+
+ for (nn = 0; keycodes[nn].kcode != 0; nn++) {
+ if (command == keycodes[nn].cmd) {
+ unsigned code = keycodes[nn].kcode;
+ if (down)
+ code |= 0x200;
+ kbd_put_keycode( code );
+ return;
+ }
+ }
+
+ // for the show-trackball command, handle down events to enable, and
+ // up events to disable
+ if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
+ emulator->show_trackball = (down != 0);
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ //qemulator_set_title( emulator );
+ return;
+ }
+
+ // only handle down events for the rest
+ if (down == 0)
+ return;
+
+ switch (command)
+ {
+ case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
+ {
+ qemu_net_disable = !qemu_net_disable;
+ if (android_modem) {
+ amodem_set_data_registration(
+ android_modem,
+ qemu_net_disable ? A_REGISTRATION_UNREGISTERED
+ : A_REGISTRATION_HOME);
+ }
+ D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" );
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
+ if (emulator->window) {
+ skin_window_toggle_fullscreen(emulator->window);
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_TRACING:
+ {
+#ifdef CONFIG_TRACE
+ tracing = !tracing;
+ if (tracing)
+ start_tracing();
+ else
+ stop_tracing();
+#endif
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
+ emulator->show_trackball = !emulator->show_trackball;
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ break;
+
+ case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
+ case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
+ if (emulator->onion)
+ {
+ int alpha = emulator->onion_alpha;
+
+ if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
+ alpha += 16;
+ else
+ alpha -= 16;
+
+ if (alpha > 256)
+ alpha = 256;
+ else if (alpha < 0)
+ alpha = 0;
+
+ emulator->onion_alpha = alpha;
+ skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
+ skin_window_redraw( emulator->window, NULL );
+ //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
+ case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
+ {
+ SkinLayout* layout = NULL;
+
+ if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
+ layout = emulator->layout->next;
+ if (layout == NULL)
+ layout = emulator->layout_file->layouts;
+ }
+ else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
+ layout = emulator->layout_file->layouts;
+ while (layout->next && layout->next != emulator->layout)
+ layout = layout->next;
+ }
+ if (layout != NULL) {
+ SkinRotation rotation;
+
+ emulator->layout = layout;
+ skin_window_reset( emulator->window, layout );
+
+ rotation = skin_layout_get_dpad_rotation( layout );
+
+ if (emulator->keyboard)
+ skin_keyboard_set_rotation( emulator->keyboard, rotation );
+
+ if (emulator->trackball) {
+ skin_trackball_set_rotation( emulator->trackball, rotation );
+ skin_window_set_trackball( emulator->window, emulator->trackball );
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ }
+
+ skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
+
+ qframebuffer_invalidate_all();
+ qframebuffer_check_updates();
+ }
+ }
+ break;
+
+ default:
+ /* XXX: TODO ? */
+ ;
+ }
+}
+
+
+static void sdl_at_exit(void)
+{
+ emulator_config_done();
+ qemulator_done( qemulator );
+ SDL_Quit();
+}
+
+
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
+{
+ QEmulator* emulator = qemulator;
+ SkinDisplay* disp = skin_layout_get_display(emulator->layout);
+
+// fprintf(stderr,"*** sdl_display_init ***\n");
+ ds->opaque = emulator;
+
+ if (disp->rotation & 1) {
+ ds->width = disp->rect.size.h;
+ ds->height = disp->rect.size.w;
+ } else {
+ ds->width = disp->rect.size.w;
+ ds->height = disp->rect.size.h;
+ }
+
+ ds->dpy_update = sdl_update;
+ ds->dpy_resize = sdl_resize;
+ ds->dpy_refresh = sdl_refresh;
+
+ skin_keyboard_enable( emulator->keyboard, 1 );
+ skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
+}
+
+
+extern SkinKeyboard* android_emulator_get_keyboard(void)
+{
+ return qemulator->keyboard;
+}
+
+static const char* skin_network_speed = NULL;
+static const char* skin_network_delay = NULL;
+
+/* list of skin aliases */
+static const struct {
+ const char* name;
+ const char* alias;
+} skin_aliases[] = {
+ { "QVGA-L", "320x240" },
+ { "QVGA-P", "240x320" },
+ { "HVGA-L", "480x320" },
+ { "HVGA-P", "320x480" },
+ { "QVGA", "320x240" },
+ { "HVGA", "320x480" },
+ { NULL, NULL }
+};
+
+/* this is used by hw/events_device.c to send the charmap name to the system */
+const char* android_skin_keycharmap = NULL;
+
+void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts)
+{
+ char tmp[1024];
+ AConfig* root;
+ AConfig* n;
+ int win_x, win_y, flags;
+
+ signal(SIGINT, SIG_DFL);
+#ifndef _WIN32
+ signal(SIGQUIT, SIG_DFL);
+#endif
+
+ /* we're not a game, so allow the screensaver to run */
+ putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1");
+
+ flags = SDL_INIT_NOPARACHUTE;
+ if (!opts->no_window)
+ flags |= SDL_INIT_VIDEO;
+
+ if(SDL_Init(flags)){
+ fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
+ exit(1);
+ }
+
+ if (!opts->no_window) {
+ SDL_EnableUNICODE(!opts->raw_keys);
+ SDL_EnableKeyRepeat(0,0);
+
+ sdl_set_window_icon();
+ }
+ else
+ {
+#ifndef _WIN32
+ /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
+ * able to run the emulator in the background (e.g. "emulator &").
+ * despite the fact that the emulator should not grab input or try to
+ * write to the output in normal cases, we're stopped on some systems
+ * (e.g. OS X)
+ */
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+#endif
+ }
+ atexit(sdl_at_exit);
+
+ root = aconfig_node("", "");
+
+ if(name) {
+ /* Support skin aliases like QVGA-H QVGA-P, etc...
+ But first we check if it's a directory that exist before applying
+ the alias */
+ int checkAlias = 1;
+
+ if (path != NULL) {
+ bufprint(tmp, tmp+sizeof(tmp), "%s/%s", path, name);
+ if (path_exists(tmp)) {
+ checkAlias = 0;
+ } else {
+ D("there is no '%s' skin in '%s'", name, path);
+ }
+ }
+
+ if (checkAlias) {
+ int nn;
+
+ for (nn = 0; ; nn++ ) {
+ const char* skin_name = skin_aliases[nn].name;
+ const char* skin_alias = skin_aliases[nn].alias;
+
+ if ( !skin_name )
+ break;
+
+ if ( !strcasecmp( skin_name, name ) ) {
+ D("skin name '%s' aliased to '%s'", name, skin_alias);
+ name = skin_alias;
+ break;
+ }
+ }
+ }
+
+ /* Magically support skins like "320x240" */
+ if(isdigit(name[0])) {
+ char *x = strchr(name, 'x');
+ if(x && isdigit(x[1])) {
+ int width = atoi(name);
+ int height = atoi(x + 1);
+ sprintf(tmp,"display {\n width %d\n height %d\n}\n",
+ width, height);
+ aconfig_load(root, strdup(tmp));
+ path = ":";
+ goto found_a_skin;
+ }
+ }
+
+ if (path == NULL) {
+ derror("unknown skin name '%s'", name);
+ exit(1);
+ }
+
+ sprintf(tmp, "%s/%s/layout", path, name);
+ D("trying to load skin file '%s'", tmp);
+
+ if(aconfig_load_file(root, tmp) >= 0) {
+ sprintf(tmp, "%s/%s/", path, name);
+ path = tmp;
+ goto found_a_skin;
+ } else {
+ dwarning("could not load skin file '%s', using built-in one\n",
+ tmp);
+ }
+ }
+
+ {
+ const unsigned char* layout_base;
+ size_t layout_size;
+
+ name = "<builtin>";
+
+ layout_base = android_resource_find( "layout", &layout_size );
+ if (layout_base != NULL) {
+ char* base = malloc( layout_size+1 );
+ memcpy( base, layout_base, layout_size );
+ base[layout_size] = 0;
+
+ D("parsing built-in skin layout file (size=%d)", (int)layout_size);
+ aconfig_load(root, base);
+ path = ":";
+ } else {
+ fprintf(stderr, "Couldn't load builtin skin\n");
+ exit(1);
+ }
+ }
+
+found_a_skin:
+ {
+ win_x = 10;
+ win_y = 10;
+
+ if (userConfig)
+ auserConfig_getWindowPos(userConfig, &win_x, &win_y);
+ }
+ if ( qemulator_init( qemulator, root, path, win_x, win_y, opts ) < 0 ) {
+ fprintf(stderr, "### Error: could not load emulator skin '%s'\n", name);
+ exit(1);
+ }
+
+ android_skin_keycharmap = skin_keyboard_charmap_name(qemulator->keyboard);
+
+ /* the default network speed and latency can now be specified by the device skin */
+ n = aconfig_find(root, "network");
+ if (n != NULL) {
+ skin_network_speed = aconfig_str(n, "speed", 0);
+ skin_network_delay = aconfig_str(n, "delay", 0);
+ }
+
+#if 0
+ /* create a trackball if needed */
+ n = aconfig_find(root, "trackball");
+ if (n != NULL) {
+ SkinTrackBallParameters params;
+
+ params.x = aconfig_unsigned(n, "x", 0);
+ params.y = aconfig_unsigned(n, "y", 0);
+ params.diameter = aconfig_unsigned(n, "diameter", 20);
+ params.ring = aconfig_unsigned(n, "ring", 1);
+
+ params.ball_color = aconfig_unsigned(n, "ball-color", 0xffe0e0e0);
+ params.dot_color = aconfig_unsigned(n, "dot-color", 0xff202020 );
+ params.ring_color = aconfig_unsigned(n, "ring-color", 0xff000000 );
+
+ qemu_disp->trackball = skin_trackball_create( &params );
+ skin_trackball_refresh( qemu_disp->trackball );
+ }
+#endif
+
+ /* add an onion overlay image if needed */
+ if (opts->onion) {
+ SkinImage* onion = skin_image_find_simple( opts->onion );
+ int alpha, rotate;
+
+ if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
+ alpha = (256*alpha)/100;
+ } else
+ alpha = 128;
+
+ if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
+ rotate &= 3;
+ } else
+ rotate = SKIN_ROTATION_0;
+
+ qemulator->onion = onion;
+ qemulator->onion_alpha = alpha;
+ qemulator->onion_rotation = rotate;
+ }
+}
+
+int qemu_main(int argc, char **argv);
+
+/* this function dumps the QEMU help */
+extern void help( void );
+extern void emulator_help( void );
+
+#define VERBOSE_OPT(str,var) { str, &var }
+
+#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
+static const struct { const char* name; int flag; const char* text; }
+verbose_options[] = {
+ VERBOSE_TAG_LIST
+ { 0, 0, 0 }
+};
+
+int
+android_parse_network_speed(const char* speed)
+{
+ int n;
+ char* end;
+ double sp;
+
+ if (speed == NULL || speed[0] == 0) {
+ speed = DEFAULT_NETSPEED;
+ }
+
+ for (n = 0; android_netspeeds[n].name != NULL; n++) {
+ if (!strcmp(android_netspeeds[n].name, speed)) {
+ qemu_net_download_speed = android_netspeeds[n].download;
+ qemu_net_upload_speed = android_netspeeds[n].upload;
+ return 0;
+ }
+ }
+
+ /* is this a number ? */
+ sp = strtod(speed, &end);
+ if (end == speed) {
+ return -1;
+ }
+
+ qemu_net_download_speed = qemu_net_upload_speed = sp*1000.;
+ if (*end == ':') {
+ speed = end+1;
+ sp = strtod(speed, &end);
+ if (end > speed) {
+ qemu_net_download_speed = sp*1000.;
+ }
+ }
+
+ if (android_modem)
+ amodem_set_data_network_type( android_modem,
+ android_parse_network_type(speed) );
+ return 0;
+}
+
+
+int
+android_parse_network_latency(const char* delay)
+{
+ int n;
+ char* end;
+ double sp;
+
+ if (delay == NULL || delay[0] == 0)
+ delay = DEFAULT_NETDELAY;
+
+ for (n = 0; android_netdelays[n].name != NULL; n++) {
+ if ( !strcmp( android_netdelays[n].name, delay ) ) {
+ qemu_net_min_latency = android_netdelays[n].min_ms;
+ qemu_net_max_latency = android_netdelays[n].max_ms;
+ return 0;
+ }
+ }
+
+ /* is this a number ? */
+ sp = strtod(delay, &end);
+ if (end == delay) {
+ return -1;
+ }
+
+ qemu_net_min_latency = qemu_net_max_latency = (int)sp;
+ if (*end == ':') {
+ delay = (const char*)end+1;
+ sp = strtod(delay, &end);
+ if (end > delay) {
+ qemu_net_max_latency = (int)sp;
+ }
+ }
+ return 0;
+}
+
+
+static int
+load_keyset(const char* path)
+{
+ if (path_can_read(path)) {
+ AConfig* root = aconfig_node("","");
+ if (!aconfig_load_file(root, path)) {
+ android_keyset = skin_keyset_new(root);
+ if (android_keyset != NULL) {
+ D( "keyset loaded from: %s", path);
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+static void
+parse_keyset(const char* keyset, AndroidOptions* opts)
+{
+ char kname[MAX_PATH];
+ char temp[MAX_PATH];
+ char* p;
+ char* end;
+
+ /* append .keyset suffix if needed */
+ if (strchr(keyset, '.') == NULL) {
+ p = kname;
+ end = p + sizeof(kname);
+ p = bufprint(p, end, "%s.keyset", keyset);
+ if (p >= end) {
+ derror( "keyset name too long: '%s'\n", keyset);
+ exit(1);
+ }
+ keyset = kname;
+ }
+
+ /* look for a the keyset file */
+ p = temp;
+ end = p + sizeof(temp);
+ p = bufprint_config_file(p, end, keyset);
+ if (p < end && load_keyset(temp) == 0)
+ return;
+
+ p = temp;
+ p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset);
+ if (p < end && load_keyset(temp) == 0)
+ return;
+
+ p = temp;
+ p = bufprint_app_dir(p, end);
+ p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset);
+ if (p < end && load_keyset(temp) == 0)
+ return;
+
+ return;
+}
+
+static void
+write_default_keyset( void )
+{
+ char path[MAX_PATH];
+
+ bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
+
+ /* only write if there is no file here */
+ if ( !path_exists(path) ) {
+ int fd = open( path, O_WRONLY | O_CREAT, 0666 );
+ int ret;
+ const char* ks = skin_keyset_get_default();
+
+
+ D( "writing default keyset file to %s", path );
+
+ if (fd < 0) {
+ D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
+ return;
+ }
+ CHECKED(ret, write(fd, ks, strlen(ks)));
+ close(fd);
+ }
+}
+
+#ifdef CONFIG_NAND_LIMITS
+
+static uint64_t
+parse_nand_rw_limit( const char* value )
+{
+ char* end;
+ uint64_t val = strtoul( value, &end, 0 );
+
+ if (end == value) {
+ derror( "bad parameter value '%s': expecting unsigned integer", value );
+ exit(1);
+ }
+
+ switch (end[0]) {
+ case 'K': val <<= 10; break;
+ case 'M': val <<= 20; break;
+ case 'G': val <<= 30; break;
+ case 0: break;
+ default:
+ derror( "bad read/write limit suffix: use K, M or G" );
+ exit(1);
+ }
+ return val;
+}
+
+static void
+parse_nand_limits(char* limits)
+{
+ int pid = -1, signal = -1;
+ int64_t reads = 0, writes = 0;
+ char* item = limits;
+
+ /* parse over comma-separated items */
+ while (item && *item) {
+ char* next = strchr(item, ',');
+ char* end;
+
+ if (next == NULL) {
+ next = item + strlen(item);
+ } else {
+ *next++ = 0;
+ }
+
+ if ( !memcmp(item, "pid=", 4) ) {
+ pid = strtol(item+4, &end, 10);
+ if (end == NULL || *end) {
+ derror( "bad parameter, expecting pid=<number>, got '%s'",
+ item );
+ exit(1);
+ }
+ if (pid <= 0) {
+ derror( "bad parameter: process identifier must be > 0" );
+ exit(1);
+ }
+ }
+ else if ( !memcmp(item, "signal=", 7) ) {
+ signal = strtol(item+7,&end, 10);
+ if (end == NULL || *end) {
+ derror( "bad parameter: expecting signal=<number>, got '%s'",
+ item );
+ exit(1);
+ }
+ if (signal <= 0) {
+ derror( "bad parameter: signal number must be > 0" );
+ exit(1);
+ }
+ }
+ else if ( !memcmp(item, "reads=", 6) ) {
+ reads = parse_nand_rw_limit(item+6);
+ }
+ else if ( !memcmp(item, "writes=", 7) ) {
+ writes = parse_nand_rw_limit(item+7);
+ }
+ else {
+ derror( "bad parameter '%s' (see -help-nand-limits)", item );
+ exit(1);
+ }
+ item = next;
+ }
+ if (pid < 0) {
+ derror( "bad paramater: missing pid=<number>" );
+ exit(1);
+ }
+ else if (signal < 0) {
+ derror( "bad parameter: missing signal=<number>" );
+ exit(1);
+ }
+ else if (reads == 0 && writes == 0) {
+ dwarning( "no read or write limit specified. ignoring -nand-limits" );
+ } else {
+ nand_threshold* t;
+
+ t = &android_nand_read_threshold;
+ t->pid = pid;
+ t->signal = signal;
+ t->counter = 0;
+ t->limit = reads;
+
+ t = &android_nand_write_threshold;
+ t->pid = pid;
+ t->signal = signal;
+ t->counter = 0;
+ t->limit = writes;
+ }
+}
+#endif /* CONFIG_NAND_LIMITS */
+
+void emulator_help( void )
+{
+ STRALLOC_DEFINE(out);
+ android_help_main(out);
+ printf( "%.*s", out->n, out->s );
+ stralloc_reset(out);
+ exit(1);
+}
+
+static int
+add_dns_server( const char* server_name )
+{
+ SockAddress addr;
+
+ if (sock_address_init_resolve( &addr, server_name, 55, 0 ) < 0) {
+ fprintf(stderr,
+ "### WARNING: can't resolve DNS server name '%s'\n",
+ server_name );
+ return -1;
+ }
+
+ D( "DNS server name '%s' resolved to %s", server_name, sock_address_to_string(&addr) );
+
+ if ( slirp_add_dns_server( &addr ) < 0 ) {
+ fprintf(stderr,
+ "### WARNING: could not add DNS server '%s' to the network stack\n", server_name);
+ return -1;
+ }
+ return 0;
+}
+
+
+enum {
+ REPORT_CONSOLE_SERVER = (1 << 0),
+ REPORT_CONSOLE_MAX = (1 << 1)
+};
+
+static int
+get_report_console_options( char* end, int *maxtries )
+{
+ int flags = 0;
+
+ if (end == NULL || *end == 0)
+ return 0;
+
+ if (end[0] != ',') {
+ derror( "socket port/path can be followed by [,<option>]+ only\n");
+ exit(3);
+ }
+ end += 1;
+ while (*end) {
+ char* p = strchr(end, ',');
+ if (p == NULL)
+ p = end + strlen(end);
+
+ if (memcmp( end, "server", p-end ) == 0)
+ flags |= REPORT_CONSOLE_SERVER;
+ else if (memcmp( end, "max=", 4) == 0) {
+ end += 4;
+ *maxtries = strtol( end, NULL, 10 );
+ flags |= REPORT_CONSOLE_MAX;
+ } else {
+ derror( "socket port/path can be followed by [,server][,max=<count>] only\n");
+ exit(3);
+ }
+
+ end = p;
+ if (*end)
+ end += 1;
+ }
+ return flags;
+}
+
+static void
+report_console( const char* proto_port, int console_port )
+{
+ int s = -1, s2;
+ int maxtries = 10;
+ int flags = 0;
+ signal_state_t sigstate;
+
+ disable_sigalrm( &sigstate );
+
+ if ( !strncmp( proto_port, "tcp:", 4) ) {
+ char* end;
+ long port = strtol(proto_port + 4, &end, 10);
+
+ flags = get_report_console_options( end, &maxtries );
+
+ if (flags & REPORT_CONSOLE_SERVER) {
+ s = socket_loopback_server( port, SOCKET_STREAM );
+ if (s < 0) {
+ fprintf(stderr, "could not create server socket on TCP:%ld: %s\n",
+ port, errno_str);
+ exit(3);
+ }
+ } else {
+ for ( ; maxtries > 0; maxtries-- ) {
+ D("trying to find console-report client on tcp:%d", port);
+ s = socket_loopback_client( port, SOCKET_STREAM );
+ if (s >= 0)
+ break;
+
+ sleep_ms(1000);
+ }
+ if (s < 0) {
+ fprintf(stderr, "could not connect to server on TCP:%ld: %s\n",
+ port, errno_str);
+ exit(3);
+ }
+ }
+ } else if ( !strncmp( proto_port, "unix:", 5) ) {
+#ifdef _WIN32
+ fprintf(stderr, "sorry, the unix: protocol is not supported on Win32\n");
+ exit(3);
+#else
+ char* path = strdup(proto_port+5);
+ char* end = strchr(path, ',');
+ if (end != NULL) {
+ flags = get_report_console_options( end, &maxtries );
+ *end = 0;
+ }
+ if (flags & REPORT_CONSOLE_SERVER) {
+ s = socket_unix_server( path, SOCKET_STREAM );
+ if (s < 0) {
+ fprintf(stderr, "could not bind unix socket on '%s': %s\n",
+ proto_port+5, errno_str);
+ exit(3);
+ }
+ } else {
+ for ( ; maxtries > 0; maxtries-- ) {
+ s = socket_unix_client( path, SOCKET_STREAM );
+ if (s >= 0)
+ break;
+
+ sleep_ms(1000);
+ }
+ if (s < 0) {
+ fprintf(stderr, "could not connect to unix socket on '%s': %s\n",
+ path, errno_str);
+ exit(3);
+ }
+ }
+ free(path);
+#endif
+ } else {
+ fprintf(stderr, "-report-console must be followed by a 'tcp:<port>' or 'unix:<path>'\n");
+ exit(3);
+ }
+
+ if (flags & REPORT_CONSOLE_SERVER) {
+ int tries = 3;
+ D( "waiting for console-reporting client" );
+ do {
+ s2 = socket_accept(s, NULL);
+ } while (s2 < 0 && --tries > 0);
+
+ if (s2 < 0) {
+ fprintf(stderr, "could not accept console-reporting client connection: %s\n",
+ errno_str);
+ exit(3);
+ }
+
+ socket_close(s);
+ s = s2;
+ }
+
+ /* simply send the console port in text */
+ {
+ char temp[12];
+ snprintf( temp, sizeof(temp), "%d", console_port );
+
+ if (socket_send(s, temp, strlen(temp)) < 0) {
+ fprintf(stderr, "could not send console number report: %d: %s\n",
+ errno, errno_str );
+ exit(3);
+ }
+ socket_close(s);
+ }
+ D( "console port number sent to remote. resuming boot" );
+
+ restore_sigalrm (&sigstate);
+}
+
+/* this function is used to perform auto-detection of the
+ * system directory in the case of a SDK installation.
+ *
+ * we want to deal with several historical usages, hence
+ * the slightly complicated logic.
+ *
+ * NOTE: the function returns the path to the directory
+ * containing 'fileName'. this is *not* the full
+ * path to 'fileName'.
+ */
+static char*
+_getSdkImagePath( const char* fileName )
+{
+ char temp[MAX_PATH];
+ char* p = temp;
+ char* end = p + sizeof(temp);
+ char* q;
+ char* app;
+
+ static const char* const searchPaths[] = {
+ "", /* program's directory */
+ "/lib/images", /* this is for SDK 1.0 */
+ "/../platforms/android-1.1/images", /* this is for SDK 1.1 */
+ NULL
+ };
+
+ app = bufprint_app_dir(temp, end);
+ if (app >= end)
+ return NULL;
+
+ do {
+ int nn;
+
+ /* first search a few well-known paths */
+ for (nn = 0; searchPaths[nn] != NULL; nn++) {
+ p = bufprint(app, end, "%s", searchPaths[nn]);
+ q = bufprint(p, end, "/%s", fileName);
+ if (q < end && path_exists(temp)) {
+ *p = 0;
+ goto FOUND_IT;
+ }
+ }
+
+ /* hmmm. let's assume that we are in a post-1.1 SDK
+ * scan ../platforms if it exists
+ */
+ p = bufprint(app, end, "/../platforms");
+ if (p < end) {
+ DirScanner* scanner = dirScanner_new(temp);
+ if (scanner != NULL) {
+ int found = 0;
+ const char* subdir;
+
+ for (;;) {
+ subdir = dirScanner_next(scanner);
+ if (!subdir) break;
+
+ q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
+ if (q >= end || !path_exists(temp))
+ continue;
+
+ found = 1;
+ p = bufprint(p, end, "/%s/images", subdir);
+ break;
+ }
+ dirScanner_free(scanner);
+ if (found)
+ break;
+ }
+ }
+
+ /* I'm out of ideas */
+ return NULL;
+
+ } while (0);
+
+FOUND_IT:
+ //D("image auto-detection: %s/%s", temp, fileName);
+ return qemu_strdup(temp);
+}
+
+static char*
+_getSdkImage( const char* path, const char* file )
+{
+ char temp[MAX_PATH];
+ char *p = temp, *end = p + sizeof(temp);
+
+ p = bufprint(temp, end, "%s/%s", path, file);
+ if (p >= end || !path_exists(temp))
+ return NULL;
+
+ return qemu_strdup(temp);
+}
+
+static char*
+_getSdkSystemImage( const char* path, const char* optionName, const char* file )
+{
+ char* image = _getSdkImage(path, file);
+
+ if (image == NULL) {
+ derror("Your system directory is missing the '%s' image file.\n"
+ "Please specify one with the '%s <filepath>' option",
+ file, optionName);
+ exit(2);
+ }
+ return image;
+}
+
+static void
+_forceAvdImagePath( AvdImageType imageType,
+ const char* path,
+ const char* description,
+ int required )
+{
+ if (path == NULL)
+ return;
+
+ if (required && !path_exists(path)) {
+ derror("Cannot find %s image file: %s", description, path);
+ exit(1);
+ }
+ android_avdParams->forcePaths[imageType] = path;
+}
+
+#ifdef _WIN32
+#undef main /* we don't want SDL to define main */
+#endif
+
+int main(int argc, char **argv)
+{
+ char tmp[MAX_PATH];
+ char* tmpend = tmp + sizeof(tmp);
+ char* args[128];
+ int n;
+ char* opt;
+ int use_sdcard_img = 0;
+ int serial = 0;
+ int gps_serial = 0;
+ int radio_serial = 0;
+ int qemud_serial = 0;
+ int shell_serial = 0;
+ int dns_count = 0;
+ unsigned cachePartitionSize = 0;
+
+ AndroidHwConfig* hw;
+
+ //const char *appdir = get_app_dir();
+ char* android_build_root = NULL;
+ char* android_build_out = NULL;
+
+ AndroidOptions opts[1];
+
+ args[0] = argv[0];
+
+ if ( android_parse_options( &argc, &argv, opts ) < 0 ) {
+ exit(1);
+ }
+
+ while (argc-- > 1) {
+ opt = (++argv)[0];
+
+ if(!strcmp(opt, "-qemu")) {
+ argc--;
+ argv++;
+ break;
+ }
+
+ if (!strcmp(opt, "-help")) {
+ emulator_help();
+ }
+
+ if (!strncmp(opt, "-help-",6)) {
+ STRALLOC_DEFINE(out);
+ opt += 6;
+
+ if (!strcmp(opt, "all")) {
+ android_help_all(out);
+ }
+ else if (android_help_for_option(opt, out) == 0) {
+ /* ok */
+ }
+ else if (android_help_for_topic(opt, out) == 0) {
+ /* ok */
+ }
+ if (out->n > 0) {
+ printf("\n%.*s", out->n, out->s);
+ exit(0);
+ }
+
+ fprintf(stderr, "unknown option: -help-%s\n", opt);
+ fprintf(stderr, "please use -help for a list of valid topics\n");
+ exit(1);
+ }
+
+ if (opt[0] == '-') {
+ fprintf(stderr, "unknown option: %s\n", opt);
+ fprintf(stderr, "please use -help for a list of valid options\n");
+ exit(1);
+ }
+
+ fprintf(stderr, "invalid command-line parameter: %s.\n", opt);
+ fprintf(stderr, "Hint: use '@foo' to launch a virtual device named 'foo'.\n");
+ fprintf(stderr, "please use -help for more information\n");
+ exit(1);
+ }
+
+ /* special case, if -qemu -h is used, directly invoke the QEMU-specific help */
+ if (argc > 0) {
+ int nn;
+ for (nn = 0; nn < argc; nn++)
+ if (!strcmp(argv[nn], "-h")) {
+ qemu_help(0);
+ break;
+ }
+ }
+
+ android_charmap = android_charmaps[0];
+
+ if (opts->version) {
+ printf("Android emulator version %s\n"
+ "Copyright (C) 2006-2008 The Android Open Source Project and many others.\n"
+ "This program is a derivative of the QEMU CPU emulator (www.qemu.org).\n\n",
+#if defined ANDROID_BUILD_ID
+ VERSION_STRING " (build_id " STRINGIFY(ANDROID_BUILD_ID) ")" );
+#else
+ VERSION_STRING);
+#endif
+ printf(" This software is licensed under the terms of the GNU General Public\n"
+ " License version 2, as published by the Free Software Foundation, and\n"
+ " may be copied, distributed, and modified under those terms.\n\n"
+ " This program is distributed in the hope that it will be useful,\n"
+ " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ " GNU General Public License for more details.\n\n");
+
+ exit(0);
+ }
+
+ if (opts->timezone) {
+ if ( timezone_set(opts->timezone) < 0 ) {
+ fprintf(stderr, "emulator: it seems the timezone '%s' is not in zoneinfo format\n", opts->timezone);
+ }
+ }
+
+ /* legacy support: we used to use -system <dir> and -image <file>
+ * instead of -sysdir <dir> and -system <file>, so handle this by checking
+ * whether the options point to directories or files.
+ */
+ if (opts->image != NULL) {
+ if (opts->system != NULL) {
+ if (opts->sysdir != NULL) {
+ derror( "You can't use -sysdir, -system and -image at the same time.\n"
+ "You should probably use '-sysdir <path> -system <file>'.\n" );
+ exit(2);
+ }
+ }
+ dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
+ "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
+ opts->sysdir = opts->system;
+ opts->system = opts->image;
+ opts->image = NULL;
+ }
+ else if (opts->system != NULL && path_is_dir(opts->system)) {
+ if (opts->sysdir != NULL) {
+ derror( "Option -system should now be followed by a file path, not a directory one.\n"
+ "Please use '-sysdir <path>' to point to the system directory.\n" );
+ exit(1);
+ }
+ dwarning( "Please note that the -system option should now be used to point to the initial\n"
+ "system image (like the obsolete -image option). To point to the system directory\n"
+ "please now use '-sysdir <path>' instead.\n" );
+
+ opts->sysdir = opts->system;
+ opts->system = NULL;
+ }
+
+ if (opts->nojni)
+ opts->no_jni = opts->nojni;
+
+ if (opts->nocache)
+ opts->no_cache = opts->nocache;
+
+ if (opts->noaudio)
+ opts->no_audio = opts->noaudio;
+
+ if (opts->noskin)
+ opts->no_skin = opts->noskin;
+
+ if (opts->initdata) {
+ opts->init_data = opts->initdata;
+ opts->initdata = NULL;
+ }
+
+ /* If no AVD name was given, try to find the top of the
+ * Android build tree
+ */
+ if (opts->avd == NULL) {
+ do {
+ char* out = getenv("ANDROID_PRODUCT_OUT");
+
+ if (out == NULL || out[0] == 0)
+ break;
+
+ if (!path_exists(out)) {
+ derror("Can't access ANDROID_PRODUCT_OUT as '%s\n"
+ "You need to build the Android system before launching the emulator",
+ out);
+ exit(2);
+ }
+
+ android_build_root = path_parent( out, 4 );
+ if (android_build_root == NULL || !path_exists(android_build_root)) {
+ derror("Can't find the Android build root from '%s'\n"
+ "Please check the definition of the ANDROID_PRODUCT_OUT variable.\n"
+ "It should point to your product-specific build output directory.\n",
+ out );
+ exit(2);
+ }
+ android_build_out = out;
+ D( "found Android build root: %s", android_build_root );
+ D( "found Android build out: %s", android_build_out );
+ } while (0);
+ }
+ /* if no virtual device name is given, and we're not in the
+ * Android build system, we'll need to perform some auto-detection
+ * magic :-)
+ */
+ if (opts->avd == NULL && !android_build_out)
+ {
+ char dataDirIsSystem = 0;
+
+ if (!opts->sysdir) {
+ opts->sysdir = _getSdkImagePath("system.img");
+ if (!opts->sysdir) {
+ derror(
+ "You did not specify a virtual device name, and the system\n"
+ "directory could not be found.\n\n"
+ "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
+ "to start a given virtual device (see -help-avd for details).\n\n"
+
+ "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
+ );
+ exit(2);
+ }
+ D("autoconfig: -sysdir %s", opts->sysdir);
+ }
+
+ if (!opts->system) {
+ opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
+ D("autoconfig: -image %s", opts->image);
+ }
+
+ if (!opts->kernel) {
+ opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
+ D("autoconfig: -kernel %s", opts->kernel);
+ }
+
+ if (!opts->ramdisk) {
+ opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
+ D("autoconfig: -ramdisk %s", opts->ramdisk);
+ }
+
+ /* if no data directory is specified, use the system directory */
+ if (!opts->datadir) {
+ opts->datadir = qemu_strdup(opts->sysdir);
+ dataDirIsSystem = 1;
+ D("autoconfig: -datadir %s", opts->sysdir);
+ }
+
+ if (!opts->data) {
+ /* check for userdata-qemu.img in the data directory */
+ bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
+ if (!path_exists(tmp)) {
+ derror(
+ "You did not provide the name of an Android Virtual Device\n"
+ "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
+
+ "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
+ "to specify a data partition image file (I hope you know what you're doing).\n"
+ );
+ exit(2);
+ }
+
+ opts->data = qemu_strdup(tmp);
+ D("autoconfig: -data %s", opts->data);
+ }
+
+ if (!opts->sdcard && opts->datadir) {
+ bufprint(tmp, tmpend, "%s/sdcard.img", opts->datadir);
+ if (path_exists(tmp)) {
+ opts->sdcard = qemu_strdup(tmp);
+ D("autoconfig: -sdcard %s", opts->sdcard);
+ }
+ }
+ }
+
+ /* setup the virtual device parameters from our options
+ */
+ if (opts->no_cache) {
+ android_avdParams->flags |= AVDINFO_NO_CACHE;
+ }
+ if (opts->wipe_data) {
+ android_avdParams->flags |= AVDINFO_WIPE_DATA | AVDINFO_WIPE_CACHE;
+ }
+
+ /* if certain options are set, we can force the path of
+ * certain kernel/disk image files
+ */
+ _forceAvdImagePath(AVD_IMAGE_KERNEL, opts->kernel, "kernel", 1);
+ _forceAvdImagePath(AVD_IMAGE_INITSYSTEM, opts->system, "system", 1);
+ _forceAvdImagePath(AVD_IMAGE_RAMDISK, opts->ramdisk,"ramdisk", 1);
+ _forceAvdImagePath(AVD_IMAGE_USERDATA, opts->data, "user data", 0);
+ _forceAvdImagePath(AVD_IMAGE_CACHE, opts->cache, "cache", 0);
+ _forceAvdImagePath(AVD_IMAGE_SDCARD, opts->sdcard, "SD Card", 0);
+
+ /* we don't accept -skindir without -skin now
+ * to simplify the autoconfig stuff with virtual devices
+ */
+ if (opts->no_skin) {
+ opts->skin = "320x480";
+ opts->skindir = NULL;
+ }
+
+ if (opts->skindir) {
+ if (!opts->skin) {
+ derror( "the -skindir <path> option requires a -skin <name> option");
+ exit(1);
+ }
+ }
+ else {
+ if (!opts->skin && android_build_out) {
+ /* select default skin based on product type */
+ const char* p = strrchr(android_build_out,'/');
+ if (p) {
+ if (p[1] == 's') {
+ opts->skin = "HVGA"; /* used to be QVGA-L */
+ } else if (p[1] == 'd') {
+ opts->skin = "HVGA";
+ }
+ }
+ D("autoconfig: -skin %s", opts->skin);
+ }
+ android_avdParams->skinName = opts->skin;
+ }
+ /* setup the virtual device differently depending on whether
+ * we are in the Android build system or not
+ */
+ if (opts->avd != NULL)
+ {
+ android_avdInfo = avdInfo_new( opts->avd, android_avdParams );
+ if (android_avdInfo == NULL) {
+ /* an error message has already been printed */
+ dprint("could not find virtual device named '%s'", opts->avd);
+ exit(1);
+ }
+ }
+ else
+ {
+ if (!android_build_out) {
+ android_build_out = android_build_root = opts->sysdir;
+ }
+ android_avdInfo = avdInfo_newForAndroidBuild(
+ android_build_root,
+ android_build_out,
+ android_avdParams );
+
+ if(android_avdInfo == NULL) {
+ D("could not start virtual device\n");
+ exit(1);
+ }
+ }
+
+ /* get the skin from the virtual device configuration */
+ opts->skin = (char*) avdInfo_getSkinName( android_avdInfo );
+ opts->skindir = (char*) avdInfo_getSkinDir( android_avdInfo );
+
+ if (opts->skin) {
+ D("autoconfig: -skin %s", opts->skin);
+ }
+ if (opts->skindir) {
+ D("autoconfig: -skindir %s", opts->skindir);
+ }
+
+ /* Read hardware configuration */
+ hw = android_hw;
+ if (avdInfo_getHwConfig(android_avdInfo, hw) < 0) {
+ derror("could not read hardware configuration ?");
+ exit(1);
+ }
+
+#ifdef CONFIG_NAND_LIMITS
+ if (opts->nand_limits)
+ parse_nand_limits(opts->nand_limits);
+#endif
+
+ if (opts->keyset) {
+ parse_keyset(opts->keyset, opts);
+ if (!android_keyset) {
+ fprintf(stderr,
+ "emulator: WARNING: could not find keyset file named '%s',"
+ " using defaults instead\n",
+ opts->keyset);
+ }
+ }
+ if (!android_keyset) {
+ parse_keyset("default", opts);
+ if (!android_keyset) {
+ android_keyset = skin_keyset_new_from_text( skin_keyset_get_default() );
+ if (!android_keyset) {
+ fprintf(stderr, "PANIC: default keyset file is corrupted !!\n" );
+ fprintf(stderr, "PANIC: please update the code in android/skin/keyset.c\n" );
+ exit(1);
+ }
+ if (!opts->keyset)
+ write_default_keyset();
+ }
+ }
+
+ if (opts->audio) {
+ if (opts->audio_in || opts->audio_out) {
+ derror( "you can't use -audio with -audio-in or -audio-out\n" );
+ exit(1);
+ }
+ if ( !audio_check_backend_name( 0, opts->audio ) ) {
+ derror( "'%s' is not a valid audio output backend. see -help-audio-out\n",
+ opts->audio);
+ exit(1);
+ }
+ opts->audio_out = opts->audio;
+ opts->audio_in = opts->audio;
+
+ if ( !audio_check_backend_name( 1, opts->audio ) ) {
+ fprintf(stderr,
+ "emulator: warning: '%s' is not a valid audio input backend. audio record disabled\n",
+ opts->audio);
+ opts->audio_in = "none";
+ }
+ }
+
+ if (opts->audio_in) {
+ static char env[64]; /* note: putenv needs a static unique string buffer */
+ if ( !audio_check_backend_name( 1, opts->audio_in ) ) {
+ derror( "'%s' is not a valid audio input backend. see -help-audio-in\n",
+ opts->audio_in);
+ exit(1);
+ }
+ bufprint( env, env+sizeof(env), "QEMU_AUDIO_IN_DRV=%s", opts->audio_in );
+ putenv( env );
+
+ if (!hw->hw_audioInput) {
+ dwarning( "Emulated hardware doesn't have audio input.");
+ }
+ }
+ if (opts->audio_out) {
+ static char env[64]; /* note: putenv needs a static unique string buffer */
+ if ( !audio_check_backend_name( 0, opts->audio_out ) ) {
+ derror( "'%s' is not a valid audio output backend. see -help-audio-out\n",
+ opts->audio_out);
+ exit(1);
+ }
+ bufprint( env, env+sizeof(env), "QEMU_AUDIO_OUT_DRV=%s", opts->audio_out );
+ putenv( env );
+ if (!hw->hw_audioOutput) {
+ dwarning( "Emulated hardware doesn't have audio output");
+ }
+ }
+
+ if (opts->cpu_delay) {
+ char* end;
+ long delay = strtol(opts->cpu_delay, &end, 0);
+ if (end == NULL || *end || delay < 0 || delay > 1000 ) {
+ fprintf(stderr, "option -cpu-delay must be an integer between 0 and 1000\n" );
+ exit(1);
+ }
+ if (delay > 0)
+ delay = (1000-delay);
+
+ qemu_cpu_delay = (int) delay;
+ }
+
+ emulator_config_init();
+ init_skinned_ui(opts->skindir, opts->skin, opts);
+
+ if (!opts->netspeed) {
+ if (skin_network_speed)
+ D("skin network speed: '%s'", skin_network_speed);
+ opts->netspeed = (char*)skin_network_speed;
+ }
+ if (!opts->netdelay) {
+ if (skin_network_delay)
+ D("skin network delay: '%s'", skin_network_delay);
+ opts->netdelay = (char*)skin_network_delay;
+ }
+
+ if ( android_parse_network_speed(opts->netspeed) < 0 ) {
+ fprintf(stderr, "invalid -netspeed parameter '%s', see emulator -usage\n", opts->netspeed);
+ emulator_help();
+ }
+
+ if ( android_parse_network_latency(opts->netdelay) < 0 ) {
+ fprintf(stderr, "invalid -netdelay parameter '%s', see emulator -usage\n", opts->netdelay);
+ emulator_help();
+ }
+
+ if (opts->netfast) {
+ qemu_net_download_speed = 0;
+ qemu_net_upload_speed = 0;
+ qemu_net_min_latency = 0;
+ qemu_net_max_latency = 0;
+ }
+
+ if (opts->trace) {
+ char* tracePath = avdInfo_getTracePath(android_avdInfo, opts->trace);
+ int ret;
+
+ if (tracePath == NULL) {
+ derror( "bad -trace parameter" );
+ exit(1);
+ }
+ ret = path_mkdir_if_needed( tracePath, 0755 );
+ if (ret < 0) {
+ fprintf(stderr, "could not create directory '%s'\n", tmp);
+ exit(2);
+ }
+ opts->trace = tracePath;
+ }
+
+ if (opts->tcpdump) {
+ if (qemu_tcpdump_start(opts->tcpdump) < 0) {
+ dwarning( "could not start packet capture: %s", strerror(errno));
+ }
+ }
+
+ if (opts->no_cache)
+ opts->cache = 0;
+
+ if (opts->dns_server) {
+ char* x = strchr(opts->dns_server, ',');
+ dns_count = 0;
+ if (x == NULL)
+ {
+ if ( add_dns_server( opts->dns_server ) == 0 )
+ dns_count = 1;
+ }
+ else
+ {
+ x = strdup(opts->dns_server);
+ while (*x) {
+ char* y = strchr(x, ',');
+
+ if (y != NULL)
+ *y = 0;
+
+ if (y == NULL || y > x) {
+ if ( add_dns_server( x ) == 0 )
+ dns_count += 1;
+ }
+
+ if (y == NULL)
+ break;
+
+ x = y+1;
+ }
+ }
+ if (dns_count == 0)
+ fprintf( stderr, "### WARNING: will use system default DNS server\n" );
+ }
+
+ if (dns_count == 0)
+ dns_count = slirp_get_system_dns_servers();
+
+ n = 1;
+ /* generate arguments for the underlying qemu main() */
+ args[n++] = "-kernel";
+ args[n++] = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_KERNEL);
+
+ args[n++] = "-initrd";
+ args[n++] = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_RAMDISK);
+
+ {
+ const char* filetype = "file";
+
+ if (avdInfo_isImageReadOnly(android_avdInfo, AVD_IMAGE_INITSYSTEM))
+ filetype = "initfile";
+
+ bufprint(tmp, tmpend,
+ "system,size=0x4200000,%s=%s", filetype,
+ avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_INITSYSTEM));
+
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+ }
+
+ bufprint(tmp, tmpend,
+ "userdata,size=0x4200000,file=%s",
+ avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_USERDATA));
+
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+
+ if (hw->disk_cachePartition) {
+ opts->cache = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_CACHE);
+ cachePartitionSize = hw->disk_cachePartition_size;
+ }
+ else if (opts->cache) {
+ dwarning( "Emulated hardware doesn't support a cache partition" );
+ opts->cache = NULL;
+ opts->no_cache = 1;
+ }
+
+ if (opts->cache) {
+ /* use a specific cache file */
+ sprintf(tmp, "cache,size=0x%0x,file=%s", cachePartitionSize, opts->cache);
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+ }
+ else if (!opts->no_cache) {
+ /* create a temporary cache partition file */
+ sprintf(tmp, "cache,size=0x%0x", cachePartitionSize);
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+ }
+
+ if (hw->hw_sdCard != 0)
+ opts->sdcard = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_SDCARD);
+ else if (opts->sdcard) {
+ dwarning( "Emulated hardware doesn't support SD Cards" );
+ opts->sdcard = NULL;
+ }
+
+ if(opts->sdcard) {
+ uint64_t size;
+ if (path_get_size(opts->sdcard, &size) == 0) {
+ /* see if we have an sdcard image. get its size if it exists */
+ if (size < 8*1024*1024ULL) {
+ fprintf(stderr, "### WARNING: SD Card files must be at least 8 MB, ignoring '%s'\n", opts->sdcard);
+ } else {
+ args[n++] = "-hda";
+ args[n++] = opts->sdcard;
+ use_sdcard_img = 1;
+ }
+ } else {
+ D("no SD Card image at '%s'", opts->sdcard);
+ }
+ }
+
+ if (!opts->logcat || opts->logcat[0] == 0) {
+ opts->logcat = getenv("ANDROID_LOG_TAGS");
+ if (opts->logcat && opts->logcat[0] == 0)
+ opts->logcat = NULL;
+ }
+
+#if 0
+ if (opts->console) {
+ derror( "option -console is obsolete. please use -shell instead" );
+ exit(1);
+ }
+#endif
+
+ /* we always send the kernel messages from ttyS0 to android_kmsg */
+ {
+ AndroidKmsgFlags flags = 0;
+
+ if (opts->show_kernel)
+ flags |= ANDROID_KMSG_PRINT_MESSAGES;
+
+ android_kmsg_init( flags );
+ args[n++] = "-serial";
+ args[n++] = "android-kmsg";
+ serial++;
+ }
+
+ /* XXXX: TODO: implement -shell and -logcat through qemud instead */
+ if (!opts->shell_serial) {
+#ifdef _WIN32
+ opts->shell_serial = "con:";
+#else
+ opts->shell_serial = "stdio";
+#endif
+ }
+ else
+ opts->shell = 1;
+
+ if (opts->shell || opts->logcat) {
+ args[n++] = "-serial";
+ args[n++] = opts->shell_serial;
+ shell_serial = serial++;
+ }
+
+ if (opts->old_system)
+ {
+ if (opts->radio) {
+ args[n++] = "-serial";
+ args[n++] = opts->radio;
+ radio_serial = serial++;
+ }
+ else {
+ args[n++] = "-serial";
+ args[n++] = "android-modem";
+ radio_serial = serial++;
+ }
+ if (opts->gps) {
+ args[n++] = "-serial";
+ args[n++] = opts->gps;
+ gps_serial = serial++;
+ }
+ }
+ else /* !opts->old_system */
+ {
+ args[n++] = "-serial";
+ args[n++] = "android-qemud";
+ qemud_serial = serial++;
+
+ if (opts->radio) {
+ CharDriverState* cs = qemu_chr_open(opts->radio);
+ if (cs == NULL) {
+ derror( "unsupported character device specification: %s\n"
+ "used -help-char-devices for list of available formats\n", opts->radio );
+ exit(1);
+ }
+ android_qemud_set_channel( ANDROID_QEMUD_GSM, cs);
+ }
+ else if ( hw->hw_gsmModem != 0 ) {
+ if ( android_qemud_get_channel( ANDROID_QEMUD_GSM, &android_modem_cs ) < 0 ) {
+ derror( "could not initialize qemud 'gsm' channel" );
+ exit(1);
+ }
+ }
+
+ if (opts->gps) {
+ CharDriverState* cs = qemu_chr_open(opts->gps);
+ if (cs == NULL) {
+ derror( "unsupported character device specification: %s\n"
+ "used -help-char-devices for list of available formats\n", opts->gps );
+ exit(1);
+ }
+ android_qemud_set_channel( ANDROID_QEMUD_GPS, cs);
+ }
+ else if ( hw->hw_gps != 0 ) {
+ if ( android_qemud_get_channel( "gps", &android_gps_cs ) < 0 ) {
+ derror( "could not initialize qemud 'gps' channel" );
+ exit(1);
+ }
+ }
+ }
+
+ if (opts->memory) {
+ char* end;
+ long ramSize = strtol(opts->memory, &end, 0);
+ if (ramSize < 0 || *end != 0) {
+ derror( "-memory must be followed by a positive integer" );
+ exit(1);
+ }
+ if (ramSize < 32 || ramSize > 4096) {
+ derror( "physical memory size must be between 32 and 4096 MB" );
+ exit(1);
+ }
+ }
+ if (!opts->memory) {
+ bufprint(tmp, tmpend, "%d", hw->hw_ramSize);
+ opts->memory = qemu_strdup(tmp);
+ }
+
+ if (opts->no_audio) {
+ args[n++] = "-noaudio";
+ }
+
+ if (opts->trace) {
+ args[n++] = "-trace";
+ args[n++] = opts->trace;
+ args[n++] = "-tracing";
+ args[n++] = "off";
+ }
+
+ args[n++] = "-append";
+
+ if (opts->bootchart) {
+ char* end;
+ int timeout = strtol(opts->bootchart, &end, 10);
+ if (timeout == 0)
+ opts->bootchart = NULL;
+ else if (timeout < 0 || timeout > 15*60) {
+ derror( "timeout specified for -bootchart option is invalid.\n"
+ "please use integers between 1 and 900\n");
+ exit(1);
+ }
+ }
+
+ {
+ static char params[1024];
+ char *p = params, *end = p + sizeof(params);
+
+ p = bufprint(p, end, "qemu=1 console=ttyS0" );
+
+ if (opts->shell || opts->logcat) {
+ p = bufprint(p, end, " androidboot.console=ttyS%d", shell_serial );
+ }
+
+ if (opts->trace) {
+ p = bufprint(p, end, " android.tracing=1");
+ }
+
+ if (!opts->no_jni) {
+ p = bufprint(p, end, " android.checkjni=1");
+ }
+
+ if (opts->no_boot_anim) {
+ p = bufprint( p, end, " android.bootanim=0" );
+ }
+
+ if (opts->logcat) {
+ char* q = bufprint(p, end, " androidboot.logcat=%s", opts->logcat);
+
+ if (q < end) {
+ /* replace any space by a comma ! */
+ {
+ int nn;
+ for (nn = 1; p[nn] != 0; nn++)
+ if (p[nn] == ' ' || p[nn] == '\t')
+ p[nn] = ',';
+ p += nn;
+ }
+ }
+ p = q;
+ }
+
+ if (opts->old_system)
+ {
+ p = bufprint(p, end, " android.ril=ttyS%d", radio_serial);
+
+ if (opts->gps) {
+ p = bufprint(p, end, " android.gps=ttyS%d", gps_serial);
+ }
+ }
+ else
+ {
+ p = bufprint(p, end, " android.qemud=ttyS%d", qemud_serial);
+ }
+
+ if (dns_count > 0) {
+ p = bufprint(p, end, " android.ndns=%d", dns_count);
+ }
+
+ if (opts->bootchart) {
+ p = bufprint(p, end, " androidboot.bootchart=%s", opts->bootchart);
+ }
+
+ if (p >= end) {
+ fprintf(stderr, "### ERROR: kernel parameters too long\n");
+ exit(1);
+ }
+
+ args[n++] = strdup(params);
+ }
+
+ /* physical memory */
+ args[n++] = "-m";
+ args[n++] = opts->memory;
+
+ /* on Linux, the 'dynticks' clock sometimes doesn't work
+ * properly. this results in the UI freezing while emulation
+ * continues, for several seconds...
+ */
+#ifdef __linux__
+ args[n++] = "-clock";
+ args[n++] = "unix";
+#endif
+
+ while(argc-- > 0) {
+ args[n++] = *argv++;
+ }
+ args[n] = 0;
+
+ if(VERBOSE_CHECK(init)) {
+ int i;
+ for(i = 0; i < n; i++) {
+ fprintf(stdout, "emulator: argv[%02d] = \"%s\"\n", i, args[i]);
+ }
+ }
+ return qemu_main(n, args);
+}
+
+/* this function is called from qemu_main() once all arguments have been parsed
+ * it should be used to setup any Android-specific items in the emulation before the
+ * main loop runs
+ */
+void android_emulation_setup( void )
+{
+ int tries = 16;
+ int base_port = 5554;
+ int success = 0;
+ int s;
+ uint32_t guest_ip;
+
+ AndroidOptions* opts = qemulator->opts;
+
+ inet_strtoip("10.0.2.15", &guest_ip);
+
+#if 0
+ if (opts->adb_port) {
+ fprintf( stderr, "option -adb-port is obsolete, use -port instead\n" );
+ exit(1);
+ }
+#endif
+
+ if (opts->port && opts->ports) {
+ fprintf( stderr, "options -port and -ports cannot be used together.\n");
+ exit(1);
+ }
+
+ if (opts->ports) {
+ char* comma_location;
+ char* end;
+ int console_port = strtol( opts->ports, &comma_location, 0 );
+
+ if ( comma_location == NULL || *comma_location != ',' ) {
+ derror( "option -ports must be followed by two comma separated positive integer numbers" );
+ exit(1);
+ }
+
+ int adb_port = strtol( comma_location+1, &end, 0 );
+
+ if ( end == NULL || *end ) {
+ derror( "option -ports must be followed by two comma separated positive integer numbers" );
+ exit(1);
+ }
+
+ if ( console_port == adb_port ) {
+ derror( "option -ports must be followed by two different integer numbers" );
+ exit(1);
+ }
+
+ slirp_redir( 0, adb_port, guest_ip, 5555 );
+ if ( control_console_start( console_port ) < 0 ) {
+ slirp_unredir( 0, adb_port );
+ }
+
+ base_port = console_port;
+ } else {
+ if (opts->port) {
+ char* end;
+ int port = strtol( opts->port, &end, 0 );
+ if ( end == NULL || *end ||
+ (unsigned)((port - base_port) >> 1) >= (unsigned)tries ) {
+ derror( "option -port must be followed by an even integer number between %d and %d\n",
+ base_port, base_port + (tries-1)*2 );
+ exit(1);
+ }
+ if ( (port & 1) != 0 ) {
+ port &= ~1;
+ dwarning( "option -port must be followed by an even integer, using port number %d\n",
+ port );
+ }
+ base_port = port;
+ tries = 1;
+ }
+
+ for ( ; tries > 0; tries--, base_port += 2 ) {
+
+ /* setup first redirection for ADB, the Android Debug Bridge */
+ if ( slirp_redir( 0, base_port+1, guest_ip, 5555 ) < 0 )
+ continue;
+
+ /* setup second redirection for the emulator console */
+ if ( control_console_start( base_port ) < 0 ) {
+ slirp_unredir( 0, base_port+1 );
+ continue;
+ }
+
+ D( "control console listening on port %d, ADB on port %d", base_port, base_port+1 );
+ success = 1;
+ break;
+ }
+
+ if (!success) {
+ fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
+ exit(1);
+ }
+ }
+
+ if (opts->report_console) {
+ report_console(opts->report_console, base_port);
+ }
+
+ android_modem_init( base_port );
+
+ android_base_port = base_port;
+ /* send a simple message to the ADB host server to tell it we just started.
+ * it should be listening on port 5037. if we can't reach it, don't bother
+ */
+ do
+ {
+ SockAddress addr;
+ char tmp[32];
+
+ s = socket_create_inet( SOCKET_STREAM );
+ if (s < 0) {
+ D("can't create socket to talk to the ADB server");
+ break;
+ }
+
+ sock_address_init_inet( &addr, SOCK_ADDRESS_INET_LOOPBACK, 5037 );
+ if (socket_connect( s, &addr ) < 0) {
+ D("can't connect to ADB server: %s", errno_str );
+ break;
+ }
+
+ sprintf(tmp,"0012host:emulator:%d",base_port+1);
+ socket_send(s, tmp, 18+4);
+ D("sent '%s' to ADB server", tmp);
+ }
+ while (0);
+
+ if (s >= 0)
+ socket_close(s);
+
+ /* setup the http proxy, if any */
+ if (VERBOSE_CHECK(proxy))
+ proxy_set_verbose(1);
+
+ if (!opts->http_proxy) {
+ opts->http_proxy = getenv("http_proxy");
+ }
+
+ do
+ {
+ const char* env = opts->http_proxy;
+ int envlen;
+ ProxyOption option_tab[4];
+ ProxyOption* option = option_tab;
+ char* p;
+ char* q;
+ const char* proxy_name;
+ int proxy_name_len;
+ int proxy_port;
+
+ if (!env)
+ break;
+
+ envlen = strlen(env);
+
+ /* skip the 'http://' header, if present */
+ if (envlen >= 7 && !memcmp(env, "http://", 7)) {
+ env += 7;
+ envlen -= 7;
+ }
+
+ /* do we have a username:password pair ? */
+ p = strchr(env, '@');
+ if (p != 0) {
+ q = strchr(env, ':');
+ if (q == NULL) {
+ BadHttpProxyFormat:
+ dprint("http_proxy format unsupported, try 'proxy:port' or 'username:password@proxy:port'");
+ break;
+ }
+
+ option->type = PROXY_OPTION_AUTH_USERNAME;
+ option->string = env;
+ option->string_len = q - env;
+ option++;
+
+ option->type = PROXY_OPTION_AUTH_PASSWORD;
+ option->string = q+1;
+ option->string_len = p - (q+1);
+ option++;
+
+ env = p+1;
+ }
+
+ p = strchr(env,':');
+ if (p == NULL)
+ goto BadHttpProxyFormat;
+
+ proxy_name = env;
+ proxy_name_len = p - env;
+ proxy_port = atoi(p+1);
+
+ D( "setting up http proxy: server=%.*s port=%d",
+ proxy_name_len, proxy_name, proxy_port );
+
+ if ( proxy_http_setup( proxy_name, proxy_name_len, proxy_port,
+ option - option_tab, option_tab ) < 0 )
+ {
+ dprint( "http proxy setup failed, check your $http_proxy variable");
+ }
+ }
+ while (0);
+
+ /* cool, now try to run the "ddms ping" command, which will take care of pinging usage
+ * if the user agreed for it. the emulator itself never sends anything to any outside
+ * machine
+ */
+ {
+#ifdef _WIN32
+# define _ANDROID_PING_PROGRAM "ddms.bat"
+#else
+# define _ANDROID_PING_PROGRAM "ddms"
+#endif
+
+ char tmp[PATH_MAX];
+ const char* appdir = get_app_dir();
+
+ if (snprintf( tmp, PATH_MAX, "%s%s%s", appdir, PATH_SEP,
+ _ANDROID_PING_PROGRAM ) >= PATH_MAX) {
+ dprint( "Application directory too long: %s", appdir);
+ return;
+ }
+
+ /* if the program isn't there, don't bother */
+ D( "ping program: %s", tmp);
+ if (path_exists(tmp)) {
+#ifdef _WIN32
+ STARTUPINFO startup;
+ PROCESS_INFORMATION pinfo;
+
+ ZeroMemory( &startup, sizeof(startup) );
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW;
+ startup.wShowWindow = SW_SHOWMINIMIZED;
+
+ ZeroMemory( &pinfo, sizeof(pinfo) );
+
+ char* comspec = getenv("COMSPEC");
+ if (!comspec) comspec = "cmd.exe";
+
+ // Run
+ char args[PATH_MAX + 30];
+ if (snprintf( args, PATH_MAX, "/C \"%s\" ping emulator " VERSION_STRING,
+ tmp) >= PATH_MAX ) {
+ D( "DDMS path too long: %s", tmp);
+ return;
+ }
+
+ CreateProcess(
+ comspec, /* program path */
+ args, /* command line args */
+ NULL, /* process handle is not inheritable */
+ NULL, /* thread handle is not inheritable */
+ FALSE, /* no, don't inherit any handles */
+ DETACHED_PROCESS, /* the new process doesn't have a console */
+ NULL, /* use parent's environment block */
+ NULL, /* use parent's starting directory */
+ &startup, /* startup info, i.e. std handles */
+ &pinfo );
+
+ D( "ping command: %s %s", comspec, args );
+#else
+ int pid = fork();
+ if (pid == 0) {
+ int fd = open("/dev/null", O_WRONLY);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ execl( tmp, _ANDROID_PING_PROGRAM, "ping", "emulator", VERSION_STRING, NULL );
+ }
+ /* don't do anything in the parent or in case of error */
+ strncat( tmp, " ping emulator " VERSION_STRING, PATH_MAX - strlen(tmp) );
+ D( "ping command: %s", tmp );
+#endif
+ }
+ }
+}
+
+
+void android_emulation_teardown( void )
+{
+}
diff --git a/android/qemud.c b/android/qemud.c
new file mode 100644
index 0000000..b127fc9
--- /dev/null
+++ b/android/qemud.c
@@ -0,0 +1,456 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/qemud.h"
+#include "android/utils/debug.h"
+#include "android/utils/misc.h"
+#include "qemu-char.h"
+#include "charpipe.h"
+#include "cbuffer.h"
+
+#define D(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
+#define D_ACTIVE VERBOSE_CHECK(qemud)
+
+/* the T(...) macro is used to dump traffic */
+#define T_ACTIVE 0
+
+#if T_ACTIVE
+#define T(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
+#else
+#define T(...) ((void)0)
+#endif
+
+#define MAX_PAYLOAD 4000
+#define MAX_CHANNELS 8
+
+#define CHANNEL_CONTROL_INDEX 0
+
+/** packets
+ **/
+#define HEADER_SIZE 6
+
+typedef struct Packet {
+ struct Packet* next;
+ int len;
+ uint8_t header[HEADER_SIZE];
+ uint8_t data[MAX_PAYLOAD];
+} Packet;
+
+static Packet* _free_packets;
+
+static void
+packet_free( Packet* p )
+{
+ p->next = _free_packets;
+ _free_packets = p;
+}
+
+static Packet*
+packet_alloc( void )
+{
+ Packet* p = _free_packets;
+ if (p != NULL) {
+ _free_packets = p->next;
+ } else {
+ p = malloc(sizeof(*p));
+ if (p == NULL) {
+ derror("%s: not enough memory", __FUNCTION__);
+ exit(1);
+ }
+ }
+ p->next = NULL;
+ p->len = 0;
+ return p;
+}
+
+/** channels
+ **/
+typedef void (*EnqueueFunc)( void* user, Packet* p );
+
+typedef struct {
+ const char* name;
+ int index;
+ CharDriverState* cs;
+ EnqueueFunc enq_func;
+ void* enq_user;
+} Channel;
+
+
+static int
+channel_can_read( void* opaque )
+{
+ Channel* c = opaque;
+
+ return c->index < 0 ? 0 : MAX_PAYLOAD;
+}
+
+
+/* here, the data comes from the emulated device (e.g. GSM modem) through
+ * a charpipe, we simply need to send it through the multiplexer */
+static void
+channel_read( void* opaque, const uint8_t* from, int len )
+{
+ Channel* c = opaque;
+
+ if (c->enq_func != NULL) {
+ Packet* p = packet_alloc();
+
+ if (len > MAX_PAYLOAD)
+ len = MAX_PAYLOAD;
+
+ memcpy( p->data, from, len );
+ p->len = len + HEADER_SIZE;
+ int2hex( p->header+0, 4, len );
+ int2hex( p->header+4, 2, c->index );
+
+ c->enq_func( c->enq_user, p );
+ }
+ else
+ {
+ D("%s: discarding %d bytes for channel '%s'",
+ __FUNCTION__, len, c->name);
+ }
+}
+
+static void
+channel_init( Channel* c, const char* name, CharDriverState* peer_cs )
+{
+ c->name = name;
+ c->index = -1;
+ c->enq_func = NULL;
+ c->enq_user = NULL;
+ c->cs = peer_cs;
+}
+
+
+static void
+channel_set_peer( Channel* c, int index, EnqueueFunc enq_func, void* enq_user )
+{
+ c->index = index;
+ qemu_chr_add_handlers( c->cs,
+ channel_can_read,
+ channel_read,
+ NULL,
+ c );
+ c->enq_func = enq_func;
+ c->enq_user = enq_user;
+}
+
+
+static int
+channel_write( Channel*c , const uint8_t* buf, int len )
+{
+ return qemu_chr_write( c->cs, buf, len );
+}
+
+/** multiplexer
+ **/
+#define IN_BUFF_SIZE (2*MAX_PAYLOAD)
+
+typedef struct {
+ CharDriverState* cs;
+
+ CBuffer in_cbuffer[1];
+ int in_datalen;
+ int in_channel;
+
+ int count;
+ Channel channels[MAX_CHANNELS];
+ uint8_t in_buff[ IN_BUFF_SIZE + HEADER_SIZE ];
+} Multiplexer;
+
+
+/* called by channel_read when data comes from an emulated
+ * device, and needs to be multiplexed through the serial
+ * port
+ */
+static void
+multiplexer_enqueue( Multiplexer* m, Packet* p )
+{
+ T("%s: sending %d bytes: '%s'", __FUNCTION__,
+ p->len - HEADER_SIZE, quote_bytes( p->data, p->len - HEADER_SIZE ) );
+
+ qemu_chr_write( m->cs, p->header, HEADER_SIZE );
+ qemu_chr_write( m->cs, p->data, p->len - HEADER_SIZE );
+ packet_free(p);
+}
+
+/* called when we received a channel registration from the
+ * qemud daemon
+ */
+static void
+multiplexer_register_channel( Multiplexer* m,
+ const char* name,
+ int index )
+{
+ Channel* c = m->channels;
+ Channel* c_end = c + m->count;
+
+ for ( ; c < c_end; c++ ) {
+ if ( !strcmp(c->name, name) )
+ break;
+ }
+
+ if (c >= c_end) {
+ D( "%s: unknown channel name '%s'",
+ __FUNCTION__, name );
+ return;
+ }
+
+ if (c->index >= 0) {
+ D( "%s: channel '%s' re-assigned index %d",
+ __FUNCTION__, name, index );
+ c->index = index;
+ return;
+ }
+ channel_set_peer( c, index, (EnqueueFunc) multiplexer_enqueue, m );
+ D( "%s: channel '%s' registered as index %d",
+ __FUNCTION__, c->name, c->index );
+}
+
+
+/* handle answers from the control channel */
+static void
+multiplexer_handle_control( Multiplexer* m, Packet* p )
+{
+ int len = p->len - HEADER_SIZE;
+
+ /* for now, the only supported answer is 'ok:connect:<name>:<XX>' where
+ * <XX> is a hexdecimal channel numner */
+ D( "%s: received '%s'", __FUNCTION__, quote_bytes( (const void*)p->data, (unsigned)len ) );
+ if ( !memcmp( p->data, "ok:connect:", 11 ) ) do {
+ char* name = (char*)p->data + 11;
+ char* q = strchr( name, ':' );
+ int index;
+
+ if (q == NULL)
+ break;
+
+ q[0] = 0;
+ if (q + 3 > (char*)p->data + len)
+ break;
+
+ index = hex2int( (uint8_t*)q+1, 2 );
+ if (index < 0)
+ break;
+
+ multiplexer_register_channel( m, name, index );
+ goto Exit;
+ }
+ while(0);
+
+ D( "%s: unsupported message !!", __FUNCTION__ );
+Exit:
+ packet_free(p);
+}
+
+
+static int
+multiplexer_can_read( void* opaque )
+{
+ Multiplexer* m = opaque;
+
+ return cbuffer_write_avail( m->in_cbuffer );
+}
+
+/* the data comes from the serial port, we need to reconstruct packets then
+ * dispatch them to the appropriate channel */
+static void
+multiplexer_read( void* opaque, const uint8_t* from, int len )
+{
+ Multiplexer* m = opaque;
+ CBuffer* cb = m->in_cbuffer;
+ int ret = 0;
+
+ T("%s: received %d bytes from serial: '%s'",
+ __FUNCTION__, len, quote_bytes( from, len ));
+
+ ret = cbuffer_write( cb, from, len );
+ if (ret == 0)
+ return;
+
+ for (;;) {
+ int len = cbuffer_read_avail( cb );
+
+ if (m->in_datalen == 0) {
+ uint8_t header[HEADER_SIZE];
+
+ if (len < HEADER_SIZE)
+ break;
+
+ cbuffer_read( cb, header, HEADER_SIZE );
+ m->in_datalen = hex2int( header+0, 4 );
+ m->in_channel = hex2int( header+4, 2 );
+ }
+ else
+ {
+ Packet* p;
+
+ if (len < m->in_datalen)
+ break;
+
+ /* a full packet was received */
+ p = packet_alloc();
+ cbuffer_read( cb, p->data, m->in_datalen );
+ p->len = HEADER_SIZE + m->in_datalen;
+
+ /* find the channel for this packet */
+ if (m->in_channel == CHANNEL_CONTROL_INDEX)
+ multiplexer_handle_control( m, p );
+ else {
+ Channel* c = m->channels;
+ Channel* c_end = c + m->count;
+
+ for ( ; c < c_end; c++ ) {
+ if (c->index == m->in_channel) {
+ channel_write( c, p->data, m->in_datalen );
+ break;
+ }
+ }
+ packet_free(p);
+ }
+ m->in_datalen = 0;
+ }
+
+ }
+ return;
+}
+
+static void
+multiplexer_query_channel( Multiplexer* m, const char* name )
+{
+ Packet* p = packet_alloc();
+ int len;
+
+ len = snprintf( (char*)p->data, MAX_PAYLOAD, "connect:%s", name );
+
+ int2hex( p->header+0, 4, len );
+ int2hex( p->header+4, 2, CHANNEL_CONTROL_INDEX );
+ p->len = HEADER_SIZE + len;
+
+ multiplexer_enqueue( m, p );
+}
+
+
+static Channel*
+multiplexer_find_channel( Multiplexer* m, const char* name )
+{
+ int n;
+ for (n = 0; n < m->count; n++)
+ if ( !strcmp(m->channels[n].name, name) )
+ return m->channels + n;
+
+ return NULL;
+}
+
+
+static Multiplexer _multiplexer[1];
+static CharDriverState* android_qemud_cs;
+
+extern void
+android_qemud_init( void )
+{
+ Multiplexer* m = _multiplexer;
+
+ if (android_qemud_cs != NULL)
+ return;
+
+ m->count = 0;
+
+ cbuffer_reset( m->in_cbuffer, m->in_buff, sizeof(m->in_buff) );
+ m->in_datalen = 0;
+ m->in_channel = 0;
+
+ if (qemu_chr_open_charpipe( &android_qemud_cs, &m->cs ) < 0) {
+ derror( "%s: can't create charpipe to serial port",
+ __FUNCTION__ );
+ exit(1);
+ }
+
+ qemu_chr_add_handlers( m->cs, multiplexer_can_read,
+ multiplexer_read, NULL, m );
+}
+
+
+CharDriverState* android_qemud_get_cs( void )
+{
+ if (android_qemud_cs == NULL)
+ android_qemud_init();
+
+ return android_qemud_cs;
+}
+
+
+extern int
+android_qemud_get_channel( const char* name, CharDriverState** pcs )
+{
+ Multiplexer* m = _multiplexer;
+ Channel* c;
+ CharDriverState* peer_cs;
+ int ret;
+
+ if (m->cs == NULL)
+ android_qemud_init();
+
+ c = multiplexer_find_channel( m, name );
+ if (c) {
+ derror( "%s: trying to get already-opened qemud channel '%s'",
+ __FUNCTION__, name );
+ return -1;
+ }
+
+ if (m->count >= MAX_CHANNELS) {
+ derror( "%s: too many registered channels (%d)",
+ __FUNCTION__, m->count );
+ return -1;
+ }
+
+ c = m->channels + m->count;
+
+ ret = qemu_chr_open_charpipe( &peer_cs, pcs );
+ if (ret == 0) {
+ channel_init(c, name, peer_cs);
+ m->count += 1;
+ multiplexer_query_channel( m, c->name );
+ }
+
+ return ret;
+}
+
+extern int
+android_qemud_set_channel( const char* name, CharDriverState* peer_cs )
+{
+ Multiplexer* m = _multiplexer;
+ Channel* c;
+
+ if (m->cs == NULL)
+ android_qemud_init();
+
+ c = multiplexer_find_channel(m, name);
+ if (c != NULL) {
+ derror( "%s: trying to set opened qemud channel '%s'",
+ __FUNCTION__, name );
+ return -1;
+ }
+
+ if (m->count >= MAX_CHANNELS) {
+ derror( "%s: too many registered channels (%d)",
+ __FUNCTION__, m->count );
+ return -1;
+ }
+
+ c = m->channels + m->count;
+ channel_init(c, name, peer_cs);
+ m->count += 1;
+ multiplexer_query_channel( m, c->name );
+
+ return 0;
+}
diff --git a/android/qemud.h b/android/qemud.h
new file mode 100644
index 0000000..4fa71d0
--- /dev/null
+++ b/android/qemud.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _android_qemud_h
+#define _android_qemud_h
+
+#include "qemu-common.h"
+
+/* recent versions of the emulated Android system contains a background
+ * daemon, named 'qemud', which runs as root and opens /dev/ttyS0
+ *
+ * its purpose is to multiplex several communication channels between
+ * the emulator and the system through a single serial port.
+ *
+ * each channel will be connected to a qemud-created unix socket on the
+ * system, and to either a emulated character device or other facility in
+ * the emulator.
+ *
+ * +--------> /dev/socket/qemud_gsm
+ * emulated GSM <-----+ ______|_
+ * | emulated | |
+ * +====> /dev/ttyS0 <===>| qemud |------> /dev/socket/qemud_gps
+ * | |________|
+ * emulated GPS <-----+ |
+ * | +---------> other
+ * |
+ * other <--------------+
+ *
+ *
+ * this is done to overcome specific permission problems, as well as to add various
+ * features that would require special kernel drivers otherwise even though they
+ * only need a simple character channel.
+ */
+
+/* initialize the qemud support code in the emulator
+ */
+
+extern void android_qemud_init( void );
+
+/* return the character driver state object that needs to be connected to the
+ * emulated serial port where all multiplexed channels go through.
+ */
+extern CharDriverState* android_qemud_get_cs( void );
+
+/* return the character driver state corresponding to a named qemud communication
+ * channel. this can be used to send/data the channel.
+ * returns 0 on success, or -1 in case of error
+ */
+extern int android_qemud_get_channel( const char* name, CharDriverState* *pcs );
+
+/* set the character driver state for a given qemud communication channel. this
+ * is used to attach the channel to an external char driver device directly.
+ * returns 0 on success, -1 on error
+ */
+extern int android_qemud_set_channel( const char* name, CharDriverState* peer_cs );
+
+/* list of known qemud channel names */
+#define ANDROID_QEMUD_GSM "gsm"
+#define ANDROID_QEMUD_GPS "gps"
+#define ANDROID_QEMUD_CONTROL "control"
+
+/* add new channel names here when you need them */
+
+#endif /* _android_qemud_h */
diff --git a/android/resource.c b/android/resource.c
new file mode 100644
index 0000000..1327ea0
--- /dev/null
+++ b/android/resource.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/resource.h"
+#include "config-host.h"
+#include <string.h>
+
+typedef struct {
+ const char* name;
+ const unsigned char* base;
+ size_t size;
+} FileEntry;
+
+const unsigned char*
+_resource_find( const char* name,
+ const FileEntry* entries,
+ size_t *psize )
+{
+ const FileEntry* e = entries;
+
+ for ( ; e->name != NULL; e++ ) {
+ //dprint("SCAN %s\n", e->name);
+ if ( strcmp(e->name, name) == 0 ) {
+ *psize = e->size;
+ return e->base;
+ }
+ }
+ return NULL;
+}
+
+#undef _file_entries
+#define _file_entries _skin_entries
+const unsigned char*
+android_resource_find( const char* name,
+ size_t *psize )
+{
+# include "android/skin/default.h"
+ return _resource_find( name, _file_entries, psize );
+}
+
+#undef _file_entries
+#define _file_entries _icon_entries
+
+const unsigned char*
+android_icon_find( const char* name,
+ size_t *psize )
+{
+#ifdef _WIN32
+ return NULL;
+#else
+# include "android/icons.h"
+ return _resource_find( name, _file_entries, psize );
+#endif
+}
+
+
diff --git a/android/resource.h b/android/resource.h
new file mode 100644
index 0000000..00453af
--- /dev/null
+++ b/android/resource.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_RESOURCE_H
+#define _ANDROID_RESOURCE_H
+
+#include <stddef.h>
+
+extern const unsigned char*
+android_resource_find( const char* name,
+ size_t *psize );
+
+extern const unsigned char*
+android_icon_find( const char* name,
+ size_t *psize );
+
+#endif /* END */
+
diff --git a/android/skin/argb.h b/android/skin/argb.h
new file mode 100644
index 0000000..b3f0a6d
--- /dev/null
+++ b/android/skin/argb.h
@@ -0,0 +1,856 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+/* this file contains template code and may be included multiple times */
+
+#ifndef ARGB_T_DEFINED
+#define ARGB_T_DEFINED
+
+#if USE_MMX
+#include <mmintrin.h>
+
+typedef __m64 mmx_t;
+typedef mmx_t argb_t;
+
+static inline mmx_t
+mmx_load8888( unsigned value, mmx_t zero )
+{
+ return _mm_unpacklo_pi8( _mm_cvtsi32_si64 (value), zero);
+}
+
+static inline unsigned
+mmx_save8888( mmx_t argb, mmx_t zero )
+{
+ return (unsigned) _mm_cvtsi64_si32( _mm_packs_pu16( argb, zero ) );
+}
+
+static inline mmx_t
+mmx_expand16( int value )
+{
+ mmx_t t1 = _mm_cvtsi32_si64( value );
+ return _mm_packs_pi32( t1, t1 );
+}
+
+static inline int
+mmx_makescale( double s )
+{
+ return (int)(s*(1 << 16));
+}
+
+static inline mmx_t
+mmx_mulshift( mmx_t argb, int multiplier, int rshift, mmx_t zero )
+{
+ mmx_t ar = _mm_unpackhi_pi16(argb, zero );
+ mmx_t gb = _mm_unpacklo_pi16(argb, zero );
+ mmx_t mult = mmx_expand16(multiplier);
+
+ ar = _mm_srli_pi32( _mm_madd_pi16( ar, mult ), rshift );
+ gb = _mm_srli_pi32( _mm_madd_pi16( gb, mult ), rshift );
+
+ return _mm_packs_pi32( gb, ar );
+}
+
+static inline mmx_t
+mmx_interp255( mmx_t m1, mmx_t m2, mmx_t zero, int alpha )
+{
+ mmx_t mult, mult2, t1, t2, r1, r2;
+
+ // m1 = [ a1 | r1 | g1 | b1 ]
+ // m2 = [ a2 | r2 | g2 | b2 ]
+ alpha = (alpha << 16) | (alpha ^ 255);
+ mult = _mm_cvtsi32_si64( alpha ); // mult = [ 0 | 0 | a | 1-a ]
+ mult2 = _mm_slli_si64( mult, 32 ); // mult2 = [ a | 1-a | 0 | 0 ]
+ mult = _mm_or_si64( mult, mult2 ); // mults = [ a | 1-a | a | 1-a ]
+
+ t1 = _mm_unpackhi_pi16( m1, m2 ); // t1 = [ a2 | a1 | r2 | r1 ]
+ r1 = _mm_madd_pi16( t1, mult ); // r1 = [ ra | rr ]
+
+ t2 = _mm_unpacklo_pi16( m1, m2 ); // t1 = [ g2 | g1 | b2 | b1 ]
+ r2 = _mm_madd_pi16( t2, mult ); // r2 = [ rg | rb ]
+
+ r1 = _mm_srli_pi32( r1, 8 );
+ r2 = _mm_srli_pi32( r2, 8 );
+
+ return _mm_packs_pi32( r2, r1 );
+}
+
+#define ARGB_DECL_ZERO() mmx_t _zero = _mm_setzero_si64()
+#define ARGB_DECL(x) mmx_t x
+#define ARGB_DECL2(x1,x2) mmx_t x1, x2
+#define ARGB_ZERO(x) x = _zero
+#define ARGB_UNPACK(x,v) x = mmx_load8888((v), _zero)
+#define ARGB_PACK(x) mmx_save8888(x, _zero)
+#define ARGB_COPY(x,y) x = y
+#define ARGB_SUM(x1,x2,x3) x1 = _mm_add_pi32(x2, x3)
+#define ARGB_REDUCE(x,red) \
+ ({ \
+ int _red = (red) >> 8; \
+ if (_red < 256) \
+ x = mmx_mulshift( x, _red, 8, _zero ); \
+ })
+
+#define ARGB_INTERP255(x1,x2,x3,alpha) \
+ x1 = mmx_interp255( x2, x3, _zero, (alpha))
+
+#define ARGB_ADDW_11(x1,x2,x3) \
+ ARGB_SUM(x1,x2,x3)
+
+#define ARGB_ADDW_31(x1,x2,x3) \
+ ({ \
+ mmx_t _t1 = _mm_add_pi16(x2, x3); \
+ mmx_t _t2 = _mm_slli_pi16(x2, 1); \
+ x1 = _mm_add_pi16(_t1, _t2); \
+ })
+
+#define ARGB_ADDW_13(x1,x2,x3) \
+ ({ \
+ mmx_t _t1 = _mm_add_pi16(x2, x3); \
+ mmx_t _t2 = _mm_slli_pi16(x3, 1); \
+ x1 = _mm_add_pi16(_t1, _t2); \
+ })
+
+#define ARGB_SHR(x1,x2,s) \
+ x1 = _mm_srli_pi16(x2, s)
+
+
+#define ARGB_MULSHIFT(x1,x2,v,s) \
+ x1 = mmx_mulshift(x2, v, s, _zero)
+
+#define ARGB_DONE _mm_empty()
+
+#define ARGB_RESCALE_SHIFT 10
+#define ARGB_DECL_SCALE(s2,s) int s2 = (int)((s)*(s)*(1 << ARGB_RESCALE_SHIFT))
+#define ARGB_RESCALE(x,s2) x = mmx_mulshift( x, s2, ARGB_RESCALE_SHIFT, _zero )
+
+#else /* !USE_MMX */
+
+typedef uint32_t argb_t;
+
+#define ARGB_DECL_ZERO() argb_t _zero = 0
+#define ARGB_DECL(x) argb_t x##_ag, x##_rb
+#define ARGB_DECL2(x1,x2) argb_t x1##_ag, x1##_rb, x2##_ag, x2##_rb
+#define ARGB_ZERO(x) (x##_ag = x##_rb = 0)
+#define ARGB_COPY(x,y) (x##_ag = y##_ag, x##_rb = y##_rb)
+
+#define ARGB_UNPACK(x,v) \
+ ({ \
+ argb_t _v = (argb_t)(v); \
+ x##_ag = (_v >> 8) & 0xff00ff; \
+ x##_rb = (_v) & 0xff00ff; \
+ })
+
+#define ARGB_PACK(x) (uint32_t)(((x##_ag) << 8) | x##_rb)
+
+#define ARGB_SUM(x1,x2,x3) \
+ ({ \
+ x1##_ag = x2##_ag + x3##_ag; \
+ x1##_rb = x2##_rb + x3##_rb; \
+ })
+
+#define ARGB_REDUCE(x,red) \
+ ({ \
+ int _red = (red) >> 8; \
+ if (_red < 256) { \
+ x##_ag = ((x##_ag*_red) >> 8) & 0xff00ff; \
+ x##_rb = ((x##_rb*_red) >> 8) & 0xff00ff; \
+ } \
+ })
+
+#define ARGB_INTERP255(x1,x2,x3,alpha) \
+ ({ \
+ int _alpha = (alpha); \
+ int _ialpha; \
+ _alpha += _alpha >> 8; \
+ _ialpha = 256 - _alpha; \
+ x1##_ag = ((x2##_ag*_ialpha + x3##_ag*_alpha) >> 8) & 0xff00ff; \
+ x1##_rb = ((x2##_rb*_ialpha + x3##_rb*_alpha) >> 8) & 0xff00ff; \
+ })
+
+#define ARGB_ADDW_11(x1,x2,x3) \
+ ({ \
+ x1##_ag = (x2##_ag + x3##_ag); \
+ x1##_rb = (x2##_rb + x3##_rb); \
+ })
+
+#define ARGB_ADDW_31(x1,x2,x3) \
+ ({ \
+ x1##_ag = (3*x2##_ag + x3##_ag); \
+ x1##_rb = (3*x2##_rb + x3##_rb); \
+ })
+
+#define ARGB_ADDW_13(x1,x2,x3) \
+ ({ \
+ x1##_ag = (x2##_ag + 3*x3##_ag); \
+ x1##_rb = (x2##_rb + 3*x3##_rb); \
+ })
+
+#define ARGB_MULSHIFT(x1,x2,v,s) \
+ ({ \
+ unsigned _vv = (v); \
+ x1##_ag = ((x2##_ag * _vv) >> (s)) & 0xff00ff; \
+ x1##_rb = ((x2##_rb * _vv) >> (s)) & 0xff00ff; \
+ })
+
+#define ARGB_SHR(x1,x2,s) \
+ ({ \
+ int _s = (s); \
+ x1##_ag = (x2##_ag >> _s) & 0xff00ff; \
+ x1##_rb = (x2##_rb >> _s) & 0xff00ff; \
+ })
+
+#define ARGB_DONE ((void)0)
+
+#define ARGB_RESCALE_SHIFT 8
+#define ARGB_DECL_SCALE(s2,s) int s2 = (int)((s)*(s)*(1 << ARGB_RESCALE_SHIFT))
+#define ARGB_RESCALE(x,scale2) ARGB_MULSHIFT(x,x,scale2,ARGB_RESCALE_SHIFT)
+
+#endif /* !USE_MMX */
+
+#define ARGB_ADD(x1,x2) ARGB_SUM(x1,x1,x2)
+#define ARGB_READ(x,p) ARGB_UNPACK(x,*(uint32_t*)(p))
+#define ARGB_WRITE(x,p) *(uint32_t*)(p) = ARGB_PACK(x)
+
+#endif /* !ARGB_T_DEFINED */
+
+
+
+#ifdef ARGB_SCALE_GENERIC
+static void
+ARGB_SCALE_GENERIC( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ ARGB_DECL_SCALE(scale2, op->scale);
+ int h;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+
+ src_line += (sx >> 16)*4 + (sy >> 16)*src_pitch;
+ sx &= 0xffff;
+ sy &= 0xffff;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* src = src_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+ int sx1 = sx;
+ int sy1 = sy;
+
+ for ( ; dst < dst_end; ) {
+ int sx2 = sx1 + ix;
+ int sy2 = sy1 + iy;
+
+ ARGB_DECL_ZERO();
+ ARGB_DECL(spix);
+ ARGB_DECL(pix);
+ ARGB_ZERO(pix);
+
+ /* the current destination pixel maps to the (sx1,sy1)-(sx2,sy2)
+ * source square, we're going to compute the sum of its pixels'
+ * colors... simple box filtering
+ */
+ {
+ int gsy, gsx;
+ for ( gsy = 0; gsy < sy2; gsy += 65536 ) {
+ for ( gsx = 0; gsx < sx2; gsx += 65536 ) {
+ uint8_t* s = src + (gsx >> 16)*4 + (gsy >> 16)*src_pitch;
+ int xmin = gsx, xmax = gsx + 65536, ymin = gsy, ymax = gsy + 65536;
+ unsigned ww, hh;
+ unsigned red;
+
+ if (xmin < sx1) xmin = sx1;
+ if (xmax > sx2) xmax = sx2;
+ if (ymin < sy1) ymin = sy1;
+ if (ymax > sy2) ymax = sy2;
+
+ ww = (unsigned)(xmax-xmin);
+ red = ww;
+
+ hh = (unsigned)(ymax-ymin);
+ red = (hh < 65536) ? (red*hh >> 16U) : red;
+
+ ARGB_READ(spix,s);
+ ARGB_REDUCE(spix,red);
+ ARGB_ADD(pix,spix);
+ }
+ }
+ }
+
+ ARGB_RESCALE(pix,scale2);
+ ARGB_WRITE(pix,dst);
+
+ sx1 = sx2;
+ src += (sx1 >> 16)*4;
+ sx1 &= 0xffff;
+ dst += 4;
+ }
+
+ sy += iy;
+ src_line += (sy >> 16)*src_pitch;
+ sy &= 0xffff;
+
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_GENERIC
+
+
+#ifdef ARGB_SCALE_05_TO_10
+static inline int cross( int x, int y ) {
+ if (x == 65536 && y == 65536)
+ return 65536;
+
+ return (int)((unsigned)x * (unsigned)y >> 16U);
+}
+
+static void
+scale_05_to_10( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ ARGB_DECL_SCALE(scale2, op->scale);
+ int h;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+
+ src_line += (sx >> 16)*4 + (sy >> 16)*src_pitch;
+ sx &= 0xffff;
+ sy &= 0xffff;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* src = src_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+ int sx1 = sx;
+ int sy1 = sy;
+
+ for ( ; dst < dst_end; ) {
+ int sx2 = sx1 + ix;
+ int sy2 = sy1 + iy;
+
+ ARGB_DECL_ZERO();
+ ARGB_DECL2(spix, pix);
+
+ int off = src_pitch;
+ int fx1 = sx1 & 0xffff;
+ int fx2 = sx2 & 0xffff;
+ int fy1 = sy1 & 0xffff;
+ int fy2 = sy2 & 0xffff;
+
+ int center_x = ((sx1 >> 16) + 1) < ((sx2-1) >> 16);
+ int center_y = ((sy1 >> 16) + 1) < ((sy2-1) >> 16);
+
+ ARGB_ZERO(pix);
+
+ if (fx2 == 0) {
+ fx2 = 65536;
+ }
+ if (fy2 == 0) {
+ fy2 = 65536;
+ }
+ fx1 = 65536 - fx1;
+ fy1 = 65536 - fy1;
+
+ /** TOP BAND
+ **/
+
+ /* top-left pixel */
+ ARGB_READ(spix,src);
+ ARGB_REDUCE(spix,cross(fx1,fy1));
+ ARGB_ADD(pix,spix);
+
+ /* top-center pixel, if any */
+ ARGB_READ(spix,src + 4);
+ if (center_x) {
+ ARGB_REDUCE(spix,fy1);
+ ARGB_ADD(pix,spix);
+ ARGB_READ(spix,src + 8);
+ }
+
+ /* top-right pixel */
+ ARGB_REDUCE(spix,cross(fx2,fy1));
+ ARGB_ADD(pix,spix);
+
+ /** MIDDLE BAND, IF ANY
+ **/
+ if (center_y) {
+ /* left-middle pixel */
+ ARGB_READ(spix,src + off);
+ ARGB_REDUCE(spix,fx1);
+ ARGB_ADD(pix,spix);
+
+ /* center pixel, if any */
+ ARGB_READ(spix,src + off + 4);
+ if (center_x) {
+ ARGB_ADD(pix,spix);
+ ARGB_READ(spix,src + off + 8);
+ }
+
+ /* right-middle pixel */
+ ARGB_REDUCE(spix,fx2);
+ ARGB_ADD(pix,spix);
+
+ off += src_pitch;
+ }
+
+ /** BOTTOM BAND
+ **/
+ /* left-bottom pixel */
+ ARGB_READ(spix,src + off);
+ ARGB_REDUCE(spix,cross(fx1,fy2));
+ ARGB_ADD(pix,spix);
+
+ /* center-bottom, if any */
+ ARGB_READ(spix,src + off + 4);
+ if (center_x) {
+ ARGB_REDUCE(spix,fy2);
+ ARGB_ADD(pix,spix);
+ ARGB_READ(spix,src + off + 8);
+ }
+
+ /* right-bottom pixel */
+ ARGB_REDUCE(spix,cross(fx2,fy2));
+ ARGB_ADD(pix,spix);
+
+ /** WRITE IT
+ **/
+ ARGB_RESCALE(pix,scale2);
+ ARGB_WRITE(pix,dst);
+
+ sx1 = sx2;
+ src += (sx1 >> 16)*4;
+ sx1 &= 0xffff;
+ dst += 4;
+ }
+
+ sy += iy;
+ src_line += (sy >> 16)*src_pitch;
+ sy &= 0xffff;
+
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_05_TO_10
+
+
+#ifdef ARGB_SCALE_UP_BILINEAR
+static void
+scale_up_bilinear( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+ int xlimit, ylimit;
+ int h, sx0;
+
+ /* the center pixel is at (sx+ix/2, sy+iy/2), we then want to get */
+ /* the four nearest source pixels, which are at (0.5,0.5) offsets */
+
+ sx = sx + ix/2 - 32768;
+ sy = sy + iy/2 - 32768;
+
+ xlimit = (op->src_w-1);
+ ylimit = (op->src_h-1);
+
+ sx0 = sx;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+
+ sx = sx0;
+ for ( ; dst < dst_end; ) {
+ int ex1, ex2, ey1, ey2, alpha;
+ uint8_t* s;
+
+ ARGB_DECL_ZERO();
+ ARGB_DECL2(spix1,spix2);
+ ARGB_DECL2(pix3,pix4);
+ ARGB_DECL(pix);
+
+ /* find the four neighbours */
+ ex1 = (sx >> 16);
+ ey1 = (sy >> 16);
+ ex2 = (sx+65535) >> 16;
+ ey2 = (sy+65535) >> 16;
+
+ if (ex1 < 0) ex1 = 0; else if (ex1 > xlimit) ex1 = xlimit;
+ if (ey1 < 0) ey1 = 0; else if (ey1 > ylimit) ey1 = ylimit;
+ if (ex2 < 0) ex2 = 0; else if (ex2 > xlimit) ex2 = xlimit;
+ if (ey2 < 0) ey2 = 0; else if (ey2 > ylimit) ey2 = ylimit;
+
+ ex2 = (ex2-ex1)*4;
+ ey2 = (ey2-ey1)*src_pitch;
+
+ /* interpolate */
+ s = src_line + ex1*4 + ey1*src_pitch;
+ ARGB_READ(spix1, s);
+ ARGB_READ(spix2, s+ex2);
+
+ alpha = (sx >> 8) & 0xff;
+ ARGB_INTERP255(pix3,spix1,spix2,alpha);
+
+ s += ey2;
+ ARGB_READ(spix1, s);
+ ARGB_READ(spix2, s+ex2);
+
+ ARGB_INTERP255(pix4,spix1,spix2,alpha);
+
+ alpha = (sy >> 8) & 0xff;
+ ARGB_INTERP255(pix,pix3,pix4,alpha);
+
+ ARGB_WRITE(pix,dst);
+
+ sx += ix;
+ dst += 4;
+ }
+
+ sy += iy;
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_UP_BILINEAR
+
+#ifdef ARGB_SCALE_UP_QUICK_4x4
+static void
+ARGB_SCALE_UP_QUICK_4x4( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+ int xlimit, ylimit;
+ int h, sx0;
+
+ /* the center pixel is at (sx+ix/2, sy+iy/2), we then want to get */
+ /* the four nearest source pixels, which are at (0.5,0.5) offsets */
+
+ sx = sx + ix/2 - 32768;
+ sy = sy + iy/2 - 32768;
+
+ xlimit = (op->src_w-1);
+ ylimit = (op->src_h-1);
+
+ sx0 = sx;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+
+ sx = sx0;
+ for ( ; dst < dst_end; ) {
+ int ex1, ex2, ey1, ey2;
+ uint8_t* p;
+ ARGB_DECL_ZERO();
+ ARGB_DECL(pix);
+ ARGB_DECL2(spix1, spix2);
+ ARGB_DECL2(pix3, pix4);
+
+ /* find the four neighbours */
+ ex1 = (sx >> 16);
+ ey1 = (sy >> 16);
+ ex2 = (sx+65535) >> 16;
+ ey2 = (sy+65535) >> 16;
+
+ if (ex1 < 0) ex1 = 0; else if (ex1 > xlimit) ex1 = xlimit;
+ if (ey1 < 0) ey1 = 0; else if (ey1 > ylimit) ey1 = ylimit;
+ if (ex2 < 0) ex2 = 0; else if (ex2 > xlimit) ex2 = xlimit;
+ if (ey2 < 0) ey2 = 0; else if (ey2 > ylimit) ey2 = ylimit;
+
+ /* interpolate */
+ p = (src_line + ex1*4 + ey1*src_pitch);
+
+ ex2 = (ex2-ex1)*4;
+ ey2 = (ey2-ey1)*src_pitch;
+
+ switch (((sx >> 14) & 3) | ((sy >> 12) & 12)) {
+ case 0:
+ *(uint32_t*)dst = *(uint32_t*)p;
+ break;
+
+ /* top-line is easy */
+ case 1:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 2:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix, spix1, spix2);
+ ARGB_SHR(pix,pix,1);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 3:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ /* second line is harder */
+ case 4:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ey2);
+ ARGB_ADDW_31(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 5:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix4,spix1,spix2);
+
+ ARGB_ADDW_31(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 6:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix4,spix1,spix2);
+
+ ARGB_ADDW_31(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 7:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix4,spix1,spix2);
+
+ ARGB_ADDW_31(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ /* third line */
+ case 8:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ey2);
+ ARGB_ADDW_11(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,1);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 9:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix4,spix1,spix2);
+
+ ARGB_ADDW_11(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 10:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix4,spix1,spix2);
+
+ ARGB_ADDW_11(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 11:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix4,spix1,spix2);
+
+ ARGB_ADDW_11(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ /* last line */
+ case 12:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ey2);
+ ARGB_ADDW_13(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 13:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix4,spix1,spix2);
+
+ ARGB_ADDW_13(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 14:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix4,spix1,spix2);
+
+ ARGB_ADDW_13(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ default:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix4,spix1,spix2);
+
+ ARGB_ADDW_13(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ }
+ sx += ix;
+ dst += 4;
+ }
+
+ sy += iy;
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_UP_QUICK_4x4
+
+
+#ifdef ARGB_SCALE_NEAREST
+/* this version scales up with nearest neighbours - looks crap */
+static void
+ARGB_SCALE_NEAREST( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+ int xlimit, ylimit;
+ int h, sx0;
+
+ /* the center pixel is at (sx+ix/2, sy+iy/2), we then want to get */
+ /* the four nearest source pixels, which are at (0.5,0.5) offsets */
+
+ sx = sx + ix/2 - 32768;
+ sy = sy + iy/2 - 32768;
+
+ xlimit = (op->src_w-1);
+ ylimit = (op->src_h-1);
+
+ sx0 = sx;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+
+ sx = sx0;
+ for ( ; dst < dst_end; ) {
+ int ex1, ex2, ey1, ey2;
+ unsigned* p;
+
+ /* find the top-left neighbour */
+ ex1 = (sx >> 16);
+ ey1 = (sy >> 16);
+ ex2 = ex1+1;
+ ey2 = ey1+1;
+
+ if (ex1 < 0) ex1 = 0; else if (ex1 > xlimit) ex1 = xlimit;
+ if (ey1 < 0) ey1 = 0; else if (ey1 > ylimit) ey1 = ylimit;
+ if (ex2 < 0) ex2 = 0; else if (ex2 > xlimit) ex2 = xlimit;
+ if (ey2 < 0) ey2 = 0; else if (ey2 > ylimit) ey2 = ylimit;
+
+ p = (unsigned*)(src_line + ex1*4 + ey1*src_pitch);
+ if ((sx & 0xffff) >= 32768)
+ p += (ex2-ex1);
+ if ((sy & 0xffff) >= 32768)
+ p = (unsigned*)((char*)p + (ey2-ey1)*src_pitch);
+
+ *(unsigned*)dst = p[0];
+
+ sx += ix;
+ dst += 4;
+ }
+
+ sy += iy;
+ dst_line += dst_pitch;
+ }
+}
+#endif
+#undef ARGB_SCALE_NEAREST
diff --git a/android/skin/composer.c b/android/skin/composer.c
new file mode 100644
index 0000000..6076449
--- /dev/null
+++ b/android/skin/composer.c
@@ -0,0 +1,401 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/composer.h"
+#include <stddef.h>
+#include "android/utils/system.h"
+
+/* forwards */
+static void skin_plate_get_region ( SkinPlate* p, SkinRegion *pregion );
+static void skin_plate_get_opaque_region( SkinPlate* p, SkinRegion *pregion );
+
+/* recompute region if needed */
+static void
+skin_plate_ensure_region( SkinPlate* p )
+{
+ if (p->any.type == SKIN_PLATE_SURFACE || p->group.hasRegion)
+ return;
+ else {
+ int n, count = areflist_count( p->group.children );
+
+ skin_region_reset(p->any.region);
+
+ for (n = 0; n < count; n++) {
+ SkinRegion r[1];
+ SkinPlate* child = areflist_get( p->group.children, n );
+
+ skin_plate_get_region( child, r );
+ skin_region_translate( r, child->any.pos.x, child->any.pos.y );
+ skin_region_union( p->any.region, r );
+ }
+
+ p->group.hasRegion = 1;
+ }
+}
+
+/* return region in 'region' */
+static void
+skin_plate_get_region( SkinPlate* p, SkinRegion* region )
+{
+ if ( p->any.type != SKIN_PLATE_SURFACE && !p->group.hasRegion ) {
+ skin_plate_ensure_region(p);
+ }
+ skin_region_init_copy( region, p->any.region );
+}
+
+
+/* recompute opaque region is needed */
+static void
+skin_plate_ensure_opaque_region( SkinPlate* p )
+{
+ if (p->any.type != SKIN_PLATE_SURFACE && !p->group.hasOpaqueRegion) {
+ int n, count = areflist_count( p->group.children );
+
+ skin_region_reset(p->group.opaqueRegion);
+
+ for (n = 0; n < count; n++) {
+ SkinRegion r[1];
+ SkinPlate* child = areflist_get( p->group.children, n );
+
+ skin_plate_get_opaque_region(child, r);
+ skin_region_translate(r, child->any.pos.x, child->any.pos.y);
+ skin_region_union( p->group.opaqueRegion, r);
+ }
+
+ p->group.hasOpaqueRegion = 1;
+ }
+}
+
+
+/* return opaque pixels region */
+static void
+skin_plate_get_opaque_region( SkinPlate* p, SkinRegion *pregion )
+{
+ if ( p->any.type == SKIN_PLATE_SURFACE ) {
+ if (p->any.isOpaque)
+ skin_region_init_copy(pregion, p->any.region);
+ else
+ skin_region_reset(pregion);
+ } else {
+ skin_plate_ensure_opaque_region(p);
+ skin_region_init_copy(pregion, p->group.opaqueRegion);
+ }
+}
+
+
+/* invalidate region in parent groups */
+static void
+skin_plate_invalidate_parent( SkinPlate* p )
+{
+ if (!p->any.isVisible)
+ return;
+
+ while (p) {
+ if (p->any.type != SKIN_PLATE_SURFACE) {
+ p->group.hasRegion = 0;
+ p->group.hasOpaqueRegion = 0;
+ }
+ p = p->any.parent;
+ }
+}
+
+
+static void
+skin_plate_invalidate_( SkinPlate* p, SkinRegion* r, SkinPlate* child )
+{
+ if (p->any.type != SKIN_PLATE_SURFACE) {
+ int n = areflist_count( p->group.children );
+ if (child != NULL) {
+ n = areflist_indexOf( p->group.children, child );
+ }
+ while (n > 0) {
+ n -= 1;
+ child = areflist_get( p->group.children, n );
+ skin_region_translate( r, child->any.pos.x, child->any.pos.y );
+ skin_plate_invalidate_( p, r, NULL );
+ skin_region_translate( r, -child->any.pos.x, -child->any.pos.y );
+ if (skin_region_is_empty(r))
+ return;
+ }
+ if (p->any.type != SKIN_PLATE_SPACE) {
+ SkinPlate* parent = p->any.parent;
+ skin_region_translate(r, parent->any.pos.x, parent->any.pos.y );
+ skin_plate_invalidate_(parent, r, p);
+ } else {
+ /* send to viewports */
+ int n, count = areflist_count( p->space.viewports );
+ for (n = 0; n < count; n++) {
+ SkinViewport* v = areflist_get( p->space.viewports, n );
+ skin_viewport_invalidate(v, r);
+ }
+ }
+ }
+}
+
+static void
+skin_plate_invalidate_region( SkinPlate* p )
+{
+ SkinRegion r[1];
+
+ skin_plate_get_region( p, r );
+ skin_plate_invalidate_(p->any.parent, r, p);
+ skin_region_reset(r);
+}
+
+/* change visibility */
+void
+skin_plate_set_visible( SkinPlate* p, int isVisible )
+{
+ isVisible = !!isVisible;
+ if (isVisible == p->any.isVisible)
+ return;
+
+ skin_plate_invalidate_parent(p);
+ skin_plate_invalidate_region(p);
+ p->any.isVisible = isVisible;
+}
+
+void
+skin_plate_set_opaque( SkinPlate* p, int isOpaque )
+{
+ isOpaque = !!isOpaque;
+ if (isOpaque == p->any.isOpaque)
+ return;
+
+ skin_plate_invalidate_parent(p);
+ skin_plate_invalidate_region(p);
+ p->any.isOpaque = isOpaque;
+}
+
+
+
+extern SkinPlate*
+skin_plate_surface( SkinPlate* parent,
+ SkinPos* pos,
+ SkinRegion* region,
+ void* surface,
+ SkinPlateDrawFunc draw,
+ SkinPlateDoneFunc done )
+{
+ SkinPlate* p;
+
+ ANEW0(p);
+ p->any.type = SKIN_PLATE_SURFACE;
+ p->any.parent = parent;
+ p->any.pos.x = pos->x;
+ p->any.pos.y = pos->y;
+ p->any.isVisible = 1;
+ p->any.isOpaque = 1;
+
+ skin_region_init_copy( p->any.region, region );
+ return p;
+}
+
+
+SkinPlate*
+skin_plate_group( SkinPlate* parent, SkinPos* pos )
+{
+ SkinRegion r[1];
+ SkinPlate* p;
+
+ skin_region_reset(r);
+ p = skin_plate_surface( parent, pos, r, NULL, NULL, NULL );
+ p->any.type = SKIN_PLATE_GROUP;
+ p->group.hasOpaqueRegion = 0;
+ skin_region_init_empty( p->group.opaqueRegion );
+
+ areflist_init( p->group.children );
+ return p;
+}
+
+
+SkinPlate*
+skin_plate_space( void )
+{
+ SkinPos pos;
+ SkinPlate* p;
+
+ pos.x = pos.y = 0;
+ p = skin_plate_group( NULL, &pos );
+ p->any.type = SKIN_PLATE_SPACE;
+ areflist_init( p->space.viewports );
+ return p;
+}
+
+
+extern void
+skin_plate_free( SkinPlate* p )
+{
+ if (p->any.type >= SKIN_PLATE_SPACE) {
+ while ( areflist_count( p->space.viewports ) )
+ skin_viewport_free( areflist_get( p->space.viewports, 0 ) );
+ }
+ if (p->any.type >= SKIN_PLATE_GROUP) {
+ skin_region_reset( p->group.opaqueRegion );
+ p->group.hasOpaqueRegion = 0;
+ p->group.hasRegion = 0;
+
+ while ( areflist_count( p->group.children ) )
+ skin_plate_free( areflist_get( p->group.children, 0 ) );
+ }
+ if (p->any.type == SKIN_PLATE_SURFACE) {
+ if (p->surface.done)
+ p->surface.done( p->surface.user );
+ }
+
+ skin_region_reset( p->any.region );
+
+ if (p->any.parent) {
+ areflist_del( p->any.parent->group.children, p );
+ }
+}
+
+void
+skin_plate_invalidate( SkinPlate* plate, SkinRegion* region )
+{
+ SkinRegion r[1];
+ skin_region_init_copy( r, region );
+}
+
+
+/* we use two regions to manage the front-to-back composition here
+ *
+ * 'updated' initially contains the update region, in parent coordinates
+ *
+ * 'drawn' is initially empty, and will be filled with the region of translucent
+ * pixels that have been
+ *
+ * for a given surface plate, we translate the regions to plate coordinates,
+ * then we do an opaque blit of 'intersection(updated,region)', then removing it from 'updated'
+ *
+ * after that, we make a DSTOVER blit of 'intersection(drawn,region)'
+ * if the plate is not opaque, we add this intersection to 'drawn'
+ *
+ */
+static void
+skin_plate_redraw( SkinPlate* plate, SkinRegion* updated, SkinRegion* drawn, SkinPos* apos, SkinViewport* viewport )
+{
+ SkinPos pos = plate->any.pos;
+
+ if (!plate->any.isVisible)
+ return;
+
+ if (skin_region_is_empty(updated) && skin_region_is_empty(drawn))
+ return;
+
+ /* translate regions to plate coordinates */
+ skin_region_translate( updated, pos.x, pos.y );
+ skin_region_translate( drawn, pos.y, pos.y );
+ apos->x += pos.x;
+ apos->y += pos.y;
+
+ if (plate->any.type == SKIN_PLATE_SURFACE) {
+ SkinRegion r[1];
+
+ /* inter(updated,region) => opaque blit + remove 'region' from 'updated'*/
+ skin_plate_get_region(plate, r);
+ skin_region_intersect(r, updated);
+ if (!skin_region_is_empty(r)) {
+ plate->surface.draw( plate->surface.user, r, apos, viewport, 1 );
+ skin_region_substract(updated, r);
+ skin_region_reset(r);
+ }
+
+ /* inter(drawn,region) => DSTOVER blit + if non-opaque add it to 'drawn' */
+ skin_plate_get_region(plate, r);
+ skin_region_intersect(r, drawn);
+ if (!skin_region_is_empty(r)) {
+ plate->surface.draw( plate->surface.user, r, apos, viewport, 0);
+ if (!plate->any.isOpaque)
+ skin_region_union(drawn, r);
+ skin_region_reset(r);
+ }
+
+ } else {
+ int n, count = areflist_count(plate->group.children);
+ for (n = 0; n < count; n++) {
+ SkinPos pos;
+
+ pos.x = apos->x + plate->any.pos.x;
+ pos.y = apos->y + plate->any.pos.y;
+
+ skin_plate_redraw( areflist_get(plate->group.children, n ), updated, drawn, &pos, viewport );
+ if (skin_region_is_empty(updated) && skin_region_is_empty(drawn))
+ break;
+ }
+ }
+
+ /* convert back to parent coordinates */
+ apos->x -= pos.x;
+ apos->y -= pos.y;
+ skin_region_translate( updated, -pos.x, -pos.y );
+ skin_region_translate( drawn, -pos.x, -pos.y );
+}
+
+
+extern SkinViewport*
+skin_viewport( SkinPlate* space, SkinRect* rect, void* surface, int sx, int sy )
+{
+ SkinViewport* v;
+
+ ANEW0(v);
+ v->space = space;
+ v->rect = rect[0];
+ v->spos.x = sx;
+ v->spos.y = sy;
+ v->surface = surface;
+
+ skin_region_init_empty( v->update );
+ return v;
+}
+
+extern void
+skin_viewport_free( SkinViewport* v )
+{
+ SkinPlate* space = v->space;
+ if (space != NULL) {
+ areflist_del( space->space.viewports, v );
+ v->space = NULL;
+ }
+ skin_region_reset( v->update );
+ AFREE(v);
+}
+
+extern void
+skin_viewport_invalidate( SkinViewport* v, SkinRegion* region )
+{
+ SkinRegion r[1];
+ skin_region_init_copy(r,region);
+ skin_region_translate(r, -v->spos.x, -v->spos.y);
+ skin_region_intersect_rect(r,&v->rect);
+ skin_region_union( v->update, r );
+ skin_region_reset(r);
+}
+
+extern void
+skin_viewport_redraw( SkinViewport* v )
+{
+ if (v->space && !skin_region_is_empty(v->update)) {
+ SkinRegion update[1];
+ SkinRegion drawn[1];
+ SkinPos apos;
+
+ skin_region_copy(update, v->update);
+ skin_region_reset(drawn);
+ skin_region_reset( v->update );
+
+ apos.x = apos.y = 0;
+ skin_plate_redraw( v->space, update, drawn, &apos, v );
+
+ skin_region_reset(update);
+ skin_region_reset(drawn);
+ }
+}
diff --git a/android/skin/composer.h b/android/skin/composer.h
new file mode 100644
index 0000000..a52a972
--- /dev/null
+++ b/android/skin/composer.h
@@ -0,0 +1,102 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_COMPOSER_H
+#define _ANDROID_SKIN_COMPOSER_H
+
+#include "android/skin/rect.h"
+#include "android/skin/region.h"
+#include "android/utils/reflist.h"
+
+/* the composer displays stacked surfaces on a target window/SDL_Surface */
+
+typedef enum {
+ SKIN_PLATE_SURFACE = 0,
+ SKIN_PLATE_GROUP,
+ SKIN_PLATE_SPACE
+} SkinPlateType;
+
+typedef union SkinPlate SkinPlate;
+typedef struct SkinViewport SkinViewport;
+
+struct SkinPlateAny {
+ SkinPlateType type; /* class pointer */
+ SkinPlate* parent; /* parent container */
+ SkinPos pos; /* position relative to parent */
+ SkinRegion region[1]; /* the plate's region */
+ char isVisible; /* flag: TRUE iff the region is visible */
+ char isOpaque; /* flag: TRUE iff the region is opaque */
+};
+
+
+typedef void (*SkinPlateDrawFunc)( void* user, SkinRegion* region, SkinPos* apos, SkinViewport* viewport, int opaque );
+typedef void (*SkinPlateDoneFunc)( void* user );
+
+struct SkinPlateSurface {
+ struct SkinPlateAny any;
+ void* user;
+ SkinPlateDrawFunc draw;
+ SkinPlateDoneFunc done;
+};
+
+struct SkinPlateGroup {
+ struct SkinPlateAny any;
+ char hasRegion;
+ char hasOpaqueRegion;
+ SkinRegion opaqueRegion[1];
+ ARefList children[1];
+};
+
+struct SkinPlateSpace {
+ struct SkinPlateGroup group;
+ ARefList viewports[1];
+};
+
+
+union SkinPlate {
+ struct SkinPlateAny any;
+ struct SkinPlateSurface surface;
+ struct SkinPlateGroup group;
+ struct SkinPlateSpace space;
+};
+
+
+extern SkinPlate* skin_plate_surface( SkinPlate* parent,
+ SkinPos* pos,
+ SkinRegion* region,
+ void* user,
+ SkinPlateDrawFunc draw,
+ SkinPlateDoneFunc done );
+
+extern SkinPlate* skin_plate_group( SkinPlate* parent, SkinPos* pos );
+
+extern SkinPlate* skin_plate_space( void );
+
+extern void skin_plate_free( SkinPlate* plate );
+extern void skin_plate_invalidate( SkinPlate* plate, SkinRegion* region );
+extern void skin_plate_set_pos( SkinPlate* plate, int x, int y );
+extern void skin_plate_set_visible( SkinPlate* plate, int isVisible );
+extern void skin_plate_set_opaque( SkinPlate* plate, int isOpaque );
+
+struct SkinViewport {
+ SkinPlate* space;
+ SkinRect rect;
+ void* surface;
+ SkinPos spos;
+ SkinRegion update[1];
+};
+
+extern SkinViewport* skin_viewport( SkinPlate* space, SkinRect* rect, void* surface, int sx, int sy );
+extern void skin_viewport_free( SkinViewport* v );
+extern void skin_viewport_invalidate( SkinViewport* v, SkinRegion* r );
+extern void skin_viewport_redraw( SkinViewport* v );
+
+#endif /* _ANDROID_SKIN_COMPOSER_H */
diff --git a/android/skin/default.h b/android/skin/default.h
new file mode 100644
index 0000000..8ab0c01
--- /dev/null
+++ b/android/skin/default.h
@@ -0,0 +1,7414 @@
+/* automatically generated, do not touch */
+
+
+static const unsigned char _data_arrow_down_png[3438] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 98, 0, 0, 0, 31, 16, 6, 0, 0, 0, 76,137,196,
+ 82, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 2,
+ 153, 73, 68, 65, 84,120,218,236,156, 59, 75,195, 80, 24,134,163,
+ 184,104,113, 18, 20, 68,135, 90,169,163, 93,189, 45, 90,156, 26,
+ 208,165, 46, 29,252, 13,222, 6, 23, 69, 71, 47,163,179, 66, 39,
+ 65,112,238,170, 80, 71, 69, 23,171, 78,186, 40, 56,137, 56,198,
+ 225,203, 43, 36,161,164,177, 39,151,230,188,207,242,129, 96, 27,
+ 206,121,159,156,227,151, 99,186, 44,203,178, 44,203, 48,102,231,
+ 170,213,151,103, 35, 38, 6, 22,157,149,232,201,103,205, 89,163,
+ 227,250,170, 82,201,141, 27, 70, 79, 50, 6, 98,189,223, 22,162,
+ 159,161,208, 90, 8,123,254,183, 99,187,130,238,120, 7, 96, 97,
+ 139, 43, 3,241,238, 20,144, 11,109,132,232,173, 74, 45,237, 48,
+ 4,196, 11,114,129,156,164, 94,136,242,152,212,190, 42, 39,159,
+ 120, 65, 46,144,147,212, 10, 49,242, 33,117,250,158,147, 78,252,
+ 65, 78,144,155,212, 9,177, 50,206, 73, 38, 73,206, 77, 68, 66,
+ 20, 10, 82,243, 7,156, 92, 18, 28,228, 6, 57,234,120, 33,202,
+ 57, 78, 42,233,132, 28,133, 44,132, 57, 44,149,109, 85,162, 2,
+ 228, 8,185,234, 24, 33,112,225,243, 79,156, 68,162, 30,228, 74,
+ 253,141, 54,164, 39,213,165, 93,169,186,180, 85,207, 95,164,190,
+ 14,198,123, 29,163, 31,122,108, 81,145, 43,228,236,172,150, 80,
+ 33,242,135, 82,117,107,171,226, 65,210,209,183,212,183,136,197,
+ 64, 91,178,148,177,127,160,201,141, 8, 57,171,219,185,107,108,
+ 36,108,203,100,238,233,185,132,227,142,181,158,113, 6, 52, 42,
+ 17,240,189,186, 62,232, 84,151, 59, 69, 66, 76, 61,216, 43,132,
+ 230,109,213,168,196,160, 8,174,157,201,129, 51,135,177, 9,129,
+ 179, 38, 38,207, 36, 69, 34, 6, 69,240, 89, 41,218, 62, 3,213,
+ 166, 16, 69,158, 86,141, 68, 12,138,208, 26,200, 97,113, 43, 98,
+ 33,240,197, 60,173, 26,174, 24, 20,161,189, 38, 71,240, 27,245,
+ 63,133, 40,243, 76, 82,168, 98, 80, 4, 53, 4,207,105, 64, 33,
+ 208, 86, 45, 76,114,176,195, 16,131, 34,168, 5, 57, 69,110,149,
+ 11,193,149, 33, 92, 49, 40, 66,220, 43, 69,139, 66,160,157, 53,
+ 250,206,193, 13, 83, 12,138, 16, 14,200,173,127, 91,214, 71, 8,
+ 180,175,202, 89, 14, 42, 73,193, 74,145,117,230,218,139,207,209,
+ 13,115,215,190,115,125,115, 48, 73,122, 86, 98,211,126,144,119,
+ 222,234, 10,241,247,246,131, 77, 14, 34, 73, 31,200,181,183, 45,
+ 219, 68,136,213, 27, 14, 26, 73, 63,222,156,187,182, 76,104, 79,
+ 229,249,194, 48,162, 1, 56, 3,149,255,146,218,216,112,173, 16,
+ 171,117, 14, 18,209,112,165,168, 55,217, 50,237, 47, 75, 61,157,
+ 145,122,123,199,193, 34,233, 3,185, 70,206,145,123,207,150,233,
+ 167, 34, 21,194,184, 23, 12,108,169, 38,142,165,142, 44, 73, 69,
+ 159,151,135,252, 72,156,224, 37,201,175, 67, 82,223, 46,165, 62,
+ 174, 97, 75,228,250,133, 19,159,191, 33,252,192, 7, 54,154,125,
+ 224,133, 83, 28, 0,129, 8, 81, 1, 2,238,206,101, 83, 90,254,
+ 79,186, 95, 0, 0, 0,255,255, 3, 0,243,175,157,107, 47,151,
+ 202,243, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_arrow_left_png[4122] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 47, 0, 0, 0, 87, 16, 6, 0, 0, 0,196,198,192,
+ 67, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 5,
+ 69, 73, 68, 65, 84,120,218,236, 93, 61, 76, 20, 65, 20, 62, 47,
+ 52,136,216,144, 0, 49, 88, 32, 8,141,198, 43, 5,172, 60, 67,
+ 37,137,132,228,108,136,208, 25, 40, 1, 41,140, 9,168, 9, 5,
+ 63,150, 98, 9, 66, 35,137,129, 4, 42, 5, 59, 14, 74,136, 54,
+ 30,160,197, 17,140, 38, 52,138, 71,107, 49,243,173,238,122,199,
+ 238,236,205,223,238,204,215, 12,176,100,127,190,121,251,189,247,
+ 102,222,204,158,235,184,181,176,176,191,151, 48, 4, 53,157,164,
+ 77,127, 33,109,126,133,180, 91,215,100,223, 73, 69,188,137,110,
+ 153, 38,109,215, 51,250,123,143,251,120,161,145,180, 59,139,164,
+ 61,237,181,196,135, 66, 42, 69,218, 76, 19,181,240,106,122, 96,
+ 170,248,255,159,167,132,119,209,227, 75,210,238, 52, 25, 15,139,
+ 30,190, 72,218,129, 1,183,164, 4, 69,250, 17,105, 27,126, 88,
+ 226,139,162,146, 90,104, 95,150, 18, 78, 45,186,101,138,207,249,
+ 239, 55, 91,226,139, 74,200, 68, 55,105,219, 63, 10,122,131,166,
+ 220,215, 51,142,120, 88,118,166,217, 45, 33,208,100,209,128,143,
+ 48,134,120,104,243,240, 5,183,246,170,186,143,174, 75, 49, 39,
+ 30, 78,237,201, 50,105, 47,127,215,227,190,110,239,185,223,192,
+ 216,132,147,109,159, 72,219,191,172,167,228, 65,218, 50,215, 73,
+ 59, 31,117,139,119, 8,223,140,134,115,135, 51, 71,248, 26, 57,
+ 226,163, 70,184, 23,200,128, 35, 67,124,212, 9,247,134,155,120,
+ 30,109,137,135,211,140, 58,225,255, 89,254, 88,185, 78, 87, 16,
+ 241, 78, 88, 88,149,136, 37,240,124,119, 70, 53, 35,126, 96, 80,
+ 110,194,163, 58,220,100, 29, 27,226, 78, 60, 50, 77, 93,226,112,
+ 105,225,102,179, 34,226, 49,182,161, 42,211, 84,141,212, 13,214,
+ 112,179, 76,226,157,209,194,205,132, 5,147,229,151, 73,124,215,
+ 184, 25, 90, 30, 20,144, 88,255,112, 51, 36,241, 8, 19, 77,149,
+ 22, 95,203,111,244, 11, 55, 67, 18, 47,111,194, 32,218, 78,183,
+ 116,184,201, 72, 60,156, 7,175, 25,159,184,227,238, 88,169,112,
+ 147,145,120,126, 99, 21,102,161,127,219,251,151, 10, 70, 75,175,
+ 182, 36,134, 1, 20,162,229, 23,105,115, 35, 1, 45, 30, 5, 64,
+ 22,101, 90,254, 86, 64,139,135, 54, 33, 65,176, 40, 15, 78, 37,
+ 91, 83, 69,176,140,212,130, 13, 5, 90,145,150,163,225,246,225,
+ 138,251,120,126,200,135,248,244, 1,253,161,201,146,121, 22,178,
+ 116,106,112,131,134,217,135,126,163,178, 35, 21,103, 39, 72, 53,
+ 203,150,212,179,136, 94,163,153,251,241, 67,214, 51,148, 32,190,
+ 117,218, 90,122, 49,233,152,157,165, 18,210, 94,238, 25, 75, 68,
+ 53,169, 87,150,236, 68, 34,145,200,215,145,246,241, 50,194, 64,
+ 94,103, 78,158, 29,119,154, 78,248,204, 9,105,249,151,111, 39,
+ 139, 39, 74,166, 75,138, 56,194, 75, 16,223,250, 34, 26,196, 28,
+ 191, 19,115,126,104,184,248, 5, 10, 30,226, 27,238,105,110,137,
+ 191, 41,241,239,249,158,127,103,151,183,134, 51, 18,175,219,132,
+ 134,151,240,195, 90, 49,215, 89,218,151,253,100, 73, 61,157,170,
+ 44,194, 17,143,139,146, 46,230,168, 38,238,132, 3,187,131,170,
+ 158, 52,169, 71, 52, 35,155,112, 71,219,119, 20, 19,111, 26,225,
+ 57,229,115,197, 73,179, 8,119, 18,164, 90,195,136, 87, 77, 56,
+ 112, 90, 48,140,120, 36, 40,135,202, 45,206, 48,226, 81,105, 85,
+ 185,104,137,151, 10, 84, 90, 97, 85,159,185, 29,160,200,185,170,
+ 238,128,150, 19, 67,137, 87,221, 1, 13,223, 52, 33, 62, 95,111,
+ 86, 7, 96, 76, 74,222,166, 17, 37,136,151,183, 79,139, 94, 29,
+ 144,222, 87, 76,188,147, 88,212,153,213, 1,168, 23,146,239,228,
+ 61,196,203, 31,165, 83,219, 1,206, 70, 65,227,138,137,247, 22,
+ 222,104,219, 1,175, 57, 75,142,234,141,130, 62, 15,233, 29,253,
+ 162, 3, 68, 45,110,235,207,202,146, 30,175,198,215, 39,140, 6,
+ 58, 20, 29, 32,141,120, 68, 55,186, 56, 89, 85,128,211,237, 19,
+ 246, 6,148, 72,160,228, 77,250,234, 13,236,218, 1,223,194,190,
+ 144,152,145,248,108,214,146, 94, 76,130,176,145, 81,122, 84, 16,
+ 241, 24,182,213, 45,188, 84, 13,103, 37, 55,173, 41,157,232,113,
+ 119, 68,112, 73,242, 41,211, 70,189, 73,186,211,146, 94, 12,144,
+ 158, 12,253, 61, 67, 39,120,114,116, 31,204, 28,149, 40,204,120,
+ 97, 34,168,240,192,135,248,141, 43,148,120,203, 49, 19,156, 53,
+ 79, 37,142,175,165,124,136,135,212,228,182,221, 39,180, 8, 7,
+ 88,252,122, 85,192, 97, 97,235,108,249, 96,233, 43,194,246,128,
+ 196, 99,155,111,235,108,195, 1,121,209,223,237,210, 25, 39, 66,
+ 86,159, 90, 18, 67, 89,250,126,192,112,210, 90, 62, 31,160, 54,
+ 243,255,132, 52,228,212,223, 92,155, 37, 53,136, 19,197,226,180,
+ 192, 9,148, 31,208,131,136,243, 45,220,248,112,213, 79, 25,202,
+ 156,236,134,118, 21,122, 45,217,255, 18,189, 62, 25,114,200,128,
+ 245, 66,107,214,233, 18, 67, 60, 64,184, 40,152,120, 39,195,157,
+ 52, 91,122, 80,125, 28,188,236,155,115, 93,205, 92,187,153, 81,
+ 207, 27,230,106, 5,206,196,227, 21,123, 57,107,134,246, 35, 92,
+ 100, 47,194, 21, 84, 73,134, 27, 65,138, 28,215,112,113, 41,244,
+ 62, 62,130, 75,248,144,112,193,233,196, 45, 92, 12, 95, 8, 38,
+ 169,118, 18,206, 23,175,102,212,195,197,213,163,114,207, 36,185,
+ 104,117,190, 61,218, 29,192, 47, 99, 87, 84, 45,140, 14,136,138,
+ 4, 33, 92, 20,190,123,135, 44, 64,130,230, 58, 52,183,244,155,
+ 188,207,168,201, 71, 22,225,132,243,180,132, 14, 27,254,171, 94,
+ 226,191, 65,103,220,142,185, 87, 21,107,182,178, 27, 97,168,179,
+ 49,143,162,245,168, 8, 23, 87,199, 69, 93, 65,211, 79,206, 33,
+ 76,155,249, 73, 90,217, 99, 65,184,158,180,253,106,116, 5,194,
+ 183,231,221, 98,223, 4, 76,209,109, 76,138,126,162,136,125, 86,
+ 20, 82,132, 55, 1, 78,153,215,208,132,188,237, 83, 34,254, 33,
+ 93, 56,101,248, 4, 72, 4,107, 71, 40,223, 40, 40,170,128, 22,
+ 67,146,188, 29,225, 55, 90, 42,127,163,160,152,126, 44,221,233,
+ 8,248,136,183,164, 77,209,132,173,141, 38,112, 88, 1,115,124,
+ 36,251, 14,255, 12, 0,112,186,137,242,235,201, 20,157, 0, 0,
+ 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_arrow_right_png[4147] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 47, 0, 0, 0, 87, 16, 6, 0, 0, 0,196,198,192,
+ 67, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 5,
+ 94, 73, 68, 65, 84,120,218,236,157, 59, 76, 20, 65, 24,199,199,
+ 11,141,248,104, 72,208, 24, 40, 4, 61, 26,141,103, 39,167,149,
+ 24, 43, 72, 32, 38,216,144,120,157,129, 22,206,194,168,128, 38,
+ 22, 60, 44,197, 18,149, 70, 18,131, 9, 84, 42,118,128,229, 33,
+ 52,242,178,128, 96, 48,161, 81, 30,173,197,204,127,143,221,123,
+ 176,183, 59,175,221,153,175,249, 2, 7,251,248,125,179,223, 99,
+ 118,230,187, 19, 55,111,189,127,191,182, 74, 20, 73,243, 50,213,
+ 245,237, 84,207, 54, 80,189,251,153,196, 92,170,212,156,246,228,
+ 4,213,157, 23,169,174,206, 82,221,194, 62, 95,249, 78,245,244,
+ 51,246,115,159, 5,207, 69,218, 6, 24,240,253,226,159, 39,135,
+ 169,238,101, 63,239,222,163,122,114,157,234, 92, 46,234,224, 19,
+ 114, 79, 87,115,151,141,236,108,176,255,235,238,102, 6, 57,203,
+ 12, 52, 98,193,251,146,204,119, 62,199,113,158,136, 51, 84, 63,
+ 152,119,187, 48, 11,158, 73, 42,229, 6,198, 91,210, 75, 84,191,
+ 236,112,159,207,120,240,157,141,114,206, 83, 61,225,118, 73,157,
+ 151,116,125, 18, 4,131,111,187,224,246,209,178, 5,177,164,247,
+ 180,218,235,144, 6, 30, 35,236,246,170, 30,183, 89,191, 67,245,
+ 147, 41,170,235,254,196, 20,124,103,131,251,209,215, 69,112, 61,
+ 79,167,220, 5, 92,228,193, 35,189, 67,176,211, 93, 50,115,170,
+ 12,192, 25,124,219,243,104,102,213,242, 13,192,169,114,197, 5,
+ 39,231,162, 93, 79,194, 0,132,221,207,194, 21, 77, 71, 60,130,
+ 104, 91, 63,137,149,192, 0,226,130,112, 72,240,119, 30,233,150,
+ 166,241,149,222, 83,162,238, 47, 32,120, 92,136, 46,233,162,240,
+ 130,172, 71, 19,240,168, 8,171, 39,136, 17,130, 58, 0,247, 45,
+ 29, 60,210,197,212, 53, 98,164,160, 18, 14, 63, 23,148, 8, 54,
+ 210, 77,151, 7,115,238,228, 66, 24,120,231, 21,221,142,133,126,
+ 212,197,226,133, 14,119,240,222, 87,116, 86,138,187,158,202,211,
+ 206,132,191,116,209,148, 32, 26, 84,238, 95,226, 4, 30,233, 98,
+ 107,191,133,234, 43,233, 24,118, 39, 31,129,193,243,122, 69,103,
+ 154,248,159,171,170, 42,158, 46, 38,207, 88,136,161, 70,254, 63,
+ 170, 75, 47, 75,241,140,248,204,130,133,199, 37,232,110,248,116,
+ 53, 45, 49,159,115,145, 45, 40, 48, 75,243,100,224, 55,107,169,
+ 158, 25,116,235,220, 34,213, 7, 93, 22,102, 16, 73, 47, 31,227,
+ 227,225,139, 86,188,159,191,118,107,228,171, 45,107,236,192, 75,
+ 22,110,217,194,179,153,234,233,143, 33,167, 12,182,216,147,241,
+ 54, 77,245, 99,118,192,249,171, 22,114,185,180,188,176,192, 10,
+ 57, 31,143, 85,189, 48,196,232, 63,235,154,138, 73,211, 8,103,
+ 240, 94,129,203,122,204,222,226,111,158,179,208, 9, 33, 36,245,
+ 70, 48,120,200, 33, 27,241,163,123,214, 0, 71,243,123,225,224,
+ 75, 25,192,116, 23,148,159, 82,144,180,118, 18, 6, 24, 27, 19,
+ 115,124,196, 26,221, 13,219,244, 74, 50,120,111, 12,224,157, 5,
+ 237,126, 97, 79,214,190,222, 6,168,107, 87, 4, 30, 50, 51, 32,
+ 230,184, 72,119,117, 53, 64,126,122, 93, 17,120,184, 6, 81,249,
+ 191,174, 6,200, 7,217,132,218, 11, 89,236, 17,123,124,125,159,
+ 0,197,224,101,109, 34,211,205, 0,201,145,132, 30,246, 95,201,
+ 154,102, 0, 77,192, 99,118, 84,150,168, 55,128, 38,224, 15, 15,
+ 212,156, 87,157, 1, 52, 1,175, 90, 96, 0, 81, 5, 94,161, 84,
+ 89,232,132, 28, 89, 63,196, 54,169,145, 29, 59,226,165, 0,199,
+ 174, 64,121, 43,229, 52, 1,159,220, 51, 5,184,102,224,235,126,
+ 155, 2, 92, 19,240,120, 37, 38,122,137,160, 62,192, 89,250,124,
+ 94, 49,120,188, 52, 55, 5,184,147, 62,119, 41, 2, 15, 32,162,
+ 54, 56,232, 10, 60,255, 38, 78, 81, 58,233,172, 66,222, 55, 3,
+ 56, 36,223,242, 75, 50,120,248,244,214, 41,206,192,223, 49,224,
+ 68, 79,224, 78,161,246, 73, 50,120,140,196,204,188,152,227, 71,
+ 101,167,138, 51, 39,181, 45,201,199, 3,184,233, 91,121,126,246,
+ 9, 30,241, 78, 9,206,186,120,164, 12, 95,234,135,160,122,216,
+ 46, 8,188,211,180, 13,193,205,174,173, 36,132, 20, 91, 39,207,
+ 201,213, 96,153, 55, 26,241,216,221,129,110,153, 47,136,109, 21,
+ 142,120,184,144,244, 15, 6,156,245,129,172, 65,207, 49,187, 73,
+ 173,104,250,184,245,176, 4,120,167,116,127,231, 46,225,235,217,
+ 239, 49,137,149, 68,222,221,232,209, 86,138, 10,246, 23, 20, 10,
+ 3,127, 61,197,242,107,236,242,235,182,208,120, 8,122, 37,147,
+ 181, 18, 62,254,235, 16,213,118,121, 53,167, 96,154,245, 86,170,
+ 37,192, 99,109,227,228, 47, 11, 77, 76, 48, 61, 38,171, 65, 43,
+ 40, 89,203, 45,226, 26, 76,143,111,169, 85, 34,157, 68,251,112,
+ 43,149,201,244,160,223,191, 76,148, 79,248,237,222, 38,222, 35,
+ 221,103, 1,133, 85,189, 54,232,150,151,241,230, 74,255, 35,225,
+ 207,146,223, 46, 91,184,229,242,244,202,191,209,193,231,148, 1,
+ 210,205,248,127,119,135, 63,129, 7,152, 12,252,234,210, 39,120,
+ 39,221, 92,183,208, 9,201,239,124, 15, 62, 16, 43,156, 36,195,
+ 178,106, 83,211, 77,184,150,217,161,176, 71, 10, 56, 59,249, 97,
+ 205, 44,224, 24,217,227,105, 94, 71, 12, 8, 30,139, 60, 77, 73,
+ 55, 95,143,185, 93,174, 50,240,144,201,141,120,167,155,227, 55,
+ 221, 3,141,159,132, 4,143, 17, 16,183,116, 19, 73,132,182,221,
+ 180,157, 82,121, 59, 30,233, 38, 92,103,248,224, 41, 9,124,240,
+ 10, 78, 47,224,111,211,178,206, 40,168,123, 71, 84,210, 77,228,
+ 227,242,128, 11, 2,239,140,252, 27,209, 8,154,112,145,242, 69,
+ 16,120,248,250,217, 97, 61, 64, 35,235, 66, 35, 35,113, 65, 83,
+ 49,120, 39,232, 14,168, 77, 55,225,242,208,184, 72,159,175, 39,
+ 149,212,175,102,102, 80,238,109,225,124,163,127,121, 23, 62, 17,
+ 1, 15, 65,122, 38,170, 83, 19, 70,246,139, 14,213,190, 91, 51,
+ 240, 78, 97,194,105,142, 7,174, 11, 65, 18, 35,123,171,150, 68,
+ 68, 36,175,143,135,143,205,177,174, 29,126,119,132, 28,120, 42,
+ 228,175,167,116,117, 33,154,130,247,142,252, 82,224,157,119,152,
+ 11, 30,208,112, 33,145,159, 27, 82, 4, 30, 96,103, 88, 11, 88,
+ 180,140, 90, 96,235, 81, 10,218,169,196,110, 18,238,255, 0, 9,
+ 225,144,193,153,103,176,249, 0, 0, 0, 0, 73, 69, 78, 68,174,
+ 66, 96,130
+};
+
+static const unsigned char _data_arrow_up_png[3493] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 98, 0, 0, 0, 31, 16, 6, 0, 0, 0, 76,137,196,
+ 82, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 2,
+ 208, 73, 68, 65, 84,120,218,236,156,189, 79,219, 80, 20,197, 93,
+ 43, 75, 17,116,161,130,165,153,160,233, 2,123, 9, 48, 85,160,
+ 142,176, 91, 85,214,238,237, 86,137, 34,161, 14, 41,255, 0, 27,
+ 66, 89,200, 2, 18, 12,136,143, 46,109,194,154, 74, 93, 26, 1,
+ 75,171, 74, 84,101, 65, 5, 70, 51,188,123, 2, 54,114, 18,219,
+ 239,197, 78,114,126,203,145,162,248, 35,215,231,216,126,247,217,
+ 121,228,186,174,235,186,150, 53, 51, 91, 42,157,158, 88,154,121,
+ 246, 87,233,192,134,247,243,225,215, 74,159,206, 91,132, 4,242,
+ 111, 95,233,197,158,247,243,235, 55, 74,127,143,232,218,210,183,
+ 175,142, 51, 54,110, 89,153,112,139, 61, 46, 41,125,177,170, 52,
+ 43,134,207,253, 23,163,207,137,194,232, 91,162, 67,190, 21, 85,
+ 68,151,120,208, 73, 19, 42, 1,254,129,175,214, 36, 48, 8,206,
+ 129,210,250,160,210, 95, 18,152,159,239,148,222, 56,173, 54,152,
+ 105,126,102,207,231,197,240, 8,192,185,124,225, 45,143, 21, 73,
+ 15, 56, 1, 67,115,254, 47, 92, 73, 64,182, 37, 48, 18,144,106,
+ 213,127,165,241, 5,226,131, 44,144, 69, 2,223,139,158,179,232,
+ 164,251,193, 9, 61, 43,190,126,181,229, 13,202,202,130,237, 93,
+ 224,104,156, 69, 35,253,199,157,239,125,129, 56,158,144,196,140,
+ 178, 72,164,247,129,207,225,251, 7,129, 0,229, 19, 22,139,244,
+ 62, 15,125, 30, 16, 8, 12, 58,106,223, 89, 52,210,123,192,215,
+ 240,121,203, 64,248, 19,116,237,176,136,164,251,129,143,131,239,
+ 128, 90, 4, 2,253,221, 47,207, 89, 76,210,253,192,199,240,117,
+ 232, 64,128,195, 98,171, 21, 17,146, 94,224, 91,248, 56,152, 54,
+ 3,129, 25,190,157,101, 22,215, 4,235,211, 94, 37,122,129,111,
+ 35,207, 84, 7,129,246, 84,254,137,210,220,103, 22, 91, 71, 16,
+ 238,218,126,194, 15, 37,133, 10,107, 20,135,186, 76,192, 29, 95,
+ 182,187,132, 29,109, 67,155,108,203,154, 9,130,239,196,195, 43,
+ 70, 60,194,251, 52, 98, 32,240,236, 71,117,146, 69,215, 25, 4,
+ 6, 67, 15,240,101,248,167, 97,237,120, 27, 46,159, 41,101, 91,
+ 86,111, 16, 24,140,104, 52,218,170,103, 81,215, 16, 51, 16, 24,
+ 164,176, 45,107, 38, 8, 12, 70, 56,224,195, 27, 39,161, 64, 52,
+ 70,241,127,148,178, 45,107, 38, 8, 12, 70,115,224, 59,248, 48,
+ 58,182,222, 29, 43,159, 50, 8, 38,131,192, 96,152,246,157,230,
+ 64,212,106, 74,209,238, 98, 16, 24, 12,147,192,103,240, 93,124,
+ 50,134, 12,242, 82,233,167, 62, 57, 48,152, 47, 40,172, 37,188,
+ 35,125, 54,111, 1,159, 89,218,110,213,109, 51, 59,138,123,186,
+ 35, 78,220, 17, 3,192, 87,250,199,172,182,217, 29,223,249,168,
+ 148,109, 89,162, 3,248, 8,190,210,143,225, 64,160,253,181,203,
+ 103,160,136, 6,118,219,126, 38, 41,165,129,104, 92,226,248,180,
+ 44,209,113, 11, 94, 52,189, 37,187,179, 63,108,125,138, 7,151,
+ 164,217, 55, 29, 14, 4, 95, 77, 37, 97, 8,126,213,179, 71, 2,
+ 1,248, 39, 6, 36,157, 62, 73, 40, 16,184, 39,228, 96,155, 52,
+ 27, 60,119,126,204,105, 39,251,195,241, 74, 31,219,178,228,190,
+ 15, 14,139, 73,237, 65, 38,217, 2,160,125,182,226,251,111, 78,
+ 210,159, 92, 44,138, 47, 18,235, 70,222, 2, 0, 0,255,255, 3,
+ 0,166,247,214, 91, 44,122,150,205, 0, 0, 0, 0, 73, 69, 78,
+ 68,174, 66, 96,130
+};
+
+static const unsigned char _data_back_png[3564] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 23, 73, 68, 65, 84,120,218,236,155, 59,108, 19, 65, 16,134, 23,
+ 43, 13, 78, 66, 67, 20, 40,156, 34,194,144, 6,228,107, 19, 83,
+ 97,100,165,177,196, 67, 10,141, 37,232, 34,187, 4, 76,129, 16,
+ 226,209,133,164,141, 41, 19,146, 42,141,145,160, 66, 28, 93, 28,
+ 74, 35,165,193, 9,105, 28,129,176,148, 6,129,211, 82,236,252,
+ 129, 59,251,228,123,236,173,207,246,252,205, 40,241,227,124,223,
+ 206,254, 59,123,119,115, 42,125,117, 99, 99,127, 79, 68, 92,151,
+ 150,189,189,191,113, 94,198,227,124,212,206,100,164,183,135, 63,
+ 189, 41,163, 97, 16,216, 95, 50,206,172,200,120, 54,235,243,139,
+ 255,200,208,162, 88, 47, 81, 28,147,177, 86,147,241,232,195,128,
+ 3, 71,166,102, 14, 8, 52, 1, 17,219,182, 55,102,213, 28, 47,
+ 142, 1, 77, 81,164,255, 47, 92,160, 1,248, 44, 99,181, 42,227,
+ 206,229, 62, 7, 14,192,185, 23,244,247, 56,189,144,138,136, 85,
+ 189,162, 72, 3,158,187, 45,227,214, 55,235, 76, 80,167, 88, 56,
+ 22,177,144,148,241,193,184,245,196,162, 46, 88, 88,161, 64,191,
+ 255, 76, 64,107, 11, 11,120,162, 73, 63,144, 60, 50, 83, 18, 3,
+ 33, 36,202,147,138,117,173,233, 25,240, 19,208,163, 50, 78,253,
+ 20, 3, 41,172, 5,200,252,217, 93,205, 30,142,145, 46, 84,196,
+ 80,234, 30, 22,249, 93,175,139,109,204, 95, 70,223,221, 22,172,
+ 255,192,187,207,120,151,192,177, 24,194, 58, 48,197, 88, 86,240,
+ 72,200,192,192,139, 69, 6,237,138, 83,193,154,160,158,129, 99,
+ 170,244, 75, 89, 23,149,178, 50,247,204, 35,240,147,122,122,154,
+ 33,250, 17,202,226,118,139,113, 0,126,253, 17, 91,136, 10,221,
+ 73,186, 4,126,109,143, 97,169,220, 56,253,219,169,198, 58,123,
+ 54,103,182, 98,139, 57,112, 0,110,172, 50,156, 48,100,164, 28,
+ 128,115, 53, 18,110,245,146,104, 18,112, 92, 70,101, 43, 9, 87,
+ 51,203, 4,124,170,201, 48,116, 40,113, 35,198,153,173, 83, 19,
+ 243,176,148,223, 12, 67, 75,134,255,136, 49, 4,157,138,111, 50,
+ 112,205, 98,224, 12,124, 40,128, 55, 38, 25,133, 14,213, 75, 4,
+ 252,232, 22,195,208,161, 86,158, 51, 92,171, 14,223, 18,240,250,
+ 67,134,161, 67, 95,239,219, 30,147,168,125,145,209, 72, 49, 28,
+ 181, 86, 66,137, 61,106,171, 82,106, 69,134, 19,134,144,200,109,
+ 101, 33, 30, 94,108,229, 25,146, 74,153, 73, 7,224,120,128,253,
+ 211, 69,134,164,166, 12,164,197,114,178,203,198,231,227, 18,103,
+ 186, 10,189,123,234,114,167,137, 76,127,255,156,161, 5,241,236,
+ 246,234,175,203,214,222,164, 76,111,156, 99,136, 94,170,145,181,
+ 185, 46, 91,251,110, 42,175,178,197,184,209,122,218,234, 16,190,
+ 129,163,249,168, 92,102,168,157, 4,235,237,222,162,226,241,106,
+ 33, 60,105, 45,205,144,133, 16,162,122,133, 22,199,239,110, 63,
+ 225,243,242, 44, 30, 64, 31, 86,240, 38, 61, 78,178, 62,231,245,
+ 147, 1,175,135, 3,252,203,155,195,225,241, 72,176,173,125,191,
+ 223,160,232, 6, 4, 10,251,199, 21,251, 86,182,191,133,234, 12,
+ 9, 21,188,143, 83,113,159, 38, 86,103,172,173,232, 5, 66, 35,
+ 170,186,246,187,112,203, 58, 44,130,230,162,234, 35,132,220, 24,
+ 139, 85, 27,113,150, 78, 36, 67, 83,178,215, 93,111,168,190, 76,
+ 74,136, 42,205,208,227,165,176,142,168,185,245, 27, 83,114, 71,
+ 88, 51, 30, 51,193,120, 45,163,234,103, 28, 97, 13,168,178,208,
+ 234,125,184,168,123,136, 71, 34,146, 97,136,120,129, 64,160,131,
+ 32,254,134, 6,104, 94,198,137,108,103, 43,176,223,185,114,188,
+ 177,210,179, 59, 92,127, 7, 0,162,170,196, 84,182,147,226,216,
+ 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_end_png[3562] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 21, 73, 68, 65, 84,120,218,236,156, 61, 72, 91, 81, 20,199, 95,
+ 31, 89,140,208, 69,209, 82,226,208,150,218,197,162, 99,243,236,
+ 166,136,131, 1, 69,112, 10,146,173,152,177,126, 76,173, 70, 40,
+ 29,172,174,149,110, 17, 51, 9,146,130, 29, 74, 81, 55,147,142,
+ 79,236,162,141,237,160,180, 24,234, 98, 75,178, 58,220,115,132,
+ 119,227,235,251,186,247,230, 37, 57,255,229,228,227,230, 37,249,
+ 221,115,207, 61,231,230,222,220, 25,124,190,185, 89,250,174,133,
+ 92, 29, 35, 86,107,167,202, 52,179,231, 93, 97,253, 38,145,112,
+ 124,140,129, 1,102,123,255,129, 93,101,182,231,194,227,133,242,
+ 96, 63, 48,115,214, 13, 22, 58,224,228, 46,179,166,201,108, 53,
+ 217,228,192, 99,101,102,135, 74, 0,186,159,217,104,142,107,120,
+ 33,230,253,176,195,208, 26,220,243,102,154,217,189,135,208, 33,
+ 115, 13, 14, 28, 67, 64,234, 43,120,110,158,107,112, 84,231,145,
+ 5, 29, 14, 3,236,102, 4,236, 44,202,234, 0, 73,192, 19,247,
+ 153, 29,155,132, 7, 38,181,134, 80,239, 59,102,103,185, 17,144,
+ 53, 68,133,160,136, 88, 79,158, 73,251,140,189, 33, 21,142,128,
+ 183, 19,204,174,149,131, 78,202,186,152,152,252, 42,223, 92,160,
+ 121,225, 28,243, 26,190,103,252,155, 98,224, 8,122,182,221,102,
+ 210,107,114,165, 14,252,130,215, 9,180, 90,240, 46,129,183, 1,
+ 216,244, 12,129,190, 77, 83, 15,172, 14, 25, 24,120,170,224,174,
+ 210,107, 85, 69, 57,135,108,203,249, 4,142, 21, 32,206,214, 36,
+ 119,217, 90, 34,227, 17, 56,246,208,212, 35,130,232, 71, 67,243,
+ 118, 17,193, 6,248,240, 2,133, 16, 17, 26,203,184, 4, 30,143,
+ 19, 44, 17, 50,142,120,199,213,111,143,217,228,217,130, 67,204,
+ 15, 27,224,253,239, 9,142,204, 37,130, 90, 15,167,108, 68,106,
+ 246, 18, 43,235,214,132,157, 10, 26,185,122,178,170,227, 13,130,
+ 161, 66,177,113,157, 60, 91,165, 58, 71, 1, 56,254,150, 72,146,
+ 236,225,191,117,130,160, 82,209, 28, 1, 87, 44, 2, 78,192, 91,
+ 2,248, 89, 23,161, 80,161,147,121, 0, 94,173, 16, 12, 21,170,
+ 36, 1,248,241, 75,130,161, 66,231, 31, 1,184,252, 45, 94, 36,
+ 230,216,220, 70, 32,243,144, 89, 90,196, 18, 29, 74,192,177,219,
+ 185, 44, 5,183,118,145,196, 10, 29,185, 38, 45,196,109,188,149,
+ 36, 65, 18,169, 98, 1,111,113, 33, 5, 55, 43,154,208,192, 32,
+ 86, 1,211, 64,176, 87, 14,133,207,167, 12,121,186, 8,225,182,
+ 103,199, 74,243,242, 11,179,251,143, 9, 90, 32,207,158,243, 88,
+ 218,239,252,130, 74,180,155, 32,122,201, 70,178,207, 28, 74,123,
+ 39,225,134,116, 10, 49,255,215,214, 79,107,132,240, 13, 28, 55,
+ 160,227, 5, 73, 86,237,193,201,137, 98,159, 83, 75,143,171,133,
+ 120,193,236, 32, 65,214, 52, 77, 43, 60, 5, 71, 44,185,125,133,
+ 207,229,217, 86, 7,143,160, 55, 60,231,205, 1,215,195, 17,252,
+ 250,122,107,196,248,173, 83,191,160, 5, 1,231, 43,212, 55, 19,
+ 214,180,168,209,133,147,223,218, 95,136,213, 43, 65,175, 24,145,
+ 244, 1,225,126, 28, 66, 78, 98,137,217,176,239, 89,196, 17,138,
+ 245,199,238,138,181, 2, 15, 46,201, 7, 99, 49,228, 20,177, 3,
+ 150,195,213, 1, 53,128,225,236, 82, 21,234, 15, 77,120,136, 84,
+ 124,244,155,239,128, 24,196,126, 3, 98,162,239, 51,246, 46, 71,
+ 222, 49,156,120, 61,132, 85, 81,243, 5,215, 80,250, 28, 84,231,
+ 63, 55,184,201,239,241,129,113,235,243,216, 1,184, 51,172,199,
+ 225,208,210, 31, 0,123,249, 25, 42,228,123,224,177,219,208, 96,
+ 187,222, 65,235,122, 0,217,217,201, 30, 62,205,111,211, 0, 0,
+ 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_home_png[3578] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 37, 73, 68, 65, 84,120,218,236,155, 61,108, 19, 49, 20,199,143,
+ 136, 5, 10, 12,128,130,144,154, 1, 40, 97, 41, 52, 43, 41, 19,
+ 65,136, 1,164, 10,164,176, 68,148, 13,114,107, 10, 27, 95, 18,
+ 83, 18,214, 68,108,169,218, 41, 75,145,202,128, 42,194,150,118,
+ 228, 16, 44,164,133,165, 21, 31, 17,217, 10, 93, 25,252, 94, 42,
+ 91,181,236,107,206,190, 75,238,253,151,167,228, 46,185,228,231,
+ 231,191,159,239,236, 3,211, 87, 22, 22, 54,214,157,136,234,208,
+ 34,139,169, 95,254, 62,215,153,139,234, 63, 58, 24,238,229, 79,
+ 92,103, 49,147, 97, 49,189, 13,177,194,226, 97, 0,238, 28,245,
+ 249,197,175, 89,232,173,176,248,181, 4, 13,113,140, 69,207, 99,
+ 113,167, 48,226,192, 47,127, 97, 49,155, 5,176,119, 36, 39, 46,
+ 6,219,160,217,207, 16,133,227,158,203, 98,235,172,173,158, 97,
+ 24, 56,102,110,254, 28, 0,104,195,129, 74, 52, 58,120,102, 10,
+ 162,195,247,128,229,167,166, 26, 32, 97,198, 34, 74,240,195,139,
+ 69,254,253,168, 11,173,172, 4, 22,150,159,224,199,146,200,100,
+ 56,102,242,236,146,224,189, 67,174,220, 35,104,136, 35, 44, 54,
+ 186, 44,110, 37, 67,202,112,244,100,204,228, 81, 1, 45, 42,245,
+ 27, 50,127,140,197,241,174,101,224, 8,250,126,219,137,149, 48,
+ 161,158, 44,241, 61,219, 24,240,184,130,150,105,182,237, 55,227,
+ 53,129,227, 23, 18,232,189, 51, 30,173, 70, 61,184, 38,244,102,
+ 122,110,145,224,234,128,119,221, 1,129,223,122, 62, 92,101, 93,
+ 84,202, 74,180, 94,109,224,104, 33, 88, 22,145,252, 41,127, 70,
+ 102, 49, 18,224,119, 39, 8, 90, 16, 22,115,237,177, 2, 56, 90,
+ 71,186, 66,208,130,208,213,117, 5,240,220,119,130,100, 34,211,
+ 119, 61, 93, 0,142, 55,115, 72,193, 42, 83, 19,128,227, 32, 73,
+ 213,136, 33,224, 83, 2,240, 11, 85,130, 98,165,108,172, 98,134,
+ 207, 16, 12, 27, 74,117, 1,248,201, 27, 4,195,206, 32,138, 25,
+ 254,147, 96, 88,177,148,237, 4, 95,190,144, 76, 43, 65, 8, 8,
+ 120, 28,128,255, 43, 16, 10,171,192,183, 78, 19, 10, 27,218, 76,
+ 82,134, 91, 85,239, 54,102,248, 27,130, 97, 53,195, 63,122, 4,
+ 195,134, 58,115,152,225, 73,178, 22,147,242, 62, 73,202,194,221,
+ 3,164, 64,129,187, 18,224, 45,122,180, 22,168,208, 49,188,190,
+ 101, 11,107, 11,209, 90,112, 21, 41, 61,106, 27, 76, 31,206,179,
+ 184,243, 67, 49,211,196,229,186,164,193, 50,251,125, 89,115,106,
+ 143,235,162,201,211,247,167,183, 47, 32,179, 11,154,192, 81,141,
+ 44, 85, 47,190,234,236, 83, 48, 22,150, 21, 83,123,153,176,133,
+ 230,167, 9,166,142,133,212,107,170, 51, 53,239, 22,226, 40,139,
+ 93,133,196,171, 94,135,169,251,138,234, 76,159, 59, 32,150, 97,
+ 180, 61,126,145, 69,220,172, 20, 87, 53,160,231,119, 38,117, 63,
+ 177,207,251,225,243,224,237,173, 74,188, 65,175, 77,250,253,228,
+ 128,123,124,154, 27, 48, 88,192, 15, 24,213,245,227,232,209,175,
+ 254,242,243, 21,255, 10,104, 83, 21,182,244, 38, 46,220, 95,101,
+ 17,247,198, 12,237,148, 28,202,226,198,152,172,204, 11, 9,184,
+ 56, 83,125, 9,175,115,176,122,244,230, 51, 22,163,254,176, 26,
+ 7,189,230, 55, 97, 74, 94, 11,234, 10,134, 55,198, 98, 61,186,
+ 122, 9, 6, 89,248, 35, 57,136, 97, 47,173,235,215,205,112, 15,
+ 105,237,129,233, 43, 90,218,250,141, 93,177,229,240,113, 28,202,
+ 169,254, 86,240,170, 25, 43,234,192,198, 2,239, 33,159,185,234,
+ 50,110, 72,129,171, 44,168,137,111,204,240,199,211,194,154,199,
+ 84,119,111,107,250, 3,224,122,239, 96,144,187, 39, 25,220,202,
+ 97,155,214,255, 1, 0,168,120,199,110, 67,179,158,126, 0, 0,
+ 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_key_png[2857] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 35, 0, 0, 0, 34, 16, 6, 0, 0, 0,133, 21,188,
+ 191, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 0,
+ 84, 73, 68, 65, 84,120,218,236,208, 49, 1, 0, 16, 16, 0, 64,
+ 212,250,112,212, 48,107, 32,207, 23,177,153,101,112, 23,225,106,
+ 236,117,114,142, 94,120, 52, 5, 98,196,136, 17, 35, 70,140, 24,
+ 49, 98,196,136, 65,140, 24, 49, 98,196,136, 17, 35, 70,140, 24,
+ 49,136, 17, 35, 70,140, 24, 49, 98,196,136, 17,243,159, 11, 0,
+ 0,255,255, 3, 0, 56,171, 5, 65,131,211,234, 11, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_layout[7714] = {
+ 112, 97,114,116,115, 32,123, 10, 32, 32, 32, 32,100,101,118,105,
+ 99,101, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 97, 99,
+ 107,103,114,111,117,110,100, 32,123, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32, 32,100,101,
+ 118,105, 99,101, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32,100,105,115,112,108,
+ 97,121, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,119,105,100,116,104, 32, 32, 32, 51, 50, 48, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,104,101,105,103,104,116, 32,
+ 32, 52, 56, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,120, 32, 32, 32, 32, 32, 32, 32, 51, 49, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 32, 32, 32, 32, 32, 32,
+ 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 98,117,116,116,111,110,115, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,115,111,102,116,
+ 45,108,101,102,116, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32,109,101,110,117, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120,
+ 32, 49, 52, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 53, 53, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,104,111,109,101, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32,104,111,109,101, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 52, 56, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 53, 57, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 98, 97, 99,107, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 98, 97, 99,107, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 50, 56, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 57, 48, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,100,112, 97,100, 45,117,112, 32,
+ 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 97,114,114,111,
+ 119, 95,117,112, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49,
+ 52, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 57, 53, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,100,112, 97,100, 45,100,111,119,110,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 97,114,114,
+ 111,119, 95,100,111,119,110, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 49, 52, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 54, 53, 54, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,100,112, 97,100, 45,108,
+ 101,102,116, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32,
+ 97,114,114,111,119, 95,108,101,102,116, 46,112,110,103, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53,
+ 57, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,100,112, 97,
+ 100, 45,114,105,103,104,116, 32,123, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109,
+ 97,103,101, 32, 97,114,114,111,119, 95,114,105,103,104,116, 46,
+ 112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 50, 50, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,121, 32, 53, 57, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,100,112, 97,100, 45, 99,101,110,116,101,114, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32,115,101,108,101, 99,116,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 52, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,121, 32, 54, 50, 54, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,112,104,111,110,101, 45,100,105, 97,108, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32,115,101,110,100, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 52, 56, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 54, 52, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 112,104,111,110,101, 45,104, 97,110,103,117,112, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32,101,110,100, 46,112,110,103,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 50, 56, 54, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121,
+ 32, 54, 52, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 112,111,119,101,114, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32,112,111,119,101,114, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 45, 51, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,118,111,108,117,109,101,
+ 45,117,112, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32,
+ 118,111,108,117,109,101, 95,117,112, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 51, 54, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 50, 54,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,118,111,108,
+ 117,109,101, 45,100,111,119,110, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32,118,111,108,117,109,101, 95,100,111,119,110,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 51, 54, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,121, 32, 51, 49, 48, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32,125, 10, 10, 32, 32, 32, 32,107,101,121, 98,
+ 111, 97,114,100, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98,
+ 97, 99,107,103,114,111,117,110,100, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32, 32,
+ 107,101,121, 98,111, 97,114,100, 46,112,110,103, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98,
+ 117,116,116,111,110,115, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 49, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,
+ 107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 48, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 32,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 50, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120,
+ 32, 51, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 51, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 55, 52, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 52, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 49, 49,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 53,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 49, 52, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 54, 32,123, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32,
+ 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 56, 53, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121,
+ 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 55, 32,123,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 50, 50, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 56, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,
+ 101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 57, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 50, 57, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 48, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,113, 32,123, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109,
+ 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,121, 32, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,119, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 51, 55, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,101, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,
+ 103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 55, 52,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 114, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,116, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 52, 56,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 49, 56, 53, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,117, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 50, 50,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 105, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,111, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 57, 54,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 112, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 97, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,
+ 103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,115, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,
+ 112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,120, 32, 51, 55, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,100, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 55, 52, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,102,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 49, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,103, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 52, 56, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,104,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 49, 56, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,106, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 50, 50, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,107,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,108, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 57, 54, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 68,
+ 69, 76, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,
+ 112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 67, 65, 80, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120,
+ 32, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,122, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,
+ 107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 51, 55, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49,
+ 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,123,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 55, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 99, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,
+ 107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32,
+ 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,118, 32,
+ 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,120, 32, 49, 52, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 48, 56, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 98, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 56, 53, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 110, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 50, 50, 50, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 48, 56, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,109, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,
+ 103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 53,
+ 57, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 80, 69, 82, 73, 79, 68, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 57, 54, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 69, 78, 84, 69, 82, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,
+ 101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49,
+ 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 65, 76,
+ 84, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 32, 49, 52, 52, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 89, 77, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 51, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,121, 32, 49, 52, 52, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 65, 84, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,
+ 101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 55, 52, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 52,
+ 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 80, 65, 67,
+ 69, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,115,112, 97, 99,101,
+ 98, 97,114, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32,
+ 49, 52, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 76,
+ 65, 83, 72, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 52, 52,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 67, 79, 77, 77, 65,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 50, 57, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 52, 52, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 65, 76, 84, 50, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 51, 51, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 49, 52, 52, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32,125, 10,125, 10, 10,108, 97,121,111,
+ 117,116,115, 32,123, 10, 32, 32, 32, 32,112,111,114,116,114, 97,
+ 105,116, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,119,105,100,
+ 116,104, 32, 32, 32, 32, 32, 57, 48, 48, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32,104,101,105,103,104,116, 32, 32, 32, 32, 55, 51, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 99,111,108,111,114, 32, 32,
+ 32, 32, 32, 48,120,101, 48,101, 48,101, 48, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32,101,118,101,110,116, 32, 32, 32, 32, 32, 69, 86,
+ 95, 83, 87, 58, 48, 58, 49, 10, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32,112, 97,114,116, 49, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,110, 97,109,101, 32, 32, 32, 32,100,101,118,
+ 105, 99,101, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 32, 32, 32, 32, 32, 32, 52, 48, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,121, 32, 32, 32, 32, 32, 32, 32, 45,
+ 49, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32,112, 97,114,116, 50, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,110, 97,109,101, 32, 32, 32,
+ 32,107,101,121, 98,111, 97,114,100, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,120, 32, 32, 32, 32, 32, 32, 32, 52, 56,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32,
+ 32, 32, 32, 32, 32, 32, 50, 48, 48, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32,125, 10, 10, 32, 32, 32, 32,108,
+ 97,110,100,115, 99, 97,112,101, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32,119,105,100,116,104, 32, 32, 32, 32, 32, 57, 48, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32,104,101,105,103,104,116, 32,
+ 32, 32, 32, 54, 55, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 99,
+ 111,108,111,114, 32, 32, 32, 32, 32, 48,120,101, 48,101, 48,101,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,101,118,101,110,116, 32,
+ 32, 32, 32, 32, 69, 86, 95, 83, 87, 58, 48, 58, 48, 10, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32,112, 97,114,116, 49, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,110, 97,109,101, 32,
+ 32, 32, 32, 32, 32,100,101,118,105, 99,101, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 53, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 32, 32, 32, 32, 32, 32, 32, 32, 52, 52, 48, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,114,111,116, 97,116,
+ 105,111,110, 32, 32, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32,112, 97,114,116, 50, 32,123,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,110, 97,109,
+ 101, 32, 32, 32, 32, 32,107,101,121, 98,111, 97,114,100, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 32, 32,
+ 32, 32, 32, 32, 50, 53, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 32, 32, 32, 32, 32, 32, 32, 52, 55, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,125,
+ 10,125, 10, 10,107,101,121, 98,111, 97,114,100, 32,123, 10, 32,
+ 32, 32, 32, 99,104, 97,114,109, 97,112, 32,113,119,101,114,116,
+ 121, 50, 10,125, 10, 10,110,101,116,119,111,114,107, 32,123, 10,
+ 32, 32, 32, 32,115,112,101,101,100, 32, 32,102,117,108,108, 10,
+ 32, 32, 32, 32,100,101,108, 97,121, 32, 32,110,111,110,101, 10,
+ 125, 10
+};
+
+static const unsigned char _data_menu_png[3079] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 84, 0, 0, 0, 34, 16, 6, 0, 0, 0,145,128, 34,
+ 94, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 1,
+ 50, 73, 68, 65, 84,120,218,236,220,161, 78,195, 80, 20,128, 97,
+ 70, 48, 44, 72, 50, 5, 10,130, 6, 75,192,162,120,132, 62,193,
+ 44, 40, 12, 15, 64,176,224, 73, 61,104, 44, 4, 11,154, 48, 53,
+ 12, 36, 56,194,228, 69,220, 94,193, 72, 89, 41, 91, 90,146,239,
+ 51, 39, 89,167, 78,254,220,110,230,118, 66, 8, 33,132, 57,104,
+ 165,121, 43,160,205, 22,198, 63,216,217,205,243,193, 83,217,215,
+ 87, 94,227,220,218,180, 58,234,187,127,136,243,185, 55,254,228,
+ 246, 38,203,214,214,127, 8,244,171,197, 60,206,131,165, 56, 87,
+ 47,139, 7,199,150, 76,125,251, 69, 71,195,171, 56, 79,223,227,
+ 28,101,191,124,197,247,251, 69,152, 47,150,202,244,165,174, 82,
+ 103,149,127,131,166, 87,249,198,137, 37, 50,123,169,179,212,221,
+ 196, 64,187, 23,150, 70, 3, 39,106,213, 64,161, 9,203,123, 2,
+ 229, 95, 17, 40, 2, 5,129, 34, 80, 16, 40, 8, 20,129,130, 64,
+ 17, 40, 8, 20, 4,138, 64, 65,160, 8, 20, 4, 10, 2, 69,160,
+ 32, 80, 4, 10, 13,251,200, 4, 74,139, 13,123, 21, 3,125, 60,
+ 140,243,237,218,210,152,189,212, 89,234,174,242, 9,122,118, 94,
+ 118,244,194,244, 94,233,169,179,239, 38,220,205,148, 46,119, 58,
+ 42,238,104,218, 30,196,217,205, 45,151,191,135,121, 87,220,209,
+ 52, 42, 61, 0, 59,238, 7,197,191,120,168,233, 19, 0, 0,255,
+ 255, 3, 0, 6, 52, 60,111, 44, 61, 74,153, 0, 0, 0, 0, 73,
+ 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_power_png[3782] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 58, 0, 0, 0, 67, 16, 6, 0, 0, 0,157, 6,202,
+ 98, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 241, 73, 68, 65, 84,120,218,236, 93, 63, 76, 83, 65, 28, 46,196,
+ 5, 84, 22,140, 70, 3,139,104, 93, 76, 90,199, 86, 93,108, 36,
+ 14,152, 72, 76,152, 72, 96, 51,178, 22, 54, 19, 37, 49, 14, 10,
+ 107,113,172,166, 19,137,209,164, 14, 6,197, 77,234, 38, 68, 22,
+ 234, 31, 6,136, 9, 70, 28, 20,203, 88,135,187,175,205, 93,251,
+ 120,175,237, 81, 30,119,223,183,252,104, 31,247,238,253,238,235,
+ 239,254,126,247,174,163, 92, 46,151,203,229, 8, 97, 9,142,224,
+ 143, 43, 87,115,185,111, 95, 89, 32, 42,250,126, 10,123, 97, 70,
+ 216,238, 92,107,247, 43,141, 10,187, 54, 41,236,230,201,125, 35,
+ 212,109,244, 14, 10,155,250, 46,108, 98, 69, 35,112, 64,218,251,
+ 134, 50,124, 41, 9,254, 39,108, 33, 38,236,226, 89, 97,183, 23,
+ 72,104, 83,184,121, 70,216,161,219,218,133, 92,123,242,199, 15,
+ 38, 53, 37,173,252,254,245,170,176,249, 31, 36,116, 79,116,201,
+ 2, 76, 31, 19,182,127, 43,156,207, 57, 36,107,130,216, 41, 97,
+ 103,119,132,221, 29,245, 75,217,233, 86, 91,248,104, 56,220, 68,
+ 234,192,115,226,185,225,135,179,132, 34, 34,199,151,204,116,106,
+ 14, 10,221,154, 31, 93, 57, 71, 9, 69, 1, 28,150,136, 12, 26,
+ 177,240,203, 25, 66,227,113,105, 99,150,250, 23, 83,253,180,158,
+ 208,145, 1, 55,250, 6,181,126, 90, 70,104,116, 70, 29, 87,186,
+ 50,126,134,223,214, 17, 26,127,234,230,120,186,234,183,165, 17,
+ 234, 26,172,141, 80, 91,122,179,205,251,221, 25, 33,172, 2, 9,
+ 181,172,234, 37,161,140, 80,130,132, 18, 36,148, 8, 21,161,174,
+ 142, 7,173, 35, 52,221, 35,237,113, 97,199,150, 88,196,135,154,
+ 208,232, 19,245,243,137, 27, 44, 98,182,161, 4, 9, 37,154, 36,
+ 20,210,135, 49, 95, 41,196,222, 72,172,182,150,158,240, 66, 64,
+ 213, 31,196, 73,233,163,194, 66,227,242,123, 90,216,124,131,189,
+ 223,241, 15,194, 66,127,154,145,247, 55, 47, 60,102,132, 6, 34,
+ 18,184,246,165,177,236, 32,100, 6,176, 64,139,251,251,171,218,
+ 136,150, 8,157,184, 91,159,200, 13,169, 23,125, 56,220, 88,118,
+ 249, 7,106,122, 64, 87,181, 17,134, 9, 69, 27,167, 75, 57, 54,
+ 52,225,111,163,146,125, 84,169, 94,233,177,174,135,252, 9, 67,
+ 132,166, 60,182, 45,205,203,239,253, 21,220,123, 3,233,243,211,
+ 245,175,199, 51,164,198, 40,161,250,202, 63, 34,179, 56,105, 54,
+ 251,194,197,250,145,106,171,252,178,237,132,122,205,193,154, 38,
+ 82,199,246, 91, 82,209,214,113,232,110, 41, 32, 49, 11, 44,210,
+ 80,141, 67, 43,132,104,219,235,162, 59,193,110,151,153, 19,246,
+ 82, 92,216, 79,104,139,125,198,151, 93,207,229, 31, 91,164,196,
+ 104,132,130,208,146,214,233,193,164,187,159,128, 25,189, 88,236,
+ 107,244,155, 40,192,253,188,218,108,194, 80,149, 91,240,232,148,
+ 140,156, 51,155,253,248,199,250,223,175, 76,144, 26,163,132, 98,
+ 107,184, 30,169,232,125,182,186,206,137,244,250,114, 27,242,123,
+ 247,152,212, 24, 37, 20, 85,239,252,122,253,235,201,207,194, 98,
+ 65,187,118, 23,148,246, 67,144,215,239,189, 82,211,215,140,115,
+ 215,205,140,115,217, 41,242, 25, 39,246,203,170, 22,239, 2,208,
+ 219,214,104,208,252, 60, 58, 61,217,203,106,126,196, 62, 15, 91,
+ 48, 67, 52, 55,103,102,120,130,244,179,127, 73,100, 91, 35, 84,
+ 199,242,178,106, 19,114,234, 46,250, 71, 88, 47,201,201,175, 55,
+ 106,103, 7,233, 35, 47, 72,193,129, 18,234, 85, 37, 23,252,254,
+ 49,201,162, 14, 85,149, 75,144, 80,130,132, 18, 36,148, 32,161,
+ 36,148, 32,161, 4, 9, 37, 72, 40,161,163, 56, 73, 66, 25,161,
+ 97,134,171,154,166,170,223,150, 17,186,150,118,147,208,170,223,
+ 150, 17, 90,236,113,180,237,236,177,148, 80,172,254,148, 28, 81,
+ 60,192,207,234,122,178,165,157,162,247,231,221, 32,180,214, 79,
+ 75, 9,133,140,212, 86, 57, 40,252,170, 61, 6,196,242, 97, 75,
+ 54,105, 87, 21, 12, 63,178, 73, 71, 39, 22, 32,244,246, 82, 47,
+ 30, 54,192, 15,111, 1,187, 35, 7,241,160,211,176, 27, 23,118,
+ 76,190, 18, 32,236,199,126, 32, 34,159, 73, 85,228,242, 29,199,
+ 38, 22,252, 0,113, 26,118,158, 23,167, 66, 58, 12,153, 82,159,
+ 179, 34,170,243,133,163,103,159, 85,100,164,242,115, 66, 70, 0,
+ 54, 58,183,251,205,216,232,228, 44, 74,253,115, 65,170, 40, 35,
+ 13,207,124,241,116, 66,165, 74,134,122, 17, 47,239,192, 46,186,
+ 190, 91,106, 21,221,123, 93,218,193, 96, 85,230,230,105,245,115,
+ 81,158,189,102,254,216,201, 14, 30, 8,107, 23, 72,168,101,248,
+ 63, 0,179,160, 16,217,188,199, 69, 53, 0, 0, 0, 0, 73, 69,
+ 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_select_png[3374] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 98, 0, 0, 0, 33, 16, 6, 0, 0, 0,114,249,162,
+ 143, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 2,
+ 89, 73, 68, 65, 84,120,218,236,156, 59, 79,219, 96, 20,134, 67,
+ 196, 2, 20,150, 86, 97, 33, 83, 43,179, 80, 53, 43,208,141,170,
+ 98,233, 90,150, 72,229, 55,132,203,136, 84,196, 68,163,142,204,
+ 69,176, 20, 9, 21, 41, 75, 85, 53, 35, 9, 99, 16, 83,211,192,
+ 18,166, 8,150,150,203,202,112,206, 73, 20, 87, 86, 76,108, 82,
+ 98, 63,207,242,202, 78,236, 47, 58, 62,175,191,139,227, 51, 48,
+ 251,122,103,167,246, 59,241, 64, 60,125, 43,234,124, 86,253, 35,
+ 250,108,190,253,123,206,167, 4, 64,147,234, 74,251,246,197,119,
+ 221, 63,166,154, 19,189,252, 17,118,203, 3,225, 26,194,201,139,
+ 190, 91, 39,209,161,119,198, 41,172,233,246,114,208, 51, 14, 6,
+ 59,124,162, 33,186,240, 66, 13, 48,170, 31, 96, 4,232, 1,118,
+ 195, 93, 74,180,247, 32, 95,107,162,231,169, 30,245, 16,115,171,
+ 162,239,159,115, 81,224,241,178,119, 42, 90,220,244,123, 68,242,
+ 126, 13,124, 40, 97, 4,232, 31, 44, 79, 45,111, 67, 51,132,157,
+ 112,230,132, 32, 67,255, 97,121,219,217, 24, 73,127, 67, 35,140,
+ 0, 81, 50,134,229,181,111, 67,216,114, 41, 67, 35,136,242, 80,
+ 202, 22,133, 58, 26, 98,241,136,160, 65,244,177,213,209, 22,174,
+ 101, 87,123,142,208, 92, 62, 5,136, 48,182,108,235,252, 21,173,
+ 46,187,122,136,185, 51,130, 4,241,163,149,247,218, 67, 12,237,
+ 138,102,174, 9, 14,196,143,204, 43,243,129,246, 16,147,121,130,
+ 2, 48,153, 87, 67,164, 27, 4, 3, 32,221, 80, 67, 56, 87, 4,
+ 3,192,185, 74, 18, 4,128, 22, 24, 2, 0, 67, 0, 96, 8, 0,
+ 191,134,168,167, 8, 5, 64, 61,101,134, 56, 32, 24, 0,245, 3,
+ 53,132,189,180, 13, 16,103,170, 57, 53,132, 85, 47,112, 87, 59,
+ 0,136,133, 17, 86,204, 7,174, 73,117,169, 68,112, 32,126,180,
+ 242,222,101,136,242,148,142,165,198, 9, 18, 68, 31, 27, 25, 89,
+ 222,123, 46,187,238,213, 8, 22, 68,159, 47,211,238, 61, 30,134,
+ 176,130, 79, 69,234, 43, 65, 4,177,188,254,183,176, 89,135, 7,
+ 115,214, 83, 48,217,134, 40, 77,158,189, 71, 64, 62,159, 84,111,
+ 109, 49,183,128,254,197,242,214,242,216, 27,159,165, 44,111,179,
+ 162, 27,186, 77,157, 38,232, 7, 74, 47, 69,183,103,252, 30,209,
+ 101,109, 87,107,224, 56,163, 6, 57, 20, 29,222,229, 34,192,255,
+ 227, 70,111,220,219,179,162,149,202,125,207, 16,176,216,177, 53,
+ 248,235,155,232,155,143,162,211, 58,123,183,250, 78, 0, 15, 65,
+ 115,217,180, 44,250,115, 68, 71, 52,149,110,207, 56, 24,206, 15,
+ 179, 33, 85, 65,183, 11,251,162, 25, 45, 54,107,111,228,217,171,
+ 170,148,201,135,110, 38,195,246, 39,212,234, 19,143, 30, 32, 27,
+ 180,165, 59, 0, 0, 0,255,255, 3, 0, 97,168,142, 82, 14,236,
+ 17,113, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_send_png[3561] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 20, 73, 68, 65, 84,120,218,236,156, 61,108,211, 64, 20,199, 15,
+ 171, 75,194,199, 66, 21, 22, 60, 32,192, 93, 64,201, 72, 93,182,
+ 34,196,208, 74, 32,164, 78, 29,186, 33, 58, 66,202, 80, 33, 8,
+ 31, 98, 32,201, 74,214, 64, 59, 69,170,130,212, 76, 72, 97,107,
+ 186, 6,193, 66, 40, 48, 36,226,163, 18, 75, 33,237,202,112,239,
+ 165,178, 19,247, 92,251,238,156,212,239,191,188,184, 57,217,201,
+ 239,222, 61,191,119,125,206,177,169,171, 43, 43, 91, 95,216,144,
+ 235,236, 54,183,201, 55, 7,143,251,243,206,105,135, 79, 99,209,
+ 94, 62,177,202,109, 38,195,173,181,195,173, 9,128,205,223, 48,
+ 176, 10,246,164,224,132,183,157,182,125,134,219, 86, 22,236, 9,
+ 110,155,205,152, 0,183, 10,220, 78,127, 3,208, 93,120, 99, 67,
+ 205,245,112,194,204, 37,184, 46,252,125,119, 30,192,127,224,182,
+ 126,129,219, 78,106,196,129, 35,224,217,167,112,140, 30,154,142,
+ 118,101, 37, 97,101,217,112,108,127,132, 21,112,138,219,242, 21,
+ 85,161,105, 76, 77,136, 88,104,128, 7, 35,224, 60, 27, 9, 89,
+ 240, 57, 95,192,113,237, 19,183,235, 63,134, 12, 56,222,212,238,
+ 31, 7, 15,234,178, 35,161,153,199,176, 32,225, 94, 80,122, 21,
+ 214,243, 67, 2,159, 4, 15, 88,168,178, 35, 45,188, 23, 60,132,
+ 239, 89,236, 6,141,249, 70, 72,208, 27, 44, 86,194,216,143, 43,
+ 25, 87,182, 50,224,113, 5, 45, 15,188, 79,224,120,194,185,115,
+ 140, 52, 0,252,226, 93,103,210, 16, 24,120,194,117,194,228, 42,
+ 65, 30,164,211,215,157,217, 89, 96,224,179, 57,231, 9, 73, 7,
+ 43,147,118, 86,206,190,129, 35,224,233, 37,130, 24, 68,115,231,
+ 189, 66,140, 7,240,153, 28, 65,147, 17, 98,174, 61, 16, 0,199,
+ 129, 88,234,146, 66,214, 41,147, 2,224,184,169, 68,146,235,233,
+ 251, 49,221, 24, 28,244, 73,146, 61,221,118, 1,199, 60,155,178,
+ 17, 53,178,242, 46,224, 19, 5,130,162,163, 64,178, 10,232,225,
+ 55, 9,138, 14,153,219, 0,124,252, 6,193,208,227,233,232,225,
+ 63, 9,134,150, 88,254,207,112,198, 24,146,106, 25,132,128,128,
+ 19,112,146,116,224, 45,218, 21,212,162,118, 10,128, 99, 99, 12,
+ 73,173,246,118, 1,120,231, 45,193,208,161,207,247, 12,124, 65,
+ 48,116,168,149,197, 24,158,165,208,162, 82,216,195,216,151,165,
+ 236,191, 65,146, 10,124,209, 3,248,102,131,224,200, 84,175, 75,
+ 183,233, 1,188,215, 71, 77,105,162,212, 80,178, 55, 47, 40,124,
+ 214, 31, 17, 44, 25,158, 93,203,249,172, 52,201,211,195,233,253,
+ 69,110,251,187,108, 5,165, 61, 54,166, 83,246,226,179,146,132,
+ 182,102,239,126,114, 1,112,156,161,202,119,130,233, 39,132,148,
+ 109,209, 72,159,155, 87,155,151,184,173,231, 9,238, 32,161, 67,
+ 138,251,197, 15,185, 91, 88,217,226,182,113,153, 32, 51,198, 88,
+ 121,202,233,144, 98, 5,220,158,125,109,199, 27,252,225, 65,135,
+ 4,238, 6, 95,249, 26,143, 24, 93, 42, 5, 5, 45, 9, 56,170,
+ 254,146,219,226, 95,175,116,104, 52,133,105,241,243, 91,238,138,
+ 49, 98,224,238,252,253, 25,124,192,218,147,209, 74, 43,209, 81,
+ 48,100, 20,119,100, 59,144,162,127,177, 97, 41,139,249,232,114,
+ 117, 56, 39,192, 13,120,121, 45,108,200, 16, 73,211,163,223,189,
+ 9,192,173, 3,120, 24, 9,187, 74,211,240,252,227, 68,145, 91,
+ 217, 61,142,238,103,238, 27,176, 73,215,185, 3, 3,214,116, 77,
+ 113,196, 63,110,128, 49,177,233, 42, 24, 18, 16,146,204, 95, 48,
+ 1,208, 25, 54, 46,152,136,118,202,185,130, 16,112,159, 82, 81,
+ 125,227,255, 3, 0,233,237,207,153, 62,209, 88,144, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_spacebar_png[2916] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0,145, 0, 0, 0, 34, 16, 6, 0, 0, 0, 15, 22,231,
+ 187, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 0,
+ 143, 73, 68, 65, 84,120,218,236,212, 49, 1, 0, 32, 12,192, 48,
+ 192,214,196,129, 13,110, 28,160,103, 70,248,144,177, 39,145,208,
+ 163, 61,238,121,185,215,108, 0, 69,134, 4,128, 17, 1, 70, 36,
+ 1, 96, 68,128, 17, 73, 0, 24, 17, 96, 68, 18, 0, 70, 4, 24,
+ 145, 4,128, 17, 1, 70, 36, 1, 96, 68,128, 17, 73, 0, 24, 17,
+ 96, 68, 18, 0, 70, 4, 24,145, 4,128, 17, 1, 70, 36, 1, 96,
+ 68,128, 17, 73, 0, 24, 17, 96, 68, 18, 0, 70, 4, 24,145, 4,
+ 128, 17, 1, 70, 36, 1, 96, 68,128, 17, 73, 0, 24, 17, 96, 68,
+ 18, 0, 70, 4, 24,145, 4, 64,181, 15, 0, 0,255,255, 3, 0,
+ 87,196, 5, 65, 55,106, 37, 28, 0, 0, 0, 0, 73, 69, 78, 68,
+ 174, 66, 96,130
+};
+
+static const unsigned char _data_volume_down_png[3586] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 67, 0, 0, 0, 49, 16, 6, 0, 0, 0,209,176,200,
+ 250, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 45, 73, 68, 65, 84,120,218,236,157,191,111,211, 64, 20,199, 13,
+ 234, 82, 68,197, 64, 21, 33,148, 12, 80, 4, 11,136,172,117, 97,
+ 138,132, 24, 26, 9,150,178, 88, 34, 27,136, 17, 8,107, 11, 35,
+ 16,254,134, 84,242, 66, 36, 36,134, 14,168, 82, 38,136, 25, 88,
+ 140,202,210,136, 76,141, 16, 32,178, 80, 53,108,152,225,222,139,
+ 100,171,174,206,241, 97,159,115,223,239,242,106,183,138,239,221,
+ 125,242,238,221, 15, 95,143, 5, 65, 16, 4,129,101, 93,187,238,
+ 186,131,175,150, 98,205,187,194, 86,190, 11,123,233, 85,186,207,
+ 219,125, 40,236,222, 25, 97,255, 56, 22,100, 89,150,101,125,120,
+ 239, 56, 75, 23,212,125,222,156, 90, 0,170, 85, 97,107,132, 88,
+ 229, 7,253,193, 2,217,245,116,207, 89,229, 31, 14, 8,144,183,
+ 194,118,169, 74,124, 31,192,104, 1,198,242, 23, 97,215,206, 9,
+ 123,194,205,182,248, 12, 94,131,236,152,128,232, 80,185, 62, 94,
+ 70, 19,103, 2, 6, 71,134,134, 71, 17,162, 71,191,232,233,225,
+ 14,131,217,160,235,234, 3, 97,219, 54, 34, 73, 50, 29, 79, 6,
+ 196,163,147, 84,225, 87,139,225, 30,151,147,203, 61,239,162,201,
+ 149,128, 17, 5, 98,146, 51, 20, 76, 92,110, 0,162, 8,140,250,
+ 70,177,129,136, 3,132,253,130, 18,230, 24, 23, 95,210,232, 98,
+ 97, 54,221,174, 53,105, 20,179, 47,108,255, 49, 80,144,138, 24,
+ 245,103,102,184,111,138,159,169,193, 40,255,164,136,241,194, 12,
+ 247,217, 79,246, 27,138, 1,195,182,205,172, 6, 83,253,150, 6,
+ 163, 98,232, 55,135,115, 42, 40, 6, 12, 83,186,144,184,209, 10,
+ 36, 57, 92,133, 0, 6,132, 46, 5, 96,196,118, 41, 57,231, 88,
+ 188, 40, 89, 63, 11, 48,180,210, 94, 41, 95, 32, 26, 61, 93,106,
+ 2, 96,104, 17, 33,244, 1,130, 53,135,198,201, 67,119,105,219,
+ 130,221,211,181,132,136, 24,249, 0,177,163,123, 73, 17, 49, 82,
+ 73, 54, 73, 44,223, 18,182,186,163, 22,176,197,155,194,182,126,
+ 3, 12,173,180,186,158,237,243,120, 79,237, 36,226,208,132,228,
+ 242,138,176,234,182, 50,162, 43, 41,148,120,179,115,191, 25,190,
+ 175,126,173, 7, 96, 20, 82,158, 23,190, 86,191,148, 1, 48, 10,
+ 169,209, 59,140, 74,160, 67, 20,157,161, 29, 59, 0,195,104,241,
+ 38,230,218, 32,124, 63,154,115, 0, 12,211, 34, 5,189,234,121,
+ 250, 70,248,126,247, 60,134,171, 90,169,181,159, 44,244,175, 45,
+ 165,123, 30,111, 90,110,211, 84,250, 34, 1,210,255, 6, 48,180,
+ 146,236,238,242, 62,231, 2,138,214, 70,254,255,171,151,232, 74,
+ 50, 21, 55,104,123, 69,247,146, 2,140, 92, 1,225,174,104,236,
+ 0, 12,232,144,174,168,117,160, 27, 32, 0, 67, 11, 13, 75, 97,
+ 64,126,109,231, 93, 34, 36,159, 33,157,122,162, 7, 32, 67, 68,
+ 12,189,244,233, 47,234, 0, 96, 64,242, 96,168,159, 90, 45, 72,
+ 18,216, 4, 10, 71,130,225,223, 55,179, 26, 76,245, 91, 30, 12,
+ 223, 80, 48,124,160,112, 36, 24, 35, 26, 38,121, 87,204,112,159,
+ 253, 28,109, 3, 5,169,228,115,107, 67,216,241,140,158,114,199,
+ 126,177,159,144, 36, 24,252, 13,218,122, 58,155,110,179, 95,136,
+ 20, 83, 14, 87,187,207,103,171,107, 97, 63,216, 47,104, 74, 48,
+ 88,155,118,177, 1,225,114,111,226,228, 28,181, 96, 68, 1,233,
+ 12,138,213,101, 0,136,164,154,114,173,132, 67,241, 46,237, 76,
+ 186, 67,135,188,231,125, 34, 15, 79, 84,189,166, 67,238,135,247,
+ 208,196,153,130,193,154,172, 10,210,117,249,182,176,252, 2, 12,
+ 31,217, 28,221,163,152, 86,156, 52,250,159,169,171,240, 34, 32,
+ 148,208,180,185,130, 17, 7, 74,135,174, 59,252, 31, 80,222, 80,
+ 68, 73,121, 98, 77,236, 86, 58,128,160, 88,255, 6, 0,161,232,
+ 198,240, 68,249,103, 76, 0, 0, 0, 0, 73, 69, 78, 68,174, 66,
+ 96,130
+};
+
+static const unsigned char _data_volume_up_png[3856] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 67, 0, 0, 0, 49, 16, 6, 0, 0, 0,209,176,200,
+ 250, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 4,
+ 59, 73, 68, 65, 84,120,218,236,157, 61, 76, 20, 65, 20,199, 87,
+ 67,163, 6, 27, 8, 24,195, 53, 66,176, 17,185, 82, 78,109,196,
+ 24, 11, 76, 52, 36, 84, 68,175,195,163,148,143, 82,161,177, 16,
+ 177, 4,236, 78,115, 21,141,197, 81,153, 80, 41,123,150,103,176,
+ 1, 65, 11,136, 2,209, 6,149, 43,207, 98,222,255,200, 12,187,
+ 183,115,183,115, 31,187,251,254,205,228,150,185,189,121, 55,191,
+ 155,247,222,124, 44,167,138,197, 98,177, 88,180,172, 27, 55, 51,
+ 153,237, 45,171,198,234,125,233,239,253,155,147, 22,171,166,250,
+ 248, 97,116,180,187,199,178, 90,204,222,182,237,142, 40, 7,191,
+ 201, 32,196,246, 13,125,192,107, 81,236,116,202,160,172, 94, 18,
+ 229,239,247,220,181,102,212, 98, 6,132,228, 39, 2, 97, 88,169,
+ 176, 95,155,102, 3,180,216, 20,129,136, 17,133,218,145,190,198,
+ 160, 52, 4,140,193,105, 81,142,116,211,133,225,230, 48,167,119,
+ 78,148,207,233,245,114,156, 70,148, 23,220,213,149,233,116,101,
+ 213, 31,217, 10, 16, 77, 46,180, 19,237,102, 25, 6, 3, 95,108,
+ 98, 61,152,102,162,221, 12,136, 33, 48,224, 50,130, 10,132, 27,
+ 32,176,139, 85, 33, 24, 8, 42,135,158,133,211,108,216, 5, 59,
+ 89,154, 96, 12,205,136,242,108, 38,156,102,195, 46,216,201,242,
+ 0, 3,191,160,176,184, 14, 93,215,194, 35,135, 7, 24,241,120,
+ 52,191,134,168,218,173, 15,198, 82, 68,193, 88, 98, 20,202,130,
+ 209,245, 51,154, 95, 3, 38,198, 88, 46, 96,132, 53,216,100, 25,
+ 202, 74,162,170,174,131,112,219,165, 31, 75, 49, 24,242,136,249,
+ 182, 57, 58,112,224,139,217,251, 77,156, 19,101, 42,165,251, 3,
+ 96, 48,154,234, 23,141, 14,108, 55,148, 62, 23, 70,157,175,143,
+ 19, 32,103, 50, 12,134,150, 98, 7,141, 5,194,111,140,167,142,
+ 56,216,118,176,184, 40,215,195,188,205,237,105, 6, 67, 75, 59,
+ 29,245,249, 28,116,156,105, 32,112,191,228, 26,101, 91,180, 81,
+ 10, 27,154,236, 62,249,125,183,190,186,141, 28, 12, 70, 93, 5,
+ 32,208,113,166,178, 64,140, 12,133,135,242,245,100, 78,126,189,
+ 50,227,156,133,158, 12, 74, 91,184,179,252, 72,119, 15, 43, 92,
+ 212,200,154, 89,192, 16,139,100, 41,150, 72, 83,123, 38, 20,151,
+ 49, 48, 43,202,220, 21, 81,230,123, 8,136,126, 81, 38, 18,244,
+ 119, 6,195,140, 38, 90, 53, 43,182,154, 5, 17, 35,142, 69,171,
+ 196, 27,127,100,151,177,121,158,234,211,196, 93,124, 65,238,248,
+ 252, 56, 93, 95,147,235, 89, 99,236, 74,130, 25, 3, 93,144, 93,
+ 7,132,205,215, 80,254,177, 2,212,156, 94, 44,117,156,198, 50,
+ 24,129, 18,210,207,213,238,202, 58, 30,177, 4,130,204, 93, 23,
+ 48,142,231,113, 24,140, 80,100, 79,106, 16,139,145,229, 68,172,
+ 179,167,251, 9, 12, 70, 32,213,118,215, 35,216,221, 43,159,189,
+ 48, 24, 33, 21,178, 8,104,115,170,252, 8,162,130,225,189, 49,
+ 137,193, 8,148, 48,223,160,198, 20,182,178,251,189,127, 65,113,
+ 45,157,206,233,179,170,227, 35,160,156,174,250,210,202,172, 94,
+ 189,174,251,242,188, 65,181,202,231, 9, 4,154,193,108, 39,151,
+ 146, 59,148, 71, 2,117,107,102,206, 13,156,117,103,112, 24, 12,
+ 159,202,254,208,172, 72, 29, 97,234,124,206,155,132,243,117, 28,
+ 21,197,201,192, 35,202, 98,236,119,114, 86, 82, 2,116, 93, 29,
+ 41, 24,140,134,168,212,161,134, 15,112,149, 92, 76,202,121, 68,
+ 43,208, 17,205,123, 23, 41, 6,249, 39,215,195,161,112,107,139,
+ 99, 12,231,104,254,160,190,128,232,186, 34, 93, 23,147,190, 46,
+ 187, 26,156,217,133,139,193,162, 89, 41, 54,233,115,203, 86,120,
+ 196, 40, 59, 63, 80, 47, 87,244,139, 58, 52,233,115, 45, 5,107,
+ 33,202,218,153,149, 26,151,179, 21,184,152,149, 7,110,119, 98,
+ 48,154, 66,232, 80, 11,139, 99,134,238,235,246,124,146,229,239,
+ 94,243, 26, 12,134,164, 35, 44, 91, 79, 54, 24, 16, 67, 66, 80,
+ 153, 38,224, 98,148, 29,229,198,188,222,201, 96, 72,218,237, 8,
+ 167, 93,110, 46,198, 93, 28,124,178,116,192, 56, 57,209, 17,145,
+ 160,179,147, 81, 40, 11, 70, 84,159,138,199, 79, 3,244, 0,195,
+ 142,232, 19,103,108,126,210, 78,121, 48, 16,124,169,171,117,161,
+ 29, 41,166,194, 29,116, 26, 3, 3,202, 62,141,134,249, 81,177,
+ 211, 24, 24,165, 7,171,134,244, 20, 56,236,226,216,162,202,116,
+ 53, 59, 19,174,168, 29,118,192, 46, 86,149, 96, 96,243,233,252,
+ 223, 96, 3,130,118,195, 14,183, 51,157, 44, 77, 48,220, 0,201,
+ 127, 14, 86,112,201, 64,212, 8, 12, 21,144, 69,218,120,178,188,
+ 45,202,163, 38,249,194,209, 14,180,107,254,144,129,168, 78, 62,
+ 215, 74,176,222,111, 95, 21,101,130, 58,100,128,246, 27,196,246,
+ 107,219,124,184, 8,108, 93,195, 78,165, 2, 63, 59,188,177, 96,
+ 168, 35,201,170, 37,151,216, 32,130,242,242, 43,127,159,179,241,
+ 68,148, 88, 46,230,255, 46, 80, 43,253, 31, 0,165, 77, 46,225,
+ 17, 27,221, 39, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_device_png[45511] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 1,149, 0, 0, 3, 34, 8, 2, 0, 0, 0, 41,105,201,
+ 136, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 0, 7,116, 73, 77, 69, 7,216,
+ 1, 30, 13, 5, 29,169,182, 54, 49, 0, 0, 32, 0, 73, 68, 65,
+ 84,120,218,236,189, 89,112,100, 87,122,231,247,157,115,111,174,
+ 88, 10, 40, 84, 21,139,100, 85,145, 44,146, 93,100, 55, 91,205,
+ 110,182,122,139,222,212,148,186, 37,185,229,112, 43, 36,217,150,
+ 34, 70,114,132,165,152,241,131, 61,178,159,198, 49,143, 19,158,
+ 183,113,204,219,196,232,101,244, 48, 19, 99, 43, 28,154,113,104,
+ 108,105, 70,106,141,130, 82,111, 86,179, 91, 18,155,108, 54,151,
+ 34,107, 97, 85,161, 10, 64, 1,185,220,229, 44,159, 31,238,118,
+ 238,205, 4,144, 0, 18,185, 0,255, 31, 73, 48,145,184,153,121,
+ 51,145,249,195,255,251,238,185,231,136,183,223,185, 78, 0,140,
+ 1, 30,121, 75,129, 23, 11,140, 5, 31, 47,193,137,209, 7, 51,
+ 49, 91,230,170, 83,152, 89, 41,165,148,178,150,247,208, 13, 51,
+ 71, 81,212,237,118,149, 82, 7,213, 20,239,103,177,122,189,190,
+ 184,184,216,104, 52,132,216, 75, 94, 66,136, 90,173, 94,171,213,
+ 164, 20,131, 63,147, 66,208,222,183,135, 58,225, 47, 48, 21,251,
+ 88,203,204,169,110,180,209, 42,142,141,177, 68,100,173, 9,130,
+ 160,215,235, 25, 99,146, 77,181,214,253, 94,175, 31, 4,198,232,
+ 92, 26,177, 82, 58,140, 60,102,203,182, 98, 18,107,237,114,171,
+ 85,243,188, 76,109,187, 6,165,154,239,175, 46, 44,202, 97,110,
+ 28,118,113,168, 21,134,171, 76, 17, 95,239,245,148,209,187, 27,
+ 36,217, 90, 40,163, 59, 81, 40,165, 28,212,151,149,162,214,108,
+ 214,234,245,252, 74,207,243,218,237,246, 66,123,193,243,189,244,
+ 13,237,251,237,118,187,213,106,121,158, 71, 68, 82,202,122,189,
+ 238,251, 62, 9, 65, 68, 82, 8, 33, 68,114,249,224, 38,131,251,
+ 102, 14,129,250,241,216,210, 80,138, 49, 38,142, 99,109,140, 53,
+ 38, 8,130,126,175,175,141,214, 90,247,251,253,126,191,111,140,
+ 49,198,132,253,126,141,200, 38,194, 98,219,170,213,219,245, 6,
+ 103, 2, 88,104, 52, 23,155,205,226, 35, 78,180,208,108, 46, 54,
+ 91,156,185, 68, 12, 81, 13, 15, 10,136,121,224, 35, 40,178,228,
+ 54,112,181,171,172, 34,224,141, 94, 65, 86,247,131,247, 80,128,
+ 16,130,119, 83,227,174,185, 46,189, 69, 47, 10,123, 81,228, 94,
+ 223,139,162,228,154,228,193, 2, 21,135, 70, 11, 33,137,200,147,
+ 82,123,178,217,110,123,158,151,184,175,221,110,251,190,159, 91,
+ 79,122,158,239,121,245,122,221,243, 60, 33, 68,146,249,136, 68,
+ 190,227, 2,178,131,191, 78,134,155,140,177,113, 28, 41,173, 85,
+ 28,119, 58,157, 40,138,162, 40,218,217,217,137,227, 56, 12, 3,
+ 161, 12, 89,107,217,122, 66,158,105,183, 83, 19, 53,155, 11,141,
+ 102,230,160,214, 98,171, 85,124,104,139,255,115,102, 16, 30, 30,
+ 130,202, 91, 14, 90,131,137,197, 96, 86,202,237,197,251, 60,185,
+ 210,157,187, 15,199, 44, 70,214, 23,237,225,163,106, 9,200,123,
+ 239, 18, 31,224,237, 44, 10,167, 11,226, 93,238, 34,255,206,117,
+ 95, 47,138,250,113,122,185, 19,133,134, 88, 10, 73, 82,138,102,
+ 189,217,108,213,235,245,229,229,229, 70,163,209,104, 52,150,150,
+ 150,106,181,122,173,230,215,235,117,233,121,105,166, 27, 48,156,
+ 128,224,224,175, 41, 26,202, 88,107,180,142,227, 56, 12,195, 78,
+ 167,211,235,245,146,196,212,235,245,132,214,100,173, 49,230,220,
+ 210,114,242,121,121,100,117, 53,185,221,197,213,179,197, 71, 87,
+ 164,159,149,146,137,184,144, 78, 38, 32, 87, 67,188,107,118,201,
+ 220, 52,236, 74, 55, 55,177,123,189,112,219, 99,195,101, 48,164,
+ 17, 54,240, 19,222, 87, 74,213, 29,216,199, 51, 98, 4, 43,241,
+ 208,102, 23, 15,127, 92, 49,228,233,141,214, 43,227,234, 19, 24,
+ 242, 35,102,190,223,221, 73,174,186,223,237, 36, 27,110, 6,125,
+ 207,243,132,231,137, 70,125, 97, 97,161,213,110, 47, 44, 44, 44,
+ 44, 44, 44, 45, 45, 53,154,205,122,173,238,251,158,148, 94,214,
+ 203, 19, 21,119, 9,216, 13,254, 58,154,164,200, 90,163,181, 14,
+ 195,176,219,237,118,187,221, 78,167,211,235,118,183,183,183,235,
+ 68, 74,233, 86,173,214,110, 52,137,248,145,213,179,196,188,216,
+ 106, 45, 54, 91,236,124, 74,133, 83, 92, 17,231, 63,201, 63, 74,
+ 69,213,198,196,185,167, 74,185,137,185,242,109,238, 29,102, 46,
+ 55,158,184,106,146,129,107,134,110, 86,242, 14,243,222, 42, 24,
+ 182, 25,237, 91, 63,138,189, 67, 20, 15,126,126,197,174,162, 97,
+ 222,213, 59, 98,151,155, 15,181,149,112, 30,125,183, 31, 21,226,
+ 203, 54,221, 93,121,188,223,149,189, 56,173, 91,239,119, 59,130,
+ 40, 80, 42,178,218,247,107,166, 94, 59,115,230,204,162, 67,179,
+ 217,244,253, 90, 18,221,134,239, 19,212, 6,127,185,111, 51,107,
+ 173, 82, 42,241,212,195, 12, 82,138,141,109,214,106,237, 70, 99,
+ 177,217, 90,104, 54, 27,181,218,217,165,229,236,131,202, 68,130,
+ 28,137,184, 98, 74,138,169,212, 79,133,151,184,164, 39,215, 77,
+ 204,101,211,229,183,229,146, 99,184, 26,202,220,123,168,214,140,
+ 21,247, 81,249, 81,134, 74,118,223, 78, 22,243, 64,206,226,145,
+ 162,215, 40,149,158, 99,135,146, 40,134, 89, 99,200,167, 88, 12,
+ 223, 94, 36, 79,177,116,231, 98,247,199, 21,187,238,149,168, 62,
+ 82,169, 8, 29, 8, 80,206, 37,167,106,173,100,232,236,133,121,
+ 24,244,149,214,189, 56, 14, 84, 28,104, 21, 91, 35,253,154,215,
+ 106,174,172,174,158, 57,115,102,101,101, 37,241, 90,173, 86,147,
+ 82,150,119, 82,140,150,218, 4,252,117,114, 84,213,239, 7,157,
+ 206,206,195,135, 15, 55, 54, 54, 58,219,219, 62,115,221,247, 23,
+ 26,205,133,102,115,177,213, 58,187,180, 92,247,125,215, 11, 84,
+ 169,188,242,203, 37,239,148, 37,149, 27,138,157,219,231, 55, 41,
+ 93, 40, 4,151, 89,136,221,138,176, 48,102,122, 57,251,105,245,
+ 178,107, 52, 46,212,199, 60,216,185,114, 36, 85,190,135, 61,234,
+ 193,193,155,140,104,174, 81,219, 83,187,186, 67,236, 37, 50, 87,
+ 49, 98,136,190,242,123,174, 4, 52,231, 74,225,124,250,179,221,
+ 112,182,174,228, 32,177,187, 4,157, 99,151,156,109,195,196, 69,
+ 142, 27,144, 32, 19,103, 7, 40,200,253,146,108,175,140,121, 24,
+ 244,123,113, 20, 40, 21,106,165,152,185, 81, 95, 94, 89, 89, 91,
+ 91, 59,115,102,101,121,121,169,221,110, 39, 82, 27,216, 35, 49,
+ 66, 94, 19,240,215, 76,219,202, 24, 27, 69, 97,183,219,221,216,
+ 216,216,220,220,220,220,220,240, 13,215, 61,175,221,104,156, 93,
+ 90,174,215,252,139,171,107,121, 84, 17,206,199,184,106,168,178,
+ 110, 50,215,148, 37,149, 93,200,111, 91,186, 80,140,127, 56,200,
+ 173,156, 58,145,203,138, 44, 41,111, 80,100,217, 13,135,199,186,
+ 129,166, 91,165,167,182, 71,147,107,247, 10,148,119,251,108,140,
+ 244, 41, 17,229,207,218,208, 44, 86,232,108,160, 29,238, 72,167,
+ 106,171,172,125,158,109,146, 29, 50,204,190, 21,149,252,149, 59,
+ 72,228,251, 36,202,114,204, 4, 38,202,138, 20,101,163,186, 30,
+ 20, 69, 95,111,184,139, 69,222,161, 19,110, 93, 91,241, 90,254,
+ 18,223,239,117,149,214,219, 97, 16, 26,173,136, 68,163,190,178,
+ 182,118,254,252,249,179,103,215,150,150, 22, 27,141,134,231,121,
+ 238,179, 28, 89,106, 2,254,154,102, 91, 61, 86,170,215,237,222,
+ 191,127,255,222,189,123,219, 91, 91,210,218,165,102,107,161,217,
+ 60,187,188,188,182,180, 92,243,125, 81,201, 26,185, 92, 92, 73,
+ 37, 67, 57, 19, 95,176,165,194, 27, 54, 21,141,107, 25,203,142,
+ 206,242, 13,153, 42, 55, 73,175, 76, 15, 79,146,107, 52,203,185,
+ 215,152,152,172,107,180,226, 2,115,177, 99,121, 76,203,246,194,
+ 186,165,107, 85,115,236, 20,168, 21, 59,239,110,180,161, 86,114,
+ 111,184,119,231, 75, 12,205,109,187, 21,133, 21, 49,149, 5, 82,
+ 114,217, 96, 2,114,135,107, 13,202,168, 16, 77,201, 50, 34,137,
+ 85,206,205,156,156,149, 95, 46, 76,148,222,133,112, 30,216, 29,
+ 46,155, 63,174, 40, 30, 37,185,151,194,128,162, 16,100,250, 20,
+ 132, 72,235,218,194,116, 92,186,156,121,173,168,241,139, 2,148,
+ 216,141,211, 68,177, 49,219, 65,176, 29, 5,129, 86,129, 49,178,
+ 213, 92, 89, 91,187,112,225,194,249,243, 23, 22, 23, 23,106,181,
+ 122,113,160, 64, 12,171,117, 79,162,209,102,220, 95,204,204,113,
+ 28,239,236,116,214,215,239,221,186,117, 75,245,251,237, 90,189,
+ 221,104, 92, 60,187,118,118,121,185,238,215,200,173,188, 28, 53,
+ 148,180,101, 45, 19,101,198,201,174, 79, 68,145,248, 34,253,202,
+ 185,152,216, 50, 37,222, 98,231, 38,217,215,193, 11,213,159, 22,
+ 119, 69,108,237,128,212, 50, 7, 13, 83,103,177,217,174, 25,205,
+ 113, 49,187,250,226, 82, 95,172, 92,150, 14,145,218, 80,175,237,
+ 114,229,208,177,102,163, 84,140,149, 2, 80,148,107, 49, 81,201,
+ 47,174, 32, 92, 69,185,201, 72,148,243, 85, 58,122, 65, 20,121,
+ 73, 56,242,202, 77,147,125, 83,186, 38,151, 86,225, 65, 81,186,
+ 57, 13, 92,147,252, 39, 75,119, 91,185,183,178,245,178,125, 22,
+ 206,147,116, 29,231,170, 37,201, 99,217,229,244, 53,207, 74,212,
+ 138,209,152, 40,214,122, 59, 10, 55,250,189,200,152, 88, 80,251,
+ 236,202,165,199, 47,157,191,240,200,242,242, 82,189, 94,207, 6,
+ 175,237, 98,180, 19,161,179, 25,244, 23,107,173, 59,157,238,221,
+ 187,119,110,220,184,145, 8,107,101,113,241,236,242,153, 71,207,
+ 174, 13, 85, 85,242,201, 31, 34, 20,235, 58, 37, 75, 73,201, 56,
+ 247,252,250,204, 86,204,214,221,158,152,147, 17,241,197, 64,212,
+ 244, 91,170,108, 89,217, 44, 55, 87,246,136,214,121,136,170,230,
+ 202,215,228, 10, 43, 5, 58, 87,199, 60,172,218,229, 97,141,185,
+ 189,155,104, 60,228,176,230,240,107,152,246, 75, 89,251,246,185,
+ 68,165,232,162,161, 1,106, 96,195, 82,149,151,121,161,148,170,
+ 210,248, 51,196, 77, 85, 79,165,114, 41,162,147, 16, 85, 85, 57,
+ 1, 45, 27,207, 37,164,115, 71, 66, 86,239,202,185, 67, 33,179,
+ 8, 39, 68,105, 63, 51,205, 13, 23,101,245, 66,201,226, 36,170,
+ 7, 37, 72,136,226,119, 34, 68,209,131,205,255,130, 17, 61,232,
+ 247,118,162,176,171, 98, 37, 69,123,117,245,242,149, 43, 23, 47,
+ 94, 92, 90, 90,242,125,223,121,225, 69, 53,242,206,173,206,102,
+ 194, 95,204, 28,199,209,131, 7, 15,110,221,186,117,239,206,157,
+ 166,244,206,180,219, 23,215,206, 61,186,182, 86, 42,178,114,103,
+ 229, 95, 43, 2,226,236,202,196, 26, 92,182, 76, 98,174,212, 35,
+ 169,131,138, 45, 45, 91,107,137,243,109,138,123,200,110,232,126,
+ 101,103,203,236,202, 92,142,249,206,100,143, 80, 85, 94, 98, 40,
+ 215,113,101,153,230,230, 74,246,161,200,137,142,197,156, 38,157,
+ 83, 84, 38, 42,119, 43,202,234, 49, 80,183,215, 50, 36,142,141,
+ 82, 99,238,253,182, 22, 67,251, 86, 67,107, 64, 81,237,181,187,
+ 193,101, 72,245, 87,117, 83, 57, 34,185, 22,203, 21, 67, 36,164,
+ 44, 46,184,186,145,194,181, 76,113,101, 73,112, 14, 50, 81, 88,
+ 182,181,112, 12, 85, 92, 87,186, 9, 13,123,172,106,124, 19,162,
+ 178,231, 78,137,234,244, 10, 69, 54,212,163,120,125, 57, 55, 90,
+ 126,188, 60, 63,166,147,252, 34, 55,250,189,141,176, 31, 88,195,
+ 173,230,197,199, 31,191,244,248,165,181,115,107,217, 89,168,135,
+ 208,153,128,191,138, 15,135, 82,234,193,131, 7,215,223,125,247,
+ 193,250,250, 98,189,241,200,217,179,143,158, 93, 91,108,181,137,
+ 170, 29,116,102, 75,182, 28,118, 42,194,178, 54,119, 4, 91,155,
+ 41, 35,221,192, 90, 75, 37,133,101,150, 73,111,101, 51,121,177,
+ 181,150,172,181,169, 89,216, 26, 91,186,243,252,230,165,123, 96,
+ 102,203,198,114, 69,118,217,157,184,254, 26,154,221, 92, 5, 23,
+ 249,142, 6,116,198,165,230,218, 94,205,126,167, 85,230,182,224,
+ 121,216,224, 47, 30,126,210,207,190,103,100, 31, 96,164,196,110,
+ 209, 76, 8,177,107,139,166,170,179,129,246, 86, 94, 48, 58,230,
+ 26, 76, 73, 37,161, 56,238, 16, 50,191, 94,230, 95, 40,243,148,
+ 227, 44, 33,132, 36,231,178,115,129,132,144,233, 13,147,155, 12,
+ 220, 48,125,208,202,198,249,163, 16,145,115, 19, 26,178,219, 89,
+ 53,234, 22,167,187, 27,141,179,226,147,139, 97,124,156, 29,254,
+ 225,158,138, 55,195,224, 97, 28,233,122,237,194,165,199,159,122,
+ 234,169,115,231,206,213,106,181,188, 39,184,107,177, 57,195, 46,
+ 155,176,191,216, 90,238,245,186,215,175, 95,127,255,189,247,234,
+ 36, 46,157, 63,255,216,185,243,201,105, 52,121, 7,138, 42,129,
+ 101,184,116,152,172, 45,164,195,108, 19,173,152,138, 98,172, 53,
+ 214,241,148,181, 54,251,169,205,175,201, 54, 54,229,111,243,203,
+ 249, 77, 56,191, 55, 46,174,103,107,179,157, 25,180,103,113,185,
+ 146,212,156,203,238,177,203,129, 60, 53, 80,250,237,209,204, 58,
+ 160,105,120,215,111, 70,127,251, 28,250,237, 44, 14,252,131, 1,
+ 235, 85, 71, 19,184,253, 44, 55,232,229, 81,173,154,215,100,166,
+ 188, 84, 53,101, 1,201,226,130,116,180, 85,124, 21, 50,255, 81,
+ 105,179, 98, 99, 41,203,130, 19, 66,122, 50,243,154, 99,183,236,
+ 135,249,110, 16,145, 24, 80, 91,226, 95,114, 52, 77,197,209,135,
+ 188, 77, 86,209, 89,250,215, 45, 63, 32,149,188,223,122, 42,222,
+ 140,194,205, 56,146, 75, 11, 79, 94,125,250,169,171, 79, 45, 44,
+ 44, 56,227,206,118,143,102, 51,230,178,201,248,139,173,181, 91,
+ 91, 91,111,188,241,198,195, 7, 15, 86,218,237,103, 47, 63,177,
+ 182,188, 92, 77, 19,238, 71,189, 82,178, 25, 91,146, 84, 69, 61,
+ 201,101,227, 92,105, 74, 63,181,198, 36,247,105,173,101, 99,202,
+ 215, 23,146, 42,127,107,115, 33,218,129,135,179, 21,169, 89,155,
+ 164,188,129, 2,147,220, 10,177, 84,241,177,155,154, 70, 27, 89,
+ 186,183,128, 14,245,123, 57,202,143,197, 17, 36,117,244,219,236,
+ 54, 80,108,143, 59, 25,140,126,110,172, 27,108,135,185, 53,160,
+ 168, 90, 70, 74, 47,243,139, 39, 11, 85,201,221, 47, 75, 33,165,
+ 20, 66, 14, 94,206,197, 39,115,247,165, 63,173,154,148,156,244,
+ 71,133,127,243, 98, 83,148,189,150,232, 76, 20,127, 6,201,105,
+ 177, 80,250, 22,222, 81,209,221,160, 23,249,222,133, 39, 46, 63,
+ 247,220,243,171,171,171,201,212, 29,123,230,178,221,106, 76,113,
+ 162,252,101,173,125,248,112,235,245,215, 95,223, 92, 95,191,114,
+ 225,145, 39, 31,125,116,177,213, 46, 26, 58,110,255,200,173,209,
+ 74,202, 48,105,170,178,156, 94,206,124,148,234, 38,253, 90,136,
+ 41,149, 84,118,125,113,193, 14,217,222, 26,147, 61,156,177, 38,
+ 123,196,108, 7,108,217,131,105,254, 42,165,194,162, 75,197,165,
+ 145, 16,187,142,255,228,145,181,194, 71,212, 18,211,172, 35, 14,
+ 255,150,223, 55,249,137,145,196, 39,118,219,184,146,242,132,219,
+ 128,207,186,105, 78, 85, 88,216, 45,245,154,148,169,143,178,175,
+ 66, 10, 41,189,226, 74, 79, 58,194,114,190, 77,172,231,201,146,
+ 212,156, 12, 40,165,164, 97,106,171, 30, 88, 16, 84,209, 89,114,
+ 122, 91,222, 75,206, 44,150,254,229,181,108,251, 74, 61,136,195,
+ 109,193,143, 60,245,228,135, 63,252,225,149,149,149, 60,145, 13,
+ 186,108,191, 80, 38,230,216, 95, 76, 28, 6,193,155,111,190,121,
+ 253,157,119,174, 62,114,241,201,199, 30, 91,108,181,203,206,114,
+ 242, 75,102,156, 60, 58,185, 57, 40,245,139, 49,169, 86, 82, 49,
+ 177, 53, 58,117, 80,162, 45, 99,172,179,153,209,154,141,181,214,
+ 88, 99,178,205,210,111,243, 59,201,228,149, 92, 40,197,177,172,
+ 243,101,171, 45,170,193,154,142,246,152,247,133, 71,116, 8, 31,
+ 202, 53,135,171, 25,231,232,200,248,161,243,155, 24, 73,124, 98,
+ 223, 15, 92,165,133, 39,134, 9,206, 61,168, 90, 4,185,212,108,
+ 110, 33,233,196, 49,175,240,154,244, 50,163,121, 82, 74,207,181,
+ 152,244, 60, 87,127,123, 8, 46, 79,115,148, 94, 40,106,210,172,
+ 137, 38,243, 3,184,204,197, 16,179,124, 88, 99,214,196, 77,255,
+ 208,247,181,218, 80,209,118,205,123,230, 35, 31,190,118,237, 90,
+ 171,213,114,250,253, 21,149, 85, 67,153, 16, 19, 21,217,152,253,
+ 197,108, 55, 55, 55,255,250,123,223,171,147,120,225,233,167,215,
+ 206,172, 84, 14,225, 85,138,178,212, 32,198,186,122, 42, 89, 38,
+ 189,172,109,241,213, 88,157,125,171,141,181,198,106, 51,240,173,
+ 177, 38,187,144, 95, 83,122,184,129, 10,212, 61, 2,232,182,198,
+ 75,126, 25, 41,217,240,168, 17,139,199,250, 55,227,164, 72,107,
+ 172,247, 39,142,176,145,216,175, 44,221, 67,112,238,103,221,237,
+ 194,201,244, 24,130,148, 78,225,153, 75, 45,215, 89,122,193,243,
+ 164, 87,254,182,162,182,228,130, 87, 14,122,110, 73, 43, 4,101,
+ 241,144,178, 35,176,238, 65,128,124, 16, 70,214,181,205,106, 21,
+ 107,181, 49, 93,163,239,153,184,241,200,249,159,254,236,103,207,
+ 158, 61, 91,137, 99,101,147,149, 69, 54,169, 68, 54, 54,127, 89,
+ 107,110,221,186,245, 55,175,190,122,113,245,236, 79, 61,243,108,
+ 221,247,147,126,188, 91, 9,218,193, 36,101,140,209,169,107, 56,
+ 19,141,209,186,176, 79, 98, 37, 99,172,214, 70, 39,230,202,182,
+ 209,218,106, 99, 76,118,165,123,219,226,223,114, 93,233, 30, 58,
+ 28,108, 69,237,217,126,218, 55, 37, 29, 78, 73, 39, 53, 62,205,
+ 161, 7,247,158,217,122, 88, 64,219, 83,112,165, 22,248, 64,106,
+ 43,186,242,233,144,142, 82, 11, 44, 79, 91,137,161,164,231,101,
+ 255,166, 49, 77,122,158,148,158,244,188, 92,124,153,203,188,193,
+ 188,150, 29, 70,112,142, 84, 8, 73,162, 24, 69,156,157, 36,146,
+ 156, 0, 98,211,201,163,108, 50,183,166,137,140,185,103, 84,124,
+ 102,241,165,207,125,246,210,165,203,217,180, 25, 3,199, 75,134,
+ 38,178,221, 78,111,154, 29,127, 49,219,251,247,239,127,231,175,
+ 254,234,218,229, 43,215,158,120,210, 29, 28,144,215,101, 73, 8,
+ 50,131,162, 73, 28, 84,185,172,181,213,218,100,194, 50,217,183,
+ 182,122, 77,106, 46,199, 89, 78, 69, 89, 58, 26,152, 31,120, 33,
+ 103, 6, 7, 30, 93, 79, 60,178,103,224,163,147,237, 59,177,235,
+ 20,178,123, 53,247,134,122,109, 31,169,149, 15, 89, 74, 41, 7,
+ 228, 37,165,231, 73,223,247,188,220, 95,158,244,189,220,101,137,
+ 239, 6, 75, 81,183,176,117,206, 16,160,188, 45,146, 30,147,226,
+ 36, 93, 24,109,180,214,198, 24,179, 73,166,187,178,244,249,159,
+ 125,249,194,249, 11, 89,251,207, 21,217,224,209,223, 99,183,216,
+ 17,253,197, 65, 16,188,242, 23,127,113,182,213,254,228, 71, 94,
+ 200, 14, 35,166,135,231,172, 49,108,147, 23, 32,247,145, 54,170,
+ 226, 35,109,148,182,233,245,202, 42, 99,180,114,174,209, 70,169,
+ 210,246,201,205,147, 56,150, 23,131, 69,191,204, 29, 17,234,230,
+ 41,222,187,178, 27, 49, 58,193, 77,112,220, 33,236, 54,108,242,
+ 177,170,215,134, 74, 45,183,129, 59,170, 67, 10, 33, 60, 79, 10,
+ 81,142,102, 82,122,158,231,121,210,247,165, 39, 61,207,151, 94,
+ 234, 50, 47,151, 90, 97, 52,175,148,203,178,222,127,158, 20,211,
+ 166, 88,122, 4, 43,249, 4, 27,173,149,210,218, 24,179,238,139,
+ 198,213, 43, 95,252,202, 87, 90,173,118, 90, 14,151,162, 36, 13,
+ 251, 58,180, 59, 38,166,233, 47,107,237, 27,111,188,254,193,245,
+ 235,159,249,232,199,150,218,109,119,152,123,210,141, 50, 73,158,
+ 82,202,104,173,149, 50, 42,249,154,252,171,139,175, 90,155, 56,
+ 46,174,209,233, 6,201,198, 73, 34, 51, 74, 23,133,100,126,108,
+ 177, 24,169,192, 92, 58,213,153, 15, 45, 41, 24, 10, 28,143,221,
+ 196,158,199, 7,246,144, 90,213,104,162, 66,214, 64,171, 84,154,
+ 158,231, 75, 79,122,190, 47,253,228,178,231,249,158,244,156,176,
+ 230,121, 89, 91, 77,150,134,170,101, 3, 47,138,118,152, 49,198,
+ 24,173,181,210, 90, 41,165,180,138,152, 31, 44, 53, 95,248,242,
+ 23,175, 61,247,188,231, 57,227,212,168,116,226,131,107,177,210,
+ 137,251,227,179,216,225,252,197,113, 28,255,233,127,252,143,207,
+ 95,186,242,212,227,143,167, 51,249,185,230, 82,218,106,173,149,
+ 54, 42,214, 74,233, 56,249, 55,185, 28,155,228,114,172,140,138,
+ 77,172,180, 82, 38, 86, 90,197, 70,105, 19, 43,163, 84, 17,193,
+ 116,214,146, 55,206,192,174, 52, 91,101,211,212, 12,158,125,188,
+ 159,136, 32, 41, 48, 35,106, 27,172,171,196,176,164, 38,134,101,
+ 180,161, 58,115,143,108,230,170,242, 60,223,243,147, 74,211,243,
+ 124, 63, 19, 89, 22,208, 60, 95,122,178,200,101,249, 64,217,196,
+ 98,201,216,162,180,142, 74, 21, 22, 43, 21, 43,213,175,251,244,
+ 252,211, 63,247,139,191,152,157, 43, 94, 29,111,187, 71,105, 57,
+ 174,138,242, 16,254,226,173,173,173, 87,254,252,207,191,252,241,
+ 151,150, 22, 22,136, 40, 29,119,154, 55,182,148, 74,157, 21,197,
+ 58,142, 84, 28,235, 40,214,113,172,162, 88, 69, 81,114, 65,199,
+ 177,137,227, 68,106, 38,142,203,129, 43,105,105, 25,174,180,177,
+ 156,105,101,170, 11, 88,192, 83,224,228, 74, 77,136,225, 58,171,
+ 4,180,138,206,210,227, 0,206, 65, 0,207, 79, 83,152,231,251,
+ 137,209, 60,223,175,232,204,243, 60,247, 56,102, 50, 7, 70,242,
+ 1, 52,214,106,163,181,210, 74,235, 88,197,113,172, 98, 21,199,
+ 68,219, 79, 60,250,213, 95,249,229,124,176,216, 32, 35, 91, 76,
+ 28,187,191,152,248,198,251,239, 95,127,253,141,207,124,244,167,
+ 234,181,154,200, 78, 69, 76, 14, 20, 38, 1, 74,199,177,142, 99,
+ 21, 70, 42, 10, 85, 24,199, 81,168,194, 72, 69, 81,250, 53,138,
+ 18,139,233, 40, 54, 74,101,129, 75, 27,109,138, 33, 93,110, 39,
+ 139,120,248, 28, 47, 80, 21, 56, 53, 82,115, 63,230, 98, 96,162,
+ 124, 55,157, 9, 18,123,187,204, 75, 19, 89, 26,196, 82,151,213,
+ 252,204,101,190,231,229,135, 8,100,118,154,122, 58, 94,219, 24,
+ 109,140,209, 74,199, 74,197, 42,142,149,138,162, 40,102,219,121,
+ 100,237, 51,191,250,141,203,151, 47,167,227,220,134,121,108,224,
+ 112,229,174,167,129, 29,151,191,152,237,107,175,189,182,125,231,
+ 238,231,126,234, 99,148,159,172,103, 44, 91,155,116,181,116, 20,
+ 167,158, 10,195, 56, 8,227, 48,140,131, 64,133, 81, 28,134,113,
+ 24,230,254, 74, 4,151, 52,188, 74, 45,173, 98, 10, 7, 34,226,
+ 253, 58, 89, 0,156, 82,163, 13,213,217, 96,177, 57,232,178,236,
+ 196, 39, 41, 18,145, 73,233,101, 69,165, 95,243, 61,207,247, 19,
+ 145, 37,245,166, 87,196,177,188,150, 76,122, 97, 74,171, 56, 86,
+ 113, 28, 71,113, 28,169, 56,138,227,238, 99,231, 63,250, 75,191,
+ 240,252,135, 63,236, 73, 47, 59,111, 93, 10, 57, 74, 28, 59, 82,
+ 16, 27,213, 95,204,246,123,223,251,222, 50,211,135,174, 60,145,
+ 62, 66, 50, 74, 36, 57, 38,168,148, 10, 67, 21, 69,113, 16,196,
+ 253, 48,238,247,163,126, 16, 5, 65, 28, 4,137,200, 84, 24,170,
+ 40, 86,113,164,227,172,127,111, 12, 59,227,221, 43, 67, 70,161,
+ 42, 0, 14,173, 51,215,101,110,247, 92,150,102,199, 72, 90,101,
+ 194,203,154,250,190,239,123,190,159,126,117, 69,150, 40, 44,233,
+ 235,103, 41, 76,169,204, 95,113, 28,197,113, 24, 71,209,217,149,
+ 167,190,241,139,159,120,233,165,100,233,223, 52,244,185,231,141,
+ 86,210,216,240, 6,255,193, 20,230,143, 38, 47,126,237,181,215,
+ 150, 12, 63,115,229, 74,209,173, 55, 54, 25,168,165,163, 56, 14,
+ 66, 21, 4, 81, 16, 68,189,126,212,235, 71,253, 94,212, 15,162,
+ 94, 63, 14,195, 56, 8,211,216,165,148,206,142, 39,186,141,173,
+ 161,163,177, 0, 0,251, 86, 30,217, 50, 34,238,100, 71,217,105,
+ 219,196,197,100,174,156,207,179,207,130, 51,145, 25,147, 72, 70,
+ 107,157,100, 49,157,212,150,169,196, 10,151,165, 69,101, 62,248,
+ 158,173,176,236, 49,249, 36, 44, 9,195,100,152,124, 38,117,103,
+ 253,237, 63,248,247,126,173,246,209, 23, 94,144,158,199,150,133,
+ 20, 44, 89,112,114,211,100, 61, 96,145, 75, 53, 23, 46, 39,203,
+ 155, 48,113,145,200,120, 68,133,249, 35,188,100,124,227,198,251,
+ 15,111,127,240,233, 15,127,132,242,179,215,147,110,189, 82, 42,
+ 138, 84, 16,196,253, 32,234,245,194,110, 47,236,246,194, 94, 47,
+ 234,245,163, 32,136,250,129, 10,195, 36,104, 22,227,182, 6, 3,
+ 23, 0,224,200, 58,219,195,101,233, 44,135, 68,194, 21, 25, 9,
+ 193,198,178, 16, 66, 88,107,165,144, 70,106, 41,165,167, 61,157,
+ 228,174, 76,100,190,163,176,164,150, 20,150,133,101,201,228, 17,
+ 249, 66, 24, 34,159,201,183,172,111,221,125,237,255,252,119, 11,
+ 11, 11, 79, 62,249,164,148, 82,178,100,102, 41,153, 89, 72, 41,
+ 89,144,116, 39, 99,115,151,124, 74,213,197,204, 7, 83,216,190,
+ 254,226,173,205,205,183,255,246,239, 62,255,209,159,202,229, 69,
+ 214, 90,173, 77,172, 84, 24,170,126, 16,245,131,176,211, 13,187,
+ 221,176,219, 13, 58,221,168,223,143,250, 65, 28,132,113, 20,169,
+ 56, 50, 74,235,108,124,124,113,226,206, 1, 39,138, 1, 0, 28,
+ 218,101,204,105,113,198,196,105,129,153,137, 76, 16, 11, 22, 44,
+ 132, 37, 43, 88, 74,107,211, 1, 95,210,120, 90, 26,207, 55,190,
+ 103,124,223,243, 18,139,121, 73,123,139,136,200, 90,193, 86, 50,
+ 121, 76, 73, 22,171,145,208, 66,154,235, 55,191,245,111,255, 96,
+ 233,191,255,239, 86,207,158,245,164,199,146, 89,178,148,169,200,
+ 178, 18, 86, 74,105,157,234,150,184,112,216,193, 20,230,253,143,
+ 255,211, 63,220,227, 53,137,227,248, 79,255,159,255,247, 43, 47,
+ 126, 60, 61, 93,221, 90, 50,198, 42,109,162, 88, 7, 97,220,235,
+ 71,157,110,184,179, 19,108,239, 4,219,219,253,237, 78,208,233,
+ 132,157,110,212,235,199, 65, 16,135,161,138, 99,163, 84,118,122,
+ 35,115,101,185, 86, 48,153,119, 54,179, 37, 50,217,192, 57, 49,
+ 116, 29,198,108, 54, 2,195,108,152,147,191,221, 98,151, 51, 2,
+ 45,167,155,101,127,132,134,111,152, 28, 66,206,142,203,236,241,
+ 184, 35,237, 30, 24, 83,203, 76, 56,225, 44, 17, 71,218,117,206,
+ 150, 96,160,129, 9, 23,210,137,249, 40,155, 51,134,146,182,143,
+ 97, 74,102,142, 49,150,181,177,198, 48,145,101,226,245,141,183,
+ 59, 15,159,254,200,135,165, 20,233,212,137,229, 79,124,117, 73,
+ 60, 42, 45,102, 55,228,108,240, 67,229, 47,182,214,254,167, 63,
+ 249,147,207, 61,247, 97,107,173, 76, 15,162,178,213,218,102,201,
+ 43,236,246,194, 78, 39,216,233, 4,157, 78,208,233,134,189, 94,
+ 212, 79,181,165,149, 74, 99,151,205,231,231,152,155,105,169, 78,
+ 144,185,200,176, 13,140,238, 25, 21, 26, 67, 68, 13,207, 91,244,
+ 106, 45,207,247,202, 11,145, 25,230,200,152,174, 86,129,213,150,
+ 185, 38,229,130, 87,107,123,126,178, 24,180,235,154,200,218,158,
+ 86,125,163, 52,179, 39, 68,219,243, 23,252, 90, 93,122, 94,121,
+ 51,197,182,175,117,207,168,216, 90, 73,212,244,252, 5,191,214,
+ 148,222,224,227, 6, 70,119,181, 10,141, 38,162,134,244, 22,252,
+ 90,203,243,124, 33, 97,177,241,230,178,106,129,201, 34, 47, 45,
+ 147, 56, 38, 4, 49,147, 48,134,165,100, 33, 44,179, 21, 50,153,
+ 25,207, 26,207,250,214, 26,227, 39, 3, 47,146, 9, 45, 44,147,
+ 101, 73,228, 17,121, 68,190,148, 62,179, 47,217,176, 53,175,190,
+ 246,103, 23,254,248,231,126,225, 23,253, 26,123, 82,178,244,216,
+ 115, 22,173,145, 44, 73, 74, 65,182, 88,125, 32, 95, 49, 47,111,
+ 135, 9, 22,249, 76, 63,226,160,254, 98, 38,122,227,141, 55,174,
+ 174,174,181, 27,117, 50,217,250, 99,198,152, 88,153, 40, 82,253,
+ 126,212,233,133,157, 78,176,189,147,248, 43,236,245,195, 36,115,
+ 69,177,214,202, 24, 99,141, 53,214,112,121, 73, 8,200,107,146,
+ 24,182,219, 42,190, 19,246, 54,226,112, 51,142, 60, 33, 26,158,
+ 119,181,189,124,174,209, 92,244,235,126,246, 7,208, 50,247,180,
+ 186, 23,246,215,163, 96, 83,133,150,185, 38,189, 71,155,237, 71,
+ 155, 11, 43,181,122, 67,122,233, 42,211,204,161, 53,247,163,224,
+ 78,208,219, 80, 81,108,141, 47,228, 90,189,113,185,181,180, 90,
+ 111,180, 60, 63, 55,157, 98,187, 25,135, 31, 4,253,141, 56,232,
+ 106,237, 9,177, 84,171, 61,209, 90, 90,107,180, 22, 60,223,203,
+ 30,215, 48,239,168,248,110,216,187, 31, 5,155, 42,146, 36, 26,
+ 158,247, 68,123,233, 92,189,185, 92,171,215, 8, 10, 59, 46,145,
+ 57,139,184,164,245,100,201, 98,214,178, 16, 44, 4, 39,195, 87,
+ 61,201,238,217,129,214,114, 58, 82,159, 18,133, 9,102,143,200,
+ 19,210,151,214,103,161,133,148, 97,188,253,202,119,223,188,122,
+ 245, 67,215,174, 89,207,243, 60,246, 88,178,231,177, 27,197, 4,
+ 137,108, 77, 21, 34,153,239,154,171, 48,218,175,144,244,119,123,
+ 166, 65,191,255,254, 27, 63,254,252,135, 95, 32, 99, 57,153,247,
+ 44, 57,107, 58,140,226,126, 16,117,187,225, 78, 42,175,126,167,
+ 147, 37,175, 40,142, 99,173,149,209,198,102,230,130,188,166, 88,
+ 54,134,214,220,139,250,215,251, 59, 55,131, 94,100, 77,114,253,
+ 205,160,251,213, 11,151,155, 73, 4, 35, 65, 68,202,218,205, 56,
+ 188, 25,116,223,233,237,116,141, 74, 54,123,167,183,243,169,213,
+ 11,139,203,103,107, 68,146, 73, 8, 50,204,219, 42,250, 32,232,
+ 253,164,247,112, 35,142,146,205,222,234,209, 67, 21,127,246,236,
+ 197,186, 76, 75,206,196,134,119,195,254,187,189,237,219, 81,223,
+ 102,111,128, 59, 97,255,203,231, 30,111,121,158, 71,156,124, 98,
+ 34,163,215,163,254,205,160,251,118,111,199,221,189,207,157,189,
+ 184,224,215,124, 65,176,215,241,137,172, 20,199, 6, 44,150,188,
+ 127, 88,202,236, 4,227,108,206, 97,203,108, 45,121, 54, 57, 5,
+ 156,152, 5,179, 96,146, 68,158, 16,158,144,190, 96, 95, 90,205,
+ 66,221,223,250,193, 31,255,167,199, 30,123,108, 97, 97,145, 45,
+ 179, 39, 37,179,231,121,196,204,228,229, 41,140,136,164,144,148,
+ 182,195,100, 69, 97,251,246,194,228,208,103,103, 45,127,243, 79,
+ 255,244,167,159,126,150,141, 33,107,217,104,214,218,196,202,132,
+ 145,234, 7,113,175, 23,117,186, 97,167, 27,118, 58, 97,167, 19,
+ 117,123, 73,195, 94,197,145, 78,166,139,176, 38, 25, 32, 65,144,
+ 215,244,176,196, 61,173, 58, 42,190, 17,116,115, 59, 16, 81, 71,
+ 171,255,252,224,131,154, 40, 10,195,200,154,109, 21,223, 14,123,
+ 185,188,136, 72,179,253,235,135,235,145, 53, 50,139, 75,138,237,
+ 142, 82,247,162,126, 46,175,132, 31,119, 31,222,137,250,126, 86,
+ 24,106,182, 93,173, 54,227,232, 3, 71, 94, 68,116, 47, 10, 94,
+ 239,108,122, 89, 97,200,196,129, 49, 59, 42,126,199,145, 87,178,
+ 123,127,181,121,183, 38,164, 32,129, 99, 60,199,106,177, 98,122,
+ 115,202, 87,106, 78, 47, 91,102, 75,156,204,185,110,172,213,214,
+ 170, 98, 46,157,164, 57,164,141,214, 73, 34, 19,196,201, 34, 75,
+ 94,250,175, 76, 46,200, 55,222,121,229,155,223, 76, 50, 77,178,
+ 189, 78,102,226, 73,166,237, 75, 7, 35,216,124,233,136,172,209,
+ 84, 44,103, 89, 89,170,116, 20,127, 17, 17,221,189,123,231,188,
+ 95,247,132, 32,203,172, 13, 43, 99, 99,101,227, 88, 7,161, 10,
+ 130,184,219,139, 58,221,112,167, 19,238,116,195, 94, 63, 31, 39,
+ 161,149, 74,167, 72,205, 23,251, 26,120,165,192, 4,139, 71, 86,
+ 214,238,104, 21, 91, 91,249,209, 70, 28,238, 8,235,249,126,242,
+ 6, 73,122,231, 15,226,176,178, 89,108,237,219, 65,167,214,168,
+ 39,198,177,233,102,209,224, 99,253,168,187, 85,111, 54,211,129,
+ 218, 76,134,121, 83, 69,102, 64, 63,127,183,179,217,168,215,165,
+ 231, 37,159, 25,205,182,111,116,232,200, 43,161,171,213,186,137,
+ 189,154,143,242,113,194, 22,203, 39,243, 76,215,122, 38, 78,142,
+ 213, 20, 34, 75,228, 99,141,214,201, 60,162, 38, 25, 14, 37, 4,
+ 73, 18,146, 74, 10, 35, 99,182,190,255,183,119,239,222, 81,201,
+ 180, 21,249, 36, 90,153,192,114,139,241, 16,133, 13, 91, 90,121,
+ 63,127, 49, 17, 25, 99,191,243,151,127,249,204, 35, 23,147,163,
+ 141,108, 12,107,109,226, 88,135,145, 10,130,184,215,143,186,189,
+ 100,192, 68,212,239,199,253, 64, 69,145,202,202, 70, 99,109,101,
+ 158, 64,152,107, 90, 72, 18, 53, 41, 3,171,135,219,205,247,252,
+ 122, 45,155, 29, 93,216, 93,126, 81, 94,173,230, 55, 82,227, 72,
+ 33,106, 82,122,195,164, 34,165, 87,107, 54,164,239, 39, 45,216,
+ 154,148, 53, 57,252, 79,227, 29,171,252, 90, 45, 89,147,218, 43,
+ 141, 2, 42,241,129, 10,235,141,134,220,229, 78,192, 49, 89,172,
+ 48, 87, 42,175,116, 22,157, 68, 97, 58, 61,207,185, 80, 88, 62,
+ 171,113,242,123, 79, 78,152,244, 10,139, 9,186,125,239,187,255,
+ 249, 47,162, 40, 82, 90,105,149,228, 54,157, 26, 76,167, 45,242,
+ 1,133, 13,134,176, 93, 87,123,144, 21,121, 49,209,173, 91, 55,
+ 47, 47, 46, 91, 99, 41, 57,155, 90,235, 52,124,133,161, 10,194,
+ 184,219,139,186,189,168,215,143,123,253, 56,200,228,165,180, 53,
+ 198, 50,228, 53, 67,120, 66, 46,250,181,203,173,197,225,141,207,
+ 90, 93,250,105,205,215,144,242,145, 70,123,248,157,248,190, 95,
+ 171, 37,135,182,125, 33,151,252,225,161, 72, 72,233,213,211,152,
+ 230, 9,185,224,213, 26,210, 27,122,135,207,158,127, 68,250, 30,
+ 9,146, 68, 45,207,111,123,195,143, 32, 61,115,238,130, 87,175,
+ 145, 68, 0,155,116, 95,140,156, 37,253,152,210,225, 20, 54, 11,
+ 233,198,178,225,108,250,119,107,147,252,197,249,192, 23, 74, 21,
+ 150,254, 75,194, 19, 34,250,241,219,183,111,223, 86,177, 82, 42,
+ 171, 60,181,214, 38,115, 88,118,164,207, 81,152, 45, 2,152,179,
+ 234,233,208, 42,178,250,247,205, 26,251,215,223,254,206,149,149,
+ 179,233,200, 14,109, 56,153,198, 43,138,117, 24,169,126, 63,238,
+ 7,113,175, 23,247,251,113, 16,170, 48, 82,113,108,180, 54, 69,
+ 240, 98,198,201, 64,179,129, 16,212,242,252,103, 23, 87,150,252,
+ 90,229, 71,143, 46,157,121,250,220,133,252,247, 84,151,222,106,
+ 189,241,161,197,149,202,102, 77,191,246,201, 75, 79,230, 17,222,
+ 23,242, 76,173,241,226,202,185,193,199,250,252,147, 79, 39,237,
+ 86, 34,242,132, 88,244,107, 31, 59,179, 86, 31, 80,216, 75,143,
+ 93, 17,158, 76,198, 22, 9, 33,154,158,127,109,105,117,173,222,
+ 172,108,182,218,106, 63,189,118, 33, 89, 52, 15,191,199,153, 80,
+ 88,210, 17, 99, 54,233, 74, 22, 54, 93, 26,167, 88, 89, 62,121,
+ 203, 37,107, 31, 9, 73, 34, 91,167,151,104,125,227, 7,223,250,
+ 118, 28, 71,233,228,135, 74,107,173, 76,230,176,244,140,112, 71,
+ 97, 92, 14, 97, 89, 25, 57,124,192,123, 62,126, 53,141, 75, 31,
+ 124,112, 91, 60,216, 90,110,182, 4,179,176, 76,214,178,214, 54,
+ 138,211,206,125,183, 31,118,187, 97,183, 23,246,250, 81, 16,196,
+ 201, 56, 47,227, 62,178, 51,234, 23,111,135,233, 43, 76, 52,164,
+ 255,196,210,202,123,253, 78,100,210, 66,242,177,229,149, 95,251,
+ 169, 79, 54,153,162,126,223, 40,149,111,246,228,226,153,187,113,
+ 184,157,181,183,154,181,218,127,253,177, 79, 62,214, 94,140,186,
+ 61, 29,199,105, 97,232,121,143,180, 22,164,231,221,236,117,242,
+ 71,249,194, 83,207,126,238,210,147, 81,175,175,194, 40, 85,152,
+ 148, 75,181,250,249,246,226,123,189, 29,205,105,247,237,233,181,
+ 243,191,242,209, 79,112, 24,199,253,192, 90,155, 20,164, 13,207,
+ 191,180,184,124, 55,238,247, 84,122,232, 96,181,189,240,247, 94,
+ 250,108,147, 41,236,245,140, 82,248, 37, 78,231,157,147,126,117,
+ 230, 76, 21,165, 63,141,206,114, 29,233,117,201,231,221, 50,167,
+ 181,103, 54, 22,218, 18,199, 65,112,230,233, 39,219,237,118,101,
+ 122,198,236,159, 98,225,224,252,254,203,139, 13, 87,150, 8, 41,
+ 30, 54,159,127, 34, 61,236,248,127,255,187, 63,252,233,179, 23,
+ 132, 16, 30, 9,201, 44,172,101,165, 77, 20,171, 32,136, 58,221,
+ 96,167,211,127,184,221,223,217, 9,186,189, 40, 8,162, 40, 82,
+ 74,233, 34, 68, 22,254,130,188,102,165, 11,230,121,126,189, 86,
+ 111,181,110, 71,193,142, 81,107, 11,139, 79,173,174,197, 65, 16,
+ 236,116,226, 94,223,102,173,125, 33,165, 95,171,213,154,205, 77,
+ 214,247,163, 96,109,113,233,209,165, 51,190,181,193, 78, 39,234,
+ 246,140,214,185, 16,165,239,213, 26,205,192, 19, 15, 84, 36,125,
+ 239,177,229,149,229, 90, 61,236,116,131,157, 78,162,185,228,157,
+ 41, 60, 89,107, 52,108,163,182,161,227, 29, 21, 63,190,178,122,
+ 113, 97, 41,234,245,251, 59, 59, 42, 8,243, 63,166,210,243,252,
+ 90,173,222,106,221,142,251, 59, 70,175, 45, 44, 94, 93, 61, 23,
+ 7, 65,176,179, 19, 57,187, 7,166,171, 48,145,157,186,232,101,
+ 199, 25,125, 41, 61, 33,124,233,249, 66,120,153, 88, 44,179,102,
+ 171,172,141,172, 9,141, 9,141, 9,173, 14,141,137,172,105,253,
+ 204,231,190,244,179, 47,215,106, 53,223,247,125, 63,253,127, 54,
+ 229, 69, 58, 67,172, 39,179,127,210, 89,100,221, 89, 43, 6,166,
+ 220, 73,218, 32,110,248,234,247,123,173, 72, 25, 99,124,145, 78,
+ 77,200,198,218, 88,153, 40, 54, 97,164,195, 72, 39, 51,225,132,
+ 81, 50, 25,180,209, 38, 63,191, 0,242,154,209,138,192, 90, 29,
+ 43, 34,122,180,209,184,220, 94, 36, 33,186, 27,155, 42, 8,117,
+ 28,187,118, 72, 38,113, 35,162,213, 70,253,252,210,170,144,210,
+ 236,116,194, 40,210, 81,156,203, 43, 9,241, 86, 27, 77, 81,171,
+ 209,120,170,181, 40, 61,143,195,184,187,221, 85, 81,228,102, 37,
+ 38,174, 62, 35,195, 0, 0, 32, 0, 73, 68, 65, 84, 38,107,117,
+ 28,251, 68,143, 54, 26,151,154, 11,100,168,243, 96, 83,133,161,
+ 86,202,173, 4,172,177,154,146,221,107, 94,110,215, 72,136,206,
+ 198, 70,242, 6,131,188,166, 94, 75,138,236, 76,239,100,230, 10,
+ 98,178,130, 4,145, 37, 50,108,133,240, 44, 91, 75, 50, 27,126,
+ 90,204, 60,150, 86,145, 73,168, 34, 18, 68, 59,111,191,219,253,
+ 244,167, 22,151,150,242, 37,117,138, 97,104,162,136,122,121, 36,
+ 147, 76,204,146,178, 19, 54,147,193,105, 34,249, 82,236,157, 59,
+ 126,149,249,205, 55,223,124,116, 97,137,141, 97, 33,153,217, 26,
+ 75,218,216, 56, 54,113,164,163, 72, 71,145, 10, 28,121, 37,171,
+ 162, 57, 29,123,136,107, 22,223,133,204,108, 76, 28, 88, 21,197,
+ 201,225,188,228,136,209,224,150,214, 90, 27, 69, 90, 41, 33,250,
+ 66,136,100, 9,173,193,223, 41, 51, 39,163,252,226, 32, 72,122,
+ 94,156,117,112, 43,155, 37, 51,142,168, 48, 20,178, 24,192, 61,
+ 68,176,198,196,198,170,120,159,221, 3, 83, 84, 88,113,214, 36,
+ 177,205, 78,182,182,214, 90, 41, 13, 89, 33,146, 65,244,249,218,
+ 222,148,205,146, 35,164, 72,207,162, 16,247, 55,223,123,239,189,
+ 107,207, 61,231,188,161,156,117,116,139, 10,178,152,120,145,136,
+ 165,180,204,210, 45, 90, 43,227, 88,253,108,166, 83,178,204,239,
+ 189,245,214,139, 75,171,172, 13, 11,203, 76,100, 12, 39,107,106,
+ 36,147,217,135, 81, 50,147,189,206,103,124,182, 54,159, 8,199,
+ 61, 4, 11,102,209, 99,150,205, 8, 94, 72, 15,134,143,166,197,
+ 145, 54, 75, 78,251, 31,211,238,129, 41,137, 44,201, 97,204, 44,
+ 88,144, 77, 38,174, 32,178,204,146,132, 77,198,239,151,187, 87,
+ 233,140,209, 89,175,140,251,193,141,183,222,126,234,234, 85, 87,
+ 16,197,242,228,130,132, 32, 35,132, 48,133,201,152,137, 89, 50,
+ 115,169,225, 85, 12,202,103, 34, 81,228,175, 48, 8, 90,177,177,
+ 218, 72,201,150, 4, 49, 11, 99, 88,105,171,148, 73,150,219,200,
+ 102,127, 54, 74, 39, 3,236, 43,167, 7, 65, 94, 0,156,200, 8,
+ 86,104, 76, 16, 23, 99, 92,133, 37,182,130, 5,145, 76,227, 87,
+ 113,114, 82,218, 50,163,108, 97, 73, 18,225, 7,119,251,189,158,
+ 88,204, 58,246,238,146,145,105,209,153,152,204, 80,102,192,228,
+ 4, 76, 34, 33, 68,126, 84,176, 52,126,199,207, 42, 81,254,224,
+ 131, 15,150,125,159, 77, 22,169, 44,179, 49,156, 44,215,152, 68,
+ 48, 85, 76,253, 92,156,222,152,141,209,192,152, 9, 0, 78, 65,
+ 21, 89,138, 96,146, 68, 30,193,178,179,237, 83, 15, 8, 55, 97,
+ 37,183,220,233,222,191,127,191,209,104, 8,167,192, 44, 45,206,
+ 43,132,169, 76,150,111,147, 42, 50, 31, 97,150,252, 87, 68, 48,
+ 63,139,239,244,238,187,239, 94,246,235,108, 12, 91,145,204, 81,
+ 72,218,176,214, 54, 89,155, 67,101, 10, 43,102,197,169,154, 11,
+ 2, 3,224, 68,167,176,116, 90,155, 44,130,165,218,226,100,134,
+ 196,116,213,219, 66, 4, 69,253,152,124,187,221,185,115,231,206,
+ 35,143, 60,146, 23,153, 84,158, 24, 63,185, 96,203, 10, 75,207,
+ 202,100, 73,201,212,215,229, 8,230,115,218,244,176, 59,119,239,
+ 25,191, 37,165,180, 66, 8, 38, 97, 44,165,245,163,182, 74, 89,
+ 149,230,175,116,204,218, 96,233, 8, 0, 56,233, 22, 75,211, 78,
+ 110,177,116,250, 73, 33, 69, 90,231, 57,155, 59, 3,184, 50,187,
+ 109,221,254, 32,254,200, 71, 74, 11,238,138,116,180,126,178,244,
+ 154, 16, 82, 72, 43,140, 21,233, 37, 43,178, 53, 40, 69, 62, 72,
+ 150,178,163,145, 68,126,178, 83, 81, 20,214, 99,109,133, 73,211,
+ 32,179,180,150,180,177, 90, 25,165,141, 54,201,130,216,233,114,
+ 103,197,128,219,188,103, 15,149, 1,112, 58, 34,152, 51, 41, 23,
+ 23,115, 87, 8,206, 38, 12, 41, 90, 96,197,188,132,169,217,212,
+ 230,195, 48, 8,220,133,213,146,149,144,210,139, 82,202,124,197,
+ 34, 43,172,176, 66,138,100, 46,178,124, 18,223,172, 17,150, 30,
+ 136,244,147,129,249, 59, 59, 59,181,164,225,101,217, 10, 18, 54,
+ 173, 31,109,178,172,172,214,214,232,114,229,232,156,228,200, 40,
+ 30, 1, 56, 53, 17,140,137, 69,222, 59, 18,201, 92,227,110, 9,
+ 57,128,115, 0, 32,138,186,221,110,189, 94,151,114,112,149,112,
+ 45,117,234, 48, 35,165,176, 54, 49,152, 16,130, 57,139, 96,194,
+ 105,132, 9,230,236,248, 35,111,111,111, 55,153,172,214, 86, 74,
+ 73,194,218, 60,127, 25, 78, 44,150, 45, 52,203,214,157,163, 7,
+ 226, 2,224,180, 69,176,172,207,149, 76,202, 75, 34, 85, 75, 50,
+ 45,229,192,108,247,238,205, 57,136,186,221,238,242,242,114,186,
+ 72,119, 58,208, 94,107,153, 99,146,175, 54, 41, 30,237, 64, 21,
+ 41, 68,145,240,152,252, 36, 4,110,111,111, 11,107,153, 12,219,
+ 108,135,146, 56,102,138,245,177,173,201, 7,124,237, 54,155, 5,
+ 0,224,180,120,204,169, 31,211,238, 23, 21,163, 28,134,247,148,
+ 216,152, 94,175,103,180,214, 89,240,210,217,127, 58, 79, 97,158,
+ 148, 86, 74,107,172,149,210, 10, 43,109, 54,143,117, 81, 69,230,
+ 231,101,250,137, 75,123,221,110, 75, 91, 43,201, 74,182, 36, 4,
+ 179,181, 76, 73,224, 74,102,209,201, 87,156,117, 98, 23, 38, 38,
+ 4,224, 52,218,139,243,229,139, 6,230, 40,101, 26,218, 79, 74,
+ 167,169, 14,163, 32, 8,180, 49, 66,235,188,112,212, 73,234, 50,
+ 198, 24, 35,165,244,140,177, 73, 12,179,198, 90, 41,172,149, 66,
+ 90, 81,116,193,210,168, 71,130, 4,167,227,239,149, 82,117,163,
+ 211, 69, 66,146, 54,156,205,230,255,178, 38, 89,109,155, 77,113,
+ 98, 7, 15,238, 27, 0,224,116, 68, 47,166,124,184,106,178,188,
+ 119,238, 52,225,142,165, 42, 47,166,155,126, 81, 74, 25,173,147,
+ 243,179,141, 54, 58,215,151,244,140, 52, 82, 74, 99,140,148,158,
+ 148,214, 74,107,173,149, 86,102, 17, 44, 31, 75,145, 87,145,194,
+ 15,131,208, 24, 19,132,161,191,211, 37,207, 99, 41, 89, 72,203,
+ 36,172, 37, 99,141,214, 42,138, 84, 24,170, 40, 82,177, 50,198,
+ 36, 19, 99,179, 59,103, 54, 97, 81, 71, 0, 78,143,194, 4, 9,
+ 182,156, 24,196, 18, 9,178,146,132, 37, 41,211,249,194,152,117,
+ 54,223, 97, 50, 45,141,205,230,212, 55,204,183,127,242,214,135,
+ 158,125, 86, 74, 45,141,212, 82, 75,147, 4,175,100, 86,124,233,
+ 25,207, 24,227,121,198,218, 76, 96,108,165, 77, 86,242,206,102,
+ 23, 44,202, 85,146, 16, 15, 0, 96,146,100,190,210,102, 24,214,
+ 38,157,246,124,105, 15,107,243, 73, 18, 75, 75,154, 49, 49, 29,
+ 98,126,113,232, 14, 0,112,120, 15,232, 76, 84,195,236,149,253,
+ 196, 49, 24,103,255, 12, 42,204,159,254,179, 1, 0,204, 15, 71,
+ 95,146,192, 24, 99, 60, 79, 26,227, 73, 89,137, 94, 38, 29,234,
+ 96,173,177,214, 75, 87, 86,179,108, 37,203,228,107, 62,248, 33,
+ 169, 32,177,190, 11, 0, 96,162,228,227,177,202, 17,204,154,252,
+ 202, 84, 96,121, 4,115,167,197, 39,119,153,141,195,251, 11,129,
+ 11, 0,112, 24,127,229, 20,101,162, 77,150, 4, 49,214, 21, 87,
+ 190,184,109, 33, 48,114,231,189, 25, 99,253,184,135,227,138,200,
+ 135, 95, 29, 0, 51, 94, 24,102, 83,204,139,177, 74,160,116, 13,
+ 115,197, 90, 89,227, 62,187,170,176, 23, 39, 11,170, 89,206,142,
+ 64, 82, 62,221,179,115,254,208,120, 35,151,187,126, 47, 51, 91,
+ 34,194, 57,146, 0,204,188,188,146, 57, 3,179,213, 58, 74,179,
+ 223,140, 57,127, 21, 10, 51,214,122,133,182, 76, 41,146,113, 58,
+ 108,190,188,168, 26,165,249, 75,112, 58,127, 14,149,150, 92, 43,
+ 205, 49,125, 96,231, 48, 81, 50,208, 67,179, 53,201, 72,144,116,
+ 9, 57, 0,192, 76, 43, 44, 89,128,182, 70,194, 23,194, 23,210,
+ 203,102,175, 31,115, 89, 86, 10, 96, 92,201, 93,249,144,137,108,
+ 101, 5,206,214,180, 45, 41, 44,249,215,207,229,149, 72,199, 79,
+ 43,203,253,246,121, 23, 27, 37,139,190,105,203, 49,155,136,109,
+ 192, 28, 18, 43, 98,131,119, 7, 0, 51, 47, 48, 65,228,179,168,
+ 147,104,145,108, 17, 55, 73,214, 73,202,100,125,142,113,231, 47,
+ 78, 7,184, 22, 2,227,106,223, 43, 95,145,187,218,187,207, 91,
+ 96, 62,101,211,244,252,248,238,237,165, 70,243,234,218,121, 95,
+ 212,188, 67, 41,215, 18, 27,203,138,109, 96, 77,151,109,135,108,
+ 143,108,223,218,190,142, 35,165,176, 64, 17, 0,115, 16,193,132,
+ 88,240,235,171,245,198,178,231, 47,177,183, 36,185, 65,146,132,
+ 28,163,194,210,252,149,228,171,226, 2, 59,253,250,108,212,106,
+ 222,253, 42,250,247,228,158,115,233, 39,123,237,121,222,139, 79,
+ 61, 29, 71,209,255,247,222, 59, 31,191,244,196, 90,171,125,192,
+ 154,145,153,200, 48,199,108, 3,107,182,217,108,145,125,104,212,
+ 253,238,206,189,157,109,188, 45, 0,152, 59, 46, 47,175, 60,187,
+ 124,150, 69,125,153, 68,147, 88,236, 82, 72, 30, 34,146,228,139,
+ 233,101,181, 97, 58,200, 43, 13, 92,153,171, 42,227, 38,184,114,
+ 0,146,136,136,100,190, 20,136,244,188,165,197,197,207, 62,115,
+ 237,221,205, 7, 94,189,126,208,178,215, 50,107,203,161, 53, 15,
+ 217,108,144,189, 27, 7, 63,190,123, 27,242, 2, 96, 78,185,185,
+ 243,240,149, 15,222,187, 21,246,250,108,227,221,103,245, 58,100,
+ 254,114,200,131, 88,170,178,162,109,239,110, 66, 78,221,152,223,
+ 73, 54,254,203, 90,171,162, 72,133,145, 71,226, 76,171,189, 19,
+ 71, 94,163, 62,226,193,135,164,147,150,132,175, 46,217,109,178,
+ 247,194,254,219,247,238,104, 44,231, 7,192, 60,163,172,253,214,
+ 221,155,239,245,119, 20,179, 41, 4,198,123,202,224,128, 6,203,
+ 60,229,246,186, 6,114, 87, 46,175,116, 41,202,252,252, 33,153,
+ 11, 40,189, 35,226,229,122, 67, 25, 45,253,154,244, 61,177,255,
+ 40, 16, 38, 78, 14, 56,218,144,237, 14,217, 45,163,222,185,127,
+ 23,191,123, 0, 78, 6,223, 90,191,253, 80, 69, 78, 24, 57,234,
+ 1, 73,102,215, 97, 84, 57,186,104,135, 92,202,167,186, 41,214,
+ 59, 75,238,196, 47,221,105,186,168, 7,179,177, 66, 10, 33, 37,
+ 141, 80,242, 38,119,170,136,251,100, 67, 98, 87, 94, 88,162, 8,
+ 128,249, 37,111, 34,253,233,221, 27,127,239,137,107,201, 85, 71,
+ 175, 35,243, 6, 86,222,207, 34, 30, 38, 48, 71,113,101,125,229,
+ 67, 40,200, 31, 22,167, 92,239,136, 81,130, 34, 51, 25,230,136,
+ 248, 65,208, 15,148,202,175,255,111,254,219,223,192,155, 0,128,
+ 57,229,255,248,183,255, 38,185,208,209,241, 91,157,135, 47,172,
+ 156, 99,107,199, 50, 48,127,160, 29,191, 23,228, 12,188,119, 87,
+ 202,102, 30,223,249,219,134,200, 16,109,245,187,248,173, 3,112,
+ 242,184, 30,246,252,122,221,243,253,253,234,177,145,228, 85,186,
+ 92, 17, 25,185,230,202,100, 71,217, 90,103,217, 63,201,247, 99,
+ 243, 87,114,135, 91, 65, 31,191,105, 0, 78, 30, 55,123, 59,245,
+ 86, 83,214,252, 97, 53,217,193,207,210, 41,157, 13,148,213,124,
+ 89,159,158,202, 35, 85,211,172,149,231,175,172,103, 69, 52,190,
+ 252, 37,136, 36,145,194, 49, 71, 0, 78, 34,161,209, 94,173,230,
+ 121,222, 56,206, 39,114,231,197,207,207,150,166,114, 49,153,127,
+ 239,230,175,234,173,229, 88,246,161,112, 24, 0,224,132, 34,199,
+ 116, 42,145,123,252, 49, 43, 10,211,132,149,127,235,172, 35,233,
+ 230,175,124,201,141,244, 58,204, 95, 8, 0, 24,177,200, 18, 36,
+ 199, 52, 39, 69, 49,141,170,155,191,138,111, 41,147, 85,166,181,
+ 114,106,226,163,231, 47, 0,192, 41,134,143,176, 49,151, 47, 23,
+ 51,122, 21,249,139,156,252, 85,174, 31,115,225,141,216,191,199,
+ 32, 46, 0,192,152,237,150,159,198,232,204,104, 95,228,175,202,
+ 189,184,103,110, 31,186,255, 5,145, 1, 0,142,170, 7,174,244,
+ 226,121,200, 72,119,103,168,132,187,100,135,243, 32, 99, 61,254,
+ 8, 0, 0, 7,151,222, 80,113, 21,134,202,199,122, 13,249, 57,
+ 252, 5, 0,152,116,252,218,237,218, 98, 97, 90,230,161, 61,178,
+ 129,219,202,169, 60, 1, 0, 0, 98, 87,217, 28,124,136, 25, 78,
+ 145,191, 0, 0,199,144, 94, 14, 21,199,170,147,244, 48, 13,255,
+ 22,254, 2, 0,204,180, 15,247,200, 99, 24,255, 5, 0, 24,107,
+ 226, 26,255, 77,121, 88, 50, 67,254, 2, 0,204,150, 7,249, 80,
+ 150,147,163, 63, 0, 0, 0,236,235, 9, 62,228,237,118,253,158,
+ 119,223, 82, 30,249,177, 0, 0,167,202, 82, 7, 80,192,168,135,
+ 20,249,144, 63, 66,253, 8, 0, 24,123,124, 25,126, 80,113,236,
+ 15, 10,127, 1, 0,166, 46,195, 67, 26, 14,254, 2, 0, 76, 51,
+ 170, 29, 5,248, 11, 0, 48,175, 28,216, 95,104,223, 3, 0,102,
+ 36,162, 73, 40, 10, 0, 48,187, 37, 34,234, 71, 0,192, 73,210,
+ 22,252, 5, 0,152,123, 70,247, 23,170, 74, 0,192,108,229, 52,
+ 57,243,123, 8, 0, 0,168, 31, 1, 0,240, 23, 0, 0,192, 95,
+ 0,128,211,194,113,244,154,228,108,238, 22, 0, 96,222,221, 52,
+ 1, 51,200,202,227, 57, 11,128,192, 75, 0,128,185,169, 31, 75,
+ 11, 74,138, 81,108,123,244,243,199, 1, 0, 39,168, 24,228,201,
+ 22,105,178,188,128, 55, 51,115, 47,142,132,148,194,243,246,118,
+ 24, 0, 0,204, 68,254, 98,182,198,178,101,102,162, 7,221,206,
+ 165, 71, 31, 21,158, 71,101,129, 33, 97, 1, 0,102,206, 95,204,
+ 204,150,147,142,215,223,220,124,255,201,199, 30,175, 53,155,100,
+ 45, 91,139, 23, 8, 0, 48,179,248, 68, 68, 36,132, 16,111,222,
+ 189, 45,132,120,254,234,213,167,159,120,146,163,216,104,205,214,
+ 50,241, 40,211, 93, 35,154, 1, 0,166,227, 47, 33,200,243,188,
+ 151,158,251,240,153,179,171,205,102,211, 42,173,131,208, 42,197,
+ 204, 48, 19, 0, 96,118,253, 37,136, 4, 9, 33, 37,179, 85, 65,
+ 72,177, 18, 74,115, 20,179,214,100, 45, 97, 20, 5, 0, 96,182,
+ 235, 71,178,214,170, 32, 12,180, 49,210,247,137,132,177,194, 88,
+ 184, 11, 0, 48,235,254,226,180,133,111,173, 54, 70,178, 32,225,
+ 113,178,202, 27, 4, 6, 0,152,249,252, 69,217,224, 47,178,123,
+ 15, 93,133,209, 0, 0,179,194,168,231, 63,242, 48,125, 65,102,
+ 0,128,195, 27,100,236,254,130,146, 0, 0,135,246,211,140,230,
+ 47, 0, 0,152,215,250, 17, 0, 0, 78,136,191, 80,102, 2, 0,
+ 144,191, 0, 0, 0,254, 2, 0, 28, 59,179, 85,122,201,121,220,
+ 105, 0, 0, 64,254, 2, 0,156, 28,127, 49,114, 23, 0, 0,249,
+ 11, 0,112, 74,153, 88,238,129,191, 0, 0, 39, 44,127, 29,216,
+ 159, 40, 52, 1, 64,210,162, 9,207, 24,136,252, 5, 0,152,215,
+ 168, 34,231,253, 9, 0, 0, 80, 63,194, 76, 0,128,185,246, 23,
+ 210, 22, 0, 96,126, 74, 76,244,191, 0, 0, 51, 43,168,113,249,
+ 11, 49, 12, 0, 48, 99, 82,144, 39,227,105, 0, 0, 78, 33,168,
+ 31, 1, 0,167,214, 95,200, 94, 0,128,185,243, 23,196, 5, 0,
+ 152,174, 9, 80, 63, 2, 0, 78,109,253,136, 36, 6, 0,152,146,
+ 40,144,191, 0, 0,227,150,210,164, 50, 13,252, 5, 0, 56,205,
+ 245, 35, 0, 0,169,107, 98, 69, 35,252, 5, 0,152,188,204,224,
+ 47, 0,192,188,168,234,216,205, 38,103,107,119, 0, 0, 39,211,
+ 122,199, 34, 15,121,200,157, 1, 0,128,105,115, 32,127,193, 92,
+ 0,128,153,247, 23,143,228, 45,232, 12, 0, 48, 55,249, 11, 0,
+ 0,118, 79, 47, 19,143, 52,242, 24,158, 4, 0,224, 52,137,140,
+ 247, 42,218,142,213, 17, 18,110, 2, 0,140, 51,149, 77,208, 28,
+ 168, 31, 1, 0,135,169,182,120, 6, 34, 15,252, 5, 0, 56, 70,
+ 205, 77,218, 95,140,130, 18, 0, 48, 15, 32,127, 1, 0, 78,142,
+ 191, 70, 27,251,133, 84, 6, 0,152, 29,127,241, 81,189, 4,145,
+ 1, 0, 80, 63, 2, 0, 0,252, 5, 0, 24, 31, 51, 87, 99,201,
+ 185,127, 6, 0,128,169,123,109, 74, 94,144,135, 85, 21, 60, 6,
+ 0,152,178, 19, 80, 63, 2, 0,230, 21,248, 11, 0, 0,127, 1,
+ 0, 0,252, 5, 0,152, 11,120,191,150,215,113,183,196,224, 47,
+ 0,192, 97,220,133,252, 5, 0,128,213,142,201, 95, 60,123,190,
+ 5, 0, 32,140, 13,245, 23,214,233, 0, 0,204, 71,233,136,250,
+ 17, 0, 48,215, 28,213, 95,200,102, 0,128,121,243, 23,188, 5,
+ 0,152,182, 40,228, 12,238, 19, 0,224, 4,120,107, 2,158, 64,
+ 255, 11, 0,112,210,234, 71, 68, 44, 0,192,188,250, 11,213, 36,
+ 0, 96,214, 63,245,114,196, 61,101,104, 10, 0,112, 88,197, 29,
+ 147, 62,208,255, 2, 0,204,107, 36,131,191, 0, 0,243, 10,252,
+ 5, 0,128,191, 0, 0, 40, 20, 39, 91, 98, 74,154,157,125, 1,
+ 0,128,177,248,107, 20, 59,193, 96, 0,128,249,171, 31, 43,230,
+ 98,152, 12, 0, 48, 7,254,130,170, 0, 0,179, 33, 10,121,168,
+ 93,129,195, 0, 0,211, 87, 26,142, 63, 2, 0,230, 49,123,193,
+ 95, 0,128,121, 70,238,237, 76,158,154, 88, 1, 0,224, 72,249,
+ 11,182, 2, 0,204,171,191, 96, 53, 0,192, 17, 57, 70, 97,160,
+ 255, 5, 0,152,148,151,198,173, 50,185,207,131, 32,107, 1, 0,
+ 102,181, 42, 67,254, 2, 0,204, 43,251,251, 11, 9, 12, 0, 48,
+ 175,254,154,233,248, 8, 0,128,191,160, 33, 0,192,220, 37, 21,
+ 244,191, 0, 0, 39,188,126, 68, 44, 3, 0,204,156, 12,228, 9,
+ 125, 94, 0,128,147,175, 55, 57, 31,187, 9, 0, 64,242, 58,162,
+ 191,224, 44, 0,192,236,248, 66,206,218, 14, 1, 0,224,168, 99,
+ 175, 31, 1, 0,128,166, 58,203, 22,252, 5, 0,152, 87,142,230,
+ 47,148,147, 0,160, 92,156, 45,127,193, 74, 0,128,113,155,237,
+ 56,188, 34,199,178,103, 0, 0, 88,139, 39,174, 15,121, 60, 79,
+ 4, 0, 0,166, 82, 63, 2, 0,192, 60, 36, 25,248, 11, 0,112,
+ 220, 22, 59, 46,167,193, 95, 0, 0,212,143, 0, 0, 84,135,147,
+ 237,131,195, 95, 0,128,227,113, 25,252, 5, 0,152,109, 99, 77,
+ 211, 98,240, 23, 0, 96, 62,211,215,110,254,226, 3,239, 52, 70,
+ 127, 1, 0,102, 58,127,241, 46,170,130,188, 0, 0,168, 31, 1,
+ 0, 0,254, 2, 0,204, 10,199, 86,161,201, 81, 31, 9, 53, 34,
+ 0, 96, 90,162, 66,254, 2, 0,156, 48,129,201,153,221, 51, 0,
+ 0,140, 54,186,191, 32, 40, 0,192, 24,165,116,236, 74,145, 71,
+ 120,112,248, 14, 0,176,191, 11,142,207, 20, 18, 90, 2, 0, 28,
+ 78, 82, 83,119, 5,250,247, 0,128,227, 83,221,241, 42, 78, 34,
+ 123, 1, 0,230,148, 35,230, 47,248, 14, 0,128,250, 17, 0,112,
+ 82,138, 70,248, 11, 0, 0,165, 29,206, 95,168, 11, 1, 0, 7,
+ 181,210,196,189, 33,247,219, 73,134,208, 0, 0,123,122,106,106,
+ 122, 56,106,253,200, 60, 19, 79, 3, 0,112,218,138,199,163,248,
+ 139,225, 44, 0,192,116, 65,255, 30, 0, 48,111,185,235, 48,254,
+ 66,210, 2, 0,204,146, 12,144,191, 0, 0,243, 42,179, 49,248,
+ 139,145,203, 0, 0,211,245, 23, 44, 4, 0,152,175, 74, 82,206,
+ 250, 14, 2, 0,192,120,235, 71, 40, 13, 0, 48,117, 63,200,185,
+ 216, 75, 0, 0, 12, 54,102,127, 1, 0, 96,168,249,171, 31, 1,
+ 0,208,215,212,109, 38, 71,182, 43,138, 69, 0,192,108, 33, 15,
+ 161, 40,152, 12, 0, 48,155,245, 35, 38,148, 0, 0,140,189,194,
+ 156,108,253, 56,115,123, 10, 0, 0,199,225, 47, 0, 0, 34,213,
+ 228, 51,142,220,247, 49,144,173, 0, 0,200, 95, 0, 0, 48, 25,
+ 127, 33,119, 1, 0,102,161,246, 28, 87,254,130,211, 0, 0,179,
+ 99, 4,121,168,253,133,199, 0, 0,211, 23,158, 68,210, 2, 0,
+ 204, 41,232,223, 3, 0, 78,149,191,152,136,145,208, 0, 0, 83,
+ 174,217,144,191, 0, 0,135,215, 20, 59, 77,241,201, 27, 76,142,
+ 79,168, 8,100, 0,156,218,160, 53,157,143, 63,242, 23, 0, 96,
+ 94,139, 75, 57,197,199, 6, 0, 64, 85,199,236, 47,216, 11, 0,
+ 48,147,160,126, 4, 0,156, 76,127, 33,122, 1, 0,102,182,124,
+ 60, 68,254,130,211, 0, 0,179,225, 9, 57, 75, 59, 3, 0, 0,
+ 71,240, 23, 68, 5, 0,152,151, 24, 38, 15,186, 19, 16, 28, 0,
+ 96, 70,202, 53, 57, 15, 59, 9, 0, 56, 45,166, 99, 62,128,102,
+ 48,126, 2, 0, 48, 99, 33,140, 71, 93,138, 3,254, 2, 0, 76,
+ 208, 90,214, 10,107,247,220, 62, 61, 19,156,247,200,104,217, 87,
+ 57,206, 61, 3, 0, 64, 85,123,210,221,220,218,185,183,110,226,
+ 184, 90, 40, 14,150,142, 67, 31,138, 75, 9, 77, 78,247,201, 0,
+ 0, 78, 21, 70,233,173, 15,238, 60,184,123,143, 43,206,170, 76,
+ 77,191, 71, 1,201,168, 31, 1, 0, 83, 66,133, 81,208,237,106,
+ 165, 6,211, 23, 87, 4,198,187, 6, 48,248, 11, 0, 48,133, 66,
+ 147,217, 90, 99,114,127,241,176, 57, 17,147,237,216, 17, 88, 69,
+ 97,188,187,191, 80, 11, 2, 0,142,160,168,125,183, 31, 24, 37,
+ 193,238,143,216,153,214,149,147, 18,147,243,105,235,157, 76,198,
+ 200, 95, 0,128,169,186,142, 51, 41, 49, 15,241,217,158, 51, 84,
+ 203,131, 62, 22, 0, 0,238, 57,186, 32,152,136,221, 24,198,204,
+ 165, 92,150,100, 45,222,251, 97,228,193,172, 5,157, 1, 0,198,
+ 105, 68,174,120,133, 19,136,220,194, 49,181, 27, 85, 15, 83, 30,
+ 168,126,100,196, 52, 0,192,120, 62,245,236, 4,175, 36,119,113,
+ 169, 13,150,133, 48,206, 47, 19, 23, 87,237,239, 47, 72, 9, 0,
+ 112,108,138,168,180,240,139,241, 19,204,133,216,156, 77,185, 52,
+ 198,226,176,227, 87,161, 53, 0,192,193,229, 48,112, 86, 99, 86,
+ 41,150, 58,243, 89, 31, 44, 43, 30,147,139,149,250, 49,147,153,
+ 28,199,126, 1, 0,224,172, 67,222, 44,209, 83,214,247, 26,158,
+ 191,168,168, 46,243,240,133,241, 19, 0,128, 25, 83, 96,145,191,
+ 56,207, 95,249,113,201, 92,111, 35,244,191, 0, 0,224,184,170,
+ 50, 46, 37,174,226, 59, 38,231,248, 99,145,185,242,248,229, 22,
+ 155,240, 23, 0, 96,170,146, 99, 87, 81, 89,205,152, 23,149,213,
+ 1, 21,165, 83, 34,229,100,247, 20, 0, 0, 40, 23, 22,231,195,
+ 86,179, 14,189,147,196,200, 29,209,202,121,242, 98,206, 7, 81,
+ 32,127, 1, 0,142, 39,196,240,104,219, 22,199, 22,179, 33,171,
+ 78, 81, 73,229,102, 88,105,152,197,208,254, 61, 82, 20, 0,224,
+ 232,101, 22,143, 82, 54,114, 81, 45,150, 2, 87,222,183,119, 11,
+ 202,242, 16,138, 49,212,143,144, 29, 0, 48,216,225,182,100, 71,
+ 97, 92,118,150,107, 43,167,161, 79,149, 30, 62,234, 71, 0,192,
+ 180, 11,205,226, 20, 34,119,198, 47,118,126,144,119,249,157, 67,
+ 147, 71,245, 23, 35,132, 1,128,216,117,120, 15,184, 67,240,221,
+ 163,141, 69,225,200,249, 68, 21,204, 85,235, 29,201, 95,124,196,
+ 93, 7, 0,204,169,196,248,232, 38, 99,118,143, 45, 14, 76,105,
+ 152, 70,176,242,144,251,242,232,175, 67,143,191,135,174, 0, 0,
+ 7,242, 4,239,187,101,249, 68, 34,103,192,106,218, 23,203, 92,
+ 135,254, 23, 0, 96,122,133, 39, 87,199, 70, 12,157, 98,149, 43,
+ 167, 64,186,163, 87,247,152,255, 30, 89, 12, 0,112,140, 31,122,
+ 75,236,249, 62, 13,214,143,206,192, 47,103, 10,252,234, 50, 68,
+ 121, 65,233, 31,101,223, 97, 46, 0,192,129,229, 37, 37,147,240,
+ 107, 53, 30,168, 31,157, 62, 24,231,229, 36,149,230,211, 57,220,
+ 248, 47, 70,246, 2, 0, 28,197, 3, 76, 68, 36,132,105,212,151,
+ 207,174,142,120, 23, 3, 43, 63,150, 78,129, 68,255, 11, 0, 48,
+ 57,180, 39,253,133,246,218,185,115,153,131,156,163,144, 78, 14,
+ 43, 29,105,220,101,137,110, 66,255, 30, 0, 48, 73, 22,151,151,
+ 159,188,122, 85,122, 94, 85, 73,110,217, 72, 84,140,100,101, 26,
+ 178,138,109,214, 0,147,251, 5,190, 17, 98, 29, 0, 0,149,226,
+ 94, 55, 40,110, 86,171,213,242,228,229,108,197,213,107, 10,151,
+ 85, 87,246,112, 55,144, 7,218, 79, 72, 11, 0,112,172,122,228,
+ 189,162, 84,181, 27, 38, 71,185, 71, 0, 0,152, 65, 23,200,221,
+ 247, 18,226, 2, 0,204,180,233,208,191, 7, 0,140, 93, 91, 99,
+ 23,152, 32, 65, 68, 98,119,127, 29,117, 25, 36, 0,192,169,118,
+ 215,193, 92, 32, 68,245,178, 16,162,170,168,244, 10, 33, 6,212,
+ 37,136, 72,200,209,118, 12, 0, 0,142, 43,225, 8,114,178, 85,
+ 234, 53,145, 74,203, 53, 87,126, 57,187, 1,234, 71, 0,192,100,
+ 41, 5, 47, 33,210,240,149, 5,173, 68, 93,130,138, 44, 38, 92,
+ 107,149,130,216,232,254,226, 61, 60,138,132, 6, 0, 2,214,161,
+ 74,199, 65,167,149, 5, 55,100,195, 60,169, 33,127, 1, 0,198,
+ 171,179,145,125, 54,208,210, 18,165,122, 81, 8,202, 26, 98, 34,
+ 41, 39, 7,110,115,120,127, 33,115, 1, 0, 14,233,129,164,104,
+ 204, 11, 67,145,235, 73,164,174, 18, 37,117,185,213,165,219, 17,
+ 147,199,184,139, 0, 0,176, 91,236, 74, 13,150,246,191, 74, 71,
+ 30, 69,185,210, 20, 67, 74,199, 68, 98,168, 31, 1, 0,179,145,
+ 204,146,204,149,143,165, 72,123,248,162, 20,208,168,100, 59,121,
+ 192, 71, 67, 20, 3, 0, 28, 77, 5, 66, 84,142, 36, 38,122, 18,
+ 110, 40, 75, 55, 40,140,230, 30,164,204,111,135,252, 5, 0,152,
+ 140,183, 74, 53,100, 81, 61,230,122,114,242,151, 40,231,175, 36,
+ 113,137,178,190,170,227,191, 24,241, 10, 0, 48, 9,165,137,234,
+ 248,251,114,254, 42,174,205, 75, 73,167,109,150, 15,108, 69,254,
+ 2, 0, 76,212,105, 98,160,142, 20,229,252,149,199, 50, 81,202,
+ 95,121,215, 94,228,135, 32,229, 65, 45,202,149, 45,121,220,193,
+ 18, 0,112,130,107, 72, 81, 58,207, 49, 27, 40, 81,228, 47,225,
+ 6,180,180, 49,150,253,143,156,250, 81, 84,253, 5, 0, 0,199,
+ 107, 54, 81, 36,169,210,120,137,188,233, 69,194,233,125, 81,254,
+ 95,233, 86, 89,252, 58, 72,255, 30,241, 10, 0, 48,220, 11,135,
+ 178, 67,169, 80, 44,138, 73,119,252, 68,169,144,204, 15, 74,230,
+ 213,166,132,165, 0, 0,147,211,157,210, 30, 17, 49,139, 74, 77,
+ 89, 20,147, 84,252, 47,111,119, 21,195,243, 75,179, 85,200,177,
+ 101, 45,136, 15, 0, 20,142,251,209,221,218,218,124,255,134,142,
+ 162,162,126,116, 38,255, 34,183,137, 79,197, 76, 20,162,226, 49,
+ 66,255, 11, 0, 48,113,145,177,181,157, 7,155, 27,119,239,209,
+ 192,176,213,226,248, 98, 49, 84,162,116, 38,209, 81,230,207, 1,
+ 0,128, 49,160,226, 40, 10, 2, 21, 69,228, 28, 75,172,158, 3,
+ 233, 76, 0, 54, 48, 45,107,225,181,113,248, 11,149, 35, 0, 8,
+ 93, 7,249, 49, 51, 91,107,135,110,155, 87,137,110, 59, 95,148,
+ 206,249, 70,254, 2, 0, 76, 47,183, 48, 15,206, 18, 86,204,178,
+ 58,100,122, 67,162,210,184,175,108, 83,248, 11, 0, 48, 5, 42,
+ 115,228,208,144,217, 9,135,174,217, 81, 2,254, 2, 0, 76, 54,
+ 125,141, 15, 57, 79, 59, 11, 0,128,219,246,244, 23, 79,120, 15,
+ 0, 0,115, 37, 38, 30,139,181,156,181,110,139,147,170,121,239,
+ 187,100,212,143, 0,128,153,148, 35,103,146,218,101, 5, 16,199,
+ 158,217,166,114, 79,193, 29,227,114,224, 0, 0, 48,204, 82,156,
+ 184, 44,213, 21,179,235, 54, 46,203, 8,249, 11, 0, 48,253,138,
+ 148,139,255,101,166,202,190,101,230,114,130,226,124,166, 85,121,
+ 248,199, 4, 0,160,228, 59,194,141,153,185,156,175, 82, 49, 57,
+ 105,139, 7,165,229, 62,166,132,166, 0, 0,147,201, 89,123, 89,
+ 144,217, 41, 24, 57, 29,224,154,248,141,179,186,145, 29,101,242,
+ 81,234, 71,184, 13, 0, 48, 62,187, 49, 57,214, 42, 76, 86,241,
+ 86,209,255,226, 61,242, 23,195, 80, 0,128,227,118, 86, 6,229,
+ 133,164,155,191,146, 43,243,252,149,111, 64, 89,149,201,232,223,
+ 3, 0,166, 82,119,241, 46,249, 43,119, 23,229,233,171,232,228,
+ 59,149, 36, 13, 25, 63,177,231,195, 48, 42, 71, 0,192, 24, 5,
+ 86, 84,140, 92, 50, 83, 58, 12,172,240, 89,186,101, 81, 26,238,
+ 223,255,130,170, 0, 0,199,150,207,152,203,227, 35,156,244,149,
+ 151,149,121, 51, 44,203, 95, 78, 5,137,241, 95, 0,128,169,248,
+ 141,203, 38,115, 7, 82,176, 51,156,130,139,178, 50,223, 52,171,
+ 40,209,255, 2, 0, 28,147,166,246, 15, 99,121,208, 42,242, 87,
+ 238,177,188, 7, 86, 12,113,205,227, 87,254, 40,242, 0,187,131,
+ 170, 18, 0, 48, 54,201, 49,187, 23,135,228,175,210,129,199,180,
+ 251, 94, 26, 27,193, 71,205, 95,144, 25, 0,168, 2,199,104,180,
+ 161,249,203, 41, 32,217, 61,211, 72, 30,249, 9, 64,100, 0,128,
+ 131, 97,139,161,170, 69,253,200, 67,149, 86, 46, 24,185,184,158,
+ 9,253,123, 0,192, 68,146,154,139,176, 68,181, 70,195,233,201,
+ 115, 49,192,190, 24, 1,230, 28,108,116, 79,140,116,206,138,148,
+ 227,219, 39, 0, 0, 74,200,221,174, 46,190,183,190, 71,158, 39,
+ 165,228,161,245, 99, 41, 99,185, 18, 27, 50,254, 84,142,229, 25,
+ 0, 0,192, 40,158, 96, 41, 85,221, 95, 89, 59,187,215,102,123,
+ 217,209, 45, 34, 15,232, 47, 40, 11, 0,112, 20,140, 39, 87, 46,
+ 92, 88, 93, 91,203, 35, 23,187, 85, 97,105,214, 9,114,103, 45,
+ 36, 26,109,254, 28, 30, 89, 96, 12,185, 1, 0, 14,194,153,149,
+ 149, 11, 23, 46, 12,243,138, 83, 54,230, 62, 43,213,147,206,229,
+ 236, 6, 99,232,223,195, 91, 0,128, 17, 77, 32,164, 40,123,202,
+ 185, 92,157,104,149,157, 51,187,135,246,211,134,143,255,130,145,
+ 0, 0, 7, 22,214,120, 22, 38,218,237, 78,134,205,234, 37,247,
+ 221, 65,200, 12, 0, 48,155,213, 25,198,127, 1, 0,102,223, 84,
+ 163,248, 11, 89, 11, 0, 48, 61, 67, 9, 34,177,219, 79, 4,149,
+ 126, 40,144,191, 0, 0,147, 38,115,144,112,101, 36,170,215, 20,
+ 54, 19,201, 79,134,121, 77,200,125, 92,139, 68, 6, 0, 24,191,
+ 189, 74,223, 10, 87, 94, 66, 20,129, 75, 36,255, 23,165, 16,150,
+ 221, 76, 32,127, 1, 0,198, 91,100,238,159,121,202,201, 75, 8,
+ 71, 74, 66,228,215, 21,181,164, 24,144, 93,134, 60,210,158, 2,
+ 0,160,172, 35,167, 48,218,181,237, 53,208,241,114, 91,100, 98,
+ 52,127, 65, 84, 0,128,221,189,192,135, 51,135, 24,200,101, 34,
+ 253,146,212,138,217,191,201,149,194, 41, 42,199,145,191,224, 55,
+ 0, 32,177, 67,109, 35,132,219,243, 18, 66,184,215, 84,234,199,
+ 244, 39,213, 66, 82, 28,201, 95,144, 22, 0,224, 16,228,210,202,
+ 84, 85, 26, 25, 81, 42, 24, 69,233,192,163, 24, 56,120,137,254,
+ 61, 0, 96, 54,114, 90,154,187,146,255,220,146, 49,189,222,209,
+ 222, 81,199,127,241,200, 59, 5, 0, 56, 45, 54, 26,237, 28,110,
+ 33, 74,255,119,234,199,114, 66, 43,108,229, 14, 3, 43, 54, 20,
+ 242,160, 59, 10, 99, 1, 0,142, 92, 67,102,101,163, 91, 63, 22,
+ 201, 43,203, 95,169,173,132,200, 47,149,238,227, 32,249,139,247,
+ 250, 17,180, 6, 0,234,192, 67,230, 28,167,127,239,182,187,132,
+ 27,204,242,186, 81,100,199, 38,105,108,253, 47,232, 11, 0, 80,
+ 81,194,110,171,119,148,235,200, 82,254,114, 19, 24,149,251, 95,
+ 197,224, 9,113,136,254, 23, 20, 5, 0, 56,122,229, 72, 36,220,
+ 241, 18,194,137, 90,228, 94,147,187,140,242, 77,168,122, 18,247,
+ 40,254, 98,232, 11, 0, 48, 62,129,149, 37, 84, 68, 45,167, 41,
+ 70,131, 61, 50,145,107, 46, 63, 50,137,241, 19, 0,128, 3, 22,
+ 134, 71,140, 95,142,184,114, 69,229, 22, 19,229,250,209, 57, 70,
+ 89,154,140, 34,249, 71, 78,243,169, 0, 0, 78,161,238, 68,121,
+ 188,132,147,191,168, 84, 46,186, 99,193,178,252, 85, 30,131, 47,
+ 15, 40, 39,134,195, 0, 0, 71,214,153, 24,146,191,178,110,151,
+ 91, 46,186, 35,238,171, 7, 40, 49,254, 30, 0,112,244, 68,117,
+ 196,233, 2, 69,245,160,164, 27,185, 10,203, 81,249,100,110,248,
+ 11, 0, 48,105,245, 13, 52,182, 74,165, 34, 21, 51, 24,150,103,
+ 93, 21,206, 20,210,217, 88, 48,248, 11, 0, 48, 89,156, 89,113,
+ 132,123, 58,163, 40,231, 47, 42,242,151,211, 35,115, 34,155, 24,
+ 115,254, 66, 47, 12, 0, 48,220, 6,251, 77, 6,230, 12,140, 24,
+ 200, 95,162, 80, 86,214, 1,195,250, 29, 0,128,137,184,107,152,
+ 175, 92,113, 21, 93,124, 39,163, 81, 54,249,189, 16,228,134, 52,
+ 167,171, 15,127, 1, 0,166, 84, 69,102, 30, 43,159,149,237, 12,
+ 254,162, 34,146,149,234,199,236, 6,163,250,171,124, 54, 19,234,
+ 68, 0,144,177, 14, 43, 46,103, 98, 85, 49,112,220,177,216,170,
+ 152,243,107,215,217,241,145,191, 0, 0, 99,212,215,126,147,209,
+ 8, 55,124,229,151, 7,214,127, 28, 50,235,234,144,197,109,225,
+ 47, 0,192,100,211,152, 16,131, 82, 27,108,135,229,162, 19,206,
+ 156, 19,229, 1,248,229,241, 19, 40, 11, 1, 0, 19, 70,236,178,
+ 168,109,105,252,151,168, 46,164,134,249,239, 1, 0, 83,241,213,
+ 174,169, 76, 84,214,241, 16,131,183, 17,168, 31, 1, 0,147, 44,
+ 26,121, 87,141,137, 93, 22,215, 22,187,155,111,232,252, 95, 40,
+ 30, 1, 0, 19,204, 97, 98,255,107,118,141, 95, 2,227, 87, 1,
+ 0, 51, 88, 76,138, 33,139,213, 14,187,149,216,219, 95, 72,100,
+ 0,128, 99, 44, 43,119,183,154, 24,205,117,200, 95, 0,128,105,
+ 9, 76,236, 91, 86,138, 61,111, 47,199,188, 63, 0,128,211,102,
+ 166,233,233, 1,249, 11, 0, 48,175,192, 95, 0,128,201, 85,140,
+ 240, 23, 0, 0,236,230, 47, 70,187, 11, 0, 48,135,254,226,209,
+ 66, 34, 4, 7, 0,152,122, 77, 41,103,115,183, 0, 0, 51, 40,
+ 36,158, 49, 29,200,131,237, 62, 92, 6, 0,152,217,250,241,192,
+ 118,130,192, 0, 64, 97,184,123, 62, 59, 86, 69,224,248, 35, 0,
+ 224,232,101,228, 76,228, 47,164, 41, 0,192,161,172, 54, 13,121,
+ 72,148,133, 0,128,113,149,144,227,191,209,184,235, 71, 44, 67,
+ 4, 0,152,146,177, 14,234, 47, 72, 10, 0, 48,155, 72,200, 11,
+ 0, 48, 71,153,235,136,245, 35, 28, 7, 0,152,135,252, 5, 0,
+ 0,115,225, 47, 30, 53, 83, 49, 2, 24, 0,224, 0,182,224,227,
+ 17, 5,242, 23, 0,224,224,166,226,153, 8, 47,114, 20,153, 34,
+ 96, 1, 0,142,150,195, 38,228,175,253,246, 2, 50, 3, 0,204,
+ 134, 17,228, 33,119, 10, 22, 3, 0,240,148,155,225,242, 32,187,
+ 10,113, 1, 0,102, 8,121,104,115, 66,100, 0,128,153,241, 23,
+ 68, 5, 0,152,111,127, 29,214, 86,176, 28, 0, 39,155, 25,252,
+ 140,203,121,221,113, 0,192,169,151, 29,198,175, 2, 0,230, 53,
+ 144, 73,100, 46, 0,192,156, 34, 15,166, 87, 72, 13, 0, 48, 31,
+ 254, 2, 0,128, 25,174, 36,225, 47, 0,192, 49,232,107, 34, 74,
+ 147, 99,217,105,148,149, 0, 0,228, 47, 0, 0,152,128,191, 16,
+ 186, 0, 64,173,136,252, 5, 0, 56,201,174, 59, 54,231,201, 17,
+ 13,203,152, 52, 26, 0, 48,170,178,120,119, 87,140, 83, 29,114,
+ 140,251, 13,165, 1, 0, 38, 89,114,202,163, 61, 52,148, 5, 0,
+ 152, 26, 7,205, 95, 12,139, 1, 0,230,200, 95,208, 19, 0, 96,
+ 22,189,128,227,143, 0,128,121,116, 23,252, 5, 0, 56,201,245,
+ 35,106, 71, 0,192,188,250, 11, 0, 0,224, 47, 0,192, 9, 99,
+ 234,229,153, 60, 41, 79, 4, 0, 48,123, 94, 59,102, 49,200,227,
+ 216,103, 0,192,169,119,215, 36,132, 32,199,183,187, 0,128,211,
+ 84, 50,242, 97,111, 56, 17,127, 49, 15, 60,250,177,159, 78, 14,
+ 0, 0,211,168, 31, 1, 0,200,101, 19,173,207,224, 47, 0,192,
+ 49, 75, 12,254, 2, 0, 64, 95, 99,240, 23,163, 1, 6, 0,152,
+ 1,144,191, 0, 0,227, 13, 95,147,139, 55,240, 23, 0,224,120,
+ 140,118,252, 30,131,191, 0, 0, 71,203, 91,243, 81, 63,162,233,
+ 5, 0,152, 37,228, 80, 65,141,106, 42,172,217, 1, 0,152, 94,
+ 214,145,179,181, 59, 0,128,121,119,215, 4,109,129,254, 23, 0,
+ 96, 54,211,213, 56,252,133,232, 5, 0,152, 77, 14,148,191,120,
+ 215,239, 25,170, 3,224, 20, 37,175, 25,249,172, 75,100, 45, 0,
+ 192,152,170,199, 73, 27, 68,162,120, 4, 0,204,125,253, 8, 85,
+ 1, 0,142, 24,200,120,228, 31, 29, 75,254,226,221,247, 15,130,
+ 3, 0,204,104,254, 26, 67,241, 11, 0, 0,179,236, 47, 24, 13,
+ 0, 48,191,254,130,175, 0, 0, 39, 37,127, 1, 0, 78, 45,211,
+ 141, 51, 18, 81, 11, 0,112,234,242, 23,220, 6, 0, 72, 93, 48,
+ 37, 29,160,126, 4, 0,204,107,177, 41, 17,175, 0, 0, 99,183,
+ 19, 79, 68, 39,200, 95, 0,128, 99, 76, 81,199,154,132,224, 47,
+ 0,192,204, 21,134,135,247, 23, 42, 71, 0,192, 92,128,252, 5,
+ 0,152,215, 12, 38,103, 44, 15, 2, 0,160, 45,228, 47, 0,192,
+ 201,182,215,232,254, 66, 30, 3, 0,204,154, 27,144,191, 0, 0,
+ 243,106, 57,248, 11, 0, 48,175,192, 95, 0, 0,248, 11, 0,112,
+ 226, 75,192, 25,107,132,203,113, 60, 39, 0,192,105,178,216,124,
+ 251,139, 33, 49, 0,224,176,131,223, 98,220,166, 64,253, 8, 0,
+ 152, 87, 14,238, 47,100, 45, 0,192, 76,250, 11,114, 2, 0,140,
+ 152,100,120,234,222,144, 72, 88, 0,128, 83, 83, 63,162,172, 4,
+ 224,212, 70,174, 25,179,129, 60,194,174, 67, 89, 0,128,105, 26,
+ 76, 30,112,167, 24,238, 2, 0,204,136, 6,228,193,118, 9,218,
+ 2, 0,186, 58,144, 10,248, 24, 13, 34, 71,122,120,222,115,167,
+ 32, 53, 0, 96,180,105,152, 0,227, 87, 1, 0,243, 10,252, 5,
+ 0,152, 72, 60,155,156,191,184,252,101,194, 59, 5, 0, 56, 65,
+ 174, 58, 62, 99,200,163,237, 24, 0, 0, 76, 45,147,201,163,237,
+ 3,212, 6, 0,152, 26, 18, 57, 11, 0, 48,163,249,234,152,242,
+ 23, 0, 0,236,165,175,137,120, 12,254, 2, 0,204,107, 0,147,
+ 227,216, 17, 20,158, 0,192, 81, 83,240,130,132,148, 0, 0,115,
+ 10,234, 71, 0,192,188,214,145,114,223, 7,102,100, 51, 0,192,
+ 12,216,106,172,249,139, 97, 50, 0,192,190, 26, 59,198, 67,146,
+ 242,104,123, 6, 0, 0, 83, 83, 5,250, 95, 0,128,121,168, 21,
+ 15,225, 47,222,115,119, 81, 65, 2, 0,133, 77, 81,238,183,167,
+ 75, 0, 0, 32, 0, 73, 68, 65, 84, 1,242,160,126,133,174, 0,
+ 0,179,159,191, 14,100, 42,104, 13, 0, 48, 99,245, 35, 0, 0,
+ 192, 95, 0, 0,112,220,254,226,161,223, 50,138, 68, 0,192, 62,
+ 76,124,182,102,121,132, 61, 3, 0,156,118, 65,237,189, 2,209,
+ 113,107, 3,245, 35, 0,224, 72, 17,107,150,234,199, 35, 61, 33,
+ 132, 52, 0, 32,178, 41,249, 11, 35, 38, 0, 0,199, 80, 87,162,
+ 126, 4, 0, 0,248, 11, 0,112,250,252,133,138, 17, 0, 48, 75,
+ 66,144,187,237, 13,100, 5, 0,152,179,252, 53,130,182, 96, 54,
+ 0,192, 92,213,143,144, 22, 0, 96, 84, 89, 76,106, 21, 72,244,
+ 239, 1, 0, 39, 61,127, 1, 0, 0,252, 5, 0, 56,169,117,227,
+ 28,251, 11, 45, 50, 0,192, 48, 37, 28,155, 27, 36,244, 3, 0,
+ 152,211, 84, 38,103,119,215, 0, 0,224,160,254,194,124, 18, 0,
+ 128,121,245, 23, 0, 0,192, 95, 0, 0,144, 21,115,199, 80,206,
+ 193, 95, 0,128,211,145,191,208, 15, 3, 0,204,142, 40,228,252,
+ 237, 50, 0,224, 20,184, 9,245, 35, 0, 96,114, 86,155,188,218,
+ 228,248,118, 30, 0,112,138, 18, 24,207,192,167, 95,142,255,105,
+ 1, 0, 80, 77,162,126, 4, 0,204,129,178,248,144,183,131,191,
+ 0, 0, 51, 33,174,169, 36, 49,121, 92,207, 12, 0,128, 82,114,
+ 6,253, 5, 89, 1, 0,102, 1, 9, 71, 1, 0, 78,152,191, 0,
+ 0, 96,214,235, 72, 57,251,187, 8, 0,128,178, 14,236,175, 97,
+ 11,218, 66, 92, 0, 0,212,143, 0, 0, 36, 50,248, 11, 0,112,
+ 250,106, 71,248, 11, 0, 48, 86,117, 77,216,102,240, 23, 0, 96,
+ 94, 67,154, 60,194, 46,160,151, 15, 0,152,102,101,233, 31,118,
+ 39, 74, 87, 11, 65,130,132,192,111, 12, 0, 48,119,245,163, 32,
+ 18, 68,146, 96, 48, 0, 78,174, 44,228,225,117,113, 76, 89, 76,
+ 30,102, 71,120, 80, 94,194, 39, 81, 39,225, 11, 52,212, 0, 56,
+ 129, 52,253,154,231,251, 98,255, 42,107,162,109,165,145,116,179,
+ 239, 44, 25, 66, 80, 77,136, 22,137, 71, 90,109,252,166, 1, 56,
+ 121, 60,125,238,188,244, 61,158,186,177,142,167,126, 20, 53, 18,
+ 109, 33, 47,183, 22,241,155, 6,224,228,241,161,181, 11,196,196,
+ 198, 28,229, 78,198,110, 58,191,122,247, 98,191,114,113,184,191,
+ 200,147,178, 97,237,179,237,229,215,182, 55,186, 90, 37,215,175,
+ 175,223,195, 47, 30,128,121,231,236,194,226,103,158,185,214,121,
+ 176,161,149,158,170,175,246,246,215,190,143,207,187,215,149,204,
+ 190,148, 45,182, 95, 90,123,244, 63,220,187,145, 92,249,231,223,
+ 252, 51,252,238, 1,152,119,190,241,209,143,235, 56,142,250,125,
+ 163, 20, 51, 19, 51,137,153, 24,111, 48,230,118,187,239,249, 79,
+ 180,151,126,246,194, 37,252,202, 1, 56, 25,252,202, 39, 62,117,
+ 237,209,199,251,219, 59,113, 16,176,181,135,136, 86,199, 23,195,
+ 252,163,221,188,180, 99,204, 44,152,165,231,125,100,245,188, 95,
+ 175,255,249,157, 27,145,209,248,245, 3, 48,167,180, 27,141,255,
+ 226, 35, 47,126,250,234, 51,157, 7, 27,253,237, 29, 29,103,225,
+ 107,102,240,199,123,119,214, 90, 18, 66, 18,191,176,118,225,202,
+ 202,217,239,109,220,253,225,157, 91,120, 31, 0, 48,119,124,234,
+ 234, 51, 63,243,236,243,231, 22,150, 58, 15, 54, 58, 27,155,113,
+ 24, 88,107,118,151,215,144,222,249,204,248,235, 32, 43, 38, 89,
+ 99,116, 76, 66,136, 51,173,214,215,159,126,254,231,174, 94,123,
+ 235,225,131,157, 56,222,137,194,135, 97,128,183,197,145,254, 60,
+ 48,199,108,243,195, 35, 68,116,161,181,192,108,217, 50, 94,135,
+ 83,248, 58,140, 23, 65,180,210, 94, 88,105,181, 86, 90,237, 23,
+ 46, 93, 89,108, 52,195,110,111,235,206,221, 96,103, 39, 14, 35,
+ 107, 44,113,106, 47, 49,145,218,240,248,242,215,222,109,125, 98,
+ 99, 84, 24, 89,109,140, 82,181, 86,235,163,107,143,212, 27, 77,
+ 175,230, 75,207, 19, 82, 10,156,104,116, 88,250, 70,223,143,195,
+ 87,119, 54,242,107,126,253,153, 23, 84, 28,233, 40,198,235,112,
+ 10, 95,135, 99,249,219, 96,140, 53, 70,245,194,141,251,155, 81,
+ 175,167,194, 72, 43,197,108,201,142, 94, 55, 78,110,174, 83,127,
+ 255, 44,120,240,221, 96, 34,182,150,149, 50,198,196, 65, 24,214,
+ 106, 94,205,247,124, 63,145,151,144,240,215, 33,233,106,125, 47,
+ 234,223,120,120, 63,191,102,107,241,156, 10, 35, 21,133,120, 29,
+ 78,225,235, 48, 70, 82, 57, 49, 39,254,210, 74, 89,173,173, 54,
+ 156,113,208, 10,109,150,243,215,136,175, 8,179, 49,108,173, 49,
+ 70,132, 68, 34, 9, 94,144,215,225,233,104,181, 21,246,214,183,
+ 214,139, 79,242,197, 45, 21,134,113, 16,226,117, 56,133,175,195,
+ 113,125,110,211,175, 76, 76,204, 51, 93,146, 31,222, 95, 60,154,
+ 120,147, 3, 22, 76, 36, 4, 49,228, 53,142,108,175,181, 46, 93,
+ 163,141, 61,218,168,104,188, 14, 96,152,195,142,226,133, 9, 37,
+ 50,127,176,242, 59,166,136,148, 88, 29,111,141,163, 70,218, 74,
+ 152, 79,255, 62, 48, 94,135, 83,248, 58,204,192,111, 98,202, 5,
+ 21,166,139,152,187,247,203,192,247,140,215,129,240,199,241,116,
+ 34, 15,249,126, 1, 0,128, 81,254,174,204, 76,254,130,196, 0,
+ 0,115,152,191, 0, 0, 96, 78,253,197,136,100, 0,128, 3,124,
+ 244, 39,162, 6,228, 47, 0,192, 73,202, 95,140, 96, 5, 0, 56,
+ 57,245, 35,152,155,216,142,215, 1,156, 30,124,188, 53, 0, 17,
+ 173, 92,185,244,137,223,248, 85, 34,122,229,159,255, 11,213, 15,
+ 136,232,133,111,124,253,194,115,207,110,189,127,235, 7,255,230,
+ 15,146,109,190,242,143,126, 55,223,254,250, 95,126,231,250, 43,
+ 223, 38,162,143,255,250,175,174, 62,113,233,214,171,127,243,147,
+ 63,249,102,242, 45, 17,185, 55,201,239, 33,217,242,155,255,244,
+ 127,199,171, 13,142,213, 95,176,216,169,163,222,110, 95,120,254,
+ 26, 17, 93,122,233,197, 68, 76, 79,125,254, 51, 11,231,207,185,
+ 219, 92,120,254, 90,220,235, 63,188,113,211,189,114,245,137, 75,
+ 23,158,191,182,114,229,242,245, 87,190,173,250,193,234, 19,151,
+ 42, 55,169,108,137,151, 26, 28,191,191, 38, 55, 1, 6,152, 33,
+ 226, 94,255,252,115,207, 94,127,229,219, 43, 87, 46, 45,156, 63,
+ 183,245,254,205,202, 91, 96,235,198,205, 63, 47, 7, 40, 38,234,
+ 221,127,176,112,254,220,181,175,189,252,218, 31,254,209, 30, 51,
+ 197,225,221,132, 82,127,146,249,107,191, 29,153,244, 80, 91,176,
+ 199,171, 60,158, 23,255,214,171, 63,188,244,137, 23,191, 71,191,
+ 127,233,165, 23,183,222,191, 25,247,251,149, 59, 95,189,114,249,
+ 103,254,209,239, 18,209, 15,254,245, 31,228, 65,172,251, 96,227,
+ 222,143,127,242,161,175,126,229,205, 63,249,179, 93,246,135,199,
+ 190,171, 60,241,143, 10,200, 16, 99,249, 85,141, 5,121,228,119,
+ 14,222, 49, 39,135,251, 63,126,171,190,208, 94,185,114,249,241,
+ 79,124,236,250, 95,126,123,244, 27,254,232, 15,255, 67,125,161,
+ 125,237,107, 47,227, 53, 60,213,127, 92,121,210,127, 81,124,188,
+ 232, 32,167,119,127, 99,235,253,155, 31,250,218, 87, 86,159,184,
+ 252,221,223,251,253,199, 63,241, 49, 26, 82, 63,254,179, 33, 55,
+ 124,240,224,221, 87,190,245,161,175,126,165,247, 96, 35, 75,109,
+ 0, 85,194,177,227,143, 92, 30,130, 83,241, 94, 89,127,227, 39,
+ 215,126,254,229,238,253, 7,149, 62,125,194,194,185,181, 23,190,
+ 241, 75,201,102,235, 63,126,179, 18,193,174,126,225,115,245,133,
+ 246,189, 55,138,235,111,125,255,135,151, 94,122,241,227,191,254,
+ 107, 68,244,200,243,215,110,125,255,135, 39,224, 51, 3,102, 7,
+ 127,212, 55, 1,227,237,115, 42, 28,118,251,213,191,185,246,243,
+ 47,223,254,254,223, 12,109,188, 47,158, 63,247,194, 55,190, 78,
+ 68,175,209, 31,173, 59,158, 34,166,222,253, 7,239,190,242,173,
+ 171, 95,248,156,123,147,239,254,222,239, 19,209,181,159,127, 57,
+ 113,217,119,127,239,247,143,247,125,130, 55,225, 4, 16,123,188,
+ 250,147,158, 12, 76,252,237,223,190,166,141,249,230, 55,255,172,
+ 241,253,215,106, 82,214,164,172,145,144, 76,194, 90, 50,214,104,
+ 165,194, 40, 10,130,160,215,239,119, 59, 97, 24, 25,182,134, 57,
+ 249,215, 18, 91,102, 78,103, 95,194,123,231,216,233, 24,117, 43,
+ 232,255,197,214,221,252,154,255,229, 99,159,137,131, 80, 5, 1,
+ 94,135, 83,248, 58, 76,201, 95, 66, 16, 9, 34, 41,132, 36, 33,
+ 133,240,132,240,132,240,133, 16, 36,136,200, 18,107,102,109,173,
+ 98, 27, 89, 19, 25, 19, 88, 19, 26, 19, 90, 19, 90,211,191,112,
+ 246, 67, 47,126,204,247,125,223,247, 61,207,175,213,124,223,247,
+ 107,181, 90,173,158,210,104, 52,234,141, 70,179,209, 72, 46, 52,
+ 234,141, 90,189, 94,175,215,106,181,122,173,230,167, 55,240,124,
+ 207,247, 60,233, 73,252,241, 2,243,249, 33,194,107,112,146,251,
+ 24, 35,130,243,135,230, 43,185,139, 90,121,245, 38, 41,229, 41,
+ 252, 36, 75, 18, 53, 33,241, 58,128,253,252, 53,254,129, 59,224,
+ 240,212,165, 60,227,215,243,111,155,190,239,215,235,167,112, 73,
+ 167,154,148,203,126,205, 85,216,233,124, 29,166,155,180,248, 64,
+ 91, 79,204, 95,208,212,236,126,110,133, 60, 91,111,188,124,225,
+ 82,195,243,155,126,237, 23,174,189, 64, 66, 48,219,211,249, 58,
+ 124,241,252, 99,201,235,240,141,143,188, 40, 78,229,235, 0, 48,
+ 254,107,174,234, 71, 33,106,158,255,209,165, 71, 62,245,212, 51,
+ 181,102,211, 26, 29,236,116,140,210,120, 29,130,157,174,209, 26,
+ 239,144,233, 36,177,249,242, 23,207,226, 19, 57, 53,239, 24,107,
+ 85, 24, 89, 99,165,215, 73,215, 73, 62,149,139, 30, 14,121, 29,
+ 52, 22,127, 60,117, 82, 67,254,154,175,183, 6, 51,179,177,214,
+ 40,133,215, 1,175,195,212,252, 36,102, 69, 96, 56,254, 8, 0,
+ 152, 87, 14,153,191, 6,231,158, 64, 1, 9,192,105, 96,164,163,
+ 188,147,210, 1,242, 23, 0, 96,156,197,229, 36,145,179,180, 51,
+ 0, 0,112, 60,249, 11, 50, 3, 0,204,148, 17, 36,132, 5, 0,
+ 152, 83,124,216, 10,127, 26,231, 2,156, 28, 52, 83,239,174, 25,
+ 249,117, 96,252,215, 73,240, 20,151,103, 48, 74,191, 61,113,242,
+ 18,217,167, 38, 57, 85, 59,249, 22, 94, 59,205, 54,131,191,230,
+ 216, 89,204,196,196, 76,148, 92,216,209, 74, 89,203, 68,129,213,
+ 193, 9, 26,148,223,146, 94,211,243, 4, 81, 77,202, 37,191, 46,
+ 136, 4,147, 32, 33, 4, 11, 74, 46,192,101,167,190,126, 28,177,
+ 18, 65,153, 57, 69,109,185,206,138,173,221,136,195, 29,173, 54,
+ 85, 20, 90, 19, 26,115,102,237,172,223,168, 17, 81,123,233, 76,
+ 107, 97,129,153,231,127, 78, 73,182,214,110,117,123, 97,191, 79,
+ 68, 42,142,187,247,239, 55, 61,175, 41,189,149, 90,125,201,175,
+ 173,213, 26, 53,233, 73, 38,153, 78,170,151,186, 12, 34, 59, 37,
+ 165, 36,242,215,156,164, 45,102, 75,100,153,183,117,124, 59,236,
+ 109,170, 56,242,196,133,199, 30, 91, 57,183,246,177,139, 23,155,
+ 237,118,115,161,173,148, 82, 74, 89,107,173,181, 74, 41,173,181,
+ 181,115, 63, 37, 3, 51, 75, 41,107,181,154,231,121,201, 53, 97,
+ 191,223,239,118, 31,222,127,112,123,123,231,245,141, 7, 77,166,
+ 85,191,241,104,179,117,198,175, 75, 33, 36, 11, 41, 72,166,179,
+ 132, 34,145, 77,255,173, 59,125,127, 49,226,215, 84, 3,151, 37,
+ 238,104,117, 35,232,174,199, 97,115,117,229,234, 39, 95,124,238,
+ 226,197,133, 51,203, 81, 20,245,251,253, 94,175,119,239,214, 70,
+ 175,215, 11,130, 32,142, 99, 99,140, 49, 70,107,109,172, 97, 59,
+ 223,191, 47, 33,132, 16,194,243, 60,223,247,189,140, 70,163,209,
+ 108, 54,151, 46,156, 63,127,229,178,239,251,253,157,206,246,198,
+ 198,107,183, 63,176, 59, 91,231,234,141,203,173,133, 69,175,230,
+ 37, 83, 27, 35,142, 77,215, 83,199,191,156, 26,242,215,172,155,
+ 235,118,216,191, 25,116,227, 86,227,185,159,254,248,199,158,120,
+ 194,107,212,187,157,206,131,173,173,159,188,251,206,246,246,118,
+ 183,219,237,247,251,169,185,230, 95, 88,251, 34,165, 76, 20,214,
+ 202,104,183,219, 11,103,150,159,185,248,136, 81,234,225,250,253,
+ 239,223,188,213, 54,252,120,179,253,104,163,237, 9,225,145,144,
+ 68,176,216, 73,197, 63,200,103, 10, 76,212, 92,111,247,118,110,
+ 134,189, 51,143, 94,252,228,207,125,105,229,252,185,157,157,157,
+ 219,119,239,220,187,119,111, 99, 99, 99,123,123,187, 31, 4, 42,
+ 142, 43, 45, 46,113,210, 63,164,204,172,181,214, 90,247,122, 61,
+ 18, 66, 10, 81,175,215,219,237,246,226,210,226,210,210,242,226,
+ 242,210,213, 79,188, 24,116, 58,239,221,184,245,206,230,189,199,
+ 155,237,167,218,139,158,144,176,216,108,100,179,241, 59,196, 31,
+ 242,120,248, 13, 79, 81, 94,204,134,248,131,176,127, 35,232,158,
+ 125,246,233,159,255,244, 79, 75,223,223,216,216,248,193, 15,126,
+ 112,231,206,157,205,205,205,126,191,175,181,182,156, 29,132, 20,
+ 167,239,143,139,243,254,180,204, 97, 20, 69, 81,244,240,225,195,
+ 68,100,203,203,203,203,203,203,143, 94,123,214, 42,189,126,227,
+ 230,131,237, 7,143, 55, 22, 30,107,166, 89,204, 59, 13,142,159,
+ 206, 59, 87, 76, 37,238,248, 71,221,109, 48,190,216,101,153, 54,
+ 85,244,126,208,181,231, 86, 63,249,213, 47, 45,173,174,222,189,
+ 123,247,198,141, 27,119,239,222,125,248,240, 97, 24,134,121, 63,
+ 94,208,240,255,159,222, 23,144, 57,138,162, 56,142,119, 58,157,
+ 214,198,198,210,210,210,210,210,210,226,197, 11,102,229,204,187,
+ 247,214, 55, 58,155,151,154, 11,103,107, 13, 22, 66,146,148, 8,
+ 98, 99, 23,214,148,114,143, 15, 65,205, 78,236,250,113,119,251,
+ 150,137, 62,245,229, 47, 61,126,245,169,245,245,245, 87, 95,125,
+ 245,198,141, 27, 91, 91, 91, 74,169,164, 78,116,163, 3,187,255,
+ 63,109,191, 39,225,252, 87,198, 26,147, 28,202,216,222,222, 94,
+ 90, 90, 58,115,230,204,234, 19,151,131,135,219, 63,184,123,239,
+ 241,122,235,217,246,114, 77, 18,130,216,113, 36,174,169,224,143,
+ 229,153,204, 26,159,254,237,223, 92,255,241, 79,174,191,242,237,
+ 121,120, 31,164,177,235,189,160,235, 95,186,248,141,159,125,185,
+ 219,235,189,246,218,107,215,175, 95,127,240,224, 65, 24,134,150,
+ 237,208,151,184, 20,189,240, 65, 44,191, 52,150, 57, 12, 67,165,
+ 84,191,223, 95, 90, 94, 94, 92, 88, 56,123,245,201,245, 59,247,
+ 162,238,214,229, 52,136, 73,143, 72,138, 98, 76,255, 76, 81,111,
+ 183, 63,255, 15,255,254,234,149,203,255,215,223,255,221,185,177,
+ 215, 52,148,230, 31,241, 89,204, 32,159,254,237,223,188,250,197,
+ 207, 93,253,226,231,136,104,150, 21,150,213,140,252, 94,208,125,
+ 43,238,127,234,203, 95,122,244,169, 39,111,221,190,253,214, 91,
+ 111,221,190,125,187,215,235, 25, 99, 40, 57, 75, 70,236,246,226,
+ 159,226,121, 35,119,143, 96, 57,198,152,126,191, 31,199,113,208,
+ 239, 47, 45, 45,181, 46,156,235,118,186,175,110,108, 62,211, 90,
+ 186,210, 90,168,145,244, 72,204, 96, 45, 89,111,183,191,242,191,
+ 254,207,171, 79, 92,158,219,100, 54, 87,249,107, 6,229, 21,247,
+ 250,245,133,246,103,126,231,183,102, 86, 97,156, 14, 73,229, 55,
+ 186,219,235, 62,125,245, 87,126, 89,248,254,235, 63,250,209,219,
+ 111,191,189,177,177, 17,171,152, 56,173,111,118,243,148,115, 10,
+ 224,124,255,189, 25, 22, 42,143,120, 47, 37, 31,105,173,187,221,
+ 110, 28,199, 11,139,139,173,102,179,113,126,237,237, 7,155,161,
+ 209,207, 46,156,169, 73,233, 39,115,176,204, 82, 45,249,233,223,
+ 249,205, 89,150,215,144,152,197,196, 83,122,249, 78,148,191,114,
+ 121,125,243,159,254,179,149, 43,151, 62,243, 59,191, 53,155, 10,
+ 203, 27, 94,127,215,217,234, 45,182,126,241,151,255,171,173,135,
+ 15,223,252,209,143,222,123,239,189, 78,167, 83, 25, 52, 63,232,
+ 169, 67, 39,175,147, 89,101,238,171, 30, 33,146,238,190, 49, 70,
+ 43,213,106,181,234,231,215,110,111,108,169,238,195,231, 23,207,
+ 176,240,124, 73, 30,207,138,194, 62,253,219,191,121,233,165, 23,
+ 183,222,191, 73, 68,115, 17,193,166,251, 71, 81,142, 99,175,102,
+ 226,239,186, 43,175,173,247,111, 94,127,229,219,223,249,151,255,
+ 138,136, 62,243, 59,191,245,212, 23, 62, 59,155,242,106, 60,117,
+ 229,107,191,246, 43,247,214,215,127,248,195, 31,190,253,246,219,
+ 59,157,157, 68, 94, 34, 29,121, 46,132, 24, 82,220,136,242, 6,
+ 46, 36, 78,226,129, 53,177,219,211, 77,158,243, 48,163, 13,219,
+ 32, 41, 39,123,189,158, 97,246,215, 86,239, 9,243, 70,119, 59,
+ 102,163,173, 53, 52, 19,103,139, 38,239,225,173,247,111,126,243,
+ 127,251,103,113,191, 79,224,216,242,215,108,213, 34, 21,121, 37,
+ 87, 38,177,107,166, 82,152, 43,175,250, 83,151, 63,241,197,207,
+ 95,191,126,253,141, 55,222,184,123,247,110, 28,151,107,198,236,
+ 211, 36,136,168,114,216,113,247, 15, 90,105,126,153,211,195, 30,
+ 209,169,220, 62, 52,198, 4, 97, 96,173,109, 52,155,220,106,222,
+ 233,246,185,251,240,185,133, 21, 34, 34, 41,167,155,194,146,247,
+ 112,247,254, 3, 87, 94, 47,252,242, 47,173,191,241,166,234, 7,
+ 249,187,122,198, 75,201, 57,170, 31,121, 70, 84, 54, 84, 94, 51,
+ 168,176,170,188,190,240,249,247,222,123,239, 71,175,191,190,126,
+ 239,158, 78,214,142, 22, 34,113,147,235,172,234, 8,251, 97,122,
+ 58, 1, 19, 77,140,179, 96,220,101,155,244,111,131,229, 40,138,
+ 152,185, 94,175,115,187,121,167, 31, 80,111,250, 10,203,223,195,
+ 127,249,207,255,133,155,188, 62,250,141,175,211, 55,190,158, 92,
+ 190,245,253, 31, 94,127,229,219,183,190,255,195,185,248, 45,241,
+ 76,249,107,102, 63, 31,123,200,107,166, 20,150, 30,109, 76,228,
+ 245,228,229, 79,124,225,243,239,223,184,241,250,235,175,223, 95,
+ 95,215,217, 92, 93,185,155, 74,249,107,132,240,133,145, 76,123,
+ 188, 8,213,235,133, 32, 34,165, 20, 17, 53, 26, 13,221,108,220,
+ 238, 5,212,123,248,252,226, 10, 89, 18, 82,202,137, 39,216,161,
+ 239,225, 31,252,235, 63, 88, 56,183,182,242,196,101, 34,186,240,
+ 220,179,171, 87, 46, 95,122,233,197,164, 53,246,221,223,251,253,
+ 153,140, 99,115,149,191,120, 6,236,182,175,188,102, 73, 97,108,
+ 153,223,232,110,119, 23,154, 63,251,197,207,223,188,121,243,141,
+ 215, 95,191,127,255,190,214,122, 80, 91, 67, 69, 54, 52,124,141,
+ 148,188,230,103, 38, 25,206,158,213,209, 83,216,224,207, 75,127,
+ 9,152,181,214, 66, 8,207,247, 2, 79,220,137, 67,191,183,243,
+ 161,133,101,193,194,159,236,184,176,221,222,195, 91,239,223,220,
+ 122,255,166,155,182,158,250,194,103,175,125,237,229,213, 39, 46,
+ 255,252, 63,249,199,223,249,151,255,106, 46,134, 55, 30, 55,242,
+ 128,166,154,167,228, 85, 81,216, 20,219,249,201, 32,213,247,130,
+ 238,186, 71, 95,254, 47,191,126,247,238,221, 55,223,124,115,125,
+ 125, 61,249, 8,229,159, 43,145,181,158, 93, 97,237,209,200, 39,
+ 218,171,175,237, 54,176,211, 65, 78, 98,166,201,159,252,136, 79,
+ 106,239, 23, 99,240,234,202,183,204,172,148, 54,218,212,235,245,
+ 190,239,221,138,250, 55,130,158,178,214,112, 58, 73,228,100,222,
+ 27,235, 63,254, 9, 17,213, 23,218, 43, 87, 46,237,251, 30,254,
+ 227,127,252, 79,254,238, 15,255, 40,121, 27, 95,120,254, 67,240,
+ 151,247, 15,254,193,255, 96,153,175, 95,191,238,221, 89,247,132,
+ 244,132,144, 66, 72, 34,145,142, 80,178,214,104,163,181, 86, 74,
+ 197,177, 49,218,230,115, 36, 20, 19, 25, 79,129, 79,252,198,175,
+ 62,251,242,151, 18,121, 45,156, 91, 91,126,236,226,206,157,187,
+ 123,108,127,237,107, 47,111,188,115,253,193,219,239, 38, 33,188,
+ 247, 96,227,225,141, 91, 19,203, 20,150,233,255,103,239, 93, 99,
+ 44,203,174,251,190,181,214, 62,231, 62,235,253,234,119,247, 76,
+ 15,103,122,154, 28,146,195,225,155,163, 33,101, 82, 50, 73, 88,
+ 68, 98,138,162, 13,136,177,101, 32,118,190,216,128, 19,125, 72,
+ 32, 27, 72, 62,200,130,191, 40,118,144, 0, 70,164, 4,145, 0,
+ 41,128, 5,135, 66, 64, 57,162, 2, 83,136, 69, 81, 36, 45,241,
+ 77,113,166,103, 56,211,211,211,239,238,170,234,122,221,215, 57,
+ 103,175,149, 15,251,236,115,246, 62,231,220,170,234, 71,245,220,
+ 234, 62,187,171,171,110,221,186, 85,117,235,220,123,126,247,255,
+ 255,239,181,215,222, 74,162, 11,189,173,143,125,238,179,163, 56,
+ 126,229,149, 87,174, 93,187,150, 36, 73,134,164, 34,182,170, 78,
+ 210,253,158,216,229, 65, 68,120,104, 6, 56,255,247,196,242, 46,
+ 72, 43, 95,237,125,234, 92, 84, 74, 9, 72,130,176, 19,141, 22,
+ 194,102,131,136,178, 25,222,131,127,122,108,188,117,165,183,186,
+ 86,126, 90,190,240,203,191,116,254,115,159,233, 46, 47,173,156,
+ 63,215, 93, 90, 68,196,225,230, 22, 0,220,122,249, 85,115,251,
+ 149,103,159,121,243,235,223,212,113,242, 54, 88,117,115,252,236,
+ 33, 37, 64, 66, 36,123,192,108, 84, 2, 44,162, 69, 18,251, 22,
+ 11,107,150,120,170,179,120,244, 40,217,161,148,121,159,143, 32,
+ 8, 84,144, 14,243,137,243, 69,251, 13,102, 32, 5,227, 78, 57,
+ 156,108,241,181,114,254, 92,166,188, 62,243,235,255, 60,234,245,
+ 119,207, 53, 95,248,210, 23,111,190,124,225, 79,127,227,127, 76,
+ 95,187,158,125,230,225,200,239,172, 78,245, 98,127,231, 29, 31,
+ 254, 64,208,106,189,242,242,203,215,174, 93, 51,249, 75,238, 19,
+ 253,229,141,178,255,240,107,247,115,236, 16, 6, 99, 89, 93,189,
+ 236,186, 9,137,136,236,106, 16,199, 95,237,191, 80,136,136,214,
+ 58, 8,130, 88, 36, 82,112,121,208,235,170,128, 8, 17, 5, 31,
+ 86,150, 95,153,111,204,157, 57,117,228,252,185, 35,231,207,101,
+ 55, 51, 79,242, 87,255,223, 63,189,248,245,111, 26,222, 61,243,
+ 153, 79,253,248,203,127, 52, 49,214,255,109,120,174, 29,214,250,
+ 213,175,254,243, 95,119, 63,109,116, 59,230,194, 39,127,237,191,
+ 113, 31,242, 31,253,225, 87, 10, 15,240,197,175,127,243,225, 6,
+ 7,194, 32,175,236,108,242,177,165, 51,231,158,185,120,241,226,
+ 149, 43, 87,134,195, 81,118, 30,185,228, 42, 99,203, 61,135,177,
+ 58, 86,222,223, 73,123, 8, 7,142,167,216,126,206,149,221,243,
+ 47,247, 19, 17, 17,145, 48, 12, 99,136,175,199,163,160,191,253,
+ 76,119,134, 4, 17, 65,193, 67, 74, 14,199, 69,180, 95,251,141,
+ 223,236, 46, 45,118,151, 23, 87,158,125,230,200,249,115,102, 97,
+ 220,149,239,124,255,199,127,248, 71, 39,223,255,252,147, 63,243,
+ 209,137,225, 87,101,226, 36, 53,191, 14,241, 48,206,113, 59,137,
+ 175, 36,163, 79,191,244, 51,183,110,221, 50, 21,246, 0, 98,242,
+ 151, 74,138,249, 32,219,243,252, 41,157,167,143,214,100,164,165,
+ 88,177,136, 68, 42, 20, 25,220,131,254, 50,151,153, 57, 8, 2,
+ 34, 26, 5,112,109,212, 63,210,104,205,135, 77, 34,194,116,129,
+ 36, 60,124,132,165,233,216,203,175,230, 47,210,157,246,147, 47,
+ 125,236,185,191,253, 11,198, 60, 70,189,254,212,242,210,252,153,
+ 83,135,100, 46, 82, 38,135, 95,147, 94,109,244,181,223,248,205,
+ 149,243,207,188,251,111,127,238,237,126,196, 82,231,248,236, 11,
+ 207, 15, 71,163, 75,111,189,181,182,182,198,204,230, 4,172,210,
+ 95,233,177,245,103,202,220, 3,190, 7,173, 42,216,117, 8,113,
+ 38,206,255,236,143,144,189,247,180,148,221,255,232,113,250,203,
+ 92,212, 90, 43,165, 18,145, 72,209,213, 97,127, 42, 8,149,228,
+ 91,180,193, 67, 71, 88,212, 43,214,223, 71,253,193,133, 63,249,
+ 218, 27, 95,255,139, 23,126,249,139,166, 61, 1, 0,156,120,255,
+ 123,223,102,126,189,173, 69,172,193, 35,197,173,201, 58, 9, 69,
+ 4,174, 13,251,219,221,230,243,231,158,121,235,173,183,178, 58,
+ 85, 87, 83,248, 20,203,213,214, 56, 9,182, 15, 49,113, 15,216,
+ 194,135, 15,168,253, 68, 96, 62,211, 65, 0,157, 4,208, 19, 97,
+ 34,178, 79, 35, 93,125,196,204, 81, 70, 36,162, 36,128,155,209,
+ 104,118, 52, 56,217,234,144, 32, 1, 10,202,195, 71, 88, 22,137,
+ 20, 70,220, 31,124,251,183,127, 23, 0, 12,194,230, 79,159,154,
+ 236,179,224, 96,185, 17,220,223,115, 79,106,162,141, 59, 72, 34,
+ 192, 34,111, 13,118,158,123,241,111,108,109,109, 93,189,122,117,
+ 48, 24,164, 82, 2, 0, 68,112,223,201,253,216, 19,178,234,226,
+ 158,130,108, 18, 76,225,254, 36,152, 20, 89, 15, 32,217, 18, 5,
+ 188,187, 39,223,126,184,111, 92,100,146, 36,163,128,110,140,250,
+ 71, 26, 45,133,164, 64, 16, 30,106,159,176, 12, 97,187,220,230,
+ 219,191,253,187,243,103, 78,205,159, 57, 21,118,218,135,194, 48,
+ 202,164,240,107, 82,135, 41,135,105,116,188, 87,173,238,226,226,
+ 219, 84, 38, 35, 2,112,117,212,167,197,249,233,133,249,139, 23,
+ 47,174,175,175,107,173, 77,236,101, 94,235, 43,201, 85,118,142,
+ 165, 83,199,171,100,242, 47,140,129, 24, 28,142, 18, 86,113,208,
+ 85,168,224,205,161,159,246,252,151,241, 57, 88,245,193,220, 93,
+ 164,186,143, 2, 17,105,165, 54,147,248,198,104,112,178,213, 85,
+ 10,201,136,191,135,120,252, 12,194,230,119,173, 8,251,238,239,
+ 255,193,167,126,237, 87,187, 75,139, 19,229, 57, 30,178,113, 11,
+ 238,230,119, 76,202,130,199,202,241,169, 95,251,213,242,149, 89,
+ 35,195,135, 79, 47, 35,190,206,127,244, 19,219,219,219,183,110,
+ 221, 26, 69, 81, 10,175,130,254,202,133, 6, 58,207, 2,207, 78,
+ 142,145, 84,233, 5,255,195, 46, 12,115,180, 15, 78, 34,183,208,
+ 119,143,230,192, 32, 8, 32, 58, 23, 50, 5, 54, 86,130,149,130,
+ 252,221,167, 34,139, 7,140,136, 68, 36, 14,212,205,104,112,164,
+ 217, 14, 4, 85, 90,251,251, 80,143,202,197,175,127,243,226,174,
+ 55,184,245,242,171,111,252,217, 95,196,143,119,155,138,224,158,
+ 158,106,147, 53,126,244,135, 95, 41, 92,211,187,189,118, 11, 94,
+ 253, 17,124,165,112,229,195, 75,190, 0,110, 69, 3,181, 56, 63,
+ 179,184,240,230,155,111,110,110,109,101,138, 32,211, 95,105,106,
+ 3,238, 82,109, 48,242,162,100, 86, 42,206, 55,239,195, 24,148,
+ 77,104,119,228,106, 55, 89,110,138,103,170, 39, 48,191, 32,146,
+ 191, 6,236,230, 30,171,181,210, 46,115, 31,133,227, 75, 68,137,
+ 162,205, 36, 94,141,134,199,154, 29,165,132, 0, 5,100,210, 14,
+ 167, 9,194,106,126, 29, 22, 82, 85,143,202, 18,152,222,234,154,
+ 59,247,252,118,136,175,222,153,247,125,168,215,235,173,174,174,
+ 70,163, 81,230, 25,119,137,189,118, 49,121,101, 85,229,128, 43,
+ 189, 8,152,214, 50, 49,155,178,217, 67, 31, 78,102,127, 99, 86,
+ 143, 15, 25,188,140,250, 42,105,176,177, 85, 20, 57, 45, 61, 10,
+ 149, 25,102, 44,164, 82, 42, 86,250,102, 52, 88,106,180, 2, 73,
+ 83,176,122,153,252,164,233,156,186,254,235,193, 63,114, 2,208,
+ 211,201, 78, 67, 45, 29, 59,122,229,202,149,205,205, 45, 95, 56,
+ 64, 86, 60, 81,157,212, 8, 8, 72,105,241, 80,122,214,185, 18,
+ 43,255, 33, 0,172, 53,107,157,232, 68,107,205,204,194, 98, 55,
+ 254, 56,172, 59,122, 34, 66,186,242,201, 89, 95,146, 47,133,178,
+ 127,152,236, 42,190, 50,167,185,191, 32, 44, 63,186, 68, 20, 7,
+ 234,206, 48,234,233,164, 65,196,136,100,148, 96,253, 20, 63,196,
+ 254,177, 30,251,146, 95,114,101,216, 59,254,212, 19,195,225,112,
+ 109,109, 61,138, 70, 89,193,151, 93,245,130, 48, 62,176,207, 88,
+ 85, 25,123,121,126, 17, 80, 64, 88,235, 40,138,162, 40, 66,196,
+ 169,110,119,170,219, 13,195, 16, 4, 26,237,150, 9,215, 36,171,
+ 65,240, 47, 76,196,235,179,184,169,125,118,127, 69, 0,132, 89,
+ 68,226,225,136,133,147, 36, 25, 70, 81, 20, 69, 74,169, 48, 12,
+ 149, 82,184,143,229,137, 34, 96,194,198,177, 49,152,163,197,202,
+ 194,214,184,200,155,163,193,116, 16, 6, 34, 10,165,210,231,214,
+ 99, 55,211, 94,243,235,208,209,139, 69,174,141,250,239, 63,125,
+ 122,123,123,123,123,123,155, 89,178, 34, 0,183, 78,181, 98,170,
+ 177,232, 31, 43, 52, 66,246, 94, 4,152,117, 20, 69,195,225,176,
+ 213,106,157, 62,121,170,213,237,184,132, 18,145, 2, 29, 38, 10,
+ 97, 30,203,220,187,237, 30, 17, 17,213, 8,145, 25,149, 82, 97,
+ 200,204, 58,142, 71,163,136, 20,101, 20, 27,107, 30,109,116,182,
+ 87, 10, 86, 93,144, 98, 22, 23, 39,138,214,226,209, 19,204, 26,
+ 137, 69,168,182,144,135, 83,127,213,101, 94,251, 60, 76, 34, 0,
+ 155, 73, 28, 76, 79,169, 70,184,121,235,230,112, 56, 44,193, 75,
+ 252, 58,213, 74,114,141, 21, 8,217, 15, 73,146,100, 56, 24, 32,
+ 209,153, 83,167,219,221, 14, 0,204,119,167,206, 46,173,156, 93,
+ 90,158,111,182, 69,235, 51,115, 11,200, 44, 6,168,249,212,246,
+ 4, 78, 34, 75, 81,138, 73,202, 49, 22,254,233,218,109, 0, 92,
+ 237,239, 92,184,117,227,213, 91, 55,110,111,109,134,141,144,147,
+ 36, 26,141,194, 70, 35, 8, 2,159, 40, 57,176,118,143,219,199,
+ 87,165,184, 22, 18,129,104, 4,122, 43,137,155,164,178,206, 43,
+ 88, 75,176,137, 9,196,106,253,245,224, 17,182, 22, 13,231,143,
+ 175,196,113,178,179,179,163,117,226,152,199, 66,242,181, 27,185,
+ 198,158, 88, 0, 34, 18, 71,113,127,208,159,157,153, 57,114,244,
+ 40, 0, 28,153,153,125,207,201,211,159,124,234, 89,142, 34, 29,
+ 69, 58,142,133,113,120,103, 67,180, 78, 85,152,100,219,116,139,
+ 147,178,165,191,216, 45,105,127,248,142, 35,223, 64,188,200, 47,
+ 17,129,147, 24, 2,192,201,169,249,247, 77, 47,200,211,207,253,
+ 63,175,191,252,157,171,111, 93,189,179,206,146,182,129, 14,195,
+ 176,236, 37,247, 76,241, 43, 41,230, 30,106,147,226, 19, 81, 66,
+ 184, 30,143, 22,194, 38,139, 72,157,128, 29, 74,253, 85,203,175,
+ 187, 48,143,112, 43, 26, 62,121,252, 88, 20,141,134,195,161, 61,
+ 145, 10,201, 87, 21,185, 82,141,180,139,191, 49,243,111, 18,199,
+ 113,191,223, 59,114,228,200,204,236, 44, 0,188,244,204,249, 95,
+ 56,255,110, 61, 24,142,238,108,232, 40,210, 73,194,137, 22,214,
+ 194, 34,194,192,226, 58, 71,215,179, 77,226,225,203, 8,109, 61,
+ 112,122, 89,196, 28,154,159, 95, 57,249,243,199,159,248,119,175,
+ 254,248,107, 63,125, 69,107,205,137,198, 46, 5,129, 74,219, 62,
+ 143,115,142, 99,143,237, 30, 41,152, 82, 42, 65,220, 78,226, 4,
+ 152,133, 88,128, 30,191,221, 81, 38, 67,105,213,250,235,224, 31,
+ 56,227, 47, 54,226,104,122, 97,254,214,173, 91,195,225,104, 76,
+ 242, 85, 69,174,252, 52,218,109,201, 94,146, 36,131,193, 96,101,
+ 101,101,122,102, 38, 84,234, 75, 31,121,233,217,185,197,209,198,
+ 102, 60, 24,234, 56, 22, 59,249,232,229, 95,238,251,137,229,151,
+ 248,255, 37,237,146, 41, 44,194, 44,194,233, 5, 0, 68,252,207,
+ 79, 62,117,118,106,230,127,251,238,183,134,113,196,219, 60, 61,
+ 59,227, 54, 43, 44, 88, 60, 83, 58,134,121,153, 89,181,255, 43,
+ 167, 96, 70,127,177,162, 94, 28,107, 17,157,234,216, 90,131, 29,
+ 190,252,171, 30,251, 37,216, 90, 52,154, 91, 94, 50,123, 62,199,
+ 113,140, 56, 54,249,170, 34,215, 30,214, 38, 73,146,225,112, 56,
+ 53, 53, 53, 53, 51, 19, 42,245, 95,127,234,179,243,168, 6, 27,
+ 155,201,112,196, 73, 98, 38,236, 64,114,120, 21, 17, 54,129,228,
+ 170, 92, 36,231,136, 47,251,102,103, 70,152, 89, 24,162,232,157,
+ 173,233,255,246,131, 31,255,245,111,254,233, 40,142,130,126,191,
+ 59, 53,101,187, 66,123,250,200, 78, 65,238,171,111,154,115,204,
+ 243, 20, 12, 17, 53,225,102, 28,181, 72,113,138, 47,168, 9, 54,
+ 33, 10, 44, 56, 4,247,241, 80, 61,114,235,241,104,230,216,177,
+ 56,142, 77, 58, 3, 78,239,151, 93, 74, 37,246,145,206,160, 8,
+ 199,113,204,154,151,150,150, 64,228,151, 63,252, 51,115, 64,195,
+ 173,237,100, 56,148, 68, 75, 42, 88,192, 65, 24, 27,231, 85,133,
+ 176,137,124, 32,197,227,186,135, 48,102, 96, 6, 97, 16, 6,102,
+ 102, 22,145, 37,162, 95,121,215, 11,191,253,195,191,236,245,251,
+ 205, 86,171,209,104, 64,177,135,199, 56,120, 57, 20, 43,177,168,
+ 92,139,175, 9,183,146,120,185,209,146,250,137,239,153,244, 67,
+ 161,191,164,102,215,126,211, 27, 17,216, 74,226,197,169, 41, 91,
+ 144, 85, 76,190,236, 52,160,236,115, 61,181,139,176, 36,209,209,
+ 104,180,178,188,196, 34, 31,126,242,169,103,103, 23, 70,155, 91,
+ 201, 96,200, 73,146, 85, 27,216,240,200,120, 46, 25, 27,222, 79,
+ 208,163, 88, 85,133, 42,249, 1, 21, 71, 75,166,115,169, 44,192,
+ 44,204, 73,162,207,119,103,127,230,228, 19,127,126,229,205,157,
+ 173,173,197,229,229,194, 26,210,253, 47, 90, 31, 23,228, 27, 11,
+ 169, 1,250, 58, 97, 16, 78,183,246,168, 35,176, 73, 1, 88,112,
+ 79,247,187, 30,227, 14,141, 36,194, 42, 8,146, 36,201,187, 77,
+ 32,250, 86,177,234,164,218,205,148, 32, 34, 48,115, 18,199,164,
+ 84,216,108, 30,153,153,253,252,115,239,139,182,123,241, 96,200,
+ 113, 92,168,249,202,135, 99, 39, 11,252,154,156,149, 69, 8, 0,
+ 192, 69,132,185, 19,145,204, 96, 18, 61, 22, 72,103, 36, 88, 88,
+ 18,150, 68, 88,115,242,217, 19, 79,190,186,190,122,171,191, 19,
+ 69, 81,179,217,130,116,186,183,170,202, 97,111,231, 87,177,206,
+ 148,136, 52, 66, 98, 66, 69,111,218,182,126,182,191,253,116,168,
+ 243,175, 7,154,126, 1,108,196,209,185,133,249,245,245,117,219,
+ 170,208,150,218,143,179,138,105,175, 9, 25,103,103,172,121,148,
+ 56, 73,102,166,166,153,249,189, 39, 78,225, 48,138,251,125,142,
+ 99, 97,206, 3,163, 76, 4, 50,155,201,199, 84, 48, 88, 59, 86,
+ 244,104,147,115, 14, 56, 34,172,184,189, 37,179,137,189,204,155,
+ 185,108,166, 87, 53,115, 34,146, 48,159,159, 95,186,213,223,233,
+ 109,111,119, 58, 29,131,238,226,161, 46, 31,228,241, 32,115, 31,
+ 168, 84,127, 33,166,250,203,217,118,171, 30, 80, 33,155, 31, 54,
+ 217,131,123,189,175,245,168,118, 60, 0,192,204,163, 81,100,246,
+ 118, 44, 39, 95, 0,126,201, 83,133, 34,171, 56,193,152,153,153,
+ 195,102,163, 25, 4, 47,157,121, 42,222,233,235, 81,196, 6,145,
+ 78,160, 38, 41,181,204,217,110,150, 64,166,225,183, 56,246,117,
+ 50, 7, 22, 67,176,244,104,102,134, 81,152, 57,101, 86,186, 49,
+ 87,204, 58, 17,121, 97, 97,229, 91, 55,174, 12,163,168,209,104,
+ 48,179,217,219,169, 64,174, 42,217,187, 27,200,242, 5,167,144,
+ 238,188,201,217,202, 38,172, 53,216,164,140,224, 0,206,100, 17,
+ 1, 51,223,204, 34,242,216,160, 79,139,172, 70,195,238,252, 92,
+ 146,232, 36,142,157,149,195,232,157, 75,166, 1,223,190, 26,113,
+ 165,223, 45, 44, 90,235, 64, 5,204,252,212,210,145,134,150,225,
+ 112,164,227,216,246,243,179, 39,187,131, 47, 73, 67,110,150,108,
+ 242, 46,151, 52, 19, 79, 46,183,139,182,145,147, 58,229, 87, 34,
+ 108,156, 99,204,156, 88,253, 21, 0,156,156,154,121,125,115, 61,
+ 138,162, 86,171,149,196,201,174, 47, 15, 99,239, 66,133,248,181,
+ 160,138, 17, 86,163, 17, 54, 80,139,132, 66,234, 81, 15,192, 12,
+ 179, 3, 36,101,122,127, 76, 42,174,131,123,133,212,216,193, 2,
+ 3,157,108, 37, 81, 79, 39, 49,243,227,163,218, 24,100, 43,137,
+ 135, 24,198,113,172, 89, 99,169,131,251,190,207,165,138,151, 4,
+ 102, 14,149,210, 90,159,156,157, 75,134, 67, 29, 69,146,232,130,
+ 211, 18, 48,188,178,240, 98,102,230,108,253, 54, 64,113, 47,144,
+ 201,129,151,140, 33, 90,206, 47,102,102,209, 41,191, 56,227, 87,
+ 156,126, 42, 75,173,246,235,155, 48,236,247,167,167,167,205,204,
+ 239,125,244,105,244, 94,116,204,131, 54, 98,189, 26, 13, 35,214,
+ 1, 81,128, 72,240,200,243, 11, 66,162,174, 10,103,130,176,165,
+ 148,154, 84,132, 5, 15,220, 47,198,172, 87,163,225,213, 81,127,
+ 53, 26,198, 34,143,143,204, 22,128,132, 57, 12,167,205, 22,244,
+ 213,103,195,189,255,116, 33,165,180,214, 79,206, 47,154, 21, 66,
+ 172, 53,218,179,223, 13,239,141,236, 98, 35, 88,220,249,187, 98,
+ 224, 52,113, 10, 12, 61,243,102, 67, 61, 22, 96,214,194, 9,139,
+ 150, 92,127, 37,204,177,131,179,149, 86, 27, 0,122,189,254,153,
+ 78,199, 76,254, 62, 56, 33, 2,134, 95,215, 71,131,213,120, 68,
+ 153,159,124,212, 7, 33,206, 4,225, 59,187,115, 10,145,198, 41,
+ 206,183,219, 72, 7,247,123,143, 74, 39, 66, 34,210,211,201, 27,
+ 131,157,190, 78,224, 49, 27, 2, 50,111,211,174, 61, 58, 21,200,
+ 126,206,104, 55,139, 65,102, 22,173, 37, 73, 52, 19,199,137,104,
+ 237,224,200, 52,156, 73,165,151,136, 88,126,177,228,107,113, 96,
+ 66, 59,128, 99,229,197, 92,127, 89,114, 89,253, 37,146,100,228,
+ 202,174,209,108, 94, 42,218,237,118,175,215, 43, 68, 96,251,191,
+ 3,227, 70, 34, 50,210, 9,242,227,149,122,221,138,134, 91, 73,
+ 252,159,173,156, 38,162,201,220,171, 39,184,111,209, 85,220,107,
+ 151, 16, 59, 42,120, 12,225,229,158, 11,105,104,176,203,241,196,
+ 187,251,161,136,200,137, 22, 17,157, 36, 76,196, 73, 34, 70,127,
+ 101,224,116,235, 38,172,225, 18,225,172,151,131, 76, 98,241,215,
+ 238, 79, 38, 83, 53, 33,137,112, 34,172,173,236,178,239, 83,138,
+ 105,243, 37,102,115,156,130, 32, 80,164,118,133,226,221, 65, 21,
+ 1, 31,231,134, 19,183,162,225,212,220,108, 52, 24, 38,209,232,
+ 238, 14,168, 60, 56, 79,247,192,243, 10,121, 31,104, 0, 0, 32,
+ 0, 73, 68, 65, 84,175, 93,238, 89,131,104,185,209, 90, 8,155,
+ 235,241,232, 49, 69,152, 25,100,170, 87,203,143,156,220,213, 73,
+ 132, 0,130, 68,136, 17,107,102,224, 68, 51, 37,150, 95, 54,248,
+ 246,249, 37, 25,190,196,246, 96,157,232, 24,210,187,119,146, 9,
+ 47, 0, 22, 51,207,232, 73, 45, 39, 5, 19, 3, 47,227, 43,205,
+ 1, 11,130, 0, 41,107, 71, 33,119,139, 44, 44, 1,236,225,109,
+ 192, 61,145,227,137,185,133,102,183, 27, 71,209, 61, 55, 41, 57,
+ 208,167, 94, 80,254, 77,114,127,247, 38, 64,154,110,168, 47,156,
+ 121,230,175, 7, 91,170,216,158,233, 81, 30, 44,178, 57, 28,220,
+ 1, 38,164,188,163,139, 61,143,156, 70, 49,120,183,103, 20, 41,
+ 82, 65,192,131,129, 22, 97,173, 89,136, 19,109,252, 35, 58,221,
+ 178,178,185, 71,157,190, 29,142, 54,248,121,113,173, 83, 86, 98,
+ 58,150,153, 63,196,211, 92,182,236,203,188,103,225,236, 54,230,
+ 149,163,217,108, 18, 17,185,125, 87,239,150, 95, 88,241,106, 52,
+ 213,104, 30,233, 76,205,180, 90, 13, 21, 4, 68,244, 56, 60,171,
+ 17, 17,241,195, 39,206,112,127, 96,158,108,111, 51,171,238, 86,
+ 127,201,125,252,229, 13,162,143, 44, 29, 11,155, 77,116, 27,155,
+ 60,202,201, 23,104,214, 87,182,183,190,183,189,102,186,215, 35,
+ 82,126, 8,241,222,142,102,122,150, 16, 82, 16, 4, 0,144, 36,
+ 201,197,181,219,167, 22,143, 49,107, 73,146, 60,249,178,213, 73,
+ 12,162, 37, 69, 24,231, 11, 32,139,143, 41,190,205,207,186,234,
+ 95, 47, 96,215,107,218,106,144,212, 60, 90,231,232,164, 96,162,
+ 133,179,191, 81, 64, 54,162, 17, 0, 44, 46, 46, 41, 82, 32,247,
+ 214, 38,181,162, 28,204,236, 26, 2, 0,221, 48,124,106,118,254,
+ 196,244,108, 39,108,180,148, 82,164, 30,125,128, 33,128, 72,188,
+ 211, 27,245,251, 58,153,208, 56, 40, 40, 61,149,240, 62,159,207,
+ 2, 2,154,147,209,136,227,100,168,122,143,137,254, 18, 0,205,
+ 50, 24,246,178,149, 67, 68,232,148,103,221, 35,196,236,206,207,
+ 24, 4, 1, 41,165,135,195,215, 87,111,189,180,120, 76, 51,107,
+ 173,109,139,153,244,189, 89,160,103,245, 23,179, 5,129, 83,120,
+ 54,225,177, 87, 90,172,102,144,148,133, 95, 58,115,139,105,224,
+ 101,213,165,243, 71,109, 68, 67, 0, 56,122,236,104,156,196,137,
+ 78,238,157, 95, 85,171, 32, 69, 68, 39,122,184,211,235,107, 16,
+ 21,196,164,212, 99, 33,192,192, 76, 4,177,214,247, 17, 64,200,
+ 195,228, 87,245,239,151,187, 71,152,137, 96,224,113, 10,241,181,
+ 72,155,101,176,189,109,214, 60,102,219,125,229,235, 98,228,174,
+ 33,150,109,229, 17,168,160,213,110,111,109,111,191,124,227, 90,
+ 252,236,123, 18,128, 88,242,130,112,247,132, 55, 20,211, 86,152,
+ 136,215,111,117,130,225, 37,158,254,202,254, 16,167,108, 34, 39,
+ 151,159,153,137, 0,172,141, 6, 0,112,250,204,153,181,181, 53,
+ 179,242,225,238,213,198,152,125,213, 0,152,153, 52, 55, 89,146,
+ 81, 20, 43,141, 68,252,120, 47,224,158,156,229, 7,245,250,199,
+ 7, 57, 66, 36, 78, 91,217,100,237,234,161,160,194,246,120,149,
+ 194,234,147, 74, 5,170,211,233, 52,130,112,117,103,251, 27, 87,
+ 47,189,119,106, 62, 78, 51,122,123,182,139, 48, 0, 91, 75,101,
+ 206,127, 55,252, 42, 76, 36,200, 4,182, 47,116,244, 87,166, 37,
+ 179,153, 71, 87,115, 21, 14,219, 91,189,237,126,146, 44,206, 47,
+ 116, 58,221, 43, 87,174,228,107,230,247,119,144,203,226, 43,123,
+ 217,128,180,158, 78, 76, 49, 58,214,173,239, 39, 34,245,170,249,
+ 117, 48,113, 1, 2,116,131, 96,184,211, 35, 34, 69,202, 84,142,
+ 230, 91,172, 34, 96,165, 10, 18,144,180,214,162,100, 97,242,109,
+ 31, 41, 12, 27,211, 51,211,107,235,235,127,254,214,197,119,191,
+ 103, 41, 65,212,206, 36,163, 43,190, 28,126, 57,251,118, 72, 85,
+ 226, 52, 73, 39, 64, 33,249,202,140,112, 82, 69, 46,112,130,255,
+ 183,122,219, 0,240,222,231,223,219,239,247,134,131,161, 51,249,
+ 136,222, 77, 81,118, 89, 33,143, 37,120, 33,166,149,255,196,210,
+ 164, 28, 94, 53,194, 38,135,111, 53,191, 30, 40,193, 16, 91,164,
+ 162,225,176, 57, 61, 21,132, 65,146, 36, 40,233,190,243,226,189,
+ 250, 75, 73,139, 75, 94, 58,230,157, 34, 89, 35, 80, 8,195, 96,
+ 97,113,113,107,107,235,226,218,237, 63,185,244,211,151,150,142,
+ 199,144,106,176, 2,182,236,101,167,239,132, 84,164,248,147, 20,
+ 179,100, 73,133,184,138,210, 53,140,133,166, 91, 25,188, 94,222,
+ 188,179, 54, 26,180, 91,173,119,190,235, 93, 23, 46,188,106,246,
+ 193, 28,243, 26, 81,121,132, 11,230,209,219, 32, 24,128, 89, 51,
+ 1,132, 68, 4,104,227,252,154, 96,247,196, 45,121, 27,249, 85,
+ 119,159,216,159,254,154, 86,225, 86,175,215,153,155, 13,195,144,
+ 211, 14, 92, 6, 95,152, 46, 39, 46, 73, 48, 41, 79,217,231, 39,
+ 88,126, 58,153,237, 14,143, 30, 59,118,249,242,229,175,189,241,
+ 234,217,153,185, 5, 84,166,158,192,203,191, 28,132,101, 68, 40,
+ 71, 96, 19, 37,189,178,254,176,118, 46, 66, 24, 64, 11,251,162,
+ 75, 4,176,112,247, 55,226,232,194,214, 58, 0,124,254, 23,127,
+ 113,115, 99,115,107,107,147,133,203,221, 62, 10,237,192,198,111,
+ 158,230,110, 82,135,136,144, 36,162,181, 38,145,182, 10,208, 86,
+ 178, 98,205,165,137, 57, 6,193,110,119, 76,118, 69, 88, 77,180,
+ 42,132,205,135,141,155, 91,219,116,138, 2, 21, 68, 24,217,189,
+ 184, 32,119,145,101, 9, 86, 37,228,202,219, 62,138, 72, 16, 4,
+ 179,179,115, 59, 91,219,119, 54, 55,254,240,181,159,252,210, 59,
+ 222,217, 64,176,179,141, 69, 9,230,216, 49,207, 62, 74, 21, 60,
+ 222,246,215,231, 66,254,229,116, 44,243,247, 11,112,198, 64,235,
+ 239,172,221, 4,128,231,223,243,222,249,249,249, 87, 94,185, 48,
+ 24, 12,210, 93,154,188,109, 32,139,237,192,138, 81,189,215, 42,
+ 199,254, 67, 52,109,215, 18,157, 4, 2,109,165, 8,144,234,198,
+ 171, 19, 54,106,255,248,128, 13,228, 76,208, 24,109,109, 34, 34,
+ 41, 34, 36, 73, 59,176,166, 77,245,196,169,100,173,120,221,144,
+ 114,132,236,157, 78, 0,208,108, 54,158, 56,251,228,232,149, 87,
+ 86,123, 59,255,247, 27, 23,254,198,137, 51, 51,168, 18, 22,102,
+ 91, 15,149,137, 47, 17,182,109, 95, 29,120,249,221,239, 39, 50,
+ 197,223, 15,230,183,226,248,251,119,110,109,199,209,177,163, 71,
+ 63,253,217,207,188,246,218,107, 27, 27,119,152,185, 96, 14,199,
+ 72,133,138, 62,171,174,246,178, 91,129, 72,146, 36, 58, 73, 90,
+ 2, 51, 65, 72,147,221, 73,166,230,215,132, 70,116,135,201, 63,
+ 34, 52,136,218,130,253,237, 29, 10, 3, 36,194,116, 97, 15, 32,
+ 216, 40, 12,100, 79,245,229, 57, 71,159, 95, 34,210,108, 54,223,
+ 253,158,247,254,240, 7,223,191,182,189,249,111, 95,253,241, 7,
+ 143,156, 56, 63,179,160, 33, 85, 97,110, 85,167, 28,170,135, 69,
+ 246,109, 87,126,186,189,249,147,205, 53, 22, 89,152,159,255, 47,
+ 254,222,223,187,122,245,234,205,155, 55,205,110, 79,222, 55,101,
+ 27, 65,250, 66,206,147,183,249, 12, 73, 74, 47,107, 30,145, 57,
+ 137,163, 8,180,110, 17, 53, 80, 17, 34, 1,214, 83,144, 19,117,
+ 254, 7, 53,150, 30,116, 4,134,115, 97,163,183,177, 57,179,178,
+ 28, 4, 1,107, 45,152, 53,177, 73,189,100, 6,179,170, 3, 46,
+ 5,229,149, 42, 2,219,181, 69, 68,180,214,173, 86,251,227,159,
+ 248,196, 15,127,240,131,235, 55,110,124,243,250,229, 43, 59, 91,
+ 231,102, 23,150, 27, 45, 45, 98,226,176, 67,251,236,151, 93,110,
+ 128, 0,183, 71,131,215,183, 55,111, 12,122, 0,240,238,231,158,
+ 251,197, 47,124,225,205, 55,223,188,124,249, 74,191, 63,200,203,
+ 238,109, 21,118,234, 28,211,233, 93,192, 10,126, 21, 95, 36,242,
+ 15,136, 81,164, 71,163,136, 88,186, 65,160, 16,149,201,239,235,
+ 103,249,225,209, 95, 82, 3,237,238,220,163, 32,161, 28,111,118,
+ 126,176,182, 54,119,244, 72, 16, 4,177,112,170,185,208, 10,177,
+ 52, 15,131, 44,209, 47, 11,178, 49,137, 76,122,182, 49,115, 20,
+ 141,130, 64,189,255, 3, 31, 88,189,189,250,151,127,249,151,151,
+ 183, 55, 47,111,111, 46,183,187,199, 58,221,217,176,185,216,104,
+ 226,164,175,217,190,139,231,149, 0,172,141,134,155,241,232,122,
+ 191,103,234, 84,195, 32,248,187,127,247,239,158, 62,115,230,181,
+ 215, 94,187,122,245,106,175,183, 99,143, 44, 88, 94,229,251,166,
+ 101, 74, 12,199,120,243,204, 51,250,230, 17,146, 36,137,162,168,
+ 5,184, 16, 54, 21, 34,161, 89,202, 93, 11,176, 58,255,122,180,
+ 35,176, 48,196,237, 81, 18,141, 40, 8,136, 40,219,253, 43,163,
+ 152, 51, 31,185,219,207, 1,172, 8,101, 50,132, 13, 6, 67, 17,
+ 88, 57,178,242,139,191,244,133, 11, 63,121,249,194,133, 87,110,
+ 15,122,183, 7,189, 71,251,240,118, 90,237, 15,127,228,195, 31,
+ 255,196, 39, 54,183,182, 94,126,249,149,219,183,111, 13, 6, 67,
+ 27,123, 65,190,211,182,117,142,206, 22,144,133,156,203, 59,182,
+ 133, 35,140,136, 73,146,140,134, 35, 78,226, 38,224, 84, 16,170,
+ 12, 94,245, 24, 99,234, 15, 31,191,106, 49, 86, 25,129,145,224,
+ 82,163,181,179,126,103,230,200, 10,145, 50,203,168,237,155, 41,
+ 200,247,138, 42,198,129,172, 60, 29,102,127,131, 65,152, 30,141,
+ 134,155,155,156, 36,201, 59,159,123,238,163, 47,190,120,253,250,
+ 181,159,190,250,234,141, 27, 55,214,238,220,121,196, 14,236,242,
+ 226,226,233,211,167,159,127,225,133,119,188,227,233,245, 59,235,
+ 111,188,113,241,246,237, 91,219, 91,219,113, 18, 23, 55, 6, 6,
+ 65,243,175,176,243,166,111, 21,161, 84, 42,225,194, 11, 0,147,
+ 68, 15, 6, 3,197, 50, 29, 52, 20,162,170,195,175,177, 16, 40,
+ 161, 76, 14, 9,191,106,138, 85, 66,135, 16, 79,182,186,223,185,
+ 117,123,246,200, 17,165,148,237, 65,159, 55,115,206,130,176,180,
+ 168,162, 12, 49,129,162,127,132, 52,125,113,202, 39, 81, 68,162,
+ 40,214,122,123, 56, 26,237,236,108, 79, 77, 77,191,248,210, 75,
+ 83,211,211,221, 78,167,209,108,154,174,229, 88,238,104, 85,245,
+ 217,196,120, 71,167,191,181,216, 99, 35,146, 36,122, 48,232,111,
+ 110,110,254,240,135, 63,216,220,220,220,217,233,197,113,204,172,
+ 237, 95,146,215, 6, 99,230, 31,205, 42, 34,255, 72, 22, 95, 21,
+ 178,216,203, 31,204, 60, 26, 13,135,195, 97, 27,112, 33,108,154,
+ 109, 44,168,198,215,225,240,143, 82,177,104,187,134,212,254, 37,
+ 24, 1, 78, 5, 65, 71,203,112,103,167, 53, 61, 69, 64,206,214,
+ 26,217,192, 10, 47,233,128, 76,178, 62,212,254,252,163,123,162,
+ 166, 15,141,112, 52, 26, 37,113,188,179,179,179,190,222,108,183,
+ 91,205,102,171,209, 8,145, 8,139,154, 99, 2,233, 85,194,150,
+ 67, 47,115,216,180,214,113, 28, 15,134,131,225, 96, 16, 69,145,
+ 214, 90,156,149,157,152, 30,180,108,122,214, 44,155,151,116,243,
+ 58, 27,185,151,253,184, 39,187, 32,109, 57,105, 70, 28,199,253,
+ 94, 95,226,120,138,130,233, 32, 12, 76,248, 85,135,247,135, 47,
+ 255,218,127,193,246, 4, 19,174,187,188, 56,181,180,100, 46,223,
+ 121,235,114,212,235, 31,180,133, 84,130,199,154,157,107,171,107,
+ 237,233, 41, 36, 18, 17, 17,146,226,216,219, 75, 22,245,151,173,
+ 0,119, 75, 58,179, 51, 86,107, 30,142,134, 81, 52, 66,220,178,
+ 137,116,206, 64,184,255,158,202, 15,135, 95,206, 94,188,146,247,
+ 149,229,236,127,245, 65, 79,191, 49, 19,182,169,121,244,177, 85,
+ 229, 25,193, 97, 23,165,101, 95,195,225,176,215,219,105, 8,204,
+ 5,141, 16, 73, 33, 41,215, 60, 62,222, 47,230,178, 63, 21, 42,
+ 19,193,175,195, 60,142,156, 63,247,228, 75, 31, 93,126,231, 51,
+ 211, 22, 94, 0, 48,234,247,191,247,123,127,240,198,159,253,197,
+ 65, 91,200, 19,173,206,155,235, 55,227,227,199,194,102,211,246,
+ 210,225, 18,194, 42,189,164, 39,196, 92,132,165, 5, 26,165,167,
+ 138,164, 69, 23, 94,169, 42, 22, 94,125, 38, 87, 60,248, 47,146,
+ 213,252,202, 86, 18,216,203, 85,155,174,217,169, 93, 44,170,215,
+ 113,158,209,113,143,100,197,215,104, 20,109,111,111, 71,131,225,
+ 34,170,229, 70, 43, 32, 12,106,243,184,219, 99,135,111,163,156,
+ 121, 4,249,213,232,118, 78,190,255,249,119,125,254, 23, 12,182,
+ 182,227,254,215,175,255,240,167,155, 87, 1, 96, 42,108,127,230,
+ 244,135, 62,242,143,126,165,119,123,237,230,203, 23, 14,212, 66,
+ 42,196,227,173,206,234,181,235,203, 79, 62, 65,100,188,141,170,
+ 66, 88,217, 75, 58,142, 50, 95,214, 13,110,253,101,254, 12,201,
+ 151,201,236,178,172, 82, 38,173,229,234, 88,140,185,251, 41, 65,
+ 190,247,155, 71,177,234,150,116, 25,255,179,248,190,202, 45, 22,
+ 235,188, 10,240, 34, 17, 30,244,251, 91,155, 91, 45,192,249,176,
+ 25, 18,165,225, 87,109, 30,239, 61,211,172,249,181,239,113,238,
+ 51, 63,247,220,231,127,161,217,233, 0,192,215,175,255,240,171,
+ 151,255,211,159, 95,255,161,123,131, 63,191,241,163,255,233,197,
+ 127,242,161,255,234,239,127,229,159,254,218,129, 90, 72, 2,124,
+ 162, 61,125,109,253,102,124,252,104,163,213,166,212,155,224, 88,
+ 132, 21,188,100,169,111, 5,238,150, 24, 85, 61,119, 76,253, 64,
+ 42, 68,196,180,143,129,251,216,214,245,225, 69, 95, 30,193,242,
+ 234, 19,219,162,162,130, 96,185, 96, 53, 69,117,228,112,203, 9,
+ 16,113, 87,120, 33,194, 96, 16,111,108,220,137, 71,195, 25, 84,
+ 199,154,237, 16, 41,176, 57, 98,205,175,253,169,176,135,250,210,
+ 24,220, 51, 49, 39,237, 21,252,228, 7,158,127,223,151,190,104,
+ 52,215, 31,191,245,237,223,185,240,199, 55,250,235,229,155,125,
+ 127,245,181,239,173,190,246,190,165,167,207,125,230,231, 46,124,
+ 245, 63, 28,160,133, 4, 8, 16,143,183, 58,215, 47, 94, 58,254,
+ 236, 51, 0, 1, 17, 2, 32, 51,102,129, 78, 17, 97, 34,206,122,
+ 201, 92, 81,164, 89, 53,186,114, 43, 91, 20,147, 63, 30,197, 94,
+ 13,232, 5,100, 89, 19,172, 73, 13,112, 10,125,202, 60, 9, 6,
+ 69, 43, 89,106,236,111, 15,187,128, 16, 82,217, 45, 86,194, 43,
+ 243,140,198, 32,106,157,236,108,111,111,108,108,118, 4,231, 27,
+ 205,144, 40,180,187,109, 63, 52,124, 29, 57,127, 14, 0, 86,206,
+ 63, 83,249,213,222,234, 90,239,246,218, 65,103,184,135,104, 60,
+ 10,250,171,209,237,124,248, 31,254,253, 83, 31,120, 95, 70,174,
+ 169,176,253,133,179, 63,251,142,217, 19,239, 91,122,250,235,215,
+ 127,248, 47,191,247,251, 59,241, 32,187,253,191,252,222,239,255,
+ 219,159,255, 31,158,251,252, 47, 28, 36,191,128,172, 4,219,220,
+ 90,235,221,217,152, 94, 92,180,243, 91,102,143, 70,220, 21, 97,
+ 48, 86,134, 21,156, 97,102,186, 42, 58,243,228,228, 50,251,160,
+ 227,196,178, 11,160, 18, 94,249,230, 74, 5, 29, 6,144,107,177,
+ 2,192,128,138,110,209, 89, 18, 84,158,106, 76,131,123, 66, 17,
+ 25, 12, 6,107,107,171,144, 36, 51, 42, 56,214,108, 55,172,248,
+ 58,232, 29,212,230,207,156,122,242,165,143, 30, 61,127,110,238,
+ 204,169,125,126, 75,127,117,237,198, 79, 46, 92,249,238,247,175,
+ 252,213,247,107,126,221,175,230,122, 27,207,137,147, 31,120,254,
+ 195,255,232, 87,154,157,206,107,155, 87,254,151, 31,255, 33, 0,
+ 252,119,239,251,229,247, 45, 61,157,221,224,165, 99,239,249,233,
+ 230,213,223,185,240,199,217, 53,207, 47, 61,189, 29,247,167, 59,
+ 157,249, 51,167,238, 92,186,124,112, 18, 76, 1, 4,136, 39, 90,
+ 221,151, 47, 95,105,207, 76, 19,181, 84, 64,132, 36,194,136, 50,
+ 70,136,101, 8,179,117,152,217,191, 98,255,174,188,184, 60, 61,
+ 219,171, 58, 91,184,226,203, 80, 12, 74,121,218,219,171,186, 42,
+ 10,117, 36,111,167, 51, 70,136, 85,244,254,201, 68, 86, 33,234,
+ 42,151,167,122,222, 49, 45, 50,193,209,104,184,190,182,190,189,
+ 185, 53, 45,176, 24, 54,155,164,140,248, 82, 7, 41,190,230,207,
+ 156,122,225, 75, 95, 52,154, 11, 0,228,198, 53,184,113, 29, 54,
+ 54,224,230,117, 24, 14, 42,190,225,204, 89,104,181,224,232,177,
+ 206, 19,103,207,126,252, 99,103, 63,254,177,222,237,213,111,253,
+ 214,239, 30, 92,152, 59,225, 89,216,225,214, 95, 47,124,233,139,
+ 207,126,230,231, 0,224,255,120,229,143,255,221, 27,255,223,175,
+ 156,251,236, 47, 61,245,179, 0,112,253,149, 11,151,254,236,155,
+ 87,190,243,125, 0,248,220,191,250,141, 47, 60,245,137,175, 94,
+ 254,246,141,254,250, 59,102, 79,252,227,231, 62,111,232,246,202,
+ 87,255,195,193,193, 43, 75,193, 20,224, 74,163,117, 39, 30,173,
+ 95,189,182,116,250, 20, 17, 82, 16, 16, 40,102, 65,100, 43,196,
+ 74, 50, 44,239, 90, 81, 4, 89, 94,239,108,150,200,152,204,204,
+ 118,217,119, 82,127, 79,124, 89, 90, 21,102,250,112, 2,159,221,
+ 226,238,231, 81,156,140,116,246,186,204,154,203, 26,245, 73,119,
+ 11, 47,114, 98, 47, 76,146,100,115, 99,227,246,237, 91, 45,128,
+ 165,176,185,220,104, 53,108,114,127,112,244,154, 63,115,234,231,
+ 254,217,175,134,157,142,188,249, 6,252,224,187,240,202, 79, 96,
+ 56, 4, 0,104,181,224,217,119,194,153, 39,225,232,177,252,214,
+ 27,119,224,230, 13,248,193,119, 97,227, 78,122,212,158,125, 39,
+ 156, 59,223,125,254,253,159,250,103,191,250,173,223,250,157, 3,
+ 157, 82,159,216, 76,233,176,242,171,209,237,188,240,203, 95, 60,
+ 251,241,143,109,199,253,127,254,159,254,247,159,110, 94,249,215,
+ 47,254,147,167,103, 79,110,175,174,126,239,247,254,192, 21,213,
+ 175,126,245,107,239,254,252,231,254,241,115,159,223,137, 7,159,
+ 61,253, 97, 67,183,191,254,191,254,232,214,193,191,100, 33, 32,
+ 33, 40,196,179,157,233, 31,173,223,217,238, 78,205, 46, 47, 42,
+ 165, 80, 41,133, 34,130, 25,197,236,182,217, 54,175,134,188,101,
+ 133,181,147, 46,200, 76, 99, 66,143,106,126,127,196,130,211, 52,
+ 63,160,172,185, 38,201, 75,138,255,206,177,198,190, 10, 3,167,
+ 223,180, 65, 23, 82,198, 41, 40, 78, 49, 86,154,198,156, 92,132,
+ 132,200, 44, 59, 59,219, 55,111,222,192, 56, 89,160,240,120,171,
+ 211,176,226,235, 64,203, 38, 94,248,210, 23,195, 78, 71,254,228,
+ 223,195,183,190,145, 95,251,145, 23,225, 19,159,196, 86,187,250,
+ 123, 62,253,183,228, 91,223,128, 63,249,247, 0, 0,175,252, 4,
+ 94,249,137, 92,120, 25,255,206,151,222,255,165, 47, 62, 60,126,
+ 77, 82, 45, 78, 48,161,207,230,189,198,167,126,237, 87,231,207,
+ 156,122,109,243,202, 63,253,198,255, 12, 0, 6, 94,151,255,234,
+ 123,223,254,237,223, 45, 68,155, 63,250,242, 87,158,248,248, 71,
+ 95, 58,246, 30, 0,216, 94, 93,253,235, 47,255,209, 67,123,164,
+ 109, 33, 5, 53, 8, 78,180,186, 63,185,244, 86,179,219, 86, 74,
+ 53, 72, 17, 41, 17, 3, 47, 76, 55,225,192, 42, 37,102,201,229,
+ 131, 44,203,244, 37, 95,239, 7, 82,202,192,138,179, 66,226,132,
+ 254, 56, 65,212,170,250, 76, 10,251,114,139,247,207,252, 49, 37,
+ 100, 21,139, 36,118, 73,235,211, 77,210, 73, 64,250,253,222,141,
+ 235,215,123, 59, 59, 51,130,139,141,102,139,148, 21, 95,116,160,
+ 101, 19, 71,206,159,147, 27,215, 60,120, 1,224,167,255, 86,220,
+ 239,191,254,213,255,112,229, 59, 63,112, 95, 98, 87,206,159,155,
+ 63,115,242,217, 79,127,170,251,145, 23,229,194, 79,224,205,139,
+ 233, 23, 94,249,137,124,255, 59,225,243,239, 95, 57,127,238,214,
+ 36,187,200, 90,127,229, 47, 81,255,232, 87, 50,120,237,196,131,
+ 95, 57,247, 89, 3,175,175,255,235,127, 83,121,251, 63,255, 87,
+ 255,230,220,167, 63,117,231,173,203, 23,191,254,205,135, 63,113,
+ 67, 8, 1,224, 74,163,181,157,196,215, 95,191,120,252,252, 57,
+ 0,108, 54,155,164, 8, 82, 9,102, 82, 48, 11, 50,191,222, 73,
+ 160, 2,100,222,123, 91,215, 89,216,105, 18,242, 46, 12, 21,128,
+ 144, 73,129,152,236,173,197, 28,102,101,253,209, 10,236, 2,172,
+ 238,225, 85,240,140,174,248, 34, 66, 17, 24,244,251, 55,174, 95,
+ 91, 93, 93,155, 22, 92, 12,155,105,242,133, 70,124, 29,252, 95,
+ 111, 12,163, 63,214, 47, 93,254,238,239,253, 65,225,202, 91, 47,
+ 95,184,245,242,133, 70,167,243,238,207,127,174,248, 13, 27, 27,
+ 143,107,124,127, 8,249,181,114,254,220,217,143,127,236,122,127,
+ 205,192, 11, 0,222, 49,123, 2, 0,174,126,247, 7,227,190,229,
+ 206,165,203,223,250,173,223,121, 91,238, 45,218,112, 38, 64, 58,
+ 219,153, 26,238,108,220,190,120,105,233,137,211, 68,212, 82, 77,
+ 36,229,194,203, 94,150,170, 50,125, 17,175, 38,170, 40, 70,188,
+ 168, 8, 74, 36,155,148,188,226, 30,189,100, 58,119, 74,128, 64,
+ 99,203,234, 11,105,215, 94,202, 11, 0,134,195,193,141, 27, 55,
+ 174, 95,191,222, 17, 88, 80,225,169,118, 55, 19, 95,198, 57,214,
+ 53, 95, 19,238, 33,233,208, 5,119,231, 62,253, 73, 0,248,151,
+ 223,251, 63,179,146,136,127,247,198,127, 4,128,119,125,254, 23,
+ 38,243,161,206,202,241, 3,164,103,187,115,221,222, 96,237,242,
+ 213,225,112, 24,199, 49, 0, 40, 69,170,106, 16, 41,162,236,139,
+ 68,138,136,148, 34, 51,148,249, 52,125,239, 12, 69,206, 53,120,
+ 104,207, 65, 76, 83, 45,239,239, 82,222, 5, 42,254,217,233, 1,
+ 82,148, 30, 58,242, 15,166,243,137, 82, 74, 33, 97, 20,141,110,
+ 221,186,121,245,242,149, 22,195,146, 10, 79,183,167, 90, 68, 13,
+ 82,117,193,253,253,159,245, 15,141, 7,193,189,210,245,109,123,
+ 233, 94,121,231,185,235,253,181,239,175,190,150, 93,243,253,213,
+ 215,254,248,173,111,127,246,244,135,223,253,249,207,253,232,203,
+ 95,153,204,199,218,184, 72, 33,122,166, 51,251,202,230,198,198,
+ 205,155,178,178,220,237, 66,171,213, 34, 82,146, 55,104, 69, 17,
+ 177, 90,172, 32,192,178,182, 11,142, 16, 43,196, 67,126,114, 84,
+ 245,113, 2,149, 23,238,126,169, 98, 55,185, 49,166,209, 79,235,
+ 177, 58,179, 71, 4,144,225, 96,120,227,250,141, 75,111,190, 25,
+ 48, 47,169,240, 84,171,219, 34,213,204, 99,251,135,245,151, 63,
+ 113, 22,254,251,223,184,235,239,250,251,255,176,134,231,131,241,
+ 143, 15,255, 60,136,250,253,169,217,206, 84,216,118, 75, 82,127,
+ 231,194, 31,255,204,177,119, 63,243,153, 79, 77, 38,191,114, 23,
+ 9,208, 84,116,178,213,189,124,115,117, 93,235,100,121, 25, 68,
+ 218,157,142, 82,100,139, 38, 80, 68,144, 42,124,100, 69, 13,148,
+ 255,222,179,142,224,150, 86, 29,198,134, 9, 89,147,212, 2,197,
+ 42,182, 53,113,186, 63,151, 99, 47, 42,173,112,148, 94,175,127,
+ 237,234,213, 75,111,190, 25,138,172, 80,176,220,104,117, 84,208,
+ 82,222,156,227, 67, 32,216,183,126,235,119,158,124,233,163,229,
+ 235,127,244,229, 63, 26,247, 45,111,124,253, 47, 42, 75,243,239,
+ 92,186,252,182,135,247,111,139,165, 12, 14, 21,187, 0, 0,174,
+ 254,213,247,159,253,204,207,125,225,236,207,102, 37,169, 71, 59,
+ 11,255,248,185,207, 79,135,157, 81, 60,185,139, 42, 28,132,209,
+ 98,216, 20,128, 43,171,119,214,163, 72,152, 89,164, 59,213, 13,
+ 84, 0, 0, 41,191, 76,187, 29,174,230, 87,198,176, 42, 9,230,
+ 130,172,234, 49,154,100,148, 97,197,231,101,241, 85,170,243, 42,
+ 240,171,162,196,222,100, 94,128,200,204, 59, 59,219,151,223,186,
+ 124,245,202,149,166,200, 18, 5,203,141,246, 66,216,104,146,202,
+ 170,237, 31,154,229,126,227,207,254,226,110,167,194,123,183,215,
+ 190,246, 47,126,243,145,176,152,147,161,191, 30,254,248,241, 31,
+ 254,209,147, 31,255,216, 63,120,246,179, 95,189,252,237,157,120,
+ 240,133,179, 63,251, 15,158,253, 44, 0,108,175,174,126,251,127,
+ 253,221, 9, 79,117,204,194, 60, 32, 90, 12,155, 45,162, 55,182,
+ 118, 86,227,183,244,137, 19, 73,146,204,204, 76, 55, 26, 77, 36,
+ 5, 25,187,200,214,231,131,219,132, 97, 44,191,252,202,207,125,
+ 185, 70,153, 28, 88,221, 27,191, 42,244, 87,101,177, 42, 34, 64,
+ 156, 36, 27,119, 54,222,186,244,230,237, 91,183, 91, 44, 75, 42,
+ 60,222,234, 76,169,176, 69,212, 32, 10,168,142,189,238, 67,114,
+ 21,186,161, 76,146,254,146,251,190,193, 3,245,143,189,254,143,
+ 191,252,149,247,127,233,239,252,250,135,254,203,163,157,133,233,
+ 176, 51,234,247,127,252,229,175, 92,248,234,215, 14,129, 41, 50,
+ 8, 3, 0,162, 41, 8,207,117,103, 95,237,109,174, 94,124,115,
+ 116,236,104, 20,141,230,231,231,219,237, 14,145, 2,112,186, 29,
+ 82,169,160, 2,202, 65,216, 56,253, 5, 19, 61, 3,137,123,127,
+ 205,181,145, 88,236, 68,232,237,217,232,252, 47,218, 71, 16, 25,
+ 12,134,183,111,223,186,244,230,155,189,237,157, 14,203, 98, 26,
+ 216,171, 38,169,166,129, 87,189,189,246,225,179,143,135,179,254,
+ 235,194, 87,191,246,196,199, 63,246,244,233, 83, 70,132,127,231,
+ 247,255, 32, 62, 84,203,241,201,244,101, 39, 2,128,115, 83,179,
+ 175,247,182,174,191,249, 86,124,100, 57,142,226,185,249,249,169,
+ 233,169, 70, 24, 34, 81, 65,115, 21, 83, 48,247, 2,184, 77,103,
+ 202, 8, 59, 92, 17, 24, 86,102, 96, 99, 54, 13, 42, 34,172, 64,
+ 48, 0,208, 73,178,189,189,125,245,234,213,183, 46, 93, 34,150,
+ 46,203, 82,208, 56,213,234, 54,149, 74,109,163,129, 87,205,174,
+ 67, 56,130,201,124, 97,222,115,252,233,191,248,205,249,211,167,
+ 122,171,171,189,219,107,135,235,136, 99,134, 48, 0, 36, 66,129,
+ 167,187, 51,221,209,224,250,237,181,213,193, 96, 48,232,207,204,
+ 204,206, 47, 44,116,187, 29,149, 38, 98, 57,196,242,126, 88,246,
+ 114, 97, 73, 13,120,123,110, 23, 58,210, 28,166, 99, 84,104,117,
+ 61,110,199,179, 18,194, 60, 33,198,204,131,193,224,246,237, 91,
+ 151,223,186,188,185,185,209,100,153, 5,181,216,108,174, 52, 90,
+ 70,118,133,182,212,171, 86, 94,135, 50,253, 58,188,235, 31,227,
+ 94,255, 80,175,150, 48, 70,210, 20,101, 34,225,137, 86,103, 46,
+ 104,188,217,223, 89,235, 95,237,207,110,247,251,189,249,133,133,
+ 217,217,217, 86,171, 77, 68,214, 28,238, 14,175, 92,133,237, 41,
+ 190,100,242,142,198,216,235,156,222,253,229,142,208, 30,194,156,
+ 6, 95,194, 50, 26,141, 54, 54,238, 92,189,114,245,218,181,171,
+ 129, 64,151,101, 65,133,199, 90,157,174, 10,154,164, 26, 68, 33,
+ 146,217, 24,173,174, 83,125,176,196,122,152,207,174, 96, 47,114,
+ 202, 94, 87,214,227,126, 78, 90, 84,102, 67, 14, 32, 10,194,103,
+ 187,179,215, 71,253, 27,235,155,235,189,254,206,246,206,157,153,
+ 233,133,133,133,153,153,217, 86,187,165, 72, 33,161,167,194,188,
+ 10,124,103, 73,115,177,145,233, 97, 61, 58, 94,183,236,194,230,
+ 103, 99,151,107, 3,179,140,134,195,205,205,205, 27,215,111, 92,
+ 187,118, 53,137,147, 54,203, 52,170,197,102,218, 85,162,129,166,
+ 194, 30, 21, 98, 93,100,255,200,250,199, 9,209,135,143, 3,194,
+ 40, 61, 3,133, 16, 78,180,186, 43,205,214, 27,253,157, 27, 55,
+ 110, 14, 55, 55, 55,239,108, 76,207,204,204,205,207,205,206,206,
+ 118, 58,157, 48,108, 16,102,114,204,239,242,231,144,171,132, 45,
+ 57, 44, 15, 23,238,170,191,220,173,152, 10,123, 9,129, 72,156,
+ 36,131,254, 96, 99, 99,227,246,173, 91, 55,110, 92,215,113, 18,
+ 178, 76,177, 44,134,141, 19,173,110,131,168, 73, 20,162, 10, 9,
+ 157,253,132,106,120, 61, 32,213,133,135,145, 95,245,120, 64, 8,
+ 51,109, 8, 17, 8, 73,148,224,211,221,153, 19,186,115,101,216,
+ 187,121,123,117,117,107,107,237,246,237,238,244,244,236,220,236,
+ 236,236,220,212, 84,183,213,110,135, 65,136, 10, 1,160,106, 17,
+ 164,159,122,201, 33, 63, 52, 30,200,138,213,247, 34,146, 36,201,
+ 112, 56,236,237,236,172,223, 89,191,125,235,214,250,250, 58, 9,
+ 4, 44, 45,150,197,176,177,210,105,119, 72,153,126, 56,153, 97,
+ 36,179,250,177,134,215,161,140,188,238,155, 95,181,234, 58, 16,
+ 21,102,119,253, 32, 20, 18, 84,136, 79,119,102, 78,104,125,109,
+ 212, 95,219,218,217,233,245,183, 86, 87,175,181, 91,221,110,119,
+ 118,110,110,122,122,166,211,105, 55,155,173, 70,163, 17, 4, 1,
+ 169,180,197,113,105,237,208,161,218,133, 24,171,240,229,171, 48,
+ 179,163,109,146, 36,113, 28,141, 70,163,126,127,176,185,177,177,
+ 182,182,182,190,190,198,204, 1, 75, 91,164, 37, 56, 27, 54,150,
+ 27,173,142,197, 86, 96,155, 17,214,178,235,225,162,236,192,159,
+ 112, 65,141,173, 73, 19, 98,102,239, 15, 5,164, 20, 6, 72, 29,
+ 53,125, 70,166, 86,163,225,237,104,184, 57,220,220,218,218,185,
+ 115,243, 54, 52,194,102,179,217,237,118,167,166,166, 58,221, 78,
+ 179,217, 10,195, 48, 8, 2, 21, 40,183, 14,224,145,200,191,192,
+ 52,147,213, 90, 39, 73, 18,199,241,112, 56,232,247,122,219,219,
+ 59,219,219, 91,189, 94, 15, 0, 2,150,134, 64,192, 50,165,130,
+ 249, 70, 99,193,238,123, 22, 34, 6, 72,138, 48, 0, 36,187,244,
+ 177,150, 93, 15, 95,143, 29,220,115,176,246,143,147,103,152, 0,
+ 76, 34, 70, 32,154, 36, 0, 12, 68,142,183, 58, 43,141,214,136,
+ 121, 53, 30,110,196,209,230, 78, 47,233, 15,214, 55, 54,110, 3,
+ 50, 2, 40, 10,131,176,209,108,132, 97,104,230, 43, 31,177,193,
+ 204, 81, 20,141,134,163, 56,137, 1,128, 4, 72,128, 64,218, 44,
+ 74,100, 90,133, 51, 97, 56, 23, 54,155, 68, 1, 82,128,104,138,
+ 233,205,214, 65, 42,171,167,168,201,245,246, 57,202, 3, 42,226,
+ 169,249, 53,177, 66, 44,111,168,170, 0, 24, 69, 35, 53, 72, 58,
+ 74,157,104,118, 18,145,141, 36,218, 74,162,190,214, 67, 78,162,
+ 36,214, 81,146,244, 7, 35,194, 71,248,176, 4, 44, 1,128, 18,
+ 9,145, 90, 74,181, 72, 77, 55,194,153, 48, 84,144,210, 74, 33,
+ 170, 44,228,202, 39, 70,108,234, 95, 63,183, 38, 0,100, 19,197,
+ 175,218, 83, 30,104, 16,148, 26, 30, 66, 96, 65,133,194, 34, 12,
+ 200, 2, 90,164, 69,106,185,209, 98, 49, 87,202,102, 18,139,200,
+ 182,142, 69, 30,205, 7, 6, 1,166,154, 1, 2, 78, 7, 33, 1,
+ 80, 74, 40, 36, 68, 83, 61,175, 16, 41, 13, 16, 17, 33,219,244,
+ 172, 38,215,193,160, 8, 39,130, 14,181,254, 58, 4, 20, 3, 0,
+ 101, 86, 28,153, 0, 27,129, 69, 24, 64, 68, 24,132, 5, 4,164,
+ 69,129,128,172, 64, 91,108, 5,190, 60,114,135, 34, 93,162,109,
+ 55, 70, 49,239, 9,210,110,170,100,191, 84, 11,174, 73,101,222,
+ 131,127, 74, 22,249, 37, 50,182,114,187,126, 54, 76,134, 28, 67,
+ 1, 81,136,166, 21,190, 0,176,221, 14,209, 33,151, 60,162,199,
+ 1,125,138,121,204, 2, 39,244,175,159,171,147,233, 29, 31,248,
+ 51, 51, 40,192,107, 63, 17,103,253,228,120, 91, 41,102, 66,177,
+ 244,129, 18, 0,195, 50,128, 20,103,143,170,177,119,254,124,183,
+ 138,181, 54,137, 19, 77, 44,187, 73,231, 65, 61, 33, 3, 31, 94,
+ 102,171, 64,244,183, 63, 78,191, 92, 63, 36,147,168,200,204,131,
+ 147,203,142, 67, 92, 50,113, 87,134,186, 6,214,225, 1,153, 28,
+ 92, 21, 69,224, 3,211,228,114,226,236, 73, 47,187,194, 11,235,
+ 8,127,162,180, 73,173, 68,234, 49, 9,186,171,156,192,102, 42,
+ 232,193,242, 34,112, 49,201,108,186,229,121, 78,181, 62, 25,234,
+ 81,143,122,220,181,115,180, 32,203,152,117, 16, 22, 46,175,117,
+ 20,246,154, 20,131,179,119,106, 22, 59, 32,212, 76,171, 71, 61,
+ 234,177, 47,136, 9,216,153, 37,176, 93, 56, 15,206, 63, 10, 51,
+ 3, 8,160, 32,152, 85,102,192, 89,111, 22,169,246, 44,133,253,
+ 234,235, 81,143,122,212,220, 74, 53, 87,222,174,206, 82,236, 32,
+ 231, 31,153, 89, 16,205,123, 1,180,173,138, 57,235,204,143,158,
+ 244, 50,248,170, 83,253,122,212,163, 30, 46,188, 50,255,230,188,
+ 25,156,129,136, 45,121, 57, 16,126, 49,128,144, 48, 18, 1, 10,
+ 164,149, 69, 34,130,144,206, 75,154,173, 16,176, 54,144,245,168,
+ 71, 61, 60, 47,230,233, 47,112,153,101,183,157, 49, 31,130,217,
+ 233, 7, 24, 68, 57,252,210, 90,139,104, 1, 66, 96, 83, 98,196,
+ 146,237,204,181, 11,179,208, 78, 89,214,163, 30,245,120, 60,217,
+ 133, 89, 57, 34,128, 0, 48, 56,204, 2, 96, 1, 6, 97, 16, 1,
+ 8,130, 7,185,230, 39,255, 89, 90,107,101, 82, 47, 20, 54,101,
+ 205, 44, 34, 12,204,238,125, 69,216, 27,157, 53,203,234, 81,143,
+ 71, 87, 99,237,246, 37,199, 48,166,204, 50,235,115,249, 0,138,
+ 39,114,126, 5, 65,192, 73,162, 17, 53, 49, 41, 69, 72, 8, 72,
+ 34,162, 89, 68,128, 5,236,186, 13,211,172, 55, 11,239,235, 2,
+ 176,122,212,227,113, 24,222,146,109,244,187, 75,230,251,214, 74,
+ 182, 73, 60,219,205,151, 83,132,137, 48,136,136,184,253,157,112,
+ 95,120,220, 7,191,186,221,238,109, 69, 20, 37, 9, 9,177,144,
+ 217, 71, 93, 0,152,133,217, 20,120, 91,120,165,157,123,177,230,
+ 86, 61,234,241, 56, 43, 50, 44, 80, 71, 0,128,157,169, 70, 6,
+ 48,189, 82, 44,194,128, 27, 97, 24,132, 15, 80,251,165,252,154,
+ 158,158,214, 0, 73, 18, 19, 42,173, 56,221, 74, 29, 32,181,177,
+ 105, 33, 5, 80,186, 83,149,160,160, 93,181, 98, 35,253, 26,103,
+ 245,168,199, 99, 9, 49,244,205, 99, 70, 43, 45,162, 93,241, 5,
+ 2, 68,141, 70,227,222,221,105,233, 75, 41,191,230,102,231,226,
+ 70,160, 54, 98, 34, 77, 28, 16,165, 18, 12, 69,140,254, 2, 16,
+ 115, 79,209,218, 70,187,134,214,172,155,172, 35,252,122,212,227,
+ 241, 32,214, 24,164, 8,100,211,141,194, 14,185,180,136,150,212,
+ 78, 74, 24, 84,240,171, 84, 80,129, 99, 63,197,106,253, 53, 53,
+ 61,165, 91,205, 36,142, 21, 41, 98, 33, 98, 84, 10,140, 6,147,
+ 180,144, 21,237,102,121,229, 55, 41,253,190,154,101,245,168,199,
+ 35,134,173, 2,114,202, 32, 51,158, 81, 11, 24,120,105,145, 68,
+ 88,131, 65, 24, 8, 0, 4, 65, 24,134,251,150, 89,123,135, 98,
+ 105,150,214, 8, 27,225,194, 92, 18,199,113, 20,197, 81,148,196,
+ 145,142, 99,157, 36, 58,209,172, 89,132, 17, 4,115,132,165, 73,
+ 24,250,197,172,117, 81, 88, 61,234,241,184, 81, 45,143,238,197,
+ 153,109, 76,201,197,218,234, 47,227,207,168,219, 81, 74,193,190,
+ 227,122,172,248, 77, 37,126, 33, 0, 18,174, 60,117, 54, 22,142,
+ 227, 40,137,226, 56,138,147, 40,214,113,194, 58,225, 36, 17,205,
+ 194,105, 9, 24, 98,190, 77,123,250,134, 21,248,170, 89, 86,143,
+ 122, 60,210,204,242, 58,157,100,105, 61, 67,238, 25, 19, 54, 18,
+ 44,173,252, 2,162,246,252, 44,238,183,254,126,215, 30,186,152,
+ 241,203, 94, 58,117,250,180,158,234, 70,163, 40,138, 70,142, 10,
+ 75, 88,107, 97, 78, 75, 40,208,238,137,144,153, 71,116,100,100,
+ 45,193,234, 81,143, 71,218, 60, 98, 94,176, 90, 60,221,179,228,
+ 62, 17, 78,172,121, 76,132,181,112,154,139, 53, 27,211, 83,211,
+ 123,253,112,191, 52,191, 80,161, 81,226, 75, 94,191,186,178,178,
+ 194,179,211,124,245, 58,105, 69,138, 73, 49,114, 0,138, 21,145,
+ 217,232, 24, 68, 80,196, 52, 29,103, 49, 93,198, 37,205,242,209,
+ 244, 0,245, 86,115,215, 41, 88, 61,234,241, 72,210, 12, 29,220,
+ 152, 79, 24,192, 77,235, 13,185, 18, 35,190,196, 54,162,104, 53,
+ 58,157,182,255, 51, 92, 58,225,238,198,173,242, 43,121, 45, 89,
+ 171,213,234,156, 61, 99,126,101,172,117,156, 36,113, 20, 37, 81,
+ 164,227,152,181,137,225,172,133,180,155,187,228, 22,178,150, 96,
+ 245,168,199, 99, 32,190,188, 62, 14,102,201,144,164,123, 47,112,
+ 78, 46, 73, 68, 98, 54, 8,227,172,255, 4,205, 76, 43, 21,148,
+ 225,229,168, 47,251,179, 17, 11,147, 3,227,150,253, 80, 14, 62,
+ 196,167,223,251, 30,152,158, 74,216,220, 3, 78, 68, 18,102,157,
+ 104, 29, 39,156,104, 96, 6,145,172,120,130,192,108,250,146, 89,
+ 72,196,146,103,173, 89, 86,143,122, 60,122, 44, 67,159, 47, 38,
+ 185,215, 32,134, 92,137,112,194, 28,139,196,146, 47,219,134, 70,
+ 56,187,184, 88, 1,174,114,241, 4, 66,105, 94, 16,171,191,238,
+ 234, 47, 4,124,234,169,167,240,137,147, 73, 46,255,216, 58, 88,
+ 97, 97,102, 6,177,155,190,228,209,125,118, 49, 79,196,246, 84,
+ 125,245,168, 71, 61, 14,159,248,242,120,147,159,217,102, 19,172,
+ 204, 54,198,204,177,112, 34,204, 22, 95, 12,160,167,186,115,179,
+ 179,222, 26, 36,180, 90, 7, 51, 27,234,125, 25,178,127,232,252,
+ 106,244,238, 26,185,182,175,213,108, 45,189,235,188, 14, 40, 17,
+ 142,141, 2,100, 73, 68,180, 48,103,205, 19, 17, 16,128, 82,253,
+ 229, 75, 48,103, 23, 43,172, 17, 86,143,122, 60, 98, 44,195,138,
+ 24,157,157, 82,175,132, 83,120,197,204, 49,179,105, 4,198, 0,
+ 64,212, 88,152, 83,165,206, 19, 25,194, 48,199,147,155,170,185,
+ 248,116,172,157,131,177,192,197, 12, 34,190,247,131, 31,184,241,
+ 31,191, 17, 95,189, 73,192, 68, 64,166,153, 33, 16, 0,187,141,
+ 199,156,153, 71, 68, 1, 2,144, 52,228, 79,247,189, 23,216,101,
+ 77, 81, 29,235,215,163, 30,147, 47,185, 42,196,151,167,155,108,
+ 147,249,212, 57, 26,114, 9, 71,204,177,176,216, 80, 95, 68,184,
+ 211, 58,178,178,226, 57,208,202, 95,107, 9,134, 69, 90, 90,187,
+ 138,197,219,146,239,107, 97,121,105,169,243,238,243,137,152,187,
+ 34, 6,165,214, 66, 10, 11,128,157,112,204, 37, 24, 98,254,169,
+ 239, 34,235, 32,172, 30,245, 56,108,163,122,227, 30,183, 82, 42,
+ 133,151, 0,167,240, 28,110,250, 69, 0, 0, 32, 0, 73, 68, 65,
+ 84,226, 68, 56, 18,142, 56,133,151,206,186, 80,152, 31,183, 48,
+ 215,110,183,209,227, 31,230, 18, 12,243,192, 62,219,143, 56,155,
+ 221,116,234,228,157,249,131,188,254,171,144,135, 17,125,240,227,
+ 47,209,241, 35,153, 8,244, 16,102,155,144,101, 8, 36, 4, 50,
+ 63, 5, 60, 23,233,108,137, 92, 35,172, 30,245, 56,220,122, 12,
+ 243,170, 79,187,229,104, 90,179,154,214,169, 26, 86, 24,132, 37,
+ 204, 98, 59,127,137, 8,119,219, 43,199,143,123, 85,171, 41,193,
+ 208,243,143, 22, 84, 46,187,114,114,184,113, 24,228,121, 24,101,
+ 19, 9,104,239,228,177, 99,199,186,239,121,103,194, 98,212, 96,
+ 108,167, 18, 44,194, 50,251,151,146,147,208,190,153,203, 37,132,
+ 65,149, 10,173, 71, 61,234, 49,177,254, 17,199,157,179,232,194,
+ 11, 76,181,106,156,139, 47, 29,177,182,133,248,144, 54, 62, 93,
+ 152,235,118,187, 0,133, 94, 21,224, 83, 36,157, 14,116, 6,128,
+ 183,218,199,185, 91,206,207, 32, 71,197,217,108,158,232, 99,159,
+ 252, 27,116,246, 84, 33,141, 51, 8, 99,225,116, 59, 34,204,193,
+ 156, 27,201,244, 55,102,156, 70,172,206,242,107,132,213,163, 30,
+ 147, 30,128, 97,201, 57,230, 38, 83,192,100,246, 49,167,228, 26,
+ 177,142,152, 51, 93,102, 42,194,146,153,169, 99,167, 78,186, 66,
+ 38,229,131,131, 41,207,174,121,235, 18, 29,118,229, 30, 19,115,
+ 177,229,215, 79,228, 42,110, 97,113,241,232, 7, 95,208,173,134,
+ 129, 87, 36,218, 32,204,148,134,153, 44,204,248,200,108, 45,183,
+ 73,190, 8,211,169, 73,196, 61, 17, 86,143,122,212, 99,226,216,
+ 133, 21,159,123,147,129,105,181, 4,136,182,202, 38, 98, 61, 98,
+ 142,152,117,218,121,213, 68, 99, 2,129,106,172, 44,181,154, 45,
+ 112,122,213, 20,126,137,195,168,140,104, 14,220,208, 7,104,138,
+ 149,252,115,207,237,101,132, 35,196, 15,191,248, 98,112,238,169,
+ 76,127,165, 8, 75,203,106,197, 24,201, 84,194, 25,102,229, 22,
+ 50,189, 6,205,123, 79,222,185, 8,171, 57, 86,143,122, 76, 46,
+ 188,156,249, 64,171,185,108,157, 61, 91,120, 69,194, 35,214,230,
+ 45,157,115,148, 84,127, 49, 64, 50, 55,115,244,248,113,116, 3,
+ 123, 39,167, 47,193,202, 14, 42, 94,145,219,200, 66,253,127,154,
+ 127,185,211,133,246,150,173, 86,235,249,159,251, 36, 44, 45, 68,
+ 204,145, 69, 88,196, 58,118,139, 90,157,169,138,180, 40,204,153,
+ 136,204, 16, 70, 99,227,252, 26, 97,245,168,199,196,217, 70, 24,
+ 51,237, 38, 86,124,153,229, 65,145,240,136,205, 91,234, 28,221,
+ 110,247,210,110, 46,158, 62, 25, 40, 5,158,214, 2,112,121,180,
+ 207,145,137, 46,155,226,103,171,199,201,129,153,123, 35, 68,196,
+ 39,159,124,114,233, 99, 31,212,205, 70, 54,179, 16,231,197,181,
+ 162,109, 81, 69,150,134,165,130,203,254,202, 12, 97, 8, 99,103,
+ 36,235,229,146,245,168,199,100,192,171, 88,246, 85,168,118, 55,
+ 193,150, 89,158,157,195, 75,235, 33,235,145,137,189,236,182, 29,
+ 90, 68, 2, 69,199,142,204,206,206,129, 95, 30, 1, 78, 56,239,
+ 165, 96,169,240,162, 42,249,149,171, 47,116,219, 94, 32, 64, 90,
+ 63,225,174, 4,114,176, 72,164, 94,252,196, 39,154,239,125,103,
+ 134,173,136,109,137,135,173,242,208,226, 86, 84, 24,132,129,231,
+ 37,193, 79,225,176, 76,250, 26, 97,245,168,199,164,195,203,246,
+ 150, 72, 69,204,136,181,133,151, 22,200,154, 23,166,251,119, 36,
+ 203, 11, 39, 78,157,242, 23,126, 99,217, 60,186,236, 34, 7, 95,
+ 84, 69, 49, 23, 34,217, 79,162,188, 2,195, 73,253,179, 31, 25,
+ 134,225,139,127,243,231,233,201,211, 57,188,204, 5,209,134, 98,
+ 153,145, 20, 71, 82, 17, 88, 33,102, 17,230, 23, 85, 96, 21,194,
+ 106,138,213,163, 30,147, 3,175,140, 92,249, 6, 28, 90, 36, 22,
+ 137, 82,120,113, 21,188,132, 69,146,185,233, 19, 79, 60,161,136,
+ 60,217, 85, 40, 85,117,194, 46,151, 88, 68, 6,101,132, 68,213,
+ 34,204, 89, 12,105,212,146, 87,129,225, 40, 48, 66, 68, 34,154,
+ 155,159,127,238,111,126, 74,150, 23,173,139,212, 17,167,240,138,
+ 36,243,146, 98,215,106,218,138, 10, 27,234, 99,246,222, 44,252,
+ 118,155,184,214, 94,178, 30,245,152, 48,120,185,121,151, 41,162,
+ 79,201,197, 98,167, 26,245,144, 51,229, 37, 34,121,231, 85, 45,
+ 194,157,246,194,147, 79, 52, 91, 45,112, 48,227, 34,204, 82, 10,
+ 115, 66, 17, 17,146, 25,233,101,123, 53,209,152, 48,223, 82,140,
+ 48,239,101,239,231,255,206, 15,127,242,201,179, 39, 62,241, 34,
+ 119, 90,110,149,173, 41,250,200,234, 42,180,216,245,154,146,247,
+ 8, 35, 64,133,102, 70,210, 80, 12, 76,129, 43,213, 94,178, 30,
+ 245,152, 84,120,217,166, 55, 32, 0,102,247, 13, 83,164, 58, 98,
+ 30, 90,120, 13, 89, 51,164,116,203, 98,123, 9,131,214,153,147,
+ 115,115,115,249, 58, 33, 39,246, 2,207,219, 17,165,174,145,178,
+ 208, 43, 3, 24,122,228, 34,215, 76,102,245,247,230, 7, 6,224,
+ 236, 37, 82, 18,117,118, 40,122,239,123,222,187,125,103, 99,253,
+ 27,223,150,193,144, 25, 4,133, 73,152, 73, 16,152, 64, 0, 25,
+ 72, 1, 40,244,148, 20, 34,128, 0,129, 89,219,141,128, 32, 2,
+ 156,173,158,242,247, 93,203, 66, 52,169, 23,120,215,163, 30, 15,
+ 11, 94, 99, 55, 67,179,150, 80,219,181,217,182, 78,149, 71,162,
+ 83,204, 57,182,145,195,128, 78, 29, 63,122,228,136, 83, 40, 95,
+ 168, 85, 45, 70, 94,228, 48,134, 28, 5,150,125, 76,111, 84, 57,
+ 27, 9,128, 0,193,152, 64,141, 28,145, 71, 68, 20, 4,234,195,
+ 31,251,232, 55,146,120,227, 91,223,145,225, 72, 0,153, 65, 16,
+ 152,132, 89, 4, 41, 32, 16, 64, 17,195, 62,191, 72, 67,132, 0,
+ 25,133, 4, 5, 5, 4, 5, 68, 16, 57,157,185, 68, 0,179,137,
+ 36, 56, 29,122,160,166, 88, 61,234,113, 48,228,130, 93,226,102,
+ 177, 93, 37,108, 51,123,187, 66,136,217, 36, 95,177,176, 57, 57,
+ 61,120, 41, 5, 39,142,158, 60,125, 58, 83, 93,110, 97,189, 23,
+ 120, 89,174,144, 21, 92, 62,195,148,197, 87,102, 49,115,129,230,
+ 152, 71, 39,191,183, 68,243, 44,164, 5, 33,102, 63, 63, 8,195,
+ 15,126,244,163,205,103,223,145, 32,102,117,183,246,175, 74, 47,
+ 251,113, 88,102,129, 49,171, 14,203,214, 75, 90, 47,233, 76, 41,
+ 64, 33, 17,195,218, 76,214,163, 30, 7, 32,187, 42,108, 99,190,
+ 117,118,222,207, 75, 76, 82, 52, 98, 30,106, 61,212,122,200, 58,
+ 102,150, 18,188,132,144, 87, 22, 79,157, 57, 67, 78,145,106,121,
+ 97, 99,166,166,200, 85, 94, 42, 3,151,242, 62,181, 34, 44,151,
+ 82,133, 90, 10, 4, 68,171,191, 42,204, 35,250,226, 78, 41, 69,
+ 212, 8,195,143,124,234,147,223, 84, 52,248,241, 43, 60,140, 24,
+ 144, 25, 24,133, 81, 24,136, 81, 24, 41, 64, 96, 68,149,229, 92,
+ 89,120,103,182, 80, 50, 91,122, 3, 18,130, 8, 8,138, 0,178,
+ 8,154, 13,190,125, 33,102, 13,104, 45,196,234, 81,143, 7, 28,
+ 120,129,179, 30,200,216, 29,179, 71,163,215,143, 80, 36, 74,157,
+ 163, 54,203,131,202,183,228, 48,224,229,133,211, 79, 61, 69, 68,
+ 246,148,205, 49, 89,172,145,168, 48,140,164,204, 40, 73, 48, 7,
+ 96, 78, 2,150,247,168, 71, 0, 8,198,205,105, 82, 46,193,188,
+ 95,212,106,182, 62,242,137, 79,252,101,163,177,253,157, 31,202,
+ 112,100,152,101, 92, 36, 35,105, 4, 38, 9,128, 24, 80, 1, 42,
+ 48,202, 43,131, 81,106, 24, 9, 68, 4, 5,205,174,146, 66,102,
+ 247, 34,144,130,119,172,237,100, 61,234,113, 64,240,114,201, 5,
+ 217,186, 31,103, 3, 33,179, 88, 48, 22, 30, 25,217,149,222, 94,
+ 76, 45, 88, 90,109, 31, 6,120,242,216,153,211,167,137,168,184,
+ 180,198,197,138, 21, 80,101,116, 21, 57, 70,202,151, 96, 89, 97,
+ 24, 21,166, 31,141, 46, 10, 10, 75,145, 8,137,137,125,237,229,
+ 252, 92,165,148,162, 70, 24,190,255, 67, 31,250, 43,129,237,239,
+ 254,128,135, 35, 1, 96, 70, 70,208, 86,136,105,148, 0, 41, 64,
+ 100, 68, 5,233,190,221, 8,130,222,159, 39,104, 18,125,200,133,
+ 152,164, 91, 45,213, 20,171, 71, 61, 14, 60,240, 42,144,139, 1,
+ 116,186,123, 16,199,156,246, 46, 53, 75, 6,115,143,153, 46,111,
+ 4,177,129,253,201,211,167, 41,239,137,143,110,145,189, 27,164,
+ 23,243,121,165, 12,188, 84, 62,204,149,164,200,190,243, 44,100,
+ 54, 13,153,215,175, 34, 66, 96,141, 93,177,144, 63,207,213, 20,
+ 145, 38, 82,100,127,133, 82, 74, 5, 65,248,190, 15,188,255, 39,
+ 157,246,173,191,250, 30,223,217, 10, 16, 83, 33,134,162, 33,189,
+ 192, 72, 10, 49, 64, 82, 89,143, 67,244,118,142, 19, 4, 18, 17,
+ 192, 28, 94,233, 5, 91,134, 81, 53, 59, 89, 83,172, 30,245,184,
+ 31,217,229,122, 64,119,146,209,172, 8,204, 91,254,177,142,132,
+ 217, 58, 35,200,225, 37, 44,160, 59,173,246,153, 83, 71,143, 28,
+ 193, 50,188,192, 53,143, 69,207,168,236,123,229,193, 43, 35,152,
+ 50, 20, 51,183, 67,155,192,251,141,193,242,245,224,129, 69,151,
+ 228,232,226, 84,130, 57,248, 74, 37,152,202, 62, 6, 42,228,240,
+ 217,103,159,237,116, 58,111,124,251, 47,229,198,109, 6,100,128,
+ 44, 17,211, 72, 26, 37, 32, 98, 16, 5,100,188,164,161,152,223,
+ 65,209, 4, 92,230, 14,165,118, 50,149,134,134, 98,104, 55,153,
+ 171, 41, 86,143,122,220,151,236, 18, 7, 67,185,230,242,247,109,
+ 116, 90,254, 9,139,243,157, 22,121,194, 0,201,236,244,194,217,
+ 39,230,230,102,157,173,206, 16, 43,245, 87, 94,199,224,103,233,
+ 46,181,220, 79, 45,189, 84,209, 64,146,151,129, 89, 33,100,242,
+ 123,241,188, 37, 33,113,209,165,234, 76,130, 25,253,165, 20, 43,
+ 21, 4,193,201,147, 39, 59,157,206,143,191,245,109,190,116,149,
+ 153, 25, 81, 91,120,105, 36, 13,162,145, 2,148, 0,145,145,200,
+ 82, 12, 11,221,250, 77, 89, 5, 32,185, 46,178, 76, 49, 7, 89,
+ 146,191,176, 72,141,177,122,212,163, 10, 94,233, 43,126, 25, 67,
+ 46,185, 50,207,152,216,192, 43,102,214,246,155,140,252,202, 58,
+ 79, 48, 97,178, 52,127,252,236, 89,211,207,222,135,151, 95,170,
+ 154,151,111,149, 51, 46, 85, 64,152,131, 47,195,153, 98, 77, 24,
+ 146, 87, 31,145,201,152,192, 82,194,199,166, 65, 88,174,192,216,
+ 252,116,118,224,149,129,108,110,110,238,133,151,126,230, 7,237,
+ 239,196, 63,189,200, 81,204,146,122, 73,141,162,193,224, 12, 53,
+ 146,114, 40, 70, 32,100, 52,159, 13,197, 76,221,106, 58,225, 56,
+ 142, 98,102, 26,211,206, 81,218, 7,198, 87,104,245,168, 71, 61,
+ 252, 61,190, 36,205,145,109,110,229,147,203,120, 70, 55,243,114,
+ 103,253, 51,217, 37, 0, 58, 12,224,232,242, 19, 79, 60,161,130,
+ 192,219,168, 49,195, 73,161,133,151,165,151,202,216,229, 36, 94,
+ 129,115, 33, 40,249,200,220, 64, 22,234,239,243, 89,205,188,126,
+ 85, 10, 11,136, 8,133, 51, 13,166, 72, 49, 49, 27,126, 25,118,
+ 217,183,128,153, 57, 96,110,181,219,239,251,208, 7, 95, 95, 90,
+ 184,253,227,151,131,181, 13, 6, 52,182,145, 57,151, 99, 10, 73,
+ 35, 42, 20,133,168, 16,149,100,229, 96,198, 59,166, 47, 26,146,
+ 115,220,163, 24,218, 87, 15,176, 20,115,181,152,179,230,180, 6,
+ 89, 61,234,145, 75,175, 98,185,131,237,129,227,206, 51,218, 29,
+ 179,153,197,227, 29, 88,217, 37, 0,201,116,183,123,250,196,202,
+ 242, 10, 22,186, 65,103, 20, 43,212,214,151, 4,151, 59, 2,165,
+ 84, 16,168, 32,112, 8,230,114, 44, 47,162, 64,127,254,177,176,
+ 29, 81,144, 22, 83, 72,158,130, 17,161, 8,146,144, 16, 19, 41,
+ 69,204, 86,130,113,192, 14,187, 20,155,207,130, 32, 96,150, 48,
+ 124,234,236, 83,243,115,243,175,126,239,251,250,202,117,197,172,
+ 80, 52, 98,144,122, 73, 84,233,123, 10, 12,191, 44,194, 8, 16,
+ 65, 40,165, 82, 30,240,167, 91, 73, 26,123, 41, 32, 32,230,243,
+ 244, 50,160, 85,110,149, 32,171, 41, 86,143,199, 28, 91, 0,142,
+ 224, 18, 17,237,151, 71,228,202, 43,237,168,204, 5,225,150,201,
+ 46,227, 25,143, 61,249,100,167,211,129,242, 14,218, 80,220,124,
+ 35,223,208,199, 15,188,200, 85, 91, 65,144, 94, 14,130, 2,190,
+ 40,207,191,148, 93,208,157, 21, 96,248, 27,172, 1, 6,238,214,
+ 106, 88,114,144, 68, 66,164,148, 98,102, 98, 86,204,172,148, 10,
+ 84,192, 86,121, 49,179,176,112,192,166,201,198,252,252,252,123,
+ 62,246,209, 87,254,250,175, 71,175, 95,226, 94,159, 17,217, 81,
+ 94,206,123, 84, 72, 25,194, 20, 34,129,160,141,198,156, 61,222,
+ 82, 24,101, 20,203,221,101,201, 84,186,138, 89,106, 57, 86,143,
+ 199,144, 92,146,151,104, 57,130, 11, 28,217,149, 98, 43, 77,235,
+ 57, 77,190,202, 4,204, 61, 99,171,169,142,173, 60,113,234,148,
+ 82,170, 2, 94,165,192, 62, 95,149,173,138,105,125,174,185, 2,
+ 243, 63,200, 63,122, 14, 50,173,172,200,218, 81, 84,245, 99, 77,
+ 239, 73,224,134,125,174,250, 19, 17, 50,255,172,246, 50, 35, 8,
+ 2,102,163,195, 2, 78, 57,198,129, 4,233,126, 35, 34,173,102,
+ 243, 93,239,126,247,141,229,229, 43, 47,191,162,111,220, 54, 66,
+ 204, 0,203, 85, 97,233,149,144,106, 49, 66,164, 92,142,229, 1,
+ 191,183, 97, 82, 26,122,165,246,220, 53,149, 70,142,165,182,189,
+ 6, 89, 61, 30, 75,181,149,113,135,157, 86,206,185, 91, 4,209,
+ 194, 9,123,179,141,229,200,204,228,245,169,236,154,159, 93, 60,
+ 125,106,110,118,214,219, 10, 49,171, 94, 24, 3,175, 66, 93,189,
+ 107, 24, 29,108,217,207,172, 18, 11,130,192,203,191, 92,255,232,
+ 172, 31,242,118, 2, 49,235,135,210,240, 9, 12, 18,220,121,207,
+ 148, 97,164,136, 36, 35, 88,134, 48, 97, 97, 49, 18,204,192, 43,
+ 72, 59, 95,139,200,209,163, 71,103,103,103, 95,187,112, 97,116,
+ 233, 74,176,211,211,130, 10,197, 72,173, 4, 41,200,225, 69, 42,
+ 179,147, 57,194,192,163, 88,161,211,142,185, 44,104,230,128, 83,
+ 147, 89,131,172, 30,143,153,212, 2,168,192,150,228,216,242,170,
+ 186,204,122, 70, 87,127, 73, 53, 10,211,159,166, 59, 45,117,100,
+ 249,137,147, 39, 85, 16, 20,100, 23,248,219,104, 87,194,203,173,
+ 21,117,224,165, 44,184,220,161, 84,250,193,175,160,200,151,113,
+ 123,240,202, 86, 62,154,187, 18,216,213,134, 89,138,238,210, 11,
+ 81,144,132, 20, 41, 33,118, 8,198, 65, 16, 8, 51, 75, 32, 22,
+ 95,146, 9, 48, 73,149,103,171,213, 62,255,174,119,173, 29, 61,
+ 250,214, 43, 23,240,214,154,138, 99, 37,152, 75, 48,112, 84, 88,
+ 198, 47,176, 90, 12,170, 65,150, 7,245, 70, 67, 10, 74, 26,150,
+ 217,116,204,250,202,253,128,172, 48, 77, 83,143,122, 76, 62,179,
+ 202,216,114,235, 33,210, 38,130,190,230, 42,240, 11,118, 37,151,
+ 40, 74, 22,231, 86, 78,159,158,158,154, 42,182,145,246,225,133,
+ 133,158,129,222, 82,233,188,210,189, 96, 24,131,208,251, 16,248,
+ 240,114,179,251,180,236,190, 80,187,234,136, 47, 0, 8,210,164,
+ 60,149, 96, 14,192,172,139, 20, 17, 81, 66,162, 72, 68,177,100,
+ 176, 98,230,192,124,200,201, 37, 89,105, 92,218, 0, 13,100,113,
+ 113,113,230, 67, 31,188,124,229,202,198,235, 23,245,157, 77,197,
+ 172,173, 97, 84,226,193, 75,153, 2,177,220, 78, 66, 14, 50, 1,
+ 52, 25, 25,102, 51,149,182,120, 76, 28, 81,107,126, 53, 26,105,
+ 182, 55,200, 32,223, 78,184, 6, 89, 61, 14,143,218,114, 23,241,
+ 56,125, 32,116,105,122, 49,213, 95,246, 74, 25,243,163, 83,114,
+ 33, 38, 51, 83,221,227, 71, 79,173,172,152,197,216, 21,158, 49,
+ 211, 92,174,246,202,219, 74, 80, 94, 35,145, 37,244, 70, 96,133,
+ 65, 16,132, 65, 24,250, 20,203,209,166,130, 64,169,128,108,210,
+ 159,215,126,149, 26,175,186,187,186, 5,206,159,226,192, 53,237,
+ 171, 35, 25,194, 20, 41, 33, 17, 37, 98, 61, 99, 16, 4, 30,184,
+ 36, 39,152,109, 37,157, 99,251,204,233,211, 43,203,203,151, 46,
+ 94, 28, 92,187, 17,108,237,104,102, 66, 84, 8, 36,168,144, 40,
+ 229,151,184,113,152,178,157,118,148, 32, 33,160,177,150,198,226,
+ 102, 91, 90,138,215,134, 45,175,189, 40,130,172,194, 90,186, 93,
+ 46,100, 76,189, 95, 61,234, 49, 25,130,107, 55,108,217,221,100,
+ 11,178, 43,189, 38,177,107,128,170,101,151, 33, 23,161,238,118,
+ 194,229,197,211,199,143,135, 97,232,166,205, 99, 60,163,173,245,
+ 42,244,195,113,224,101,125,161, 51, 50,201, 21, 26,140,133,110,
+ 118, 31, 84,184, 71,242, 26,226, 64,161,195,150,229, 23,162, 73,
+ 190,220,134, 93, 64,132, 0, 36, 2, 41,193,148, 40, 33, 17, 35,
+ 194,198, 13,200, 62,184, 7,200,252,241,157, 78,231,233,115,231,
+ 122, 39, 79, 94,122,253,245,232,198,109,181,211,215,166,175,180,
+ 72, 6,172, 28, 94,246,211, 92,130, 33, 42,163,194, 28,156, 33,
+ 0, 66, 74, 52, 41,246,195, 77, 11, 67,140, 57,206, 50, 50,176,
+ 235,195, 51,227,233,227,170,102, 89, 61, 38, 72,112,185,229,163,
+ 92,165,182, 50,102,185,202,203, 37, 26,148,150,110,139,127, 65,
+ 119, 90,184, 56,127,226,228,201,102,179, 9,165,189,117,220, 10,
+ 175,138,181, 65, 88,174,174,183,153, 87,102, 25,195, 48,116, 25,
+ 150,193,203,185,214, 22,130,145, 87,249,133,101, 5,230, 78, 28,
+ 128, 89, 63, 4, 5, 9,230, 6, 97,150, 98, 6, 97, 74, 21,146,
+ 174, 10,205, 85, 65, 46,119, 76, 77, 77, 61,251,220,115,155,167,
+ 54,175, 94,186, 20,221, 90, 85, 59,125, 66,212, 54,182,119,225,
+ 69,227, 66, 49,107, 45,209,128, 12, 28, 81,230, 77, 89,122,123,
+ 169,184, 25, 25,166, 12,243,220, 37,212, 44,171,199,164, 96,171,
+ 156,109, 85,152,196,242,101,183,194,171, 18, 88, 80, 34, 23, 44,
+ 204,173, 28, 63,222,237,116,188,170,208,113,178,203,201,188,104,
+ 156,109,116,224,149,139,172, 48, 27,198, 71,250,240, 82,121, 0,
+ 150, 59,199,194,172, 99,149,248, 2,183,254,190, 32,193, 32, 95,
+ 62, 46, 78, 16,230, 32, 12,202,242, 11,100,252, 73,238,238,165,
+ 52, 55, 55, 55, 61, 61,189,181,181,117,237,210, 91,209,234,186,
+ 234,245,137,153, 16, 82,144, 57,252, 34, 79,136, 65, 33,221, 71,
+ 123,125,198, 50, 91,220,230,177, 12,220,248,223,110,146, 4, 54,
+ 58,203, 86,120,213, 44,171,199, 65, 15,172,164,137,236,109, 18,
+ 199,161,138,237,101, 22,209,105, 10, 63,158,143,230, 61,161,238,
+ 180,113,126,118,229,216,177, 49,228,242,211,174, 66,230,149,245,
+ 115, 46,182, 55, 37,107, 28, 85,230, 19, 51,118, 5,238, 91,224,
+ 41,175,140, 94, 94,236, 85,220,202,182, 66,124,249,249,151,157,
+ 136,116,251, 97, 16,129,233, 25,145, 39,243, 74, 84,154,206,167,
+ 4, 43, 62, 32, 82,129,174,108,227, 54, 68,208, 90,167, 20,155,
+ 157,157,126,238, 93,189, 94,239,218,149, 43,163,155,183,105,167,
+ 79, 90, 27,123,104,202,193, 84,129,101,217,110, 70,185, 16,203,
+ 182,200,205, 68, 89,186,245,145,207, 50,243,203,165,114, 87,116,
+ 183,238,127, 23,150,185,121, 89,197,236, 77,125,106,214,163,138,
+ 86, 48,238,228, 16, 40,119, 4, 76, 75,183, 82, 30,121,241,214,
+ 56,132,177,128,185,176,159, 95, 42,138,116,167, 29, 44, 45, 28,
+ 63,122,180,101,221, 98,217, 48,150,101, 87,117,157, 68, 33,243,
+ 202,164,151, 27,121, 25,120,101,232,242,117,152,101, 87,154,220,
+ 231,225,151,227, 28,193,111,155, 83,248,243,178,250, 85,201, 38,
+ 34, 69,160, 92,225, 65, 68,230, 60, 86,160,188,249,197,172,165,
+ 108,182,227,146, 20,101, 87,174,252,156,163,160,181, 70, 68,208,
+ 122,106,106,234, 29,207, 60, 51, 58,115,230,198,205, 27, 59, 87,
+ 111,192,206,142, 26, 70, 70,100, 37,136,132,144, 7,249, 14,200,
+ 82,198,101,101, 22,246,178,105,171,143,150,101,148,109, 59, 46,
+ 128,254,110,154,224,239, 62, 57,142,101, 96,203,255, 37,127,241,
+ 220, 27,103, 53,209, 30,123, 90,217, 72,214,127, 62,236, 71,106,
+ 165,151, 93, 90,101, 32,203,175, 44, 98,107, 23,253, 0, 0,186,
+ 25,114,167,211, 57,178,188,180,180, 20, 6,193,158,228, 2,187,
+ 78, 58, 87, 94, 68,165,201,198,162,109,244, 74, 84,173,248,114,
+ 254, 59,174, 49,180,177, 87,154,223,147, 82, 94,205,106,185,216,
+ 222,157,118,204,238,120, 80,117,204,109,163,231,244,219,210,198,
+ 214, 41,182, 76,150, 15, 42,223, 37,174,178, 36, 52,207,159,208,
+ 149, 96,238, 65,201,132, 24, 34,182, 90,173,211,167, 78, 39,199,
+ 142,175,175,175,175, 93,187,158,220,217,164,193,144, 88, 19, 98,
+ 82,150, 93, 96,251,235, 23,138,197,108, 58,134, 62,203,208,122,
+ 76,203, 50, 65,191,203,218, 56,150,185,182, 81,242, 70,110,123,
+ 227, 76,188,103, 70, 77,180, 71,155, 86,187,236,229, 35,149,204,
+ 202, 42,182,178,114, 83,183, 98, 62,223, 11,214, 65, 88,134, 45,
+ 115, 97,191,129, 26,162,110, 55, 97,118,122,110,101,101,110,118,
+ 150,148,170,190,211,238, 41, 80, 50,140,224,247,147, 40, 7,246,
+ 148,205, 30,250,202,171,196,175, 84,129, 57,213, 19, 42, 40, 57,
+ 199, 76,219,121, 11,182,177,186,137,108,224,162, 43, 91, 53, 45,
+ 158,139,204,162,176, 84,131,121, 15, 78,126,102,138,247,128,250,
+ 252, 42, 21,113,160,246,133, 88, 54, 86, 86, 86, 22, 23, 23,123,
+ 189,222,173,155, 55,135,171,107,180,181, 67,113,162, 33,163, 82,
+ 78, 49, 85, 84, 97,222,167, 70,130,185, 44, 67,251, 41, 34,144,
+ 100, 96,207,113, 6, 14,206,178, 99,229,224,204,101, 25, 56,171,
+ 196,115,156, 85,153,205,154,104,143,158,176,218, 51,130,207,236,
+ 97,133,206,178, 43, 19,129,211,205,171,203, 83,138, 69,231,152,
+ 239,244, 83, 84, 90, 99,239, 12,135,129,158,234, 52,230,231,150,
+ 151,151,219,237,118,113,253,207,238,228,170, 90,146, 93,222,125,
+ 99, 23,120, 21,249, 21,230, 73, 88, 81,124,121,173,191,138,229,
+ 170, 57, 69,161, 66,124,149,244,151, 83, 75, 33,146,183,225, 7,
+ 48, 26,140,211, 44,204, 60, 56,169,143,180,150, 81,198, 88,232,
+ 221,118,176, 76, 7, 51,103, 20, 99,102, 68,156,158,158,158,154,
+ 154,138, 79,159,222,216,216, 88,191,117, 43, 89,223,160,193,144,
+ 18,109,154, 85,160, 64,133,236, 74,185, 6, 25,206,208, 94, 46,
+ 216,201, 20, 94, 98, 5,154, 43,205, 0, 48, 93, 88,153,215,249,
+ 150, 15, 91,182,172,220,193, 89,246,188,245,112,230, 18, 13,198,
+ 90,206, 7, 10, 53,169, 73,115, 32,156, 66, 40, 60,172, 69,102,
+ 185,203,167,211, 60,203,210,170,176,154, 90,198,184,197, 92,136,
+ 57,159,234,187, 89,240, 38,138,116,187,133,115, 51,179,139,139,
+ 179,179, 51, 74, 41,128,187, 35, 23,140,221,106, 22,203,105,253,
+ 184,216, 43,197,151,143, 45, 91, 71, 17,102,101,171,233,226, 34,
+ 82,222,198,143, 78,175, 9,215, 32, 85,110,167, 24, 84,204,141,
+ 160,123,106,162, 83,214,154, 27, 73,115, 90, 42, 80,165, 71,220,
+ 57, 14, 80,220,215,168,140,243, 84,130, 49,187, 20, 19,251,105,
+ 163,209, 88, 94, 94, 94, 92, 92, 28, 13,135,171,107,107, 59, 55,
+ 111, 37,189,190, 26, 12,137,133, 77,229,151, 83, 17, 86, 86, 97,
+ 104,233,230,238, 53,153,251,202,140,101,230, 30, 10,148,112,102,
+ 136, 38,224,108, 70, 89, 38,154, 20,158, 9,197,236, 44,111,151,
+ 237,105, 52,128,253, 65,173,144,249,222,223, 57, 44, 53,164,202,
+ 223,141,119,245,179,197,153,177, 25, 23,102,153,141, 20,157, 5,
+ 137, 41,158,138, 61, 33,138, 87,122,202, 75,246,245,136,217,215,
+ 60, 36,221,110, 74,167,221, 93, 94, 90,152,159,111, 52, 26, 48,
+ 78,112,237, 77, 46,175, 54, 53, 43, 79,117,235, 36,188, 22,208,
+ 222,140, 99,161, 64, 53, 12,131, 48, 47,249,114,107,190,108,197,
+ 170,221,174, 67,149,108, 99,190,207, 99,121,114,116,156,254,202,
+ 93,100,222,153,198,126, 15, 17, 48,151,109,100,193, 53, 66,190,
+ 67, 27, 22, 68,104,105, 10,195,182,218, 64,173,217, 26, 73,179,
+ 190, 18,153, 13,200, 88, 4, 17,219,237,246,201, 19, 39,244,177,
+ 99,253,126,127,253,206,122,255,214, 42,244, 7, 6,100, 8,192,
+ 6,100, 86,112,161,151,232, 67,214, 37,145,192,185, 96,111,105,
+ 54,214,205,246, 36,183, 56, 75,213, 89,122, 4,197,217, 70,216,
+ 30,162, 2,209, 92,117,235, 9, 80,231, 53,218,211,104, 0,224,
+ 30, 92, 7,122,165, 87,248,187, 0,146, 60,168, 51, 95, 14, 25,
+ 149,118,253, 49,120, 63,191, 74, 74, 10,203,166, 90,134, 83, 46,
+ 176,210,166,242,165,120,203,107, 54,239,139,175,236,154,244,242,
+ 190, 31, 4,113,177,213, 94, 92, 88,158,155,107,183, 90, 72,180,
+ 43,155,139, 9,125, 41,223, 1,111,175,198,170,253, 26,221,126,
+ 132, 65, 5,191, 50, 88,165,162, 43,229,150,191, 96,200,237,151,
+ 227,146,171, 80,173, 10,232, 85,113, 86,214,127, 85, 61,224,198,
+ 69,250, 65, 24, 0, 24, 23,201,224, 31,164, 49, 7,203, 69,121,
+ 118, 76,204,125, 77,136, 48, 73, 50,138,145,137,195,136, 88,107,
+ 205,140,214, 75, 26, 35,203,204, 98, 12, 45,226,244,212,212, 84,
+ 183,171,143,159, 24,244,251,235,119,238,244,111,167, 32, 67, 22,
+ 11, 26, 73,213,147,128, 59, 35, 73,182,168, 34, 47, 28, 75,223,
+ 251, 42,204,197,153, 11, 50, 68, 18,103, 58,213, 33,154, 57, 90,
+ 89,209,172,255,106, 81,140, 17, 11, 7,202,217,219, 37,219,182,
+ 36,127,226, 98, 33,105,188, 59,180,237,113, 22,200, 67,161,201,
+ 193,195, 13,239,246,190,163, 39,132,171, 15,203, 46,185,123,145,
+ 86, 78,149,105,118, 61, 59, 20,147, 42,241,229,198, 94, 50,166,
+ 100, 75,118,137,216,144,116,187,181, 95,108, 85, 10, 46, 39,161,
+ 135, 42,114, 21,100,151,103, 26,169, 74,121, 41,127, 69,118, 9,
+ 91,110,181,106, 9, 94, 10, 75, 21,171, 94,236, 53,254, 17, 13,
+ 198, 60,190, 94, 16,230, 43, 11, 34, 98, 0,103, 95,218,194, 97,
+ 171, 84, 91,136,229,100,142,144,144,146,188, 79, 99, 38,192,172,
+ 10,203,133,152, 67, 49, 17, 65,162,169,233,233,238,212, 20, 31,
+ 63,222, 31, 12,238, 24,144, 13,134, 52, 24,145,214, 8, 98, 56,
+ 194,144,110, 49,105,147,175,146,157,116,244, 90, 94, 53,230, 70,
+ 99, 2,142,187, 68, 74,165,169,103, 57,115,105,102, 55, 17,207,
+ 178,198,130,247,244,184,230,100,139,222,151,164, 98, 62, 68,156,
+ 202, 23, 41, 61, 65,221,109, 50,177,226, 4,192, 93, 78,227,201,
+ 144, 97,248, 64, 88,122,247,170,170,172,173,138,151,197, 22, 62,
+ 102,192,170,242,137,238,123,225,116,107,159, 92,115, 73,149, 22,
+ 219,253,224, 86,126,137, 21,113,187, 37,173,230, 56,108, 85, 38,
+ 92, 37,209,181, 71,212, 85, 53,205,152,243, 75,149,150, 8, 21,
+ 27,226,132, 89,127,137,226, 10,161,172,237,106, 65,121,217,212,
+ 190, 4,175, 98,236,133,251,225, 87, 33, 8,179, 89,190,157, 79,
+ 36, 2,102, 27,132,249,235, 13,253,250,216, 10,138, 21,142, 74,
+ 66, 9, 38, 72, 68,148, 36,121,205,154,214,154,136,181,102,127,
+ 152,251, 33,110,183, 30, 17, 68,156, 74, 21,217,241,209,104,184,
+ 185,185,181,189,182,198,189, 62, 13, 70,106, 20,165, 0, 23, 64,
+ 0,134,180,127, 43, 58,243,152,232,106, 49,119,154, 18, 60,195,
+ 152, 87,195,186,251, 7, 72, 73,163,217,202, 19,175,103,153,228,
+ 152,242,184,102, 27, 96,227,152,249,120,116,152,133,206, 51, 90,
+ 74, 79,111, 41,213,245, 73,213,163, 93,104,179, 13,187, 87, 87,
+ 190,125, 50, 12,239,255, 70,197, 63, 52,191,162, 16, 90,249,168,
+ 2, 17,143, 89, 25,173,220, 60,158, 11,215, 88, 96,121, 20,203,
+ 57,149,111,176, 40,251,240,134, 99, 75,183, 90, 45,234,182,187,
+ 243,243, 51, 51, 51,205, 70, 99, 47,108,249,217, 5, 86, 87,210,
+ 195,248, 84,218,221,107, 86,249,240,242, 58,169, 58,174, 81, 21,
+ 123,226,184, 5,170,249, 59,149,214,122,145,242, 11, 38,208,209,
+ 94,224,192, 11,112,143,135, 60,216, 69,101,103,255, 49,109,224,
+ 128, 37,132, 49,216, 8, 63, 37, 92,161,232, 13,252,109,120,137,
+ 144, 40,241,187, 99, 39, 73, 98, 62, 32,145, 46, 33, 44,181,147,
+ 68,100, 26, 37,162,213, 96, 14,200,140, 80, 84,157,110,187,221,
+ 57,114,228, 72, 28,199, 59, 59, 59,155,119,238, 68, 91,219, 48,
+ 24,170, 76,148,229,189,119,128,197, 54, 15,131,220,102, 22,112,
+ 150,170,179, 28, 91, 46,200, 42, 84, 88, 6, 71, 23,106,144,221,
+ 88, 50, 87,157,114, 13,138,117, 45,153,247,148, 92,161,137,191,
+ 84,160,218,235,151, 31,188,202,178,198,113, 25,194,216,197,170,
+ 15, 96, 50,225,190,106, 17, 96,247,186,170, 49,156,146,114,165,
+ 104, 73, 94,101,107,221, 28, 84,185,215,123,179,135,187,130, 44,
+ 5,150, 87, 27,225,210,109,159,144,146,170,105, 68,105, 53,195,
+ 153,169,249,217,185,169,110, 55,112,138, 78,247,233, 19, 97, 92,
+ 25,125, 85,235, 46, 55,237,170, 10,235,199,194,203, 47,250, 42,
+ 119, 38,204,192,149,175, 18,202,160,152,109, 80,155,195, 43, 63,
+ 41,156,109, 98,199, 63, 79,130,221,131, 2,183, 48,223,236, 91,
+ 102,142,161,131, 48,193,146, 88,200,238, 5, 22, 85, 97,134, 46,
+ 52, 9,152,135, 48,173,117,146, 20, 16, 70,204,154,136, 53, 51,
+ 49, 89, 71, 41, 34,156,129,172, 52,154,141, 70, 99, 97, 97,126,
+ 126,158,153, 71,163,209,214,246,214,206,157, 13,189,211,195,225,
+ 136, 70,113,198, 50, 43,148, 32,157,202,132,220, 27, 86, 9, 49,
+ 231,122,135,104,249, 52,101, 9, 94,224, 41,181,156, 86,249,151,
+ 32, 45, 42,203, 35, 51,119, 97,128,100, 83,159,158,118,243, 30,
+ 79,172,148,111, 99,108,253,125, 72, 30,169,186,237,253,104, 51,
+ 217,189,126, 74,170,111, 44,254,109,220, 13,190,192,223,169, 16,
+ 28, 54,249,151,253, 48,171, 82,115,249, 85,166,174, 16,203,108,
+ 99, 81,118,229,215, 20,235,192,246,143, 45, 81,164,155, 13,105,
+ 54,212, 84,183, 59, 59, 59, 61, 61, 93, 41,181,238, 17, 91,176,
+ 91, 21,147,107, 24, 83,162,100, 2,169,104, 27,109,187,155,192,
+ 237, 0,237, 55,179,175,144, 93,206,182,143,182, 57,180, 19,176,
+ 21,218,171,162,255,220,222,237,137, 22,236,231, 5, 51, 91,222,
+ 13,144,199, 97, 22, 97, 44, 64,174,101,202,151, 90, 22,242, 47,
+ 180,201,125,102, 21, 41,195,149, 97, 87, 74,177,236,141,137, 52,
+ 51,105,157,162,203, 25, 70,144, 73,149, 22,203,158, 97,132,168,
+ 58,157,118,187,125,100,121, 69,107, 61, 28, 13,183,119,118,122,
+ 27,155, 62,203,114,143,153, 97, 69, 91,156,129, 31,231,147,135,
+ 173,146, 16, 3, 40, 66,205, 89,244,144,177, 12,160,160,215, 28,
+ 33, 38,121,255, 50,112,103,114,115,199,151,191, 40, 33, 56,171,
+ 1, 60,223,224, 61,240,184,235, 60, 28, 30,140, 67,148, 10,155,
+ 91,165, 50,220,169,180,162,203,205,247,239,130,106, 60,229,242,
+ 198,153, 19, 44,244, 38, 5, 40,114, 10, 96, 12,170, 74,162,204,
+ 208,170, 58,182,207,110, 80, 42,100,216, 27, 91,227,153, 53,211,
+ 237, 78,181,154, 77, 34,218,135,212, 42,154,196,202,140,107, 79,
+ 205, 53, 54,237,170,174,242,242, 82,123, 85, 6, 88, 1, 91,165,
+ 180, 43, 23, 95,233,174,142,227,224,133,251,124, 94, 6,251,152,
+ 171,129,172,162,162,140, 48, 17, 98, 16,242,154, 21,102, 39,121,
+ 33,193, 79,239, 43, 89,144, 17, 17, 37, 58, 73, 63,106,143, 98,
+ 68,202,216, 73,102, 67,177,114, 34,150, 35,108,140, 22,179, 75,
+ 204, 17, 68,144,168, 27, 4,221, 78, 87, 86,142,104,173,135,195,
+ 225,206,206, 78,111,115, 83,239,244, 32,138,213, 40,162, 56, 49,
+ 249,184, 43,205,210,214,135,153, 35,147, 10,108,145,215,161,191,
+ 240, 85, 39, 26,203, 29,118,222, 57, 54,163, 21,166,175, 18, 78,
+ 243, 31,219, 90,214,179,150, 37,198, 57, 2, 13, 43, 83,252, 76,
+ 26, 99,249,249, 47, 37,154, 61, 24,120,237,102, 51,165,240,191,
+ 202, 0, 58,218,170, 60, 27,232, 56, 68,103, 81,151,107, 12,221,
+ 73,195,242, 4, 98,149,127,172, 6, 25, 87,125,117, 76, 33,131,
+ 236,143,212, 0, 0, 28, 6,220,108, 72, 24,170,169,206,238,204,
+ 26, 39,181,118, 81, 91, 62,182,160, 80, 0, 80, 25,117,141,139,
+ 234,171, 23, 55,170, 34,187,242, 13,132, 2, 15, 93,206, 94,142,
+ 123, 4, 94, 69,120,249,149, 72,247,195,175,226,116,100,142, 48,
+ 231,119, 56, 94, 18,179,141,217,192, 93, 34,100, 9,102,143, 85,
+ 26,219,155,220,139, 52,105,107, 24, 51,138,153,145,169, 48, 67,
+ 49, 19,135,101, 35,219, 58,132,153,169,152,236,143, 5,153, 0,
+ 16, 98, 48, 53, 53,213,237,202,202,138,102,142,162,104, 48,232,
+ 247,122,253,225,198, 38, 12, 6, 24, 37, 20, 39, 70,154,185, 56,
+ 131,172,248, 43,133,136, 91,211,144, 71, 99, 96,101, 26, 20, 68,
+ 153,175,197,192, 93,214,158,151, 98, 56, 97,191, 56, 55,206,226,
+ 87,241,204, 96, 70, 45,148,210,228,102,225, 9, 47,176,159, 56,
+ 180,170,148, 19,171,214,169,148, 42, 16,100,207,243,214, 59,197,
+ 165, 52, 35, 33,254,151,188, 50,209,236, 39, 72,113,222,176, 50,
+ 228, 2,135, 77, 80,149,115,193,190,253,227, 94,101,163,178, 31,
+ 102,137, 34, 14, 67, 14, 3,108,183,154,115,179,211,157, 78,187,
+ 221,110,132,225,190,153, 85,144, 90, 80,209,220, 6,138,205, 81,
+ 247,227, 22,211,247, 46,184,118, 85, 94,121,148, 21,120,197, 19,
+ 170,224, 21, 11,171,130, 20, 17,209,252,252,194, 65, 40,253, 96,
+ 31,183,113, 16, 6,214, 72,250, 79,105, 35,196,192, 32,206, 81,
+ 95,160,243, 3,105,145,159, 30, 49,163,179, 18, 75, 46,247,189,
+ 46, 13,165,181, 86,202,196, 97, 69, 33, 38, 66,101, 71,105,125,
+ 101,230, 37, 29,144,129,136,160, 85,109, 72, 20, 40,213,110,183,
+ 23,230, 23,228,196,137, 56, 73,134,195, 97,191,223,239,111,109,
+ 233,254, 0,162,136,140, 52, 99,169,194, 89,246,108, 18,118,202,
+ 83,193,115,133, 78, 51,178, 60,249, 66,175,204,194, 41,203, 0,
+ 159,110,224, 86,252,123, 24,205,251,100, 87, 71, 99,251,155, 1,
+ 192, 93,242,116,217,175, 30,147, 10, 67, 56,246,196,118, 97, 52,
+ 54,125,175,116,145,110,237,104, 81,109,185,193,150,231, 25,193,
+ 223,205,112,156,127,220,207,164, 68, 73, 53,142, 7, 22, 34, 55,
+ 2,110, 52,160,217, 80,237,118,103,102,186,211,105, 55,155,173,
+ 32, 8,198, 25, 35, 28, 63, 49, 83,237, 16,199, 4,243, 80,170,
+ 65, 40,212, 45,121,216, 42, 40, 47,139,173, 74,118, 21,172,163,
+ 242, 46, 6,110, 52, 86, 41,187, 14,104,182, 58,216,223,205, 28,
+ 35,153,182,152,113,235,194,204, 87,217, 82,204,129, 63,160, 70,
+ 141,140,136,230, 93, 22,222,231,177,189, 54, 22, 50,231,151,210,
+ 58, 41, 35,140,180,102,165,204,251,178,151, 76,101,152,253,152,
+ 226,202,180, 93, 76, 41,230,117, 92,180, 79,109,139, 51,251,190,
+ 73,212,104, 52,102,166,167,229,200, 17, 97,142,227,120, 48, 28,
+ 14,134,131, 81,127, 16,245,122, 48, 24, 98,148,144,214, 20, 39,
+ 110, 74, 85,144, 69, 94,123, 68, 17, 44, 86, 45,160,183, 74,161,
+ 112,217,121,121, 69, 55,219,170,138,240,177,212, 5, 5, 75,175,
+ 215, 56,158, 86, 21, 98, 76, 42,151,215,200,158,181, 22, 50,206,
+ 61,150,112, 38, 69, 61, 38,126, 53, 86,110, 32,139, 22,210,111,
+ 152, 5,165,110,165,224, 1, 75, 74, 45,152, 1,224,238, 42, 69,
+ 203, 34,107, 28,176, 56, 12, 68, 41, 14, 3,104,183,194,110,167,
+ 213,105,183, 91,173, 86,171, 29, 26, 96,221, 63,179, 74, 14,209,
+ 243,137,197,108,190,184, 0,104,111,114, 57,216, 26, 11, 47,101,
+ 203,230, 51,127, 24,184,166,210,219,126, 54,133, 23,229,187,104,
+ 191,189,252, 42, 32, 44,175, 11,195,172,183, 2, 18,176, 0, 8,
+ 17, 8, 10,176, 19, 17, 99,198, 47, 55,188,207, 2,252,132, 52,
+ 233,140, 95, 74,235,164, 66,130,105,173, 89,107,173,148, 30,135,
+ 48,159, 98, 57,200,178,230,177,213,190,210,129,152,248, 21,187,
+ 136,164, 84,179,217,156,155,157, 21, 0, 97,142,147, 36, 26,141,
+ 70, 81,212, 31,244,163,141, 45,142, 99,140, 19,138, 34, 76,152,
+ 76, 47, 32,223,178, 21,160,102,143, 94,102, 60,203, 5, 89, 88,
+ 76,238, 43,167, 38, 43, 2,178,146, 4,195,170,116,191, 26, 94,
+ 78, 75,218,251,159, 82,172, 58,219,165,138,101, 34,197,200,172,
+ 100, 33,139,104,115, 90, 24,185, 78,208,201,245,247,242,125,123,
+ 3, 75,246, 84,142, 32,138, 56, 80,220,104, 64,160,176,209,104,
+ 206,206, 76,181,219,141, 70,163,217,108,238,162,176, 96,236, 90,
+ 129,253, 49,171, 50,150,135, 61,123, 35,228, 57,211, 88,114,237,
+ 11, 94,185, 43,116, 86,255,228, 23,201, 65,151,211, 12, 71,101,
+ 167,251,219,206,175,221, 17, 6, 8, 32,100, 26,130, 17,179, 80,
+ 186,188,144,253, 37,144,140,108, 86, 11,229, 32,211,218, 82, 44,
+ 139,190,198, 72, 48,173,181, 98,214, 90,179,102,173, 52, 87,133,
+ 250,149, 66,108,175,104, 44,155,180, 4, 79,154,217,191, 15,204,
+ 86,108, 74, 53, 21, 53, 27,141, 41,128, 69, 88,148, 19,194,172,
+ 147, 56, 25,142, 70, 81, 52, 26, 14, 71,209,214, 22, 39, 9,142,
+ 98,140, 19, 20, 86,163,216, 43, 95,200, 48, 83, 44, 31,205,159,
+ 175,130,174, 3,173, 40, 34, 64,255,249,238, 87,141,129, 23,143,
+ 8,140, 41,142,245, 85, 88,190, 1,221, 61, 87,137, 86, 82,108,
+ 183, 32,223, 45, 50, 40, 92, 41, 62, 70,164,202, 66, 2,236,127,
+ 145,224, 93,208,106,172,182,106,134,130,196, 97, 96,104,213,152,
+ 153,110,181, 90,141, 70,163,213,108,170, 32, 48,116,184,187, 74,
+ 219,221, 58,205,131,219,167,175,210, 36,230,200,218, 71, 73,196,
+ 126,101,151,227,245,118, 17, 95, 99, 63,117, 42,196,168,208,200,
+ 203,206, 51, 78, 2,191, 60,132, 65,182,192,200,188,130, 59,203,
+ 140,213,100, 61, 27, 0, 0, 17, 42, 73, 68, 65, 84,140,145, 76,
+ 27,185, 22,123,229, 32, 35, 34, 49,105, 36,180, 5,171,105,213,
+ 132, 19,119, 37, 74,107,237, 83,140, 53,107,118, 46,229, 20,243,
+ 64,150,239, 10,206,214, 60,122, 91,236,150, 88,230, 33, 44, 83,
+ 100,142,193,204, 89,150,170, 30, 35, 87,144, 16, 3, 21, 52, 91,
+ 173, 44, 84, 97, 22,157, 36, 81, 28, 69, 81, 60, 28, 14, 71,189,
+ 158, 30,142, 32,138, 68, 51,197, 9, 10,211, 40,198,138,148,170,
+ 136,182, 2,221,192,109, 92,129, 21,168,192, 93, 79,217,177,177,
+ 125, 53,188, 16,238,105,133,115,169,136,107, 87,241, 53,222,108,
+ 142, 99,206, 1,169,170,106, 84, 17, 65,179,161,154,205,102,183,
+ 99,104, 21,134,161, 57,189,239,154, 86,187, 3,107, 63,193, 86,
+ 101,188, 85, 5, 47,119, 74,207, 78,246, 59,145,179, 27,214,103,
+ 213, 93,238, 63, 7, 68,187,194,203,243,137,150, 92, 84,213,131,
+ 208,105,134, 51, 25,252, 2,119,226, 41, 91,230, 93,152,242,202,
+ 50, 83, 34,176, 39,123,169,227,151,193,151, 70,237,191, 28, 16,
+ 105,149,209,140, 85,209, 63,154, 11, 70,133,217,247,198, 87,114,
+ 105,106, 50, 19, 99, 25,182, 76,216, 47,187,142, 2,194, 10,239,
+ 114, 80,167,210, 76,108,133, 5,162, 8, 41, 80, 74, 53,154,205,
+ 124, 91, 80, 17,214, 58,209, 58,137, 99,195,181, 40,138,226,237,
+ 109,102,198,225, 72, 4, 84, 20, 1,128,153, 34, 40, 63,203, 93,
+ 21,134,227,107, 73,101,215, 22, 11,178, 71,167,235,187, 5,197,
+ 62, 26, 35,220,211,247, 11,220,251,111,222,127, 17,131, 16, 74,
+ 24, 8, 0, 55, 26, 8, 32,173, 38, 41, 10,166,167, 26,141, 70,
+ 35,108, 52, 26,141, 48, 72,251, 25, 23,155,138,220,179, 37, 28,
+ 11,172,241,106,171, 44,183,246, 97, 21, 51, 90, 56,236, 40,112,
+ 203,153,103,244, 61,163,219,143,208, 71, 84,225,162,231, 20,199,
+ 147, 43,215,127,147,198,175,202, 73, 73, 47,209, 55,137,138,241,
+ 146,217,169,239,250,200,180,225, 4, 35,103,201,125, 58,255,145,
+ 86, 77, 80, 26,116,149,224,101,104,229, 92, 74,241,149,161, 75,
+ 103, 85, 22,169, 12,147,130,169,204, 18,253, 42, 57, 6, 99,230,
+ 43, 11,121, 63,120,210, 12, 16,196,238,206, 38,229,122, 19, 34,
+ 10,194, 0,154, 77, 55, 36, 98, 17,102,157, 36, 58,142,227, 56,
+ 142,147, 36,137,227, 56, 30, 12,244,104, 36,137,198, 40, 22, 3,
+ 53, 97, 96,177,181,105,149, 26, 10,177,116,170,226, 94,132, 56,
+ 232,101,141,242,160,111,191, 31, 60, 21, 2,117, 32, 52, 98, 10,
+ 1,164, 17, 98,160,168,209,108,116,218, 78, 43,189, 48, 8, 2,
+ 115,182,237, 39,253, 27, 31,194, 99, 69,205, 73,101,113, 41,184,
+ 221,202,113,108,221,214,248,249, 68, 24, 47,184, 60,120,149, 10,
+ 234, 51,177, 53,166,157,132,175,165, 84,197, 52,162,173, 65,173,
+ 16, 92,202,229, 99,169, 48,117, 50,249, 53, 38, 14,203,218, 79,
+ 59,183, 33, 18, 17, 19,234,163,109,140, 67, 72, 22, 55,166,111,
+ 142, 49,145,236,112, 76,147,210, 74,171,162,123,100,135, 98, 69,
+ 33,102,249,165,115, 9, 54,206, 81, 90,148,249, 56,219,167,175,
+ 172,164, 25,218,171, 28,117,150,154,205,212,170, 73, 78,125, 5,
+ 162,136,194, 32,108,183, 90,133, 60, 72,152, 53,179, 41,229,205,
+ 135, 78,146,193, 80,143, 34, 17,129, 56,198, 68, 11, 0,106,109,
+ 230, 13, 0, 32,115,166,251,203,176, 14,172,244,254, 46, 51,254,
+ 253,131,204,117,121,233, 5,165, 68, 41, 4,144, 64, 65, 24, 32,
+ 18, 53, 26, 97,187, 85,108,216, 66, 68, 74, 33,226,126,244,212,
+ 30,124,175,108,134, 80, 85,159, 85,182,132,123, 82,107,255, 62,
+ 177, 68, 47, 79,119,149,221,162, 93,134,157,243,171, 32,187, 10,
+ 2,140, 28,177,229,250, 74,175,192,194,153, 91, 76,169, 85, 37,
+ 187,252, 38,132,147,197,175,170, 56, 44,109,160,239,204,147, 57,
+ 66, 12, 81,152, 1, 17, 25, 77,151, 46, 27,241,155,142, 57,100,
+ 150, 11,165,213,170,100, 10,190,116, 10,179, 20, 82, 90,235, 44,
+ 194,231,156,101, 5,132,105,167,208, 85,118,161, 88,233,194,158,
+ 32, 43,196,252,197,212, 63, 95,210, 82, 52,155,105,127, 29,143,
+ 104, 21,103, 50, 2,128, 82, 74, 41,177,219,184,187, 22, 80,108,
+ 204,102,254,160, 36,209, 90, 39,204,194,172,163, 56,102,205, 34,
+ 146, 68,145,238,255,255,237,157,235,118, 27, 57, 14,132, 1,182,
+ 146,153,221,247,127,215, 61, 51,137,200,253,209, 55, 92, 10, 0,
+ 91,182, 99,249, 34, 29,123,168, 30,197,246, 81,172, 47,133, 98,
+ 1,252,223,249,253,255,249, 71,126,147,246,239,191,230, 87,169,
+ 253,250, 77,190,116,125,107, 69,214,184,255,184,153, 39,244,159,
+ 63,213,166,232, 95,127, 29,239,223,229,191,255,185,253,252,201,
+ 204,109,105, 63,110, 63,150,101, 97,230, 53, 58,121, 28,181, 69,
+ 87, 8, 85,113,138,242,177,203, 70, 91, 89, 72, 81,148,140,151,
+ 212, 74,247, 18,243,106,209,152,243, 1,185,116, 48,213,194, 75,
+ 210,107, 3,214,142, 48,169,203, 20,185,188, 61,175,125, 46, 48,
+ 192,139,101,150,241,233,248,229,236,176,163,150,180,191, 71,188,
+ 59, 98, 60, 70,223,103, 68,111,145,138,179,189,241,104, 23,218,
+ 40,182,194,107, 89,150,131, 95,242,174, 4,152,208, 94, 93, 94,
+ 16, 20,115, 21,165,248,124, 30, 43,158,128, 44, 46, 45,141,221,
+ 79,190,204, 20,186,108, 39, 26, 29, 26,237,124, 5,161, 60, 25,
+ 71,152,139, 7, 19,181,182, 14,253,216, 74,210, 1, 74,173, 67,
+ 233,172, 82,116, 19, 44,189,255,250,253,235,126, 63,251,246,122,
+ 239,191,127,255,186,223,187,159,148, 96, 80,120,249,215, 66, 64,
+ 7,252,175,165,221,110, 63,228,182,186,185,114,188, 49,200, 15,
+ 183,189,254,219, 57, 3,169,136, 83, 24, 85,211, 30,124,104,199,
+ 7, 69, 98, 6, 46,239,207, 55,215, 4, 20,198, 82,245,210, 9,
+ 48,229,226,139,103,156, 66, 11,109, 44, 6,154,235,196, 22,243,
+ 133,102,198,119,225,215,140, 16,219,118,239,134,213, 98,107, 45,
+ 185,105,177, 19,100, 39,197, 86,134,245, 53, 56,177, 44,203,253,
+ 222,151,142,252,251, 29, 90,119,101,129, 73, 83,204,148,148,189,
+ 175,236,218,239,178,176,220, 64,134, 88, 38, 17,150, 81, 44,228,
+ 89,184,128, 80, 19, 92, 27,226,112, 2,169,203, 88, 29, 11,174,
+ 195, 98, 68,212,150, 38,255,192,223,244,247,181,194,237, 49,122,
+ 189, 12, 58, 47,162, 82,181,143,202,181,215,238, 5, 88,129,170,
+ 201, 13,196,156, 92, 24, 94,102,178,223,217, 67,204, 7, 65,108,
+ 7, 35,203, 86, 32,167,192, 54, 44, 1,255,222,225,173, 53,117,
+ 178,134,194, 86,228,115, 5,211, 7,249,201,249,149, 11,177, 67,
+ 142,169, 78,107,230, 49, 58,119,238, 60,152,185,141,182,166,195,
+ 36,197,118,152, 45,189,111, 8,235,189, 47,247,123, 95,182,252,
+ 215, 94, 42,138,133,208, 96, 14,100,128, 95, 39,200,156, 55, 86,
+ 236, 84,122,168, 17,138,146, 69,114,140,236, 85,146,173,203,199,
+ 53, 83,126, 42,189,118,152, 88, 99, 4,182,189, 2, 92,130, 42,
+ 118,123,149,122,127,224, 57,110, 92,213,124,243, 10,107, 78, 94,
+ 57, 48,249, 93,195, 76,112, 37,187,136, 51,219,137, 65,181,232,
+ 176,133,199, 71, 52,233,217, 47,106,109, 23, 74,163, 5, 69,162,
+ 23, 92, 59,194, 28,182, 20,187,222,214,105,189,189,193,175, 88,
+ 234,136,137,232, 17,143, 49,120,112,231, 62, 6,175,159,152, 71,
+ 27,146, 98,167,123,213, 78,164,173, 20, 91, 65,181,116,100,123,
+ 9,114,221,141, 10,219,120,101, 19,175,160,168,148, 44, 11,228,
+ 152,151,100,228, 45,255, 74,145, 57,136,129,133, 50,191,197, 73,
+ 148, 82,178, 9,216,145, 5,156, 11, 81,132, 27,148,252,154, 27,
+ 139,175, 47,172,174, 52, 60, 63,198,172, 89,157,117, 85,109,249,
+ 131, 80, 33,194, 76, 49, 38, 39, 11,234, 82,209,170, 46, 54, 77,
+ 216,106,179, 81, 92,148,120, 90,150, 5, 33, 79, 24,255,154, 92,
+ 98,167, 96,255, 17, 15, 32, 67,217,245,214,255,250,221,222,236,
+ 151,208, 10, 49,115, 20,236, 56,182,227,218,104, 99,109,169,238,
+ 123,226,189,141,214,219, 62,177,176,157,198,123,211,228, 57, 65,
+ 6,157,123,141,173,172,223, 72,218,251, 39,190,124,224, 66,211,
+ 236, 2,203,140, 46, 43,253,178,124, 33,101, 26,153,254,227,177,
+ 143,122, 85,128,147,242, 77,138, 56, 11, 38, 14,135, 78, 95, 8,
+ 144,189, 34,176,102,106, 64,247, 99,207, 2, 43,252,152,220, 61,
+ 156,138,154, 78, 49, 75,159, 9,113,140,107, 57, 74, 52, 5,174,
+ 67,127, 37,253, 64,190,238, 3,240,130, 26,107,166, 78,180, 62,
+ 23, 46, 24,153,248,202, 63, 76,207,195, 47, 36,196,116, 57, 41,
+ 236,232,213, 17, 91,171,202,253,120, 14,238, 99,108,190,216,230,
+ 227,247,214,155,243,224,205, 6, 99,239,125, 57, 96,134,203, 70,
+ 253,108, 68,177, 49,122, 71, 20, 83,139,138, 98,175, 10,178,144,
+ 107, 33,209,156,105, 5,103,154,234,190,114,198,204, 98, 60,139,
+ 186,172, 58, 95, 86, 9,206,168, 42,232, 88, 65, 84, 25, 51, 14,
+ 210,170, 84, 88,111,140, 45, 77, 46,161,185,172, 59,207, 25,185,
+ 56, 67,211,146,240,202,126, 81, 41,184,206, 34,209, 24, 93,100,
+ 68, 87, 92, 48,242,199,210, 95, 72,136,157,229, 36, 29,199, 83,
+ 31, 97, 40,222,167,216,239, 51, 34,184,143,157, 96, 99,172,181,
+ 100, 27,237,208, 98, 67, 81,204, 19,109, 21,101,227,188, 56, 74,
+ 150,137,116,133, 79,237, 43,156,217,252,107, 78, 49, 61,245,194,
+ 98,108, 6,103, 22,100, 88,144,129, 21, 4,153,223,101,196, 50,
+ 106, 76,207,185, 31,227,241,209,135,243,189, 56,209, 60, 82,175,
+ 188, 2,108, 17,202,189,195, 82,103, 30, 91,114,224, 48,235,133,
+ 81, 38,137,183, 37,231,227,113, 11,183, 22,163,116, 4,167, 82,
+ 138, 17,217, 0, 2,245,134,128,199, 86, 83,135,185,198,228,138,
+ 165,240, 71,228, 23, 40, 39,137, 78, 83, 44,162, 24,211,174,196,
+ 6,143, 49,250, 1,178, 85,139,141,118, 18, 76,237, 33,122, 18,
+ 105,113,229,130, 20,138, 98, 67,242, 78, 55,129,203,187,140,236,
+ 251, 94, 74, 37,205,232, 64, 23,225, 8,198, 5,138,205,179, 12,
+ 235,179,151,176,204,122,106,127,196,255, 74,124,174,107,204, 2,
+ 235,151, 48, 43, 34, 23,134,151,120,179, 75,145,197,201, 28,103,
+ 143, 18, 37,140, 68,123,142,101,146,213, 99,108, 48,167, 63,212,
+ 38,128, 70,167,207,246, 43, 62, 3,114,121,171,235, 15,237,250,
+ 220,232, 15,221,144, 41,230, 40,182,111, 79,186,109,202, 29,104,
+ 141, 91, 31,125, 28,254,152,215, 72,214,200, 50, 8, 83, 56,139,
+ 117,156,253, 34, 88,139, 25,130,117, 80, 88,210, 69, 69,118,158,
+ 236, 76,149, 46,139,161,166,230, 58, 76,226, 44,138, 74, 84, 39,
+ 21,226,192,218,107,137, 47, 40,187,114,126, 65, 96, 57,193,101,
+ 80, 85, 49, 75,127,154, 83, 91, 51, 7,161,130, 41, 17, 78,115,
+ 177,211, 74, 86, 55, 65, 96,105,238,153, 71,199,103, 41,181,252,
+ 126, 34,156,239,236,201,245,103,172,174,247,229,151,162,152, 50,
+ 197,172,189,191,185,251, 58,108, 65,135, 32, 91,181,216,104, 99,
+ 19, 98, 27,197,128, 72, 58, 52, 26,196,153,128,151, 95,184,103,
+ 129, 78,240, 97,146,252,197,164,158, 1,180,152, 57,112,132, 0,
+ 193,106, 81,118,244, 6, 62, 34,202, 60,181, 2,138,213,136,154,
+ 167,216, 76, 83,244, 12,185,226,135,165,212, 18,179,214, 43,193,
+ 101,220,105,127, 28,134,215, 92,161,197, 37,225, 37, 39, 68, 0,
+ 106, 1,226, 56, 91,221,199, 26, 52,176, 84, 51,164,185, 35, 96,
+ 133,198,188,202,161, 62, 7,185,222,133, 95,128, 98,251,193,178,
+ 167, 47, 38, 40,118, 32, 76,190,215,133, 54,107, 99,195, 87,219,
+ 234,202,131, 39, 43,198, 70,164,157,188,182, 50,251,143, 49,185,
+ 108,108,223,231,197,142,239, 62, 5,178,173,204,164, 25,171,127,
+ 14, 97,136,104, 50,128,241, 50,150, 77, 3,237,138, 20,227, 73,
+ 144,205, 48, 11, 84, 53,230,173,151,195,203,232, 46,184,144,181,
+ 212, 76,132, 75,146,194,229,185, 18,237,197, 46,190,224,210, 12,
+ 64, 85, 65,133,165, 44, 54,177,205,233,180, 22, 19,206, 67,176,
+ 60, 39,241, 93,170,197, 39,225, 87,224,139,109, 50,108,168,225,
+ 87,103, 85,185, 78, 25,211, 39,114,172, 97,254,181,160, 28, 99,
+ 180,190,141, 91, 85,161, 7,211,235,232,244,147,188, 26,222,193,
+ 179, 20,191, 92, 63,101, 92, 83,134, 8,219,175,208,121, 33,160,
+ 152,199, 88,205, 50,105, 99,169,225,205, 49,206, 2, 85,245,186,
+ 240,202, 16,230,174,170, 11, 25,177, 10,102,225, 18, 49, 35,151,
+ 47, 14, 47,204, 62,197, 93,139, 62, 76,207, 14, 91, 64, 55, 1,
+ 74,233,144,131, 14, 94, 88,223, 77, 7,204, 72,185,242, 81, 6,
+ 53, 72, 69,188, 39,185,222,157, 95,193, 30,165, 43, 40,247,243,
+ 115,181, 28,147,198, 18,239, 71,114,172, 73,178,209, 71, 19,115,
+ 163, 97,127, 35, 88, 36,132, 83,208, 82, 20, 3,124, 4, 31, 3,
+ 216,252,208, 30,155,152,123, 1, 53,152,133,150,188,160, 63, 41,
+ 138,145, 56,149, 98, 68,216,242,231, 86,228,215,175,253,237,227,
+ 173, 75,119, 61,212, 93,136, 97,165,202, 2,218,162, 12, 65, 4,
+ 180, 34, 84,123, 97,225,229,234, 54, 35,142, 32,138,124,117,233,
+ 57, 5,228, 21,216, 43,128, 1,136,160, 72, 44, 75,197,247, 39,
+ 215,147,240, 43,165, 24,185,243, 87,135,247,248,201,181, 36,182,
+ 131, 12,221,176, 44,200,163,186,105, 58,129,164, 58,153, 5, 22,
+ 82,241,193, 14,202, 50, 62, 38,116, 87,156,230,143, 71,146,129,
+ 22,165, 97,201, 21, 38,251, 35, 69, 70,193,240,210,241,200, 12,
+ 194,124, 46, 13,231,226, 43,240,183, 8,246, 30, 6,197, 33, 37,
+ 135, 95, 32,108, 17, 56, 25,131, 38,203, 68,219,189,232,212, 80,
+ 139, 23,225,136, 9,196,196, 24, 88,219, 37,154, 96,150, 73, 66,
+ 168,198,132,167, 36,215, 83,241,203,188, 46,135, 53,230,229,152,
+ 44, 41, 15,167, 31,131,140, 86,151,159, 52, 63, 26, 10,110, 25,
+ 177, 20,104,168, 30,172,149,225,213, 61,180, 76, 73,105, 52, 88,
+ 21,126,213, 92, 19, 68,219,141,179,253, 68,176, 65, 80,157,157,
+ 103, 92, 20, 8,203,214,122, 25, 32,108, 92,249, 59,246,118,190,
+ 30,203,111,119, 33, 47, 79,125, 56, 36,131,243,183,228, 89,241,
+ 18, 73, 39,173, 28,167,168,112,186,148,157,212, 92, 90,162,217,
+ 135,141, 91, 54,246, 57,229,148, 69,149,181,178,212,232, 45,241,
+ 41,147, 90,198,225,122, 94,193,245,204,252, 10,229,152,240,248,
+ 135,252,237, 21,231, 5, 69, 32, 19,198,191, 58,135, 40, 56,149,
+ 168, 7,140,193,125,144, 50, 60,225, 60,251,158, 38, 92, 67,138,
+ 145,254,148, 38,199, 52,188, 30,138,245,203, 78,164, 17,145,107,
+ 148, 89,176,107,133,100,176,107,101,219,125, 2,138, 57, 51,230,
+ 114,122,203, 32, 12,108, 39,186, 24, 4, 21,161, 8,164,125, 0,
+ 91,162, 93, 63,115,212, 25,250,170,177,227,206,133, 13, 95, 97,
+ 43,138,154, 60, 53,185,158,153, 95, 86,142, 73,143,159,252,104,
+ 177, 26,100, 64,154, 69,246, 83,102, 87,141, 62,137,187,137, 47,
+ 149,103, 43,204, 35, 83, 89,198, 6, 63,196,214,113, 22,153, 2,
+ 153,214,101,132,167, 96,212,245,100,164,206, 10,241, 5,255,113,
+ 103,125,108, 9, 16, 3,168, 45, 81, 83, 76,138,175, 60, 15,225,
+ 236,121,184,175, 72,145,225, 21,235,176,153, 28, 69,140,163,118,
+ 229, 75, 77,137,172, 73,108,125, 8,193,245,129,248,149,200,177,
+ 75, 32, 3, 20, 3, 60,168,112, 54,201,186, 7,110,161,226,194,
+ 63,157,170, 38, 61,200, 8, 4, 96, 47, 25, 98,117,204,194,116,
+ 91,214, 27,150,241, 91, 36,172, 85, 46,133,185,210, 77, 69, 16,
+ 224,114,216,170, 49, 6,115, 81,111,115,163, 41, 96, 17,116,229,
+ 242,242,112, 14, 91, 31,131, 92, 31,136, 95, 72,142, 77,130,108,
+ 237, 25, 39,142,219,117,108, 40,158, 48, 74, 40,194, 24,165,185,
+ 136, 20,124, 38,140, 95,106, 45,109,222,203,159,212, 56,250,208,
+ 11,195, 27,147, 38,114, 97, 19, 23,117, 53, 73,143,231,239, 83,
+ 195, 62, 37, 24,206, 70, 88,112,133, 33, 84,181,144, 9, 84,149,
+ 144,136, 24, 17,213,104,136,114, 25,151,226, 63,230,190, 23,217,
+ 168,131,137,104,165, 17,249, 79,136,173,143,200,175, 7, 64,118,
+ 28,240, 38, 96,134,222,211,129, 52,203,184,230, 69, 19, 21,138,
+ 138, 52, 8,131,194, 54, 36, 23,153,108, 24,218,145,212,216, 58,
+ 46, 88,150,229,177, 49,151,172,176,187,147,100, 79,165,125, 36,
+ 69,129,236, 97, 38,148, 70, 21,181,163, 89,104,108, 57,183, 94,
+ 20,145,206,188,135, 32, 35,182,142,190,193,150,181,198, 40,234,
+ 116, 12,255, 67,185,148,139, 57, 21,136,172,184, 54, 4, 61,213,
+ 159, 7, 91, 31,154, 95,240,117, 31,114, 95,106,159,247,170,118,
+ 45, 19, 81,166, 93,240,204, 62, 11,138, 55, 39,136,230,235,190,
+ 202,155,199,237,145,104,243,209,237, 69, 6,119,155,180,192,228,
+ 42,118, 36, 35,116,129, 7, 28, 24, 96,214, 8, 75,119, 27, 51,
+ 138, 89,219, 43,186, 71,254,189,230,156,179,243, 51,143, 31, 20,
+ 155,232,127,133,193,215,128,149,161, 83, 23,248,122,105,208,244,
+ 131, 89,242, 95,135, 95,133,217,191,237, 86, 14, 63,138,229, 28,
+ 129,113,204,251,195,177,208, 64,166,121, 53, 20, 74, 36,183,206,
+ 47, 82, 49,105, 39,115,185, 10,120, 61,232,223,151, 97,176, 23,
+ 12,200, 7, 27,145,248,109,247,160,127, 31, 35, 44, 48,200,180,
+ 174,201,131,248,112,244, 68, 60,143,130, 98, 25,133, 0,138, 75,
+ 66, 36,177, 96, 91,207, 39,148, 90,159,155, 95, 69,117, 41, 56,
+ 54,246,243, 48,118,152,145,103, 89, 8,180, 68,239,224, 5, 10,
+ 157, 22,166, 21, 46, 3,211,198,238,172, 45, 50,182,237,135, 56,
+ 151,141, 46, 12,121,173, 44,252, 57,197, 60, 87, 73,170, 53,192,
+ 153,130, 23, 52,242,243,161, 18, 19, 62,127,186,155,151, 44, 60,
+ 179,220, 2,234,193, 9,235, 29,190, 42,148,245, 51,124,210,219,
+ 141, 62,237,141,205,187,234,140,146,173,110,153,110,178, 36,127,
+ 236,200, 86, 99, 38, 56,192,133, 39,190,168,188, 40,163,141, 2,
+ 175, 42, 52,176,242,125,197, 25,143, 62,238,136, 76,234, 69, 56,
+ 198,181,134, 86,108,224,211, 99,161,251,164,219, 17,166,239, 97,
+ 173, 85,226, 34,182,207, 92, 61,167,168, 4,159, 97, 36, 85, 18,
+ 239,160,216,201,138,152,245, 53,164,214, 87,227,215,156, 83,134,
+ 89,198, 18, 99,242,196,159, 41,156,165,152, 35, 71,165,217, 2,
+ 48, 42, 10, 19,213, 85,128,235,138,217,229,227,247, 52,153,250,
+ 154,175, 32,169, 26, 57,113,173, 99,219,230, 91,125, 28,191,114,
+ 204,242,242,211, 64,141, 42, 48,205, 2,171,142,149,126,105,102,
+ 125, 65,126, 77,177,140, 8, 28,147, 68, 99,247,254, 69, 39, 83,
+ 133,179,163,190,138, 88, 70,186,187,231,130,215, 30,195,203,244,
+ 9, 5,252, 10,125,250,224, 3,130, 42,113,237,231,234, 71, 70,
+ 69, 36, 37, 45, 68,174,166,140,125,125,192, 47,229,244,187,237,
+ 75,119,191,176, 39, 80, 73, 59,188, 87,154, 5,178,130,210, 57,
+ 0,214, 87,100,214, 23,231,215, 76,141, 9,188,255, 3,101, 37,
+ 206, 16,194,242,135,225, 69,131,171, 8, 85,214,198, 74,189,249,
+ 2, 94, 51,252, 74, 46, 92,124,209,201, 82, 42,227, 87,240, 80,
+ 113,170,240,248,245, 2, 66,205, 48, 43, 39, 17,100, 97,244,240,
+ 10,176,190,153,245,205,175,199, 89, 22, 72,179, 24,103,123,104,
+ 99,156,224,203,130, 9, 97,141,231,205,245,218,116,159, 89, 80,
+ 48,244,235,129,209, 57,145, 6, 43, 73,198,149, 32,171,211, 21,
+ 248, 33,132, 23,101,153,139,116,145, 86,161,213,152,158,178,250,
+ 75,236,246,111, 96,125,243,235,157,112, 38,144, 6, 38, 99,231,
+ 68,171, 48,231,158, 95,112, 42,189, 72,190,189,209, 62,156, 13,
+ 73,140, 64,137, 93,120,101, 57, 40, 38, 9, 71, 43,114, 61,150,
+ 174,243,139,190,248,156, 91,212,180, 74,107,192,111, 96,125,243,
+ 235,121,112,230,254,192,224,108,214,127, 57,183,166, 30,108,163,
+ 114, 15, 84, 78,193,177,161, 7,247,144, 8,228, 36, 8,158,239,
+ 104,190,204, 35, 47,104, 54, 57,157, 17,218,176, 73, 22, 62,228,
+ 234, 88, 15,136,173, 18, 79,217,122,134, 86,133, 18,253,190, 93,
+ 185,253, 31,230,204,154,229,115, 62,144, 15, 0, 0, 0, 0, 73,
+ 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_keyboard_png[11032] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 1,112, 0, 0, 0,178, 8, 2, 0, 0, 0,212, 44, 3,
+ 99, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 0, 7,116, 73, 77, 69, 7,216,
+ 1, 30, 13, 6, 32,218,243, 41,227, 0, 0, 32, 0, 73, 68, 65,
+ 84,120,218,237,125,207,111, 35,199,181,110,217, 20,203,160, 89,
+ 6,221,101,112,186, 7, 84, 51,144,154,198,168, 21,152,116, 48,
+ 212, 98, 56,139,153, 0, 17, 3,220,120, 17,103,241,222, 91, 36,
+ 249,227,238,189,139, 36, 11,123, 51, 94,152, 50,144, 81,128,105,
+ 45,166, 7, 30,210,184, 67, 14,204,166, 16,182,136,116, 13,145,
+ 238, 33, 82, 52,145,226, 37,240, 22, 53,106,211, 36,245,139,234,
+ 106, 73,156,250,160,133,212, 18,120, 84,213,117,190,250,206,169,
+ 211,125,222,217,223,255, 27,136, 5,185,117, 29, 0,208, 59,114,
+ 165, 57,105, 78,154, 91, 85,115,239, 2, 9, 9, 9, 9, 73, 40,
+ 18, 18, 18,146, 80, 36, 36, 36, 36,161, 72,196,136, 68, 34,145,
+ 74,165,228, 60,220, 68, 32,132, 52, 77,147,132,114, 89,164, 82,
+ 169, 66,161, 16,155, 27,108,108,108, 64, 8, 33,132, 27, 27, 27,
+ 49,152,203,231,243,124,104, 24,227, 24,150, 75, 42,149,202,229,
+ 114, 66, 77, 96,140, 63, 41,126,242,233, 47, 62,205,102,179,225,
+ 69, 8, 97,161, 80, 72, 36, 18,162,233,178, 80, 40, 64, 8, 69,
+ 79, 99, 38,147,217,222,222,254,244, 23,159,110,111,111, 99,140,
+ 227, 89,153,169, 84, 42,123, 43, 27,167, 15,167, 82,169,141,141,
+ 13,209,119,141,223,184,141,141,141,211,125,252,221, 8,141,161,
+ 15, 80, 12,163,226,206,144, 74,165, 24, 99,154,166, 77, 38,147,
+ 56, 44,126,132,185, 33,132,144,232,123,150,207,231, 55, 54, 55,
+ 208, 7,232,211, 95,124, 90, 40, 20, 4, 89,204,173,231, 14, 59,
+ 135, 47,254,231,133,118, 91, 11,151,136,166,105,140, 49,209, 83,
+ 154,205,102, 83,239,167, 68,243, 50,132,112, 99,115,131, 82,218,
+ 254,190, 77, 41,205,255, 44, 47,148,194, 66, 81, 57, 26,141, 70,
+ 63,140,226,148,153, 27, 27, 27,163,209, 40, 6, 71,152, 76, 38,
+ 163,209,232,244, 45,252, 70,134, 60,217,108,150, 82,154, 72, 36,
+ 240, 71,152, 82, 26,131,136,157, 76, 38,140, 49,190, 27, 8,181,
+ 200,119,128,254,171,254,232,135, 81,251,251,246,104, 52,226,118,
+ 35, 31, 81, 34,145,160,148, 50,198, 70, 63,140, 56,103, 33,132,
+ 50, 31,102,122,189,158,104,198,204,222,202,182,191,111,227,143,
+ 176, 80, 15,231, 31,238,251, 62,165,212,247,253,240,138, 56,153,
+ 112,103,235,206,246,246,182,166,105, 92,232,125, 82,252, 36,159,
+ 207,199,176,185,194,247, 96,191,223,143,199,245,250,253, 62,124,
+ 15,158, 34,247,214,162,178, 20,131, 99,135, 11, 37,245,126,170,
+ 223,239,103, 50, 25,209,118,249, 46,154, 74,165, 38,255, 59,121,
+ 243,253,251,169, 76, 38,131, 16,242, 60, 79, 8,121,125,128,186,
+ 127,239, 50,198, 16, 66,148,210,120,102,149,235, 74, 77,211,250,
+ 175,250, 49,200,147,193,235,193,104, 52,242,255,233,107,154,214,
+ 237,118, 5, 25, 26,141, 70,225, 6,192,183, 4,126, 69, 16,184,
+ 20, 2, 0,228,114, 57,238,225,158,231,137,216, 12,230,195,186,
+ 193,235, 65, 60, 58,157,139,148,193,235, 65, 38,147,225, 28,189,
+ 10, 10,133, 49,246,252,219,231,190,239,251,190,255,252,219,231,
+ 49,220, 51, 30, 94,113, 46, 99,255, 22, 27, 17,208,127,209,108,
+ 54, 43, 58,191, 48, 63,132, 76, 38, 3, 33,244, 60, 15, 33, 36,
+ 78,168, 67, 8,179,183,178,156,139, 61,207, 19, 42, 82, 38,147,
+ 73,255, 85, 95,187,173,109,108,108,100,111,101,187,127,239,138,
+ 246, 58, 74,105, 42,149, 74, 36, 18,189,163, 94, 54,155, 21,164,
+ 46,103,111,220,135, 25,161, 68,185,144,169, 51, 31,102, 98, 10,
+ 121, 98,211, 41,241,192,243, 60,207,243, 38,147, 9,223,112, 70,
+ 163,209,104, 52,226, 23, 5, 89,236,245,122,147,201,132, 7,252,
+ 24, 99, 65, 57, 41, 30,114, 35,132,184,220, 27, 12, 6,185, 92,
+ 174,215,235,221,185,115, 39,151,203, 21, 62, 46, 76,103,106,163,
+ 85,124,131,215, 3,238,102,140, 49, 46, 82,132,238, 61,137, 68,
+ 34,243, 97,166,251,247,238, 96, 48,136, 65, 59,231,214,115,124,
+ 171, 75,172, 37, 68,167,213,249, 86, 23,191,211,113,115, 39,237,
+ 58,242,216,248, 28,183,237,253, 84,168,159, 69,239, 6,163,209,
+ 168,221,110,119,255,222, 77,172, 37, 52, 77,187,115,231,142, 32,
+ 189,112,216, 57,220,216,220,216,254,249,182,255, 79, 63,147,201,
+ 112, 39, 79, 36, 18, 47, 95,190,124,217,122,153, 91,207,137,240,
+ 55,252, 17,158,230, 98,161, 34, 37,151,203,105,183,181,222, 81,
+ 111,244,195, 40,255,179, 55,135,116,252, 44, 82,144, 69,198, 88,
+ 251,251,118,191,223,159, 76, 38,135,157, 67,209,217,168, 48, 86,
+ 189, 18,156,100,122, 77,242,197, 73,192, 24,135, 26,129,103,215,
+ 82,239,167, 38,255, 59, 65, 8,241, 93, 72,232,214, 58,250, 97,
+ 116,120,120, 88, 40, 20, 52, 77, 59, 60, 60, 20,177,207,124,215,
+ 248,142,175,140,237,159,111, 31,118, 14, 17, 66,161,118, 0, 0,
+ 240, 36, 78,180, 70, 95,182, 94, 78, 71, 1,140,177,151,173,151,
+ 226, 98,171,222, 81,175,223,239,251,190, 95, 40, 20,242,249,124,
+ 187,221,230,225,164,184, 72, 36,156,177, 21,147,234,231, 71,148,
+ 132,194,147, 82, 43, 3,126, 8,194, 19,218,124, 95, 45,124, 92,
+ 224,161,120, 12,177, 49,207, 2,112,209, 46,212, 74, 46,151, 27,
+ 188, 30,240,204,165, 80, 67, 11, 39, 77,144,226,227, 26,132,127,
+ 248,100, 50,105,183,219,133, 66,225,206,157, 59,240, 61,184, 98,
+ 171,244,186, 33,210, 58, 20,132,174, 80,131,137,112, 0,190,207,
+ 12, 6, 3,254,205,100, 50,225,223,139, 35,148,237,237,237,124,
+ 62,143, 49,230, 71,143,153, 15, 51, 66, 79, 4, 83,169, 84,230,
+ 195, 12,167,203,153, 65,197,118,112, 32,142,188,194,104,113, 50,
+ 153,248,190, 15,223,131,236,223, 44,230, 20,230, 21,166, 51,174,
+ 36,113,179,118,190,219, 51,110, 54,155,105,132, 10,198,230, 73,
+ 127,147,205,102,181,219, 90,184,153, 47, 59, 65,195,102,171,229,
+ 251, 1, 0, 0, 99,197,220,218, 66, 40, 45,108,205,141,187,174,
+ 75, 8,161,116, 8, 0,208,212, 91,134, 97,204,155, 75,165, 82,
+ 60,159,151, 74,165,120,193, 82, 52,106,206,233, 12, 41,157,183,
+ 216,239,247,121,174, 52,177,150, 24, 13, 70,221,110,119, 57,242,
+ 162,116,232, 56,206,204,197,249, 59,152,203,229,250,175,250,220,
+ 4,165, 52,183,158,227,135,226, 75, 59, 94,219,233, 76, 79,105,
+ 169, 84,140,252,198,121,132, 16,143, 44,252, 85, 56, 64,198,216,
+ 224,245, 32,183,158,131, 16,242,244, 51,250, 0,245,142,122, 24,
+ 227, 66,161,208,110,183, 47, 74,151,140,141,219,142,227,186, 71,
+ 0, 0,132,210,134,177,169,169,170, 72, 66,252,209,220,233,142,
+ 48,250, 97, 20, 9,161,180,157,142,227,116,206,227,119,167, 59,
+ 194,217,132,226, 7,193,227,199,251,148, 82, 85,213, 78, 33,148,
+ 193, 96,128, 16,186, 76, 46,189, 94,111,212, 27, 13, 0,128,170,
+ 106,227, 49,107, 54,155,142,227, 84,171,187, 88, 81, 34,191, 97,
+ 126, 16,212,106,123,188,220, 35,157, 70,227, 49,171, 55, 26,205,
+ 86,107,222,220, 96, 48,224,174,197,143,120, 34,177,222,117, 93,
+ 203,178, 0, 0,170,166,206, 19, 10,231, 20, 77,211, 46,147,213,
+ 163, 67,202, 39,115, 26, 51,119,144,215,182,133, 10,136, 49,214,
+ 253,123, 55,155,205, 78, 38,147, 37,178, 54,140,141,107,123,123,
+ 190,239, 67, 8, 21, 5,243, 73, 22,225,108,196, 35,243, 67,155,
+ 31,224,225,225, 97, 54,155,229,197, 74,163,209, 27,106,246,125,
+ 63,155,205, 94,116,161, 50, 54,126,244,213, 87,148, 82,140,113,
+ 50, 9, 93,215,117, 28,167, 92, 46,111,155, 91, 98,116,199,240,
+ 209, 87, 95,241,112, 59,153,132,167, 59,130,239,251,218,109, 13,
+ 92,174,154,231,235,218, 55,132,120,220, 23,206,244,187,204,135,
+ 25,239, 31,222,146,132,242,162,217,178,109,251, 60,207, 65,240,
+ 227,137, 75, 78,165,174,235,247, 43, 21, 8,147,156, 50, 45,203,
+ 170,215, 27,191,124,248, 32,242,123,134,210, 72,215,245,233,125,
+ 134,155,123,250,244,217,175,171,191,250,201,126,120, 44,184,162,
+ 74,179, 49, 54,182,172,131,211, 83,131,124,233, 95,114, 81, 2,
+ 0,170,213,221, 83, 54,210,201,100, 50, 35, 39, 7,131,193,210,
+ 91, 2,103, 19,113,110, 22,162, 84, 42,206, 11, 31,143,144, 90,
+ 109, 79, 83,111,205,179,243,233, 67, 62, 15,158,218, 54,165,180,
+ 82,169, 28,203,159,113,109,111,207,182,237,188,174,139, 80,208,
+ 79,172, 3,198, 88,120,239,248,230,247,248,241,254,239, 62,255,
+ 237, 73,132,130, 49, 94,122,193,180,157, 14, 33,158, 97, 24,247,
+ 43,247, 66,115,150,117,240,217,111,254, 99,254,143, 57, 21,156,
+ 98,235,221,211,181,165,109,219,134, 97, 84,119,119, 99,136,205,
+ 74,165,226, 47, 31, 62,224,108, 2, 0, 40, 24,155, 24, 99,215,
+ 21,242,166, 41, 8,147,247, 43,247,166,157,141,155, 35,196, 19,
+ 61,204, 39,150, 5, 0, 48, 12,227,244, 20,192, 37, 9,101, 24,
+ 239, 41, 67,219,233,248,190, 95, 42, 22, 69,179,201, 73,224,114,
+ 221, 52, 77, 65,146,129,175,144,112,241,232,235,235, 92, 6,138,
+ 8,118,184,123,135,139, 19, 43, 74,185, 92,166,148,182,157,206,
+ 194, 93,161,119,212,211, 52,109,233,244,101,171,213, 2, 0,236,
+ 148,203,161, 57,195, 48,124,223,159, 23,152,137, 68, 66,211,180,
+ 222, 81,239,148,128,241, 52, 66,209, 84,181, 90,221,189, 95,185,
+ 23, 58,121,204, 72, 38, 97,156,230, 24, 99,162, 75, 84,219, 78,
+ 199,117,221, 74,229, 30, 76,198, 49,165, 66,227,252,216,252,249,
+ 156, 9, 35,195, 48, 4, 45, 84, 46, 67, 56,173, 28, 71,148, 67,
+ 174,115, 5, 4,227, 62, 0, 0,165,127, 34,124,242,186, 14, 0,
+ 8, 78, 8, 33,125,223,127,241,226,197,210, 73,116,223,247, 85,
+ 85,155,158, 58, 93, 95, 7, 0,184, 93,119,158,188, 94,188,120,
+ 113,250, 86,247,238, 53, 89,145, 39, 81,181,170,198,244,106,137,
+ 182,211,161,148,154, 91, 91, 66,215, 61, 87,124,124,125,136,245,
+ 177,225, 48,206,155,197,239, 20,132, 73,198,198, 30, 33,130,178,
+ 39, 39,161,217,106, 1, 0, 76, 97,226,136,127,242,227,253,125,
+ 206, 41, 47,154, 45,199,113, 76,211, 20,119, 98, 48, 47,168, 1,
+ 0,252,176, 34,106,254, 10, 66,198,156, 78, 8, 44,157, 2,187,
+ 190,133,109,205,102, 19, 0, 96,156,156, 6,142,106,103, 3, 0,
+ 120,228, 85, 16,248,165, 98, 81,196,169,196,116,108, 12, 33, 12,
+ 181,165,232, 77, 27, 0,240,167, 63,255,133,103,106, 48,198,250,
+ 250,186,105,154, 34,246,240,112, 81, 62,181,159,241,187, 6, 0,
+ 64, 8,149,203,119, 99,160, 78,198,198,142,227,168,170, 38, 34,
+ 121, 31, 70, 1, 15, 31, 62,176,172,131, 47,190,252,146,151,255,
+ 137, 91, 42, 88,193,124, 65,150,126,186,219,137, 83,229,243,130,
+ 136,243, 11, 99,227,213, 33, 20,143,144,122,163,113,250,185, 82,
+ 20,219,248,143, 71, 33,170,170, 37, 69,198, 59,245,122,131, 16,
+ 175, 90,221,141, 39,126, 52,205, 59, 0, 0,158,164,100,227,177,
+ 235,186,245, 70,195, 61, 58,170,238, 70,255, 15,240, 69, 73, 8,
+ 129, 16, 62,124,248,128,231,155,109,251,153,101, 29,224,223, 96,
+ 209,219,120,219,113, 24, 99, 66, 55,158, 99,153, 0,249, 96, 25,
+ 99,108, 60,102,108, 44,226, 86, 66,152, 52, 77,179,217,108, 62,
+ 177, 14,248,160,136, 71,220,163, 35,112, 67,112, 29, 9,133, 31,
+ 84, 99,140, 69,156,239,204, 4,116,127,252,195,239, 67,169, 98,
+ 219,118,167,211, 89,152,220,190,252,136,234,141, 70,169, 88,140,
+ 45,132,204,235,250,180, 58,216, 41,223,125, 98, 29, 56,142,211,
+ 118, 28,113,121,211,105,182,130, 16,214,106,123,205, 86,107,167,
+ 124, 87,232, 72, 91,173, 22, 58,181, 66, 42,146,112,216,178, 44,
+ 195, 48,184,186,108, 54,155,245, 70,131, 16, 34, 98,169, 0, 0,
+ 74,197, 34, 99,204,113, 28, 46,159, 17, 66,149,202,189, 90,109,
+ 47,182, 8,107,165, 8,133,210, 97,173,182, 7, 0,120,248,224,
+ 65,108,201, 96,132,210, 92,193,214, 27,141,182,211,137,124,117,
+ 242,115, 98, 85, 83, 61, 66,166,115, 28,111, 74,248, 20, 28,195,
+ 72, 75,197,162,227, 56,174,123, 36,136, 80,140,205,205,233, 81,
+ 188, 57,242,244,197, 38, 83,120,230,171, 84, 44, 10,181, 98,219,
+ 182,170,106,252, 84, 21, 0, 80, 42, 21,147, 16,218,182,253,162,
+ 217, 18, 49,153,252, 8,114,167, 92,246, 3, 31, 66,136, 21,133,
+ 47,155,153,192, 36,154,149,159, 70, 96, 46,227,198,227,229,229,
+ 214,228,245, 34, 20,198,198,143,247,247, 1, 0,213,234,110,252,
+ 124,172,106, 42,104, 8, 57,112,229,137,113, 78,148, 51, 43, 21,
+ 156, 85, 45, 18, 33,105, 10, 75, 49, 96, 16,123, 26,152,195,113,
+ 58, 16, 66,161,167, 75, 30, 33,140,177,153, 10,151,109,115,203,
+ 182,109,113,236,204,253, 57, 92, 21,188,100, 86,207,235,130, 86,
+ 197,244, 1, 22, 56, 62, 14, 95, 46, 39,181,118,173,216,164,182,
+ 183, 71, 41, 21, 84, 29,123, 14,183, 15, 0, 0, 34, 50, 41,213,
+ 234,238,188, 39,240,106, 75,140, 21,238,144, 49,164,165, 0, 0,
+ 24, 43, 34,150, 62,198,152, 16, 50,191,203,137, 48, 55, 61, 34,
+ 94,178, 17,127, 89, 3, 79, 88,198, 99, 87,116,214, 89,215,117,
+ 215,117,167, 83, 66,156,191,148,165,238,221,187,215,138, 77,120,
+ 129, 96, 12,108, 50,127,180,233, 17,210,104, 52, 32,132,133, 83,
+ 75,206,150, 78,214,204,124,113,249,138,177,162,169,170,136,117,
+ 217,118, 58,211, 89,122, 74,135,182,253, 12, 28,151, 24, 68,142,
+ 173,173, 45, 74,233, 19,235, 32,188,155, 79,109, 91,156,185,144,
+ 148,121, 40, 39,116,169,104,170, 10, 33,108,182, 90,211, 11,230,
+ 120,116,122, 12, 11,181,182,183, 7, 0,216,217, 17,149,138,226,
+ 169, 95, 62, 34, 0,128, 31, 4,142,227, 32,132,150, 59,161,187,
+ 46, 10,197, 15,222,188, 97,228,209,163,175,230,131,255,200,143,
+ 232,248,243, 32,225, 83, 39,195, 33,165,148, 66, 8,203,229,242,
+ 85, 85,241, 69,157,181,177, 44, 0,248,195, 32,227,241,155,186,
+ 219, 74,165, 34, 40,182, 42, 24,155,132, 16,199,113, 8, 33,233,
+ 52, 10, 2,159, 49,102,154,166,184, 80,142,231,209, 85, 85,139,
+ 33, 52,174, 84,238, 61,126,188,255,232,209, 87,188, 42,138,143,
+ 206, 48, 12, 65,153, 96,254, 24,193, 84, 84,130,132,238,178,121,
+ 93, 55, 12, 35,188,119,132,120,252,180,110,185, 79, 59, 47,161,
+ 148,138,197,180,200,247,101,160, 52, 58,105,171, 81,181,232, 23,
+ 165,105,154,105,132,194,231, 98, 21, 69,217,218,218, 18,244,104,
+ 198, 73,131, 42,129,162,136, 82, 75,142,207, 62,251,141,219,117,
+ 61,242, 10, 0,144, 76,194, 82,177,184,240, 89,234, 8,113,191,
+ 114, 79, 85, 85, 46,158,103,158,147, 18, 66, 40, 67, 90, 42, 22,
+ 69,164, 21, 22,186,220,239, 62,255,220,113, 28, 62,159,162, 71,
+ 135, 21, 28,250,130,170,169, 49,228,215,166,239,157,105,154,151,
+ 121,202,255,157,253,253,191,197,227, 66,178,199,189, 52, 39,205,
+ 173,188, 57,249, 78, 89, 9, 9, 9, 73, 40, 18, 18, 18,146, 80,
+ 36, 36, 36, 86, 24,239,180,157, 67, 57, 11, 18, 18, 18, 82,161,
+ 72, 72, 72, 92, 47,172,201,228,182, 52, 39,205, 73,115, 82,161,
+ 72, 72, 72,200,144, 71, 66, 66, 66, 18,138,132,132,132, 68,124,
+ 132, 2, 33,212, 52, 77, 78,232,229,193,223, 45, 46,186, 49,168,
+ 132,196,181, 39,148,219, 43, 75, 40, 27, 27, 27, 16, 66, 8,225,
+ 198,198,134,104, 91,147,201, 4, 66,152,207,231, 99,238,235,154,
+ 205,102, 11,133,130,104, 43,185, 92, 46,151,203,173, 82,203, 90,
+ 9, 25,242, 92, 12, 24,227, 84, 42,197, 24,211, 52, 45,158,142,
+ 191,221,110,151, 82, 26,167,226,211, 52, 77,187,173, 81,241,221,
+ 124, 70,163, 17, 66, 40, 6, 94,150,144,132,114, 77,145,205,102,
+ 41,165,137, 68, 2,127,132,105, 92, 13,180,186,221,238,101, 90,
+ 145, 94, 20, 8,161,209, 15,163,203,244,165, 62, 39,124,223, 31,
+ 12, 6,232, 3, 25,208, 69,131, 84, 42, 21,131,174, 60, 63,214,
+ 228, 45, 57, 51,148, 75,189,159,234,247,251,188, 75, 46,141,183,
+ 35,159,132,196,233, 72, 36, 18, 49,176,115, 34,145, 88,216,146,
+ 125,222, 29, 36,161,156, 1,198,216,243,111,159,135,187,171,156,
+ 16,137,183, 84, 7,125,188, 64, 7,133,174,113, 83, 9, 37,145,
+ 72,108,108,108,160, 15,208,100, 50, 25,188, 30,112, 15,207,102,
+ 179,135,135,242,137,164,203, 78,236,104, 52,138,141,163,185,197,
+ 120, 18, 82,171,234,225,185, 92,142, 79, 35, 0, 32,140,122,218,
+ 237,182, 8,115,148,210,121,238, 88,133,144, 39,149, 74, 81, 74,
+ 61,207, 75, 36, 18, 24, 99,206,154,253, 87,125,185,194,150, 6,
+ 198, 24, 99,156, 72, 36,250,253,152,166,113, 48, 24,208,127,209,
+ 59,119,238,248,190, 31, 67,214, 38,102, 94, 14, 67, 3,222, 17,
+ 76,144,161,201,100,194,195, 13, 30,146, 95,159, 72,252,134, 17,
+ 10,165, 52,156,187,193, 96, 32,233, 32, 18,142,230,242, 68,220,
+ 234,159,119,134,209,104,148, 72, 36, 86,175,214,102, 58, 52,240,
+ 254,225,137,163, 75,198, 24,255,112,132, 16,254, 8,139,230,101,
+ 132,208,106,134, 60, 18,145,131,159, 37,109,111,111,107,154, 22,
+ 207,185, 82, 38,147,201,222,202,190,248,159, 23,177, 81, 88,156,
+ 27,222, 57, 67,131,155,133,209,104,212,254,254, 92,193,148, 36,
+ 20,137, 55, 59,222,194, 52,190,160,109, 28, 28,103, 82, 36, 98,
+ 115,245, 72, 34,172,203, 18,138, 71,136,235, 30,241, 14, 88, 8,
+ 165, 85, 85,141,176,117, 0,239,132,160, 96,101,166, 3, 72,219,
+ 233, 12, 41,157,121, 75, 59,255,227,116,164, 93,108,235,245,198,
+ 252, 69, 65,111,135,231,131, 10,127, 84,176,162,169,154,160,150,
+ 29, 51,182,102, 16,121, 79, 18, 62,141,243, 31,187,240, 62, 70,
+ 53,186,147,204, 69, 62,186,208, 17,136,247, 99, 39,179,180,224,
+ 110,202,231,247,187,243,187,250,249,135,166,169,234,210,183,108,
+ 237,228, 45,107,252,196,178, 92,215,229, 17, 20,132,208,113, 60,
+ 199,113, 90,173,214,195, 7, 15, 34, 89, 34, 16,194,122,163,129,
+ 49,158, 33, 20,219,182,249,246, 53,189, 56,252,192,175, 55, 26,
+ 209, 54,157,172, 55, 22, 16,138,170,169, 34, 8,197,113, 58,132,
+ 204, 6,186, 34, 90, 14,157,100, 75, 28,161,208,225, 2,174,167,
+ 116,104, 89, 22, 66, 40,114,115,124,116,243, 31,123,210,245,168,
+ 224, 7, 1, 33,132, 49,166,170,154, 33, 44,251, 19,131,223,205,
+ 128,247,168,138,106,101,158, 72, 40,124, 84,186,174,239,148,203,
+ 124, 24,140,141,121,223,249,199,251,251,213,221,221,203,239,174,
+ 188,133,165,239,251,211,109, 16,121, 43, 89, 0,128, 71, 94,149,
+ 166,135, 77, 94, 1, 0,212,159,182,152,189, 60, 84, 85,251,117,
+ 245, 87,177, 9,212, 63,254,225,247,124, 38, 61,226, 89,214, 65,
+ 189,209,152, 23,104,151,199,244,136,190,174,125, 67,136,199,237,
+ 158, 30,242, 32,132, 16, 66, 75,108,119,188, 13,123,171,213,154,
+ 38, 20,199,113, 0, 0,197,185, 94, 75,169, 84, 42,149, 74,177,
+ 127,223,176,120,135,247,123,228,147, 41,116,193,196,224,119, 11,
+ 193, 27,108, 95,126,101,190,123,178,226,114, 49,198,191,124,248,
+ 35, 41, 66,152, 44,149,138,165, 98,209,247,253,102,179, 25,201,
+ 48,244,245,117, 0,128, 55,181,157,114,245, 85, 42, 22, 9,241,
+ 166,155,105,114,249,167,169,171,240,252, 33,132,201,188,174, 87,
+ 42,247,192,113, 63,205, 43, 71,175,215, 27,141, 70, 11, 51,249,
+ 103, 2,161,180, 97, 24,190,239,123,199,237,141, 25, 27, 55, 91,
+ 45,180, 40, 46,200,229,114, 16,194,120,234,134, 10,133,194,167,
+ 191,248,116,250,235, 90, 85,169, 95,161,223,157,190, 50,203,229,
+ 242,210, 43,115,237, 36, 85, 9, 0,216,218, 90,208, 89,222, 52,
+ 205,122,163,225,116, 58,145,104, 75, 85, 83, 65, 3, 16,242, 42,
+ 228, 66,143,188,194, 24,243, 70,205, 30,241,194,235,132,120, 24,
+ 227,213,232, 19, 26, 70,124,224,184,237,246,149, 99, 50,153, 92,
+ 198,201,185, 72,169,215,191,211,170, 42, 0,160,237, 56,140, 49,
+ 190, 46,103, 51, 29,237,118,108,131,138,211, 86, 84,209, 92, 60,
+ 126,119,230, 14,177,244,202, 92,172, 80,130, 32, 0, 0, 44, 20,
+ 60, 60, 78,161,148,206,216, 91, 46,219,204,219, 44,242,136,145,
+ 143,129, 16, 79, 85, 85,174, 68,120,152,195,153, 27, 0,160,138,
+ 239,201, 24, 39,120,100, 23, 91,243, 83,209, 75,208, 48, 12, 66,
+ 60,222, 81,188,117,130, 60,145, 56, 29, 75,248,157, 80,181, 18,
+ 25,161,240,146,246,147, 62, 49,153,132, 0, 0, 63,240,103,182,
+ 184,229,178,205,170,170, 81, 74,121,143, 97, 30,251,168,234, 45,
+ 8,147,170,170,133, 68,195,227,160,200, 19, 40, 0,128,225,144,
+ 214,235,141,233,175,120,238, 22,165,195, 70,227, 59, 0,128,177,
+ 42, 94,199,219,241, 54,155,173,182,211,161,148, 22,139, 69, 73,
+ 16, 23,197, 18,126, 39, 2,205,102, 11, 0,160, 47,149,218,187,
+ 250, 58, 20, 93, 95, 39,196,243, 8, 41,160, 77, 46, 73,184, 60,
+ 209,245,117,219,182, 41, 29, 34,148,230,251,158,136, 4, 10,165,
+ 116, 38,197, 45, 84, 82,126, 93,251, 6, 0, 48, 30, 51,223,247,
+ 33,132,149, 74, 69, 91, 21,217,197, 69,138,227, 56,132, 16, 41,
+ 79,110, 28, 28,167, 67, 60,194,198, 99,215,117, 41,165, 24,227,
+ 229,238,224,213, 19,138,166,169, 0, 0, 66, 72,193,216, 36,132,
+ 132,137, 18,126,253,152,104,136,160, 4, 74,204,167, 60, 33,139,
+ 1, 0,170,213, 93,172, 40,171,180, 40,121, 38,133, 82, 90,169,
+ 84,164,139,222, 52, 66,113,248, 55, 24,227,114,185,188,109,110,
+ 45,247, 57,139, 9,101,254, 52,119, 26,227, 49, 3, 0, 96, 5,
+ 71, 50, 18,172, 40, 16,194, 32, 8, 24, 27,251,190, 95, 58,150,
+ 202,252,186,235,186,154,170, 50,198, 86, 35,129,194,201,203, 35,
+ 164, 86,219,123,250,244, 89,252, 92, 38, 90,164,168,170, 70,136,
+ 39,229,201,146,190, 16,163,223,205,128, 31, 27, 95,254,115, 22,
+ 231, 80, 20, 69, 1, 0,116,221, 5,205,129,184,219, 35,132, 34,
+ 212, 11,170,170,250,190,207,131, 67, 85, 83,167,162, 33,157, 16,
+ 242,230,186,128, 4,202,149,137, 50, 85,213,117,157, 16,111,225,
+ 12, 75,156, 7,243,185,201,225,240,198,191,251, 42,102,191, 19,
+ 129,197,132,194, 51,133,173, 86,107,254, 87, 60,227, 96,108, 70,
+ 185, 5,241,244, 79,189,254, 29, 56, 62,247, 9,137,134, 49,198,
+ 207,210, 86,163, 2, 37,196, 78,185, 12, 33,180,237,103,215,228,
+ 216,248, 6, 65,215,215,231,189,142,210, 33,165, 84,143,186, 68,
+ 48,102,196,236,119,241, 17, 10,223, 66,125,223,255,235,227,125,
+ 126,254,194, 57,178, 94,111, 52,155, 77,140,113,180, 37,240,156,
+ 68,134, 67,170,254,148, 53,248,249, 89, 16, 4, 43, 86,129,194,
+ 163, 3,115,107,107, 62, 37, 44,113, 38,242,186, 14, 33,180,109,
+ 59,172,163,163,116,248,120,127, 31,220,252, 35,179,152,253, 78,
+ 4, 78, 76,202,222,175, 84,120, 21,176,235,186,252,153, 2,126,
+ 166,133, 49,142,188,254, 23,161, 52, 47,250,158, 41,233, 9,107,
+ 243,197,205, 35, 33,222,127,254,215,127,139, 8, 38,207, 68,169,
+ 84,116, 58,157,102,179,105, 24,155, 43,150,157, 21,205,197,229,
+ 114,217,178,172, 90,109,111,122,101,154,166,153, 23,166, 80, 60,
+ 66,154,205, 86, 16,248, 0,128,175,107,223, 24,198,166,160, 60,
+ 81,156,126, 23, 43,161, 64,152,252,229,195, 7,211, 79, 61,242,
+ 81,125,246,155,255, 16,241,127, 20,139,197, 33,165,243, 11,162,
+ 88,252, 36,240, 3, 61, 47,100,161,148, 22,213, 74,160,180,144,
+ 231,190, 12, 99, 83,155, 75, 3, 85, 42,247,136, 71, 40,165,226,
+ 8,101,161, 93,161,162, 61, 6,115, 5, 99, 83, 83,213,102,171,
+ 197, 87,166, 97, 24,134,177, 41,122, 27,192,138, 18, 3,239,207,
+ 251,157, 97, 24,209, 62,229, 63, 3, 85, 83, 75,160, 24,213,178,
+ 95, 59, 83,131,133,247,137, 63, 25,213,118, 58, 34,198,118,210,
+ 103,230,117, 93,220,182, 19, 67, 21,243,233, 3,156,158,222, 56,
+ 237,174,128, 57,132,210, 59,229,187,113, 6, 35,113, 86, 12,197,
+ 105, 46, 90, 91, 23,232,203,179,179,115, 23, 66,104, 89, 86,251,
+ 122, 60,207, 38, 33, 33,113,221,112, 1, 66,193,138, 82,173,238,
+ 66, 8, 91,173,150, 60,155,144,144,144,184,112,200,179,152, 83,
+ 146,112,197,206, 92, 36, 36, 36, 34,193, 59,109, 71,118,180,145,
+ 144,144,136, 61,228,145,144,144,144, 56, 35,228,233, 29,197, 84,
+ 253,157, 91,215, 1, 0,210,156, 52, 39,205,173,176, 57,169, 80,
+ 36, 36, 36, 36,161, 72, 72, 72, 72, 66,145,144,144,144,132, 34,
+ 33, 33, 33,113, 54,110, 94, 43, 82, 8, 97, 62,159,239,118,187,
+ 49,247,178,212, 52,109, 52, 26,197,211,161, 61,151,203,241,126,
+ 157,188,187,133, 80, 91, 24, 99,140, 49, 0,192,247,125,254, 28,
+ 154,132,196, 91,164, 80, 24, 99, 16,194,108, 54, 27,167,209, 68,
+ 34,161,221,214, 38,147, 73, 60,230, 82,169, 20,132,144, 82, 26,
+ 131, 69,198, 24,165, 20,125,128,120, 91, 15, 9,137,183, 75,161,
+ 0, 0,250,253,190,118, 91,235,245,122,177, 89,204,100, 50,224,
+ 248, 93,176,177,241,166,231,121, 49, 24,162,148, 82, 74,181,219,
+ 87,240,254, 42,132,144,166,105,130,186,231, 32,132, 48,198,158,
+ 231,197,223,149,125,185, 6,140, 87,104, 46,108,134, 61,221, 45,
+ 112,186, 67,118,169, 84,228,111,159, 57,243, 49,194, 27,153, 67,
+ 241,125, 63,145, 72,112, 39,143,141, 80, 70, 63,140,128, 68,116,
+ 62, 80, 40, 20, 54, 54, 55,196, 57, 30, 15, 21,183,127,190,157,
+ 207,231,227, 20, 95,217,108,182,240,113, 33, 54, 5, 29,137, 57,
+ 199,233, 36, 33, 84,176,226, 56,157, 39,214,193,244, 69, 85, 83,
+ 249, 91, 89,137,247,147,158,234, 43,165, 80, 38,147,137,255, 79,
+ 31, 99, 28, 79, 70, 3, 0, 16, 79,235,204,183,132, 74, 52, 77,
+ 131, 16,122,158, 55, 56, 28,136,139,233, 38,147, 73,183,219,245,
+ 60, 15, 99,124,103,235,206,224,245, 32, 30,181,194, 77,196, 38,
+ 139,162, 50,135,177,162,169,106, 94,215,191,174,125,227, 7, 1,
+ 127,243, 11,191,184,250, 33, 15, 0, 96, 48, 24,108,108,110, 64,
+ 8,227, 23,180, 18,203,129,103,211, 57,149,196,150,253,229,145,
+ 99,191,223,207,102,179,156, 86,186,221,174,232,149,249,252,219,
+ 231,113, 58, 66,180,230, 52,245,150,219,117, 57,161,240,102, 61,
+ 233,139,116, 89,122,247,230, 18, 10,251, 55,227,199, 19, 18, 55,
+ 11,137, 68, 34,145, 72,172,182,197,213,128,162, 40,170,166, 98,
+ 124,129,247,212,173,221,220,209,250,190,207,179,110,242,198,223,
+ 8, 48,198,218,237, 54, 66, 40,155,205,106,183,181,120, 98, 16,
+ 110, 14,125,128, 6,175, 7, 47, 91, 47,165,158, 61,219,173,130,
+ 32,124,215,247, 91, 20,242,112, 66,209,110,107, 49,103,212, 37,
+ 46, 9,126,168, 4, 33,212, 52,109,251,231,219,131,215, 3, 65,
+ 249, 41, 8,225,198,198, 6,124, 15,246, 95,245,187,221,110,108,
+ 71,254, 55,153,241,199,109,199, 25, 14,135,151,121,233,234,218,
+ 77, 30, 63, 27,188, 30,240,150,244,114, 53,220,184,123,215,237,
+ 118,123,189,158,184,211,144, 68, 34,209,239,247,227, 47,213,131,
+ 16, 66, 8, 71,163, 81, 60, 20,150, 72, 36,178,217,108,191,223,
+ 191,140, 57,140,149,227,174, 88,183,170,187,187,211, 23,235,224,
+ 59, 0,192,175,171,191, 74, 35,228, 56, 29,175,246, 13, 0, 96,
+ 103,231,238, 73,239,235, 62, 23,161,116, 93, 55,240, 3,211, 52,
+ 69,191,168,141,115,164,235, 30, 1, 0, 32, 76,170,170,154,215,
+ 117,132,210,167,100, 82,242, 63,203,247,122,189,139,206,166, 71,
+ 126,114, 6,150,132, 80,211, 84,209,239, 52,159, 62,216, 15,161,
+ 106, 2, 95, 71,236, 7,129,219,117, 61,242, 42, 92, 34,170,122,
+ 43,242,151,126,243,113,205,191,241,251,164,235, 33, 38,147,201,
+ 37, 35,214, 83, 76,140, 70,163,168,138,140,249,106, 49, 12, 99,
+ 122, 41, 50, 54,110, 54,155, 73, 8,103,218, 0, 99,140,181,219,
+ 218,119,141,239, 4,141,107, 6, 60,126, 4, 0, 92,102, 38, 23,
+ 190,238,123,230, 98,225,124,157, 67,206, 69, 40,150,117,192, 24,
+ 155,159,187,200,217,164,182,183,231,251, 62,132, 80, 81, 48,111,
+ 77, 50, 28, 14, 79,121,185, 57,255,227, 68, 34,113, 81, 66, 33,
+ 30,153,239,176,133, 16,122,248,240,129, 56, 90,113,156, 14, 33,
+ 179,119,189, 4,138, 34, 8,133,177,241, 95, 31,239,115,115, 8,
+ 161,116, 26, 17,226, 17,226, 53,155,205, 74,165, 18,237,187,233,
+ 249,184,230, 87,255, 73,215, 99, 48, 29, 45,248,106, 81, 53,117,
+ 154, 80,248, 90,253,236,179,223,204,175,162,193,235,203, 30,135,
+ 159,127, 92,131,193, 0, 33, 20, 73,253, 4, 99, 99,222,246,247,
+ 108, 69,163,156,216,120,239,108, 66,233,186, 46, 99, 12, 33,212,
+ 233,116,132, 18, 74,179,217,244,125,223, 48,140,251,149,123,225,
+ 206,112,102,187,144,203, 16,115,216,211,139,239,228,205, 86,235,
+ 209,163,175, 68, 55,250,250,227, 31,126,127, 78, 41,139, 16, 90,
+ 78, 57,135,212,172,235,250, 78,185, 28,186, 1,165,195,174,235,
+ 206,176, 9,151,232, 50, 10,187, 16,158, 88, 7,190,239, 87, 42,
+ 149,249,237, 7,125,128,218,223,183, 99,251, 79, 70,163, 81, 36,
+ 165,198,225,154,185,144,227, 44, 67, 40,142,211,129, 16,110,109,
+ 109,217,182, 29, 86,188,136, 0, 87,230, 59,229,114,120, 37,182,
+ 214, 36,188,135,147,170,169,181,218,158,101, 29,252,238,243,223,
+ 94,249,146, 77,189,159, 42,124, 92,104,127,223, 94, 34, 67,244,
+ 212,182,103,168,249,120,243, 76,207,111, 9, 92,162, 75,142, 56,
+ 63, 94, 52, 91,142,227,148,138,197,121,161, 7, 33,236, 29,245,
+ 110, 92, 82,143,179, 9,165,244,179,207,126, 19, 58, 56,165, 67,
+ 190, 21,133,223,240, 61,190, 86,219, 59,229,163,222, 61,211,146,
+ 235,186,250,113,183, 45, 71,124, 71,158, 43, 60,216,211, 84,213,
+ 48, 12, 74,233,149, 55, 30,106,183,219,207,191,125,254,252,219,
+ 231, 75, 44, 77,198,198,142,227, 64, 8,167,169,249,116,137,199,
+ 109,201, 3,248,115,102, 55,108,219, 54, 12, 99, 97, 60,194, 24,
+ 235,247,251, 55,148, 77,170,213,221,144, 77,234,245,198,163,175,
+ 190,242,131,160,237,116,190,248,242,203,176,141,244,153,120,247,
+ 172,233,115, 0, 0,134,177,137, 80, 90,215,117,199,113,196, 13,
+ 76,215,215,193,113,151,249,171, 2,255, 31,130, 32,184,185, 43,
+ 222, 35, 30, 0, 64,215,117,217,234, 36,114,248, 65, 96,219, 54,
+ 198,120, 70,250,221, 92, 44,100, 19, 0,128,105,154, 8,161, 90,
+ 109,207,178, 44,195, 48,206, 31, 43,156, 17,242,116, 58, 29,132,
+ 16,255, 56, 93,215, 93,215,237,186,174,160,222,160, 5,195,232,
+ 116, 58,142,227, 16, 66,138,139,244,100, 12,224,217,132,176,151,
+ 243, 77, 68,224, 7, 0, 0,148, 78,199,108,183, 94,159,221, 9,
+ 134,195,149, 58,206,103,140, 89,214, 1, 0, 32, 60, 88, 93, 1,
+ 120,196,227,185,182,153, 84, 6,132,201,205,205, 77,219,182, 1,
+ 0,230, 69, 50,167,107,167,243,177,239,251,166,105,242, 31,243,
+ 186,110, 1,224, 56, 29, 65,132, 2, 97,178,186,187,251,212,182,
+ 29,199,177, 44,171,209,104,148,203,119,197, 53, 54,190, 42,252,
+ 231,127,253,247,244,143,162,115,192,243, 70, 85, 85,251,117,245,
+ 87,209, 19,202,149, 74,203, 24, 96,219,207, 24, 99,140,177,182,
+ 227, 8, 61,157,136, 19,121, 93,175, 84, 42,150,101, 61,177, 14,
+ 166,101, 87, 24,217, 5, 65, 80,171,237,205,232,151, 37, 9,133,
+ 103, 76, 24, 99,225,230,131, 16,114, 93,151,177,177, 32, 57, 13,
+ 97,242,126,229, 94,169, 88,172, 55, 26,142,227, 60,126,188,255,
+ 240,225,131, 21,227,148, 82,241, 39,177,119, 84, 93,239,207,105,
+ 84,156,219,207,159, 94,125, 93,251,102,254,152,252,230, 34,157,
+ 70,213,221,123,181,189,189, 70,163,113,122,121,212,205, 2, 15,
+ 5, 44,203, 2, 0,132,156,130,177, 98,154,230, 78,249, 46, 99,
+ 227, 39,150, 21,141, 66,225, 25,147,249,188,137,104,134, 70, 40,
+ 125,191,114, 79,215,215, 31, 63,222,111, 52,190,139,147, 80, 40,
+ 29, 2, 0, 52,245,150, 64,223, 22, 92, 52,161, 96, 5, 0, 64,
+ 135,195,133, 70, 87, 94, 71,136,188,113,159, 32,148,174, 84,238,
+ 213,106,123, 79,172, 3, 17, 42,239,202, 57,133, 49, 22, 42, 17,
+ 152, 76,114, 37,129, 21,197,237,186,110,215,157, 95, 87, 23, 32,
+ 20, 94,126, 82, 46,151,103,184,227, 79,127,254,139,232,130,148,
+ 80,140, 97,140, 99, 46,157,230,162, 76,193,202,205, 93, 28,154,
+ 170, 1, 0,200,185,211,242, 18, 23,156, 94,213, 52,205,102,179,
+ 249,162,217, 90,153,192, 39,228, 20,199,233,132,117,213, 39, 65,
+ 85,181, 83, 10,151,214, 78,119,173,130, 97,204, 92, 55, 12,163,
+ 217,108, 10, 45, 72,185, 42,180,157, 14, 33, 30, 66,232, 70, 7,
+ 89, 16, 38, 13,195,112, 28,167, 94,111,136, 86, 67,111,169, 84,
+ 41, 22, 93,215, 93,177,192, 7,156,187,184,254,116, 44, 62, 54,
+ 14,203, 79,230,115, 37,198, 49,147, 69, 62,158, 23,205, 22, 99,
+ 227,105,247,230,213, 89, 49, 76,165, 71,200, 19,235,192,178, 44,
+ 8,225,195,135, 15, 86, 96,197, 67, 8,235,141,198, 83,251, 25,
+ 15,226, 36,162,165,236, 74,229, 30, 99, 44,124, 91,162,196, 25,
+ 10,133,151,159,232,139, 54,106,172, 40, 8, 33,199,113, 78,121,
+ 196,102, 57,216,182,109,219, 54,127,240,100, 56,164,148, 82,140,
+ 241, 57,171,179,150,195, 76,205,159,170,106,167, 60, 70,121,131,
+ 128, 80,186, 90,221,125,252,120,191,217,108, 54,155,205,233, 41,
+ 149, 43, 62,170,192,135,203, 64,161,129,207,204,129, 96,169, 88,
+ 188,254,146,115,237, 4, 14,134,165, 98,241, 36,229, 95, 46,223,
+ 13,252, 96,186, 32, 55, 18, 84,171,187,174,123,196,107, 64, 20,
+ 69,217,218,218, 42, 24,134,160,227, 36, 85, 83, 75,224,199,123,
+ 147, 70, 72, 83, 85,209,242,213, 48, 54,133,166,123,103,120,255,
+ 119,159,255,182,237,116, 8, 33, 92,164,164,211,200,216,220, 76,
+ 31, 87, 21,197, 48,174, 56,199, 43, 20,124,181,204,156,199,237,
+ 148,203,226,138,125, 22, 78, 29,127, 89,244,141, 36,148,211, 67,
+ 169,252,113, 37,126,228,172, 31,219,195, 59,113,218, 58,231,172,
+ 94,219,168,120,233,113,197, 96,122, 56,164, 49, 60,217,184,112,
+ 181, 64,152, 20,167, 23,174,164,170, 83, 32,161, 72, 72, 92, 91,
+ 80, 58,244, 8,129, 48,233, 56, 29, 74,105, 88,120, 41, 33, 9,
+ 69, 66,226,226,132, 50,164,214,113,169,149,174,235, 51,133,130,
+ 18,146, 80, 36, 36, 46, 22,128, 84,171,187, 0, 0,148, 70,171,
+ 116,106,187, 26,120,167,237,200, 22, 86, 18, 18, 18,209,224, 93,
+ 57, 5, 18, 18, 18,145,133, 60,189, 35, 55, 30, 75,185,117, 29,
+ 0, 32,205, 73,115,210,220, 10,155,147, 10, 69, 66, 66, 66, 18,
+ 138,132,132,132, 36, 20, 9, 9, 9, 73, 40, 18, 18, 18, 18,146,
+ 80, 36, 36, 36, 36,161, 72, 72, 72, 72, 66,145,144,144,144,132,
+ 34, 33, 33, 33,113, 37,132,194,216,120,190, 3,139,132,132,132,
+ 4,184,232,195,129, 97, 71,101, 58, 28,174, 76,243, 52, 9, 9,
+ 137, 43, 80, 40, 97,215,194, 82,177,232, 56,142,124,161,166,132,
+ 132,196,146, 10,101,166, 7,106, 26,161,153,206, 64, 18, 18, 18,
+ 18,231, 34,148,249,142,202, 11,187,141, 73, 72, 72, 72, 66,185,
+ 48,155,112, 72, 78,145,144,120,171,208,118, 58,173, 86, 43,157,
+ 78,223,175, 84, 78,122,123,252,218,114,108, 18, 57,167, 80, 58,
+ 156,239,121,202, 97, 24, 70,228, 47,230,122,209,108,141, 25,155,
+ 127,201,112,215,117, 3, 63, 48, 77, 83,208,219,246,193,155,118,
+ 98,111,222, 68,143, 80, 90, 81,148,104, 95,238,239, 17, 66, 60,
+ 162,106, 11,222,171,204, 39, 57,141, 80,228,239, 64,158, 57,248,
+ 19,218, 69,128,219,210,243,250,204,130,228,163, 91, 56,240,203,
+ 204,228, 66, 91,211,255,137,136,249,188,158,112,156,142,239,251,
+ 190,239,159,210,140,248, 12, 66,225,103, 58, 8,161,167, 79,159,
+ 241, 43,188,115,141, 31, 4,225, 21, 8,161,227, 56, 16,194,203,
+ 116,234,161, 67,122, 82,219, 93, 85, 19,178, 52,185,185,105, 78,
+ 161,116,248,248,241,254,194,246,102,145,192, 15, 2,203, 58,224,
+ 205, 85, 49,198, 0, 0,199,241, 0, 0, 11,169,109,105,240, 22,
+ 95,198,208,152,247,171,174,235,214, 27,141,178,128, 86, 71, 11,
+ 239, 29,239,182, 45,200,150, 71, 94,205,116, 23,230, 75,168, 4,
+ 138, 81, 17, 10,241, 8,183,181,240, 76,147, 79, 38, 0, 64, 85,
+ 181,149, 33,148,115,118, 4, 29, 51,182,100,200,163, 40, 74, 50,
+ 249,166, 77,193,120,204,124,223,103,140, 1, 0, 24, 99,132,120,
+ 170,170, 1, 0, 20, 5, 3, 0, 96,242, 82, 78,168,169,234, 31,
+ 255,240,251, 25,113,244,197,151, 95, 66, 8, 69,244,187,216, 54,
+ 183, 58,157, 78,179,213,154,150, 63, 79,172, 3, 8,161,160,214,
+ 98,140,141,107,181, 61,198,152,105,154,165, 98, 49,228,172,182,
+ 211,137,182, 39, 9,239,196,230,186, 46, 0,179, 62,224,186, 71,
+ 0, 0, 65,141, 86, 85, 85, 11, 61,188,235,186,150,117,208,108,
+ 54, 13, 99, 83, 80,227, 52, 66,188,174,235,198,208, 52,246,148,
+ 201,132, 16,178,147, 93,235, 38,178, 73,173,182,247,255,254,239,
+ 255, 17,152, 67,153, 38,102,143,144, 90,109,207,113, 58,196, 35,
+ 188, 9,187,208, 6,244, 79,109,155, 49, 38,174, 49,104,165,114,
+ 239,209,163,175,158, 88, 7,124, 20,188,177,113,185, 92, 22, 36,
+ 212,249,112,230, 55,109, 17,155,155,174,235,205,102,115,198,223,
+ 24, 27, 19,226, 97,140, 99,120,177,115, 94,215, 89,121,108, 89,
+ 150,219,117, 69, 16,138,170,106, 65,224,219,246,179, 24, 8, 69,
+ 85, 87,231,206,243, 0, 0, 10,171, 73, 68, 65, 84, 85,199,113,
+ 230,201,139,247,234, 61, 41, 78,191,161,108,114,121,126,188,112,
+ 165,172,227, 56,245, 70, 67,244, 60,122,132, 56,142,163,235,186,
+ 184,118, 92, 88, 81, 76,211,228, 27, 29, 99, 99,219,182, 49,198,
+ 130,218, 74, 50, 54,230, 81, 97, 60, 61, 31,120,255,105,174, 71,
+ 166, 37, 58, 0, 96,115, 51, 38,113, 46,154,182,138,197, 34,165,
+ 52,134,162,109, 93, 95, 95, 56,153,140, 49, 83, 88, 19,210, 27,
+ 202, 38,224, 66,149,178, 40,141, 98,235,129, 98,219,207, 32,132,
+ 247, 43, 21,161, 86, 74,197,162,235,186,150,117,160,235, 58, 99,
+ 172, 34,236,172,202, 35, 30, 23, 14,226,114,189,103, 70, 61,174,
+ 235,138,139,119, 22,109, 60, 29, 0,128,158, 23,101,110,219,220,
+ 106,181, 90,205, 86, 75,104, 6,157,231,164,116, 93,159,155,204,
+ 35,132,208, 10,180,193, 62, 63,155,248, 65, 64,136, 23, 37,161,
+ 204,231, 77, 5,181, 98,172,215, 27,190,239,151,203,101,209,238,
+ 7, 97,178, 82,185, 87,171,237, 57,142, 99,154,166,184,245, 17,
+ 248, 1, 0, 64, 92, 43,220, 51,163, 30,198,198,174,235, 10,141,
+ 119,134,195, 31,245,130, 71, 94, 5,129, 95,169, 84,132,186, 28,
+ 191,119, 79,109, 91,116,213, 2, 39,148,233,168,199,117, 93,195,
+ 48, 86,146, 77,102, 58,180, 47,158,144,147,247,137, 11, 55,250,
+ 170, 86,119, 53, 85,229,249, 20, 17, 35,164,116,216,108,181,196,
+ 69, 31,243,178,139,127,163,172,196,110, 51, 29,245, 52,155, 77,
+ 215, 61,226, 62, 16, 67,188, 67,233, 79,246, 27,211, 52, 69, 71,
+ 61,154,170,170,170,230, 56,142, 97,108, 10,237, 84,157,215,117,
+ 11,128,112, 50,219, 78,135, 49,102,220,252,147, 29, 74,135, 75,
+ 68, 58,170,170,157,178, 79, 92,152, 80,108,251, 89, 50, 9,199,
+ 99, 81,201,109,158,188, 44, 11, 56,110, 60,201, 28,132, 16, 33,
+ 100,219,118, 62,174,144, 36,158,168, 7, 99, 28, 10,117, 30,239,
+ 20, 68,110,170,211,167, 60,126, 16,212,235,141, 90,109,175, 82,
+ 169, 8, 61, 82,189, 95,185,247,197,151, 95,214,235,223,105, 85,
+ 129,132, 2, 97,114, 58,234,113, 93,119, 53,226, 29,132,210, 23,
+ 205, 43,235,186,126,122, 34, 98,237, 34,107, 20, 79,231, 80, 68,
+ 108,119, 30, 33,174,235,154,166, 41,116,195,153, 49, 87, 42, 22,
+ 85, 77,173,213,246,234,141,198,142, 24, 34, 83,176, 2, 0, 96,
+ 227,113,156,203,101,115,115,211,182,237,174,235,106,170,198,143,
+ 36, 98,163, 75,172, 40,247, 43,149, 63,253,249,207,141, 70, 67,
+ 40,161, 32,148, 46, 21,139,245, 70,163,237,116,132, 10,162, 48,
+ 234,225,147, 89, 22, 83, 91, 16, 63,120,180, 56,205, 41,188,205,
+ 235, 73,114,254,204, 73,190, 0,161, 64,152, 20,148, 52,225, 96,
+ 108,108, 89, 7,177, 29,133, 0, 0, 44,235, 0, 33,196, 7,165,
+ 170,154,184,186, 9,172, 96,190,179,237,196,165,188,184, 80,183,
+ 109,219,117,143, 24, 27,115,151,136,115,165,114,242,162,148,138,
+ 54,100,154,102,179,213,106, 52, 26, 66, 85,109, 24,245,240,201,
+ 204,199, 59,153,113,114,202, 37,247,242,107,244,198,182,102,179,
+ 73, 41,141, 33, 23,203, 81,175, 55, 40,165,225,201, 14,159,214,
+ 176,252, 55,242,141, 84, 85, 53, 74,233,139,102, 43, 78, 65,139,
+ 49, 38,132, 16, 66,226,247, 1,238,120, 8,161, 24,152,171, 92,
+ 46, 83, 74,155,205,151, 49, 68, 61,162,115,219, 87,197, 41, 81,
+ 229,152,175, 11,161, 80, 58,172, 55, 26,177, 85, 49,243,212,239,
+ 116,157, 11, 66,105,195, 48, 8,241,218, 78, 71,132,197,157,157,
+ 187, 0, 0,219,182,235,245, 6,119,182, 48,221, 48,253, 99,228,
+ 81, 15,165,148, 16,162,199,155, 30,242,131,160,182,183, 7, 0,
+ 48, 98, 41,123, 41, 24,155, 24,227,243, 28,106, 94, 50,234, 97,
+ 140,185,174, 27, 91, 45,207, 95, 31,239,255,233,207,127,241, 8,
+ 185, 65,156,178,118, 77, 8,133, 43, 46, 66,188,249, 83,171, 82,
+ 177, 24,121,168,197,223, 14, 53, 83,101,191, 83, 46,187,174, 43,
+ 40, 59,139, 21,229,225,195, 7,150,117, 80,111, 52,234,141, 6,
+ 198, 56,153,132,220, 7,248,193,153,184,168,135, 82, 90, 20, 31,
+ 69,206,223, 59, 93,215,133,198,200,211, 40,151,239, 10, 58,118,
+ 156,137,122,226,212,122, 60,149, 78, 60, 18, 79, 74,241,126,229,
+ 30,132,112, 69, 8, 69,213,212, 18, 40,158,244,171,200,213,184,
+ 166,222, 50,205, 59, 51,194,149,151,165, 4,126, 64,135, 20, 67,
+ 69,196,138,212, 62,215,218,142, 67, 8,225,170,196, 48, 12, 69,
+ 81,120,134, 69, 80,212, 83, 46,151,199,140,137,246,129,153,180,
+ 87, 18, 66, 77, 83, 5,157,131,148,138,197,244, 92, 36,165,169,
+ 42, 31,105,132,171,133,175,201,176,176, 0,194,100,165, 82, 97,
+ 140, 77, 47,155,133,255, 76,116, 44, 89, 38,132,196, 89,240,114,
+ 249, 28,223, 59,251,251,127,139,231,127,149, 61,238,165, 57,105,
+ 110,229,205,201, 54, 26, 18, 18, 18,146, 80, 36, 36, 36, 36,161,
+ 72, 72, 72,172, 48,222,105, 59,135,114, 22, 36, 36, 36,164, 66,
+ 145,144,144,184, 94, 88,147,201,237,155,104, 78, 66, 46,149,235,
+ 105, 78, 42, 20, 9, 9, 9, 73, 40, 18, 18, 18,146, 80, 36, 36,
+ 36, 36,161, 72, 72, 72, 72,156,141, 53, 57, 5, 18, 18,145, 32,
+ 147,201, 96,140, 51, 31,102, 0, 0,244, 95,180,215,235,141, 70,
+ 35,169, 80, 36, 36, 36,150, 4, 99,172,253,125,187,253,125,123,
+ 50,153, 20, 62, 46,200,144, 71, 66, 98, 53,161,105, 90,161, 32,
+ 214,195, 7,131, 65,175,215,163,148, 82, 74,123,189, 94, 34,145,
+ 136,225,253, 82,146, 80, 36, 36, 36, 36,161, 72, 72,220, 64,228,
+ 114,185,171, 18, 68,236,223, 44,134, 87,234, 74, 66,145,144,136,
+ 15,217, 91,217,124, 62, 31,179,209,124, 62,159,249, 48,115,120,
+ 248, 54, 62, 37, 39, 79,121, 36,110, 62,107,100,179,137, 68,226,
+ 164,223,226,143, 48, 0, 32,146,198,189,231,212, 38,248, 35,252,
+ 178,245,242, 45, 60,226,145,132, 34,177, 18,113,205,250, 25,113,
+ 77,230,195,204,224,245, 32,158,127, 6, 33,228,255,211,127, 59,
+ 217, 68, 18,138,196, 42,224,101,235,229, 73, 10,165,240,113, 97,
+ 50,153,180,191,111,103, 50,153,203,191,129,249, 60,232,245,122,
+ 147,201,228,173,189, 23,146, 80, 36,110, 60, 78,145, 3,156, 77,
+ 70,163, 81, 38,147,137,231,159,225,180, 21, 91,132, 37, 9,229,
+ 122,193, 15, 2,207, 35, 99,198, 0, 0, 10, 86, 52, 85, 91,153,
+ 246,198, 18, 0, 0,206, 38,209,126, 38,165, 67,199,113, 84, 77,
+ 93,216,221, 98, 99,115, 3, 0,240,252,219,231,146, 80,222, 46,
+ 116, 93,215,182,159, 81, 74, 33,132,138,130,199, 99, 86,111, 52,
+ 0, 0,166,105,150,138, 69, 73, 43, 43, 47, 94, 46,179,114,234,
+ 141, 70, 85, 91,220, 3,184,255,170,255, 54, 79,248, 91, 74, 40,
+ 79,172, 3,199,113, 12,195,168,238,238, 78,183, 89,105, 59, 29,
+ 219,182, 9, 33,213,221, 93,201, 41,171, 4,198, 88, 84,228,210,
+ 106,181, 16, 66, 39, 53,223,234,245,122,111,243, 60,191,141,117,
+ 40,245,122,195,117,221,106,117,247,126,229,222, 76,175,175,130,
+ 177, 89,173,238, 82, 74,159, 88,150,116,194,149,138,109,125, 63,
+ 18, 87,247,131,128, 82,106,196,213,141,116, 5, 21, 10,132, 16,
+ 99, 12, 0,240,188, 55,189, 99, 49,198, 16, 66,254, 99,248,219,
+ 169, 8,147, 46, 81, 32,232, 17, 66, 60,146,132,176, 96, 24,116,
+ 72,221,174,171,231,117,222,122,142, 55, 24,223, 54,183,234,245,
+ 6, 0,192, 48, 12,206, 2,126, 16,184, 93, 23, 0,112,161,126,
+ 151,188,137,114,185, 92,230, 59,140, 31, 4,205,102,139,210, 33,
+ 0, 0, 99, 69, 85,111,229,117,189, 92, 46, 91,150,229, 7,129,
+ 160,222,119, 18, 55, 23,205,102,139, 47,194, 21, 27, 87, 84,110,
+ 126, 54,161,100, 50,153,236,173,108, 34,145, 24, 12, 6, 92, 52,
+ 98,140,209, 7, 40,180,164,221,214,126, 66, 13,255,240, 46, 74,
+ 40, 30, 33, 97, 99,218,225,112, 88, 42, 22,155,173,150, 71, 94,
+ 253,186,250, 43, 63, 8,108,219,230,157, 46,121,142,131,141,199,
+ 188, 97,162,227,116,154,205,230, 69, 9,165,222,104, 32,132,182,
+ 205, 45, 30,224, 88,150,165,170,154,166,222, 2, 0, 52, 91, 45,
+ 223, 15,242,186, 94, 48, 54,109,219,118,187,174, 36, 20,137, 25,
+ 184,174,171,170,218,140,176, 93, 1, 68,229,230,103, 19, 74, 54,
+ 155, 29,188, 30, 32,132, 48,198,243,162,145, 82,250,252,219,231,
+ 8,161,194,199, 5,239, 31, 94, 72,111, 23, 2,241, 8, 0,160,
+ 90,221,229, 93,126, 33, 76,154, 91, 91,245, 70,195, 35,196,113,
+ 58, 16, 66,211, 52,127,252,227,227,102,244,174,235, 34,132, 46,
+ 74, 94,174,235,154, 91, 91, 0, 0,198,198,182,109,235,186,254,
+ 203,135, 15,222,252,234,232, 40,204,155, 40, 10,246,200,171,146,
+ 116, 32,137, 41,180,157, 14, 99,204, 48, 86, 48,222,137,202,205,
+ 207,200,161,164, 82, 41,248, 30,164,148, 14, 6, 3, 94,194, 44,
+ 2,188,221, 52, 23,147,220,165, 77,211,132, 16,218,246, 51,199,
+ 113,204,173,173,208,207,117, 93,247,125,159,210, 33, 15,101,213,
+ 11,118,165,247,131,128, 29,247,211,238,186, 46, 99,108, 90,221,
+ 248,190, 47, 78,146, 60,181,159,125, 93,251,230,204, 63,251,186,
+ 246,205,121,254, 76,226,170,228, 9,132, 80,116,231,249,248, 17,
+ 161,155,159, 65, 40, 60,112, 26, 12, 6,148,210, 68, 34, 33,168,
+ 58,168, 96,108,154,166,233,186,238, 23, 95,126,233, 7, 1,167,
+ 149,114,185,236,251,254,140, 60,193,138, 2, 33,244, 8,241, 60,
+ 130, 49, 70,233,139, 41,207,233,114,163, 33,165,252, 3,227,185,
+ 103,190, 31, 16,114,182,124, 35,196, 59,207,159, 73,196, 15, 74,
+ 135,174,235,234,186,190,122,199,127, 17,186,249,218,153,145, 21,
+ 0,224,147,226, 39,225,143,131,129,144,103, 34,118,202,119, 13,
+ 99,243,209,163,175,234,245, 6,143, 65, 10,198,166,101, 89,138,
+ 130,103,238,159,174,235,174,235, 14,135, 67,125,125,253,242,118,
+ 25, 27,243,207,231,121,217, 31,233,102, 40, 36,147, 47,213,199,
+ 205, 69,215,117, 1, 0,186,190,190,122, 67,139,208,205,215,206,
+ 20, 66,254, 63,125,190,177, 35,132, 50, 31,102, 64,247,205,111,
+ 249,219,168, 38,147,201,229,143,247,249,173, 58,231,163, 22,170,
+ 170,218,182,205, 24,171, 84,238,241, 83,158,243, 99,186, 44, 90,
+ 207,235,245, 70,163,237, 56, 60, 65, 91,111, 52, 32,132,116, 56,
+ 4, 0,120,132, 80, 74, 69,100,242,165,250,184,185,232,116, 58,
+ 8,161, 85,141,119,162,114,243,181, 51,133,144,231,121,220, 18,
+ 198, 56,255, 65, 62,148, 67,252,149,153,244, 95,180,221,110, 95,
+ 114, 72,129, 31,240, 19, 28, 8,161,105,110,157,254,199,121, 93,
+ 183, 44, 11, 33,132, 21,229,162,132,194, 35, 38, 66, 94,229,117,
+ 29, 43,138, 97, 24,182,109,119, 58, 29,254, 91,126, 90, 76,233,
+ 48, 8,124,211, 52,163,205,228,239,236,220,125,107,159,239, 88,
+ 1,248, 65,224,251,254,116,244,189, 98,241, 78, 84,110,190,118,
+ 106,216,239, 15, 6,131,208, 13, 6,131, 65,251,251, 54, 99,140,
+ 191, 47,147, 95,228, 15, 86,142, 70, 35,254,171,229,134, 84, 42,
+ 21,245,188,206, 24,195, 63, 13,112,170,213,221,105,217, 82,173,
+ 238,162, 52,130, 48, 25, 94, 55, 12,131,103, 88,207, 15, 93,215,
+ 29,199,225,197,245,247, 43,247,116,125, 61,240,131, 52, 66, 5,
+ 99, 19, 0,128, 80,154,120,164, 84,250, 68,187, 96,186,247, 60,
+ 92, 38,221,242,230,194,113, 58, 0, 0,126, 62, 24, 27,158, 88,
+ 7,148, 14,119,118,238, 10, 93, 60,209,186,249,105,132, 50, 35,
+ 114, 38,147,201, 73,103,180,167,252,234, 50,254, 54,227,213,225,
+ 143,225, 55, 8,165, 47,170, 35,118,202,101,215,117,107,123,123,
+ 188,184, 62,175,235,211, 34, 86, 83,213,200,169, 68, 98, 37, 8,
+ 197,193, 24,199, 92,126,226, 56, 14,132, 80,244, 86, 20,173,155,
+ 191,117,165,247, 92,224, 80, 74,191,248,242,203,122,189,225, 29,
+ 87,181,120,132,180,157,206, 19,235,128, 31, 51, 73, 72,132,160,
+ 116,104,110,109,149,203,119,227, 52,202, 87,166,126,211, 82, 54,
+ 111,227,195,129, 88, 81,126,247,249,231,245, 70,163,217,106,241,
+ 220,205,116, 64, 4,147, 80,186,144,196, 52, 16, 74, 95,168, 26,
+ 59,162, 72, 36, 0, 0,156,153, 82,148,132,114, 93,116,202, 78,
+ 249,238, 78,249, 46,165, 67, 58,164,128, 63,173, 32,211, 28, 18,
+ 215, 6, 65, 16, 96,140,111,220,154,124,219, 95,176,180, 68, 22,
+ 70, 66, 34, 6,220,175,220,187,137,255,182,108,163, 33, 33, 33,
+ 17, 25,254, 63,181, 34,148,206,219,178, 22,153, 0, 0, 0, 0,
+ 73, 69, 78, 68,174, 66, 96,130
+};
+
+
+static const FileEntry _file_entries[] =
+{
+
+ { "arrow_down.png", _data_arrow_down_png, 3438 },
+ { "arrow_left.png", _data_arrow_left_png, 4122 },
+ { "arrow_right.png", _data_arrow_right_png, 4147 },
+ { "arrow_up.png", _data_arrow_up_png, 3493 },
+ { "back.png", _data_back_png, 3564 },
+ { "end.png", _data_end_png, 3562 },
+ { "home.png", _data_home_png, 3578 },
+ { "key.png", _data_key_png, 2857 },
+ { "layout", _data_layout, 7714 },
+ { "menu.png", _data_menu_png, 3079 },
+ { "power.png", _data_power_png, 3782 },
+ { "select.png", _data_select_png, 3374 },
+ { "send.png", _data_send_png, 3561 },
+ { "spacebar.png", _data_spacebar_png, 2916 },
+ { "volume_down.png", _data_volume_down_png, 3586 },
+ { "volume_up.png", _data_volume_up_png, 3856 },
+ { "device.png", _data_device_png, 45511 },
+ { "keyboard.png", _data_keyboard_png, 11032 },
+ { NULL, NULL, 0 }
+};
+
diff --git a/android/skin/file.c b/android/skin/file.c
new file mode 100644
index 0000000..b0cb9cf
--- /dev/null
+++ b/android/skin/file.c
@@ -0,0 +1,693 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/file.h"
+#include "android/utils/path.h"
+#include "android/charmap.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/system.h"
+#include "android/utils/debug.h"
+
+//#include "qemu-common.h"
+
+/** UTILITY ROUTINES
+ **/
+static SkinImage*
+skin_image_find_in( const char* dirname, const char* filename )
+{
+ char buffer[1024];
+ char* p = buffer;
+ char* end = p + sizeof(buffer);
+
+ p = bufprint( p, end, "%s" PATH_SEP "%s", dirname, filename );
+ if (p >= end)
+ return SKIN_IMAGE_NONE;
+
+ return skin_image_find_simple(buffer);
+}
+
+/** SKIN BACKGROUND
+ **/
+
+static void
+skin_background_done( SkinBackground* background )
+{
+ if (background->image)
+ skin_image_unref(&background->image);
+}
+
+static int
+skin_background_init_from( SkinBackground* background,
+ AConfig* node,
+ const char* basepath )
+{
+ const char* img = aconfig_str(node, "image", NULL);
+ int x = aconfig_int(node, "x", 0);
+ int y = aconfig_int(node, "y", 0);
+
+ background->valid = 0;
+
+ if (img == NULL) /* no background */
+ return -1;
+
+ background->image = skin_image_find_in( basepath, img );
+ if (background->image == SKIN_IMAGE_NONE) {
+ background->image = NULL;
+ return -1;
+ }
+
+ background->rect.pos.x = x;
+ background->rect.pos.y = y;
+ background->rect.size.w = skin_image_w( background->image );
+ background->rect.size.h = skin_image_h( background->image );
+
+ background->valid = 1;
+
+ return 0;
+}
+
+/** SKIN DISPLAY
+ **/
+
+static void
+skin_display_done( SkinDisplay* display )
+{
+ qframebuffer_done( display->qfbuff );
+}
+
+static int
+skin_display_init_from( SkinDisplay* display, AConfig* node )
+{
+ display->rect.pos.x = aconfig_int(node, "x", 0);
+ display->rect.pos.y = aconfig_int(node, "y", 0);
+ display->rect.size.w = aconfig_int(node, "width", 0);
+ display->rect.size.h = aconfig_int(node, "height", 0);
+ display->rotation = aconfig_unsigned(node, "rotation", SKIN_ROTATION_0);
+
+ display->valid = ( display->rect.size.w > 0 && display->rect.size.h > 0 );
+
+ if (display->valid) {
+ SkinRect r;
+ skin_rect_rotate( &r, &display->rect, -display->rotation );
+ qframebuffer_init( display->qfbuff,
+ r.size.w,
+ r.size.h,
+ 0,
+ QFRAME_BUFFER_RGB565 );
+
+ qframebuffer_fifo_add( display->qfbuff );
+ }
+ return display->valid ? 0 : -1;
+}
+
+/** SKIN BUTTON
+ **/
+
+typedef struct
+{
+ const char* name;
+ AndroidKeyCode code;
+} KeyInfo;
+
+static KeyInfo _keyinfo_table[] = {
+ { "dpad-up", kKeyCodeDpadUp },
+ { "dpad-down", kKeyCodeDpadDown },
+ { "dpad-left", kKeyCodeDpadLeft },
+ { "dpad-right", kKeyCodeDpadRight },
+ { "dpad-center", kKeyCodeDpadCenter },
+ { "soft-left", kKeyCodeSoftLeft },
+ { "soft-right", kKeyCodeSoftRight },
+ { "volume-up", kKeyCodeVolumeUp },
+ { "volume-down", kKeyCodeVolumeDown },
+ { "power", kKeyCodePower },
+ { "home", kKeyCodeHome },
+ { "back", kKeyCodeBack },
+ { "del", kKeyCodeDel },
+ { "0", kKeyCode0 },
+ { "1", kKeyCode1 },
+ { "2", kKeyCode2 },
+ { "3", kKeyCode3 },
+ { "4", kKeyCode4 },
+ { "5", kKeyCode5 },
+ { "6", kKeyCode6 },
+ { "7", kKeyCode7 },
+ { "8", kKeyCode8 },
+ { "9", kKeyCode9 },
+ { "star", kKeyCodeStar },
+ { "pound", kKeyCodePound },
+ { "phone-dial", kKeyCodeCall },
+ { "phone-hangup", kKeyCodeEndCall },
+ { "q", kKeyCodeQ },
+ { "w", kKeyCodeW },
+ { "e", kKeyCodeE },
+ { "r", kKeyCodeR },
+ { "t", kKeyCodeT },
+ { "y", kKeyCodeY },
+ { "u", kKeyCodeU },
+ { "i", kKeyCodeI },
+ { "o", kKeyCodeO },
+ { "p", kKeyCodeP },
+ { "a", kKeyCodeA },
+ { "s", kKeyCodeS },
+ { "d", kKeyCodeD },
+ { "f", kKeyCodeF },
+ { "g", kKeyCodeG },
+ { "h", kKeyCodeH },
+ { "j", kKeyCodeJ },
+ { "k", kKeyCodeK },
+ { "l", kKeyCodeL },
+ { "DEL", kKeyCodeDel },
+ { "z", kKeyCodeZ },
+ { "x", kKeyCodeX },
+ { "c", kKeyCodeC },
+ { "v", kKeyCodeV },
+ { "b", kKeyCodeB },
+ { "n", kKeyCodeN },
+ { "m", kKeyCodeM },
+ { "COMMA", kKeyCodeComma },
+ { "PERIOD", kKeyCodePeriod },
+ { "ENTER", kKeyCodeNewline },
+ { "AT", kKeyCodeAt },
+ { "SPACE", kKeyCodeSpace },
+ { "SLASH", kKeyCodeSlash },
+ { "CAP", kKeyCodeCapLeft },
+ { "SYM", kKeyCodeSym },
+ { "ALT", kKeyCodeAltLeft },
+ { "ALT2", kKeyCodeAltRight },
+ { "CAP2", kKeyCodeCapRight },
+ { 0, 0 },
+};
+
+static unsigned
+keyinfo_lookup_code(const char *name)
+{
+ KeyInfo *ki = _keyinfo_table;
+ while(ki->name) {
+ if(!strcmp(name, ki->name))
+ return ki->code;
+ ki++;
+ }
+ return 0;
+}
+
+
+static void
+skin_button_free( SkinButton* button )
+{
+ if (button) {
+ skin_image_unref( &button->image );
+ AFREE(button);
+ }
+}
+
+static SkinButton*
+skin_button_create_from( AConfig* node, const char* basepath )
+{
+ SkinButton* button;
+ ANEW0(button);
+ if (button) {
+ const char* img = aconfig_str(node, "image", NULL);
+ int x = aconfig_int(node, "x", 0);
+ int y = aconfig_int(node, "y", 0);
+
+ button->name = node->name;
+ button->rect.pos.x = x;
+ button->rect.pos.y = y;
+
+ if (img != NULL)
+ button->image = skin_image_find_in( basepath, img );
+
+ if (button->image == SKIN_IMAGE_NONE) {
+ skin_button_free(button);
+ return NULL;
+ }
+
+ button->rect.size.w = skin_image_w( button->image );
+ button->rect.size.h = skin_image_h( button->image );
+
+ button->keycode = keyinfo_lookup_code( button->name );
+ if (button->keycode == 0) {
+ dprint( "Warning: skin file button uses unknown key name '%s'", button->name );
+ }
+ }
+ return button;
+}
+
+/** SKIN PART
+ **/
+
+static void
+skin_part_free( SkinPart* part )
+{
+ if (part) {
+ skin_background_done( part->background );
+ skin_display_done( part->display );
+
+ SKIN_PART_LOOP_BUTTONS(part,button)
+ skin_button_free(button);
+ SKIN_PART_LOOP_END
+ part->buttons = NULL;
+ AFREE(part);
+ }
+}
+
+static SkinLocation*
+skin_location_create_from_v2( AConfig* node, SkinPart* parts )
+{
+ const char* partname = aconfig_str(node, "name", NULL);
+ int x = aconfig_int(node, "x", 0);
+ int y = aconfig_int(node, "y", 0);
+ SkinRotation rot = aconfig_int(node, "rotation", SKIN_ROTATION_0);
+ SkinPart* part;
+ SkinLocation* location;
+
+ if (partname == NULL) {
+ dprint( "### WARNING: ignoring part location without 'name' element" );
+ return NULL;
+ }
+
+ for (part = parts; part; part = part->next)
+ if (!strcmp(part->name, partname))
+ break;
+
+ if (part == NULL) {
+ dprint( "### WARNING: ignoring part location with unknown name '%s'", partname );
+ return NULL;
+ }
+
+ ANEW0(location);
+ location->part = part;
+ location->anchor.x = x;
+ location->anchor.y = y;
+ location->rotation = rot;
+
+ return location;
+}
+
+static SkinPart*
+skin_part_create_from_v1( AConfig* root, const char* basepath )
+{
+ SkinPart* part;
+ AConfig* node;
+ SkinBox box;
+
+ ANEW0(part);
+ part->name = root->name;
+
+ node = aconfig_find(root, "background");
+ if (node)
+ skin_background_init_from(part->background, node, basepath);
+
+ node = aconfig_find(root, "display");
+ if (node)
+ skin_display_init_from(part->display, node);
+
+ node = aconfig_find(root, "button");
+ if (node) {
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinButton* button = skin_button_create_from(node, basepath);
+
+ if (button != NULL) {
+ button->next = part->buttons;
+ part->buttons = button;
+ }
+ }
+ }
+
+ skin_box_minmax_init( &box );
+
+ if (part->background->valid)
+ skin_box_minmax_update( &box, &part->background->rect );
+
+ if (part->display->valid)
+ skin_box_minmax_update( &box, &part->display->rect );
+
+ SKIN_PART_LOOP_BUTTONS(part, button)
+ skin_box_minmax_update( &box, &button->rect );
+ SKIN_PART_LOOP_END
+
+ if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
+ skin_part_free(part);
+ part = NULL;
+ }
+
+ return part;
+}
+
+static SkinPart*
+skin_part_create_from_v2( AConfig* root, const char* basepath )
+{
+ SkinPart* part;
+ AConfig* node;
+ SkinBox box;
+
+ ANEW0(part);
+ part->name = root->name;
+
+ node = aconfig_find(root, "background");
+ if (node)
+ skin_background_init_from(part->background, node, basepath);
+
+ node = aconfig_find(root, "display");
+ if (node)
+ skin_display_init_from(part->display, node);
+
+ node = aconfig_find(root, "buttons");
+ if (node) {
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinButton* button = skin_button_create_from(node, basepath);
+
+ if (button != NULL) {
+ button->next = part->buttons;
+ part->buttons = button;
+ }
+ }
+ }
+
+ skin_box_minmax_init( &box );
+
+ if (part->background->valid)
+ skin_box_minmax_update( &box, &part->background->rect );
+
+ if (part->display->valid)
+ skin_box_minmax_update( &box, &part->display->rect );
+
+ SKIN_PART_LOOP_BUTTONS(part, button)
+ skin_box_minmax_update( &box, &button->rect );
+ SKIN_PART_LOOP_END
+
+ if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
+ skin_part_free(part);
+ part = NULL;
+ }
+ return part;
+}
+
+/** SKIN LAYOUT
+ **/
+
+static void
+skin_layout_free( SkinLayout* layout )
+{
+ if (layout) {
+ SKIN_LAYOUT_LOOP_LOCS(layout,loc)
+ AFREE(loc);
+ SKIN_LAYOUT_LOOP_END
+ layout->locations = NULL;
+ AFREE(layout);
+ }
+}
+
+SkinDisplay*
+skin_layout_get_display( SkinLayout* layout )
+{
+ SKIN_LAYOUT_LOOP_LOCS(layout,loc)
+ SkinPart* part = loc->part;
+ if (part->display->valid) {
+ return part->display;
+ }
+ SKIN_LAYOUT_LOOP_END
+ return NULL;
+}
+
+SkinRotation
+skin_layout_get_dpad_rotation( SkinLayout* layout )
+{
+ SKIN_LAYOUT_LOOP_LOCS(layout, loc)
+ SkinPart* part = loc->part;
+ SKIN_PART_LOOP_BUTTONS(part,button)
+ if (button->keycode == kKeyCodeDpadUp)
+ return loc->rotation;
+ SKIN_PART_LOOP_END
+ SKIN_LAYOUT_LOOP_END
+
+ return SKIN_ROTATION_0;
+}
+
+
+static int
+skin_layout_event_decode( const char* event, int *ptype, int *pcode, int *pvalue )
+{
+ typedef struct {
+ const char* name;
+ int value;
+ } EventName;
+
+ static const EventName _event_names[] = {
+ { "EV_SW", 0x05 },
+ { NULL, 0 },
+ };
+
+ const char* x = strchr(event, ':');
+ const char* y = NULL;
+ const EventName* ev = _event_names;
+
+ if (x != NULL)
+ y = strchr(x+1, ':');
+
+ if (x == NULL || y == NULL) {
+ dprint( "### WARNING: invalid skin layout event format: '%s', should be '<TYPE>:<CODE>:<VALUE>'", event );
+ return -1;
+ }
+
+ for ( ; ev->name != NULL; ev++ )
+ if (!memcmp( event, ev->name, x - event ) && ev->name[x-event] == 0)
+ break;
+
+ if (!ev->name) {
+ dprint( "### WARNING: unrecognized skin layout event name: %.*s", x-event, event );
+ return -1;
+ }
+
+ *ptype = ev->value;
+ *pcode = strtol(x+1, NULL, 0);
+ *pvalue = strtol(y+1, NULL, 0);
+ return 0;
+}
+
+static SkinLayout*
+skin_layout_create_from_v2( AConfig* root, SkinPart* parts )
+{
+ SkinLayout* layout;
+ int width, height;
+ SkinLocation** ptail;
+ AConfig* node;
+
+ ANEW0(layout);
+
+ width = aconfig_int( root, "width", 400 );
+ height = aconfig_int( root, "height", 400 );
+
+ node = aconfig_find( root, "event" );
+ if (node != NULL) {
+ skin_layout_event_decode( node->value,
+ &layout->event_type,
+ &layout->event_code,
+ &layout->event_value );
+ } else {
+ layout->event_type = 0x05; /* close keyboard by default */
+ layout->event_code = 0;
+ layout->event_value = 1;
+ }
+
+ layout->name = root->name;
+ layout->color = aconfig_unsigned( root, "color", 0x808080 ) | 0xff000000;
+ ptail = &layout->locations;
+
+ for (node = root->first_child; node; node = node->next)
+ {
+ if (!memcmp(node->name, "part", 4)) {
+ SkinLocation* location = skin_location_create_from_v2( node, parts );
+ if (location == NULL) {
+ continue;
+ }
+ *ptail = location;
+ ptail = &location->next;
+ }
+ }
+
+ if (layout->locations == NULL)
+ goto Fail;
+
+ layout->size.w = width;
+ layout->size.h = height;
+
+ return layout;
+
+Fail:
+ skin_layout_free(layout);
+ return NULL;
+}
+
+/** SKIN FILE
+ **/
+
+static int
+skin_file_load_from_v1( SkinFile* file, AConfig* aconfig, const char* basepath )
+{
+ SkinPart* part;
+ SkinLayout* layout;
+ SkinLayout** ptail = &file->layouts;
+ SkinLocation* location;
+ int nn;
+
+ file->parts = part = skin_part_create_from_v1( aconfig, basepath );
+ if (part == NULL)
+ return -1;
+
+ for (nn = 0; nn < 2; nn++)
+ {
+ ANEW0(layout);
+
+ layout->color = 0xff808080;
+
+ ANEW0(location);
+
+ layout->event_type = 0x05; /* close keyboard by default */
+ layout->event_code = 0;
+ layout->event_value = 1;
+
+ location->part = part;
+ switch (nn) {
+ case 0:
+ location->anchor.x = 0;
+ location->anchor.y = 0;
+ location->rotation = SKIN_ROTATION_0;
+ layout->size = part->rect.size;
+ break;
+
+#if 0
+ case 1:
+ location->anchor.x = part->rect.size.h;
+ location->anchor.y = 0;
+ location->rotation = SKIN_ROTATION_90;
+ layout->size.w = part->rect.size.h;
+ layout->size.h = part->rect.size.w;
+ layout->event_value = 0;
+ break;
+
+ case 2:
+ location->anchor.x = part->rect.size.w;
+ location->anchor.y = part->rect.size.h;
+ location->rotation = SKIN_ROTATION_180;
+ layout->size = part->rect.size;
+ break;
+#endif
+ default:
+ location->anchor.x = 0;
+ location->anchor.y = part->rect.size.w;
+ location->rotation = SKIN_ROTATION_270;
+ layout->size.w = part->rect.size.h;
+ layout->size.h = part->rect.size.w;
+ layout->event_value = 0;
+ break;
+ }
+ layout->locations = location;
+
+ *ptail = layout;
+ ptail = &layout->next;
+ }
+ return 0;
+}
+
+static int
+skin_file_load_from_v2( SkinFile* file, AConfig* aconfig, const char* basepath )
+{
+ AConfig* node;
+
+ /* first, load all parts */
+ node = aconfig_find(aconfig, "parts");
+ if (node == NULL)
+ return -1;
+ else
+ {
+ SkinPart** ptail = &file->parts;
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinPart* part = skin_part_create_from_v2( node, basepath );
+ if (part == NULL) {
+ dprint( "## WARNING: can't load part '%s' from skin\n", node->name ? "<NULL>" : node->name );
+ continue;
+ }
+ part->next = NULL;
+ *ptail = part;
+ ptail = &part->next;
+ }
+ }
+
+ if (file->parts == NULL)
+ return -1;
+
+ /* then load all layouts */
+ node = aconfig_find(aconfig, "layouts");
+ if (node == NULL)
+ return -1;
+ else
+ {
+ SkinLayout** ptail = &file->layouts;
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinLayout* layout = skin_layout_create_from_v2( node, file->parts );
+ if (layout == NULL) {
+ dprint( "## WARNING: ignoring layout in skin file" );
+ continue;
+ }
+ *ptail = layout;
+ layout->next = NULL;
+ ptail = &layout->next;
+ }
+ }
+ if (file->layouts == NULL)
+ return -1;
+
+ return 0;
+}
+
+SkinFile*
+skin_file_create_from_aconfig( AConfig* aconfig, const char* basepath )
+{
+ SkinFile* file;
+
+ ANEW0(file);
+ if ( aconfig_find(aconfig, "parts") != NULL) {
+ if (skin_file_load_from_v2( file, aconfig, basepath ) < 0) {
+ skin_file_free( file );
+ file = NULL;
+ }
+ }
+ else {
+ if (skin_file_load_from_v1( file, aconfig, basepath ) < 0) {
+ skin_file_free( file );
+ file = NULL;
+ }
+ }
+ return file;
+}
+
+void
+skin_file_free( SkinFile* file )
+{
+ if (file) {
+ SKIN_FILE_LOOP_LAYOUTS(file,layout)
+ skin_layout_free(layout);
+ SKIN_FILE_LOOP_END_LAYOUTS
+ file->layouts = NULL;
+
+ SKIN_FILE_LOOP_PARTS(file,part)
+ skin_part_free(part);
+ SKIN_FILE_LOOP_END_PARTS
+ file->parts = NULL;
+
+ AFREE(file);
+ }
+}
diff --git a/android/skin/file.h b/android/skin/file.h
new file mode 100644
index 0000000..8f95368
--- /dev/null
+++ b/android/skin/file.h
@@ -0,0 +1,132 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_FILE_H
+#define _ANDROID_SKIN_FILE_H
+
+#include "android/skin/image.h"
+#include "android/config.h"
+#include "framebuffer.h"
+
+/** Layout
+ **/
+
+typedef struct SkinBackground {
+ SkinImage* image;
+ SkinRect rect;
+ char valid;
+} SkinBackground;
+
+typedef struct SkinDisplay {
+ SkinRect rect; /* display rectangle */
+ SkinRotation rotation; /* framebuffer rotation */
+ char valid;
+ QFrameBuffer qfbuff[1];
+} SkinDisplay;
+
+typedef struct SkinButton {
+ struct SkinButton* next;
+ const char* name;
+ SkinImage* image;
+ SkinRect rect;
+ unsigned keycode;
+} SkinButton;
+
+typedef struct SkinPart {
+ struct SkinPart* next;
+ const char* name;
+ SkinBackground background[1];
+ SkinDisplay display[1];
+ SkinButton* buttons;
+ SkinRect rect; /* bounding box of all parts */
+} SkinPart;
+
+#define SKIN_PART_LOOP_BUTTONS(part,button) \
+ do { \
+ SkinButton* __button = (part)->buttons; \
+ while (__button != NULL) { \
+ SkinButton* __button_next = __button->next; \
+ SkinButton* button = __button;
+
+#define SKIN_PART_LOOP_END \
+ __button = __button_next; \
+ } \
+ } while (0);
+
+typedef struct SkinLocation {
+ SkinPart* part;
+ SkinPos anchor;
+ SkinRotation rotation;
+ struct SkinLocation* next;
+} SkinLocation;
+
+typedef struct SkinLayout {
+ struct SkinLayout* next;
+ const char* name;
+ unsigned color;
+ int event_type;
+ int event_code;
+ int event_value;
+ SkinSize size;
+ SkinLocation* locations;
+} SkinLayout;
+
+#define SKIN_LAYOUT_LOOP_LOCS(layout,loc) \
+ do { \
+ SkinLocation* __loc = (layout)->locations; \
+ while (__loc != NULL) { \
+ SkinLocation* __loc_next = (__loc)->next; \
+ SkinLocation* loc = __loc;
+
+#define SKIN_LAYOUT_LOOP_END \
+ __loc = __loc_next; \
+ } \
+ } while (0);
+
+extern SkinDisplay* skin_layout_get_display( SkinLayout* layout );
+
+extern SkinRotation skin_layout_get_dpad_rotation( SkinLayout* layout );
+
+typedef struct SkinFile {
+ SkinPart* parts;
+ SkinLayout* layouts;
+ int num_parts;
+ int num_layouts;
+} SkinFile;
+
+#define SKIN_FILE_LOOP_LAYOUTS(file,layout) \
+ do { \
+ SkinLayout* __layout = (file)->layouts; \
+ while (__layout != NULL) { \
+ SkinLayout* __layout_next = __layout->next; \
+ SkinLayout* layout = __layout;
+
+#define SKIN_FILE_LOOP_END_LAYOUTS \
+ __layout = __layout_next; \
+ } \
+ } while (0);
+
+#define SKIN_FILE_LOOP_PARTS(file,part) \
+ do { \
+ SkinPart* __part = (file)->parts; \
+ while (__part != NULL) { \
+ SkinPart* __part_next = __part->next; \
+ SkinPart* part = __part;
+
+#define SKIN_FILE_LOOP_END_PARTS \
+ __part = __part_next; \
+ } \
+ } while (0);
+
+extern SkinFile* skin_file_create_from_aconfig( AConfig* aconfig, const char* basepath );
+extern void skin_file_free( SkinFile* file );
+
+#endif /* _ANDROID_SKIN_FILE_H */
diff --git a/android/skin/image.c b/android/skin/image.c
new file mode 100644
index 0000000..051fc6d
--- /dev/null
+++ b/android/skin/image.c
@@ -0,0 +1,742 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/image.h"
+#include "android/resource.h"
+#include <assert.h>
+#include <limits.h>
+
+#define DEBUG 0
+
+#if DEBUG
+static void D(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+#else
+#define D(...) do{}while(0)
+#endif
+
+/********************************************************************************/
+/********************************************************************************/
+/***** *****/
+/***** U T I L I T Y F U N C T I O N S *****/
+/***** *****/
+/********************************************************************************/
+/********************************************************************************/
+
+SDL_Surface*
+sdl_surface_from_argb32( void* base, int w, int h )
+{
+ return SDL_CreateRGBSurfaceFrom(
+ base, w, h, 32, w*4,
+#if WORDS_BIGENDIAN
+ 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
+#else
+ 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
+#endif
+ );
+}
+
+static void*
+rotate_image( void* data, unsigned width, unsigned height, SkinRotation rotation )
+{
+ void* result;
+
+ result = malloc( width*height*4 );
+ if (result == NULL)
+ return NULL;
+
+ switch (rotation & 3)
+ {
+ case SKIN_ROTATION_0:
+ memcpy( (char*)result, (const char*)data, width*height*4 );
+ break;
+
+ case SKIN_ROTATION_270:
+ {
+ unsigned* start = (unsigned*)data;
+ unsigned* src_line = start + (width-1);
+ unsigned* dst_line = (unsigned*)result;
+ unsigned hh;
+
+ for (hh = width; hh > 0; hh--)
+ {
+ unsigned* src = src_line;
+ unsigned* dst = dst_line;
+ unsigned count = height;
+
+ for ( ; count > 0; count-- ) {
+ dst[0] = src[0];
+ dst += 1;
+ src += width;
+ }
+
+ src_line -= 1;
+ dst_line += height;
+ }
+ }
+ break;
+
+ case SKIN_ROTATION_180:
+ {
+ unsigned* start = (unsigned*)data;
+ unsigned* src_line = start + width*(height-1);
+ unsigned* dst_line = (unsigned*)result;
+ unsigned hh;
+
+ for (hh = height; hh > 0; hh--)
+ {
+ unsigned* src = src_line + (width-1);
+ unsigned* dst = dst_line;
+
+ while (src >= src_line)
+ *dst++ = *src--;
+
+ dst_line += width;
+ src_line -= width;
+ }
+ }
+ break;
+
+ case SKIN_ROTATION_90:
+ {
+ unsigned* start = (unsigned*)data;
+ unsigned* src_line = start + width*(height-1);
+ unsigned* dst_line = (unsigned*)result ;
+ unsigned hh;
+
+ for (hh = width; hh > 0; hh--)
+ {
+ unsigned* src = src_line;
+ unsigned* dst = dst_line;
+ unsigned count;
+
+ for (count = height; count > 0; count--) {
+ dst[0] = src[0];
+ dst += 1;
+ src -= width;
+ }
+
+ dst_line += height;
+ src_line += 1;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return result;
+}
+
+
+static void
+blend_image( unsigned* dst_pixels,
+ unsigned* src_pixels,
+ unsigned w,
+ unsigned h,
+ int alpha )
+{
+ unsigned* dst = dst_pixels;
+ unsigned* dst_end = dst + w*h;
+ unsigned* src = src_pixels;
+
+ for ( ; dst < dst_end; dst++, src++ )
+ {
+ {
+ unsigned ag = (src[0] >> 8) & 0xff00ff;
+ unsigned rb = src[0] & 0xff00ff;
+
+ ag = (ag*alpha) & 0xff00ff00;
+ rb = ((rb*alpha) >> 8) & 0x00ff00ff;
+
+ dst[0] = ag | rb;
+ }
+ }
+}
+
+
+static unsigned
+skin_image_desc_hash( SkinImageDesc* desc )
+{
+ unsigned h = 0;
+ int n;
+
+ for (n = 0; desc->path[n] != 0; n++) {
+ int c = desc->path[n];
+ h = h*33 + c;
+ }
+ h += desc->rotation*1573;
+ h += desc->blend * 7;
+
+ return h;
+}
+
+
+static int
+skin_image_desc_equal( SkinImageDesc* a,
+ SkinImageDesc* b )
+{
+ return (a->rotation == b->rotation &&
+ a->blend == b->blend &&
+ !strcmp(a->path, b->path));
+}
+
+/********************************************************************************/
+/********************************************************************************/
+/***** *****/
+/***** S K I N I M A G E S *****/
+/***** *****/
+/********************************************************************************/
+/********************************************************************************/
+
+enum {
+ SKIN_IMAGE_CLONE = (1 << 0) /* this image is a clone */
+};
+
+struct SkinImage {
+ unsigned hash;
+ SkinImage* link;
+ int ref_count;
+ SkinImage* next;
+ SkinImage* prev;
+ SDL_Surface* surface;
+ unsigned flags;
+ unsigned w, h;
+ void* pixels; /* 32-bit ARGB */
+ SkinImageDesc desc;
+};
+
+
+
+
+static const SkinImage _no_image[1] = {
+ { 0, NULL, 0, NULL, NULL, NULL, 0, 0, 0, NULL, { "<none>", SKIN_ROTATION_0, 0 } }
+};
+
+SkinImage* SKIN_IMAGE_NONE = (SkinImage*)&_no_image;
+
+static void
+skin_image_free( SkinImage* image )
+{
+ if (image && image != _no_image)
+ {
+ if (image->surface) {
+ SDL_FreeSurface(image->surface);
+ image->surface = NULL;
+ }
+
+ if (image->pixels) {
+ free( image->pixels );
+ image->pixels = NULL;
+ }
+
+ free(image);
+ }
+}
+
+
+static SkinImage*
+skin_image_alloc( SkinImageDesc* desc, unsigned hash )
+{
+ int len = strlen(desc->path);
+ SkinImage* image = calloc(1, sizeof(*image) + len + 1);
+
+ if (image) {
+ image->desc = desc[0];
+ image->desc.path = (const char*)(image + 1);
+ memcpy( (char*)image->desc.path, desc->path, len );
+ ((char*)image->desc.path)[len] = 0;
+
+ image->hash = hash;
+ image->next = image->prev = image;
+ image->ref_count = 1;
+ }
+ return image;
+}
+
+
+extern void *loadpng(const char *fn, unsigned *_width, unsigned *_height);
+extern void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height);
+
+static int
+skin_image_load( SkinImage* image )
+{
+ void* data;
+ unsigned w, h;
+ const char* path = image->desc.path;
+
+ if (path[0] == ':') {
+ size_t size;
+ const unsigned char* base;
+
+ if (path[1] == '/' || path[1] == '\\')
+ path += 1;
+
+ base = android_resource_find( path+1, &size );
+ if (base == NULL) {
+ fprintf(stderr, "failed to locate built-in image file '%s'\n", path );
+ return -1;
+ }
+
+ data = readpng(base, size, &w, &h);
+ if (data == NULL) {
+ fprintf(stderr, "failed to load built-in image file '%s'\n", path );
+ return -1;
+ }
+ } else {
+ data = loadpng(path, &w, &h);
+ if (data == NULL) {
+ fprintf(stderr, "failed to load image file '%s'\n", path );
+ return -1;
+ }
+ }
+
+ /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
+ * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
+ * on our CPU endianess
+ */
+ {
+ unsigned* d = data;
+ unsigned* d_end = d + w*h;
+
+ for ( ; d < d_end; d++ ) {
+ unsigned pix = d[0];
+#if WORDS_BIGENDIAN
+ /* R,G,B,A read as RGBA => ARGB */
+ pix = ((pix >> 8) & 0xffffff) | (pix << 24);
+#else
+ /* R,G,B,A read as ABGR => ARGB */
+ pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
+#endif
+ d[0] = pix;
+ }
+ }
+
+ image->pixels = data;
+ image->w = w;
+ image->h = h;
+
+ image->surface = sdl_surface_from_argb32( image->pixels, w, h );
+ if (image->surface == NULL) {
+ fprintf(stderr, "failed to create SDL surface for '%s' image\n", path);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* simple hash table for images */
+
+#define NUM_BUCKETS 64
+
+typedef struct {
+ SkinImage* buckets[ NUM_BUCKETS ];
+ SkinImage mru_head;
+ int num_images;
+ unsigned long total_pixels;
+ unsigned long max_pixels;
+ unsigned long total_images;
+} SkinImageCache;
+
+
+static void
+skin_image_cache_init( SkinImageCache* cache )
+{
+ memset(cache, 0, sizeof(*cache));
+#if DEBUG
+ cache->max_pixels = 1;
+#else
+ cache->max_pixels = 4*1024*1024; /* limit image cache to 4 MB */
+#endif
+ cache->mru_head.next = cache->mru_head.prev = &cache->mru_head;
+}
+
+
+static void
+skin_image_cache_remove( SkinImageCache* cache,
+ SkinImage* image )
+{
+ /* remove from hash table */
+ SkinImage** pnode = cache->buckets + (image->hash & (NUM_BUCKETS-1));
+ SkinImage* node;
+
+ for (;;) {
+ node = *pnode;
+ assert(node != NULL);
+ if (node == NULL) /* should not happen */
+ break;
+ if (node == image) {
+ *pnode = node->link;
+ break;
+ }
+ pnode = &node->link;
+ }
+
+ D( "skin_image_cache: remove '%s' (rot=%d), %d pixels\n",
+ node->desc.path, node->desc.rotation, node->w*node->h );
+
+ /* remove from mru list */
+ image->prev->next = image->next;
+ image->next->prev = image->prev;
+
+ cache->total_pixels -= image->w*image->h;
+ cache->total_images -= 1;
+}
+
+
+static SkinImage*
+skin_image_cache_raise( SkinImageCache* cache,
+ SkinImage* image )
+{
+ if (image != cache->mru_head.next) {
+ SkinImage* prev = image->prev;
+ SkinImage* next = image->next;
+
+ /* remove from mru list */
+ prev->next = next;
+ next->prev = prev;
+
+ /* add to top */
+ image->prev = &cache->mru_head;
+ image->next = image->prev->next;
+ image->prev->next = image;
+ image->next->prev = image;
+ }
+ return image;
+}
+
+
+static void
+skin_image_cache_flush( SkinImageCache* cache )
+{
+ SkinImage* image = cache->mru_head.prev;
+ int count = 0;
+
+ D("skin_image_cache_flush: starting\n");
+ while (cache->total_pixels > cache->max_pixels &&
+ image != &cache->mru_head)
+ {
+ SkinImage* prev = image->prev;
+
+ if (image->ref_count == 0) {
+ skin_image_cache_remove(cache, image);
+ count += 1;
+ }
+ image = prev;
+ }
+ D("skin_image_cache_flush: finished, %d images flushed\n", count);
+}
+
+
+static SkinImage**
+skin_image_lookup_p( SkinImageCache* cache,
+ SkinImageDesc* desc,
+ unsigned *phash )
+{
+ unsigned h = skin_image_desc_hash(desc);
+ unsigned index = h & (NUM_BUCKETS-1);
+ SkinImage** pnode = &cache->buckets[index];
+ for (;;) {
+ SkinImage* node = *pnode;
+ if (node == NULL)
+ break;
+ if (node->hash == h && skin_image_desc_equal(desc, &node->desc))
+ break;
+ pnode = &node->link;
+ }
+ *phash = h;
+ return pnode;
+}
+
+
+static SkinImage*
+skin_image_create( SkinImageDesc* desc, unsigned hash )
+{
+ SkinImage* node;
+
+ node = skin_image_alloc( desc, hash );
+ if (node == NULL)
+ return SKIN_IMAGE_NONE;
+
+ if (desc->rotation == SKIN_ROTATION_0 &&
+ desc->blend == SKIN_BLEND_FULL)
+ {
+ if (skin_image_load(node) < 0) {
+ skin_image_free(node);
+ return SKIN_IMAGE_NONE;
+ }
+ }
+ else
+ {
+ SkinImageDesc desc0 = desc[0];
+ SkinImage* parent;
+
+ desc0.rotation = SKIN_ROTATION_0;
+ desc0.blend = SKIN_BLEND_FULL;
+
+ parent = skin_image_find( &desc0 );
+ if (parent == SKIN_IMAGE_NONE)
+ return SKIN_IMAGE_NONE;
+
+ SDL_LockSurface(parent->surface);
+
+ if (desc->rotation == SKIN_ROTATION_90 ||
+ desc->rotation == SKIN_ROTATION_270)
+ {
+ node->w = parent->h;
+ node->h = parent->w;
+ } else {
+ node->w = parent->w;
+ node->h = parent->h;
+ }
+
+ node->pixels = rotate_image( parent->pixels, parent->w, parent->h,
+ desc->rotation );
+
+ SDL_UnlockSurface(parent->surface);
+ skin_image_unref(&parent);
+
+ if (node->pixels == NULL) {
+ skin_image_free(node);
+ return SKIN_IMAGE_NONE;
+ }
+
+ if (desc->blend != SKIN_BLEND_FULL)
+ blend_image( node->pixels, node->pixels, node->w, node->h, desc->blend );
+
+ node->surface = sdl_surface_from_argb32( node->pixels, node->w, node->h );
+ if (node->surface == NULL) {
+ skin_image_free(node);
+ return SKIN_IMAGE_NONE;
+ }
+ }
+ return node;
+}
+
+
+static SkinImageCache _image_cache[1];
+static int _image_cache_init;
+
+SkinImage*
+skin_image_find( SkinImageDesc* desc )
+{
+ SkinImageCache* cache = _image_cache;
+ unsigned hash;
+ SkinImage** pnode = skin_image_lookup_p( cache, desc, &hash );
+ SkinImage* node = *pnode;
+
+ if (!_image_cache_init) {
+ _image_cache_init = 1;
+ skin_image_cache_init(cache);
+ }
+
+ if (node) {
+ node->ref_count += 1;
+ return skin_image_cache_raise( cache, node );
+ }
+ node = skin_image_create( desc, hash );
+ if (node == SKIN_IMAGE_NONE)
+ return node;
+
+ /* add to hash table */
+ node->link = *pnode;
+ *pnode = node;
+
+ /* add to mru list */
+ skin_image_cache_raise( cache, node );
+
+ D( "skin_image_cache: add '%s' (rot=%d), %d pixels\n",
+ node->desc.path, node->desc.rotation, node->w*node->h );
+
+ cache->total_pixels += node->w*node->h;
+ if (cache->total_pixels > cache->max_pixels)
+ skin_image_cache_flush( cache );
+
+ return node;
+}
+
+
+SkinImage*
+skin_image_find_simple( const char* path )
+{
+ SkinImageDesc desc;
+
+ desc.path = path;
+ desc.rotation = SKIN_ROTATION_0;
+ desc.blend = SKIN_BLEND_FULL;
+
+ return skin_image_find( &desc );
+}
+
+
+SkinImage*
+skin_image_ref( SkinImage* image )
+{
+ if (image && image != _no_image)
+ image->ref_count += 1;
+
+ return image;
+}
+
+
+void
+skin_image_unref( SkinImage** pimage )
+{
+ SkinImage* image = *pimage;
+
+ if (image) {
+ if (image != _no_image && --image->ref_count == 0) {
+ if ((image->flags & SKIN_IMAGE_CLONE) != 0) {
+ skin_image_free(image);
+ }
+ }
+ *pimage = NULL;
+ }
+}
+
+
+SkinImage*
+skin_image_rotate( SkinImage* source, SkinRotation rotation )
+{
+ SkinImageDesc desc;
+ SkinImage* image;
+
+ if (source == _no_image || source->desc.rotation == rotation)
+ return source;
+
+ desc = source->desc;
+ desc.rotation = rotation;
+ image = skin_image_find( &desc );
+ skin_image_unref( &source );
+ return image;
+}
+
+
+SkinImage*
+skin_image_clone( SkinImage* source )
+{
+ SkinImage* image;
+
+ if (source == NULL || source == _no_image)
+ return SKIN_IMAGE_NONE;
+
+ image = calloc(1,sizeof(*image));
+ if (image == NULL)
+ goto Fail;
+
+ image->desc = source->desc;
+ image->hash = source->hash;
+ image->flags = SKIN_IMAGE_CLONE;
+ image->w = source->w;
+ image->h = source->h;
+ image->pixels = rotate_image( source->pixels, source->w, source->h,
+ SKIN_ROTATION_0 );
+ if (image->pixels == NULL)
+ goto Fail;
+
+ image->surface = sdl_surface_from_argb32( image->pixels, image->w, image->h );
+ if (image->surface == NULL)
+ goto Fail;
+
+ return image;
+Fail:
+ if (image != NULL)
+ skin_image_free(image);
+ return SKIN_IMAGE_NONE;
+}
+
+SkinImage*
+skin_image_clone_full( SkinImage* source,
+ SkinRotation rotation,
+ int blend )
+{
+ SkinImageDesc desc;
+ SkinImage* clone;
+
+ if (source == NULL || source == SKIN_IMAGE_NONE)
+ return SKIN_IMAGE_NONE;
+
+ if (rotation == SKIN_ROTATION_0 &&
+ blend == SKIN_BLEND_FULL)
+ {
+ return skin_image_clone(source);
+ }
+
+ desc.path = source->desc.path;
+ desc.rotation = rotation;
+ desc.blend = blend;
+
+ clone = skin_image_create( &desc, 0 );
+ if (clone != SKIN_IMAGE_NONE)
+ clone->flags |= SKIN_IMAGE_CLONE;
+
+ return clone;
+}
+
+/* apply blending to a source skin image and copy the result to a target clone image */
+extern void
+skin_image_blend_clone( SkinImage* clone, SkinImage* source, int blend )
+{
+ SDL_LockSurface( clone->surface );
+ blend_image( clone->pixels, source->pixels, source->w, source->h, blend );
+ SDL_UnlockSurface( clone->surface );
+ SDL_SetAlpha( clone->surface, SDL_SRCALPHA, 255 );
+}
+
+int
+skin_image_w( SkinImage* image )
+{
+ return image ? image->w : 0;
+}
+
+int
+skin_image_h( SkinImage* image )
+{
+ return image ? image->h : 0;
+}
+
+int
+skin_image_org_w( SkinImage* image )
+{
+ if (image) {
+ if (image->desc.rotation == SKIN_ROTATION_90 ||
+ image->desc.rotation == SKIN_ROTATION_270)
+ return image->h;
+ else
+ return image->w;
+ }
+ return 0;
+}
+
+int
+skin_image_org_h( SkinImage* image )
+{
+ if (image) {
+ if (image->desc.rotation == SKIN_ROTATION_90 ||
+ image->desc.rotation == SKIN_ROTATION_270)
+ return image->w;
+ else
+ return image->h;
+ }
+ return 0;
+}
+
+SDL_Surface*
+skin_image_surface( SkinImage* image )
+{
+ return image ? image->surface : NULL;
+}
diff --git a/android/skin/image.h b/android/skin/image.h
new file mode 100644
index 0000000..a94a372
--- /dev/null
+++ b/android/skin/image.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_IMAGE_H
+#define _ANDROID_SKIN_IMAGE_H
+
+#include "android/android.h"
+#include <SDL.h>
+#include "android/skin/rect.h"
+
+/* helper functions */
+
+extern SDL_Surface* sdl_surface_from_argb32( void* base, int w, int h );
+
+/* skin image file objects */
+
+/* opaque skin image type. all skin images are placed in a simple MRU cache
+ * to limit the emulator's memory usage, with the exception of 'clones' created
+ * with skin_image_clone() or skin_image_clone_blend()
+ */
+typedef struct SkinImage SkinImage;
+
+/* a descriptor for a given skin image */
+typedef struct SkinImageDesc {
+ const char* path; /* image file path (must be .png) */
+ AndroidRotation rotation; /* rotation */
+ int blend; /* blending, 0..256 value */
+} SkinImageDesc;
+
+#define SKIN_BLEND_NONE 0
+#define SKIN_BLEND_HALF 128
+#define SKIN_BLEND_FULL 256
+
+/* a special value returned when an image cannot be properly loaded */
+extern SkinImage* SKIN_IMAGE_NONE;
+
+/* return the SDL_Surface* pointer of a given skin image */
+extern SDL_Surface* skin_image_surface( SkinImage* image );
+extern int skin_image_w ( SkinImage* image );
+extern int skin_image_h ( SkinImage* image );
+extern int skin_image_org_w ( SkinImage* image );
+extern int skin_image_org_h ( SkinImage* image );
+
+/* get an image from the cache (load it from the file if necessary).
+ * returns SKIN_IMAGE_NONE in case of error. cannot return NULL
+ * this function also increments the reference count of the skin image,
+ * use "skin_image_unref()" when you don't need it anymore
+ */
+extern SkinImage* skin_image_find( SkinImageDesc* desc );
+
+extern SkinImage* skin_image_find_simple( const char* path );
+
+/* increment the reference count of a given skin image,
+ * don't do anything if 'image' is NULL */
+extern SkinImage* skin_image_ref( SkinImage* image );
+
+/* decrement the reference count of a given skin image. if
+ * the count reaches 0, the image becomes eligible for cache flushing.
+ * unless it was created through a skin_image_clone... function, where
+ * it is immediately discarded...
+ */
+extern void skin_image_unref( SkinImage** pimage );
+
+/* get the rotation of a given image. this decrements the reference count
+ * of the source after returning the target, whose reference count is incremented
+ */
+extern SkinImage* skin_image_rotate( SkinImage* source, SkinRotation rotation );
+
+/* create a skin image clone. the clone is not part of the cache and will
+ * be destroyed immediately when its reference count reaches 0. this is useful
+ * if you need to modify the content of the clone (e.g. blending)
+ */
+extern SkinImage* skin_image_clone( SkinImage* source );
+
+/* create a skin image clone, the clone is a rotated version of a source image
+ */
+extern SkinImage* skin_image_clone_full( SkinImage* source,
+ SkinRotation rotation,
+ int blend );
+
+/* apply blending to a source skin image and copy the result to a target clone image */
+extern void skin_image_blend_clone( SkinImage* clone, SkinImage* source, int blend );
+
+#endif /* _ANDROID_SKIN_IMAGE_H */
diff --git a/android/skin/keyboard.c b/android/skin/keyboard.c
new file mode 100644
index 0000000..6a9c79b
--- /dev/null
+++ b/android/skin/keyboard.c
@@ -0,0 +1,783 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/keyboard.h"
+#include "android/utils/debug.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/system.h"
+#include "android/android.h"
+
+#define DEBUG 1
+
+#if DEBUG
+# define D(...) VERBOSE_PRINT(keys,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+
+#define USE_KEYSET 1
+
+/** LAST PRESSED KEYS
+ ** a small buffer of last pressed keys, this is used to properly
+ ** implement the Unicode keyboard mode (SDL key up event always have
+ ** their .unicode field set to 0
+ **/
+typedef struct {
+ int unicode; /* Unicode of last pressed key */
+ int sym; /* SDL key symbol value (e.g. SDLK_a) */
+ int mod; /* SDL key modifier value */
+} LastKey;
+
+#define MAX_LAST_KEYS 16
+#define MAX_KEYCODES 256*2
+
+struct SkinKeyboard {
+ const AKeyCharmap* charmap;
+ SkinKeyset* kset;
+ char enabled;
+ char raw_keys;
+ char last_count;
+ int keycode_count;
+
+ SkinRotation rotation;
+
+ SkinKeyCommandFunc command_func;
+ void* command_opaque;
+ SkinKeyEventFunc press_func;
+ void* press_opaque;
+
+ LastKey last_keys[ MAX_LAST_KEYS ];
+ int keycodes[ MAX_KEYCODES ];
+};
+
+
+void
+skin_keyboard_set_keyset( SkinKeyboard* keyboard, SkinKeyset* kset )
+{
+ if (kset == NULL)
+ return;
+ if (keyboard->kset && keyboard->kset != android_keyset) {
+ skin_keyset_free(keyboard->kset);
+ }
+ keyboard->kset = kset;
+}
+
+
+const char*
+skin_keyboard_charmap_name( SkinKeyboard* keyboard )
+{
+ if (keyboard && keyboard->charmap)
+ return keyboard->charmap->name;
+
+ return "qwerty";
+}
+
+void
+skin_keyboard_set_rotation( SkinKeyboard* keyboard,
+ SkinRotation rotation )
+{
+ keyboard->rotation = (rotation & 3);
+}
+
+void
+skin_keyboard_on_command( SkinKeyboard* keyboard, SkinKeyCommandFunc cmd_func, void* cmd_opaque )
+{
+ keyboard->command_func = cmd_func;
+ keyboard->command_opaque = cmd_opaque;
+}
+
+void
+skin_keyboard_on_key_press( SkinKeyboard* keyboard, SkinKeyEventFunc press_func, void* press_opaque )
+{
+ keyboard->press_func = press_func;
+ keyboard->press_opaque = press_opaque;
+}
+
+void
+skin_keyboard_add_key_event( SkinKeyboard* kb,
+ unsigned code,
+ unsigned down )
+{
+ if (code != 0 && kb->keycode_count < MAX_KEYCODES) {
+ //dprint("add keycode %d, down %d\n", code % 0x1ff, down );
+ kb->keycodes[(int)kb->keycode_count++] = ( (code & 0x1ff) | (down ? 0x200 : 0) );
+ }
+}
+
+
+void
+skin_keyboard_flush( SkinKeyboard* kb )
+{
+ if (kb->keycode_count > 0) {
+ if (VERBOSE_CHECK(keys)) {
+ int nn;
+ printf(">> KEY" );
+ for (nn = 0; nn < kb->keycode_count; nn++) {
+ int code = kb->keycodes[nn];
+ printf(" [0x%03x,%s]", (code & 0x1ff), (code & 0x200) ? "down" : " up " );
+ }
+ printf( "\n" );
+ }
+ kbd_put_keycodes(kb->keycodes, kb->keycode_count);
+ kb->keycode_count = 0;
+ }
+}
+
+
+static void
+skin_keyboard_cmd( SkinKeyboard* keyboard,
+ SkinKeyCommand command,
+ int param )
+{
+ if (keyboard->command_func) {
+ keyboard->command_func( keyboard->command_opaque, command, param );
+ }
+}
+
+
+static LastKey*
+skin_keyboard_find_last( SkinKeyboard* keyboard,
+ int sym )
+{
+ LastKey* k = keyboard->last_keys;
+ LastKey* end = k + keyboard->last_count;
+
+ for ( ; k < end; k++ ) {
+ if (k->sym == sym)
+ return k;
+ }
+ return NULL;
+}
+
+static void
+skin_keyboard_add_last( SkinKeyboard* keyboard,
+ int sym,
+ int mod,
+ int unicode )
+{
+ LastKey* k = keyboard->last_keys + keyboard->last_count;
+
+ if (keyboard->last_count < MAX_LAST_KEYS) {
+ k->sym = sym;
+ k->mod = mod;
+ k->unicode = unicode;
+
+ keyboard->last_count += 1;
+ }
+}
+
+static void
+skin_keyboard_remove_last( SkinKeyboard* keyboard,
+ int sym )
+{
+ LastKey* k = keyboard->last_keys;
+ LastKey* end = k + keyboard->last_count;
+
+ for ( ; k < end; k++ ) {
+ if (k->sym == sym) {
+ /* we don't need a sorted array, so place the last
+ * element in place at the position of the removed
+ * one... */
+ k[0] = end[-1];
+ keyboard->last_count -= 1;
+ break;
+ }
+ }
+}
+
+static void
+skin_keyboard_clear_last( SkinKeyboard* keyboard )
+{
+ keyboard->last_count = 0;
+}
+
+static int
+skin_keyboard_rotate_sym( SkinKeyboard* keyboard,
+ int sym )
+{
+ switch (keyboard->rotation) {
+ case SKIN_ROTATION_90:
+ switch (sym) {
+ case SDLK_LEFT: sym = SDLK_DOWN; break;
+ case SDLK_RIGHT: sym = SDLK_UP; break;
+ case SDLK_UP: sym = SDLK_LEFT; break;
+ case SDLK_DOWN: sym = SDLK_RIGHT; break;
+ }
+ break;
+
+ case SKIN_ROTATION_180:
+ switch (sym) {
+ case SDLK_LEFT: sym = SDLK_RIGHT; break;
+ case SDLK_RIGHT: sym = SDLK_LEFT; break;
+ case SDLK_UP: sym = SDLK_DOWN; break;
+ case SDLK_DOWN: sym = SDLK_UP; break;
+ }
+ break;
+
+ case SKIN_ROTATION_270:
+ switch (sym) {
+ case SDLK_LEFT: sym = SDLK_UP; break;
+ case SDLK_RIGHT: sym = SDLK_DOWN; break;
+ case SDLK_UP: sym = SDLK_RIGHT; break;
+ case SDLK_DOWN: sym = SDLK_LEFT; break;
+ }
+ break;
+
+ default: ;
+ }
+ return sym;
+}
+
+#if USE_KEYSET
+static AndroidKeyCode
+skin_keyboard_key_to_code( SkinKeyboard* keyboard,
+ unsigned sym,
+ int mod,
+ int down )
+{
+ AndroidKeyCode code = 0;
+ int mod0 = mod;
+ SkinKeyCommand command;
+
+ /* first, handle the arrow keys directly */
+ /* rotate them if necessary */
+ sym = skin_keyboard_rotate_sym(keyboard, sym);
+ mod &= (KMOD_CTRL | KMOD_ALT | KMOD_SHIFT);
+
+ switch (sym) {
+ case SDLK_LEFT: code = kKeyCodeDpadLeft; break;
+ case SDLK_RIGHT: code = kKeyCodeDpadRight; break;
+ case SDLK_UP: code = kKeyCodeDpadUp; break;
+ case SDLK_DOWN: code = kKeyCodeDpadDown; break;
+ default: ;
+ }
+
+ if (code != 0) {
+ D("handling arrow (sym=%d mod=%d)", sym, mod);
+ if (!keyboard->raw_keys) {
+ int doCapL, doCapR, doAltL, doAltR;
+
+ if (!down) {
+ LastKey* k = skin_keyboard_find_last(keyboard, sym);
+ if (k != NULL) {
+ mod = k->mod;
+ skin_keyboard_remove_last( keyboard, sym );
+ }
+ } else {
+ skin_keyboard_add_last( keyboard, sym, mod, 0);
+ }
+
+ doCapL = (mod & 0x7ff) & KMOD_LSHIFT;
+ doCapR = (mod & 0x7ff) & KMOD_RSHIFT;
+ doAltL = (mod & 0x7ff) & KMOD_LALT;
+ doAltR = (mod & 0x7ff) & KMOD_RALT;
+
+ if (down) {
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 1 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 1 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 1 );
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 1 );
+ }
+ skin_keyboard_add_key_event(keyboard, code, down);
+
+ if (!down) {
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 0 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 0 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 0 );
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 0 );
+ }
+ code = 0;
+ }
+ return code;
+ }
+
+ /* special case for keypad keys, ignore them here if numlock is on */
+ if ((mod0 & KMOD_NUM) != 0) {
+ switch (sym) {
+ case SDLK_KP0:
+ case SDLK_KP1:
+ case SDLK_KP2:
+ case SDLK_KP3:
+ case SDLK_KP4:
+ case SDLK_KP5:
+ case SDLK_KP6:
+ case SDLK_KP7:
+ case SDLK_KP8:
+ case SDLK_KP9:
+ case SDLK_KP_PLUS:
+ case SDLK_KP_MINUS:
+ case SDLK_KP_MULTIPLY:
+ case SDLK_KP_DIVIDE:
+ case SDLK_KP_EQUALS:
+ case SDLK_KP_PERIOD:
+ case SDLK_KP_ENTER:
+ return 0;
+ }
+ }
+
+ /* now try all keyset combos */
+ command = skin_keyset_get_command( keyboard->kset, sym, mod );
+ if (command != SKIN_KEY_COMMAND_NONE) {
+ D("handling command %s from (sym=%d, mod=%d, str=%s)",
+ skin_key_command_to_str(command), sym, mod, skin_key_symmod_to_str(sym,mod));
+ skin_keyboard_cmd( keyboard, command, down );
+ return 0;
+ }
+ D("could not handle (sym=%d, mod=%d, str=%s)", sym, mod,
+ skin_key_symmod_to_str(sym,mod));
+ return -1;
+}
+#else /* !USE_KEYSET */
+/* this will look for non-Unicode key strokes, e.g. arrows, F1, F2, etc...
+ * note that we have some special handling for shift-<arrow>, these will
+ * be emulated as two key strokes on the device
+ */
+static AndroidKeyCode
+skin_keyboard_key_to_code( SkinKeyboard* keyboard,
+ unsigned sym,
+ int mod,
+ int down )
+{
+ AndroidKeyCode code = 0;
+ int doAltShift = 0;
+
+ sym = skin_keyboard_rotate_sym(keyboard, sym);
+
+ switch (sym) {
+ case SDLK_LEFT: code = kKeyCodeDpadLeft; doAltShift = 1; break;
+ case SDLK_RIGHT: code = kKeyCodeDpadRight; doAltShift = 1; break;
+ case SDLK_UP: code = kKeyCodeDpadUp; doAltShift = 1; break;
+ case SDLK_DOWN: code = kKeyCodeDpadDown; doAltShift = 1; break;
+ case SDLK_HOME: code = kKeyCodeHome; break;
+ case SDLK_BACKSPACE: code = kKeyCodeDel; doAltShift = 1; break;
+ case SDLK_ESCAPE: code = kKeyCodeBack; break;
+ case SDLK_RETURN: code = kKeyCodeNewline; doAltShift = 1; break;
+ case SDLK_F1: code = kKeyCodeSoftLeft; break;
+ case SDLK_F2: code = kKeyCodeSoftRight; break;
+ case SDLK_F3: code = kKeyCodeCall; break;
+ case SDLK_F4: code = kKeyCodeEndCall; break;
+ case SDLK_F5: code = kKeyCodeSearch; break;
+ case SDLK_F7: code = kKeyCodePower; break;
+
+ case SDLK_F8: /* network connect/disconnect */
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_NETWORK, 1 );
+ }
+ return 0;
+
+#ifdef CONFIG_TRACE
+ case SDLK_F9: /* start tracing */
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_TRACING, 1 );
+ }
+ return 0;
+
+ case SDLK_F10: /* stop tracing */
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_TRACING, 1 );
+ }
+ return 0;
+#endif
+
+ case SDLK_F12: /* change orientation */
+ if (down && (mod & (KMOD_LCTRL | KMOD_RCTRL)) != 0) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_CHANGE_LAYOUT, +1 );
+ }
+ return 0;
+
+ case SDLK_PAGEUP: return kKeyCodeSoftLeft;
+ case SDLK_PAGEDOWN: return kKeyCodeSoftRight;
+
+ case SDLK_t:
+ if (down && (mod & (KMOD_LCTRL| KMOD_RCTRL)) != 0) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_TRACKBALL, 1 );
+ return 0;
+ }
+ break;
+
+ case SDLK_KP5:
+ if ((mod & (KMOD_LCTRL | KMOD_RCTRL)) != 0)
+ code = kKeyCodeCamera;
+ break;
+ }
+
+ if (code != 0) {
+ if (doAltShift && !keyboard->raw_keys) {
+ int doCapL, doCapR, doAltL, doAltR;
+
+ if (!down) {
+ LastKey* k = skin_keyboard_find_last(keyboard, sym);
+ if (k != NULL) {
+ mod = k->mod;
+ skin_keyboard_remove_last( keyboard, sym );
+ }
+ } else {
+ skin_keyboard_add_last( keyboard, sym, mod, 0);
+ }
+
+ doCapL = (mod & 0x7ff) & KMOD_LSHIFT;
+ doCapR = (mod & 0x7ff) & KMOD_RSHIFT;
+ doAltL = (mod & 0x7ff) & KMOD_LALT;
+ doAltR = (mod & 0x7ff) & KMOD_RALT;
+
+ if (down) {
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 1 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 1 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 1 );
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 1 );
+ }
+ skin_keyboard_add_key_event(keyboard, code, down);
+
+ if (!down) {
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 0 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 0 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 0 );
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 0 );
+ }
+ code = 0;
+ }
+ return code;
+ }
+
+ if ((mod & KMOD_NUM) == 0) {
+ switch (sym) {
+ case SDLK_KP8: return kKeyCodeDpadUp;
+ case SDLK_KP2: return kKeyCodeDpadDown;
+ case SDLK_KP4: return kKeyCodeDpadLeft;
+ case SDLK_KP6: return kKeyCodeDpadRight;
+ case SDLK_KP5: return kKeyCodeDpadCenter;
+
+ case SDLK_KP_PLUS: return kKeyCodeVolumeUp;
+ case SDLK_KP_MINUS: return kKeyCodeVolumeDown;
+
+ case SDLK_KP_MULTIPLY:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_ONION_ALPHA_UP, 1 );
+ }
+ return 0;
+
+ case SDLK_KP_DIVIDE:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_ONION_ALPHA_DOWN, 1 );
+ }
+ return 0;
+
+ case SDLK_KP7:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV, 1 );
+ }
+ return 0;
+
+ case SDLK_KP9:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT, 1 );
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+#endif /* !USE_KEYSET */
+
+/* this gets called only if the reverse unicode mapping didn't work
+ * or wasn't used (when in raw keys mode)
+ */
+static AndroidKeyCode
+skin_keyboard_raw_key_to_code(SkinKeyboard* kb, unsigned sym, int down)
+{
+ switch(sym){
+ case SDLK_1: return kKeyCode1;
+ case SDLK_2: return kKeyCode2;
+ case SDLK_3: return kKeyCode3;
+ case SDLK_4: return kKeyCode4;
+ case SDLK_5: return kKeyCode5;
+ case SDLK_6: return kKeyCode6;
+ case SDLK_7: return kKeyCode7;
+ case SDLK_8: return kKeyCode8;
+ case SDLK_9: return kKeyCode9;
+ case SDLK_0: return kKeyCode0;
+
+ case SDLK_q: return kKeyCodeQ;
+ case SDLK_w: return kKeyCodeW;
+ case SDLK_e: return kKeyCodeE;
+ case SDLK_r: return kKeyCodeR;
+ case SDLK_t: return kKeyCodeT;
+ case SDLK_y: return kKeyCodeY;
+ case SDLK_u: return kKeyCodeU;
+ case SDLK_i: return kKeyCodeI;
+ case SDLK_o: return kKeyCodeO;
+ case SDLK_p: return kKeyCodeP;
+ case SDLK_a: return kKeyCodeA;
+ case SDLK_s: return kKeyCodeS;
+ case SDLK_d: return kKeyCodeD;
+ case SDLK_f: return kKeyCodeF;
+ case SDLK_g: return kKeyCodeG;
+ case SDLK_h: return kKeyCodeH;
+ case SDLK_j: return kKeyCodeJ;
+ case SDLK_k: return kKeyCodeK;
+ case SDLK_l: return kKeyCodeL;
+ case SDLK_z: return kKeyCodeZ;
+ case SDLK_x: return kKeyCodeX;
+ case SDLK_c: return kKeyCodeC;
+ case SDLK_v: return kKeyCodeV;
+ case SDLK_b: return kKeyCodeB;
+ case SDLK_n: return kKeyCodeN;
+ case SDLK_m: return kKeyCodeM;
+ case SDLK_COMMA: return kKeyCodeComma;
+ case SDLK_PERIOD: return kKeyCodePeriod;
+ case SDLK_SPACE: return kKeyCodeSpace;
+ case SDLK_SLASH: return kKeyCodeSlash;
+ case SDLK_RETURN: return kKeyCodeNewline;
+ case SDLK_BACKSPACE: return kKeyCodeDel;
+
+/* these are qwerty keys not on a device keyboard */
+ case SDLK_TAB: return kKeyCodeTab;
+ case SDLK_BACKQUOTE: return kKeyCodeGrave;
+ case SDLK_MINUS: return kKeyCodeMinus;
+ case SDLK_EQUALS: return kKeyCodeEquals;
+ case SDLK_LEFTBRACKET: return kKeyCodeLeftBracket;
+ case SDLK_RIGHTBRACKET: return kKeyCodeRightBracket;
+ case SDLK_BACKSLASH: return kKeyCodeBackslash;
+ case SDLK_SEMICOLON: return kKeyCodeSemicolon;
+ case SDLK_QUOTE: return kKeyCodeApostrophe;
+
+ case SDLK_RSHIFT: return kKeyCodeCapRight;
+ case SDLK_LSHIFT: return kKeyCodeCapLeft;
+ case SDLK_RMETA: return kKeyCodeSym;
+ case SDLK_LMETA: return kKeyCodeSym;
+ case SDLK_RALT: return kKeyCodeAltRight;
+ case SDLK_LALT: return kKeyCodeAltLeft;
+ case SDLK_RCTRL: return kKeyCodeSym;
+ case SDLK_LCTRL: return kKeyCodeSym;
+
+ default:
+ /* fprintf(stderr,"* unknown sdl keysym %d *\n", sym); */
+ return -1;
+ }
+}
+
+
+static void
+skin_keyboard_do_key_event( SkinKeyboard* kb,
+ AndroidKeyCode code,
+ int down )
+{
+ if (kb->press_func) {
+ kb->press_func( kb->press_opaque, code, down );
+ }
+ skin_keyboard_add_key_event(kb, code, down);
+}
+
+
+int
+skin_keyboard_process_unicode_event( SkinKeyboard* kb, unsigned int unicode, int down )
+{
+ const AKeyCharmap* cmap = kb->charmap;
+ int n;
+
+ if (unicode == 0)
+ return 0;
+
+ /* check base keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].base == unicode) {
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ return 1;
+ }
+ }
+
+ /* check caps + keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].caps == unicode) {
+ if (down)
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ if (!down)
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ return 2;
+ }
+ }
+
+ /* check fn + keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].fn == unicode) {
+ if (down)
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ if (!down)
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ return 2;
+ }
+ }
+
+ /* check caps + fn + keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].caps_fn == unicode) {
+ if (down) {
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ }
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ if (!down) {
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ }
+ return 3;
+ }
+ }
+
+ /* no match */
+ return 0;
+}
+
+
+void
+skin_keyboard_enable( SkinKeyboard* keyboard,
+ int enabled )
+{
+ keyboard->enabled = enabled;
+ if (enabled) {
+ SDL_EnableUNICODE(!keyboard->raw_keys);
+ SDL_EnableKeyRepeat(0,0);
+ }
+}
+
+void
+skin_keyboard_process_event( SkinKeyboard* kb, SDL_Event* ev, int down )
+{
+ unsigned code;
+ int unicode = ev->key.keysym.unicode;
+ int sym = ev->key.keysym.sym;
+ int mod = ev->key.keysym.mod;
+
+ /* ignore key events if we're not enabled */
+ if (!kb->enabled) {
+ printf( "ignoring key event sym=%d mod=0x%x unicode=%d\n",
+ sym, mod, unicode );
+ return;
+ }
+
+ /* first, try the keyboard-mode-independent keys */
+ code = skin_keyboard_key_to_code( kb, sym, mod, down );
+ if (code == 0)
+ return;
+
+ if ((int)code > 0) {
+ skin_keyboard_do_key_event(kb, code, down);
+ skin_keyboard_flush(kb);
+ return;
+ }
+
+ /* Ctrl-K is used to switch between 'unicode' and 'raw' modes */
+ if (sym == SDLK_k)
+ {
+ int mod2 = mod & 0x7ff;
+
+ if ( mod2 == KMOD_LCTRL || mod2 == KMOD_RCTRL ) {
+ if (down) {
+ skin_keyboard_clear_last(kb);
+ kb->raw_keys = !kb->raw_keys;
+ SDL_EnableUNICODE(!kb->raw_keys);
+ D( "switching keyboard to %s mode", kb->raw_keys ? "raw" : "unicode" );
+ }
+ return;
+ }
+ }
+
+ if (!kb->raw_keys) {
+ /* ev->key.keysym.unicode is only valid on keydown events, and will be 0
+ * on the corresponding keyup ones, so remember the set of last pressed key
+ * syms to "undo" the job
+ */
+ if ( !down && unicode == 0 ) {
+ LastKey* k = skin_keyboard_find_last(kb, sym);
+ if (k != NULL) {
+ unicode = k->unicode;
+ skin_keyboard_remove_last(kb, sym);
+ }
+ }
+ }
+ if (!kb->raw_keys &&
+ skin_keyboard_process_unicode_event( kb, unicode, down ) > 0)
+ {
+ if (down)
+ skin_keyboard_add_last( kb, sym, mod, unicode );
+
+ skin_keyboard_flush( kb );
+ return;
+ }
+
+ code = skin_keyboard_raw_key_to_code( kb, sym, down );
+
+ if ( !kb->raw_keys &&
+ (code == kKeyCodeAltLeft || code == kKeyCodeAltRight ||
+ code == kKeyCodeCapLeft || code == kKeyCodeCapRight ||
+ code == kKeyCodeSym) )
+ return;
+
+ if (code == -1) {
+ D("ignoring keysym %d", sym );
+ } else if (code > 0) {
+ skin_keyboard_do_key_event(kb, code, down);
+ skin_keyboard_flush(kb);
+ }
+}
+
+
+SkinKeyboard*
+skin_keyboard_create_from_aconfig( AConfig* aconfig, int use_raw_keys )
+{
+ SkinKeyboard* kb;
+ const char* charmap_name = "qwerty";
+ AConfig* node;
+
+ ANEW0(kb);
+
+ node = aconfig_find( aconfig, "keyboard" );
+ if (node != NULL)
+ charmap_name = aconfig_str(node, "charmap", charmap_name);
+
+ {
+ int nn;
+
+ for (nn = 0; nn < android_charmap_count; nn++) {
+ if ( !strcmp(android_charmaps[nn]->name, charmap_name) ) {
+ kb->charmap = android_charmaps[nn];
+ break;
+ }
+ }
+
+ if (!kb->charmap) {
+ fprintf(stderr, "### warning, skin requires unknown '%s' charmap, reverting to '%s'\n",
+ charmap_name, android_charmaps[0]->name );
+ kb->charmap = android_charmaps[0];
+ }
+ }
+ kb->raw_keys = use_raw_keys;
+ kb->enabled = 0;
+
+ /* add default keyset */
+ if (android_keyset)
+ kb->kset = android_keyset;
+ else
+ kb->kset = skin_keyset_new_from_text( skin_keyset_get_default() );
+
+ return kb;
+}
+
+void
+skin_keyboard_free( SkinKeyboard* keyboard )
+{
+ if (keyboard) {
+ AFREE(keyboard);
+ }
+}
diff --git a/android/skin/keyboard.h b/android/skin/keyboard.h
new file mode 100644
index 0000000..45efd18
--- /dev/null
+++ b/android/skin/keyboard.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_KEYBOARD_H
+#define _ANDROID_SKIN_KEYBOARD_H
+
+#include "android/charmap.h"
+#include "android/config.h"
+#include "android/skin/image.h" /* for SkinRotation */
+#include "android/skin/keyset.h"
+#include <SDL.h>
+
+typedef struct SkinKeyboard SkinKeyboard;
+
+typedef void (*SkinKeyCommandFunc)( void* opaque, SkinKeyCommand command, int param );
+
+typedef void (*SkinKeyEventFunc)( void* opaque, AndroidKeyCode code, int down );
+
+extern SkinKeyboard* skin_keyboard_create_from_aconfig( AConfig* aconfig, int use_raw_keys );
+
+extern void skin_keyboard_set_keyset( SkinKeyboard* keyboard, SkinKeyset* kset );
+
+extern const char* skin_keyboard_charmap_name( SkinKeyboard* keyboard );
+
+extern void skin_keyboard_free( SkinKeyboard* keyboard );
+
+extern void skin_keyboard_enable( SkinKeyboard* keyboard,
+ int enabled );
+
+extern void skin_keyboard_on_command( SkinKeyboard* keyboard,
+ SkinKeyCommandFunc cmd_func,
+ void* cmd_opaque );
+
+extern void skin_keyboard_set_rotation( SkinKeyboard* keyboard,
+ SkinRotation rotation );
+
+extern void skin_keyboard_on_key_press( SkinKeyboard* keyboard,
+ SkinKeyEventFunc press_func,
+ void* press_opaque );
+
+extern void skin_keyboard_process_event( SkinKeyboard* keyboard, SDL_Event* ev, int down );
+extern int skin_keyboard_process_unicode_event( SkinKeyboard* kb, unsigned int unicode, int down );
+
+extern void skin_keyboard_add_key_event( SkinKeyboard* k, unsigned code, unsigned down );
+extern void skin_keyboard_flush( SkinKeyboard* kb );
+
+/* defined in android_main.c */
+extern SkinKeyboard* android_emulator_get_keyboard( void );
+
+#endif /* _ANDROID_SKIN_KEYBOARD_H */
+
diff --git a/android/skin/keyset.c b/android/skin/keyset.c
new file mode 100644
index 0000000..7a92971
--- /dev/null
+++ b/android/skin/keyset.c
@@ -0,0 +1,542 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/keyset.h"
+#include "android/utils/debug.h"
+#include "android/utils/bufprint.h"
+#include "android/android.h"
+#include <SDL.h>
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(keys)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(...) VERBOSE_PRINT(keys,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+#define _SKIN_KEY_COMMAND(x,y) #x ,
+static const char* const command_strings[ SKIN_KEY_COMMAND_MAX ] = {
+ SKIN_KEY_COMMAND_LIST
+};
+#undef _SKIN_KEY_COMMAND
+
+const char*
+skin_key_command_to_str( SkinKeyCommand cmd )
+{
+ if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX)
+ return command_strings[cmd];
+
+ return NULL;
+}
+
+SkinKeyCommand
+skin_key_command_from_str( const char* str, int len )
+{
+ int nn;
+ if (len < 0)
+ len = strlen(str);
+ for (nn = 0; nn < SKIN_KEY_COMMAND_MAX; nn++) {
+ const char* cmd = command_strings[nn];
+
+ if ( !memcmp( cmd, str, len ) && cmd[len] == 0 )
+ return (SkinKeyCommand) nn;
+ }
+ return SKIN_KEY_COMMAND_NONE;
+}
+
+
+#define _SKIN_KEY_COMMAND(x,y) y ,
+static const char* const command_descriptions[ SKIN_KEY_COMMAND_MAX ] = {
+ SKIN_KEY_COMMAND_LIST
+};
+#undef _SKIN_KEY_COMMAND
+
+const char*
+skin_key_command_description( SkinKeyCommand cmd )
+{
+ if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX)
+ return command_descriptions[cmd];
+
+ return NULL;
+}
+
+#define _KEYSYM1_(x) _KEYSYM_(x,x)
+
+#define _KEYSYM_LIST \
+ _KEYSYM1_(BACKSPACE) \
+ _KEYSYM1_(TAB) \
+ _KEYSYM1_(CLEAR) \
+ _KEYSYM_(RETURN,ENTER) \
+ _KEYSYM1_(PAUSE) \
+ _KEYSYM1_(ESCAPE) \
+ _KEYSYM1_(SPACE) \
+ _KEYSYM_(EXCLAIM,EXCLAM) \
+ _KEYSYM_(QUOTEDBL,DOUBLEQUOTE) \
+ _KEYSYM_(HASH,HASH) \
+ _KEYSYM1_(DOLLAR) \
+ _KEYSYM1_(AMPERSAND) \
+ _KEYSYM1_(QUOTE) \
+ _KEYSYM_(LEFTPAREN,LPAREN) \
+ _KEYSYM_(RIGHTPAREN,RPAREN) \
+ _KEYSYM1_(ASTERISK) \
+ _KEYSYM1_(PLUS) \
+ _KEYSYM1_(COMMA) \
+ _KEYSYM1_(MINUS) \
+ _KEYSYM1_(PERIOD) \
+ _KEYSYM1_(SLASH) \
+ _KEYSYM1_(0) \
+ _KEYSYM1_(1) \
+ _KEYSYM1_(2) \
+ _KEYSYM1_(3) \
+ _KEYSYM1_(4) \
+ _KEYSYM1_(5) \
+ _KEYSYM1_(6) \
+ _KEYSYM1_(7) \
+ _KEYSYM1_(8) \
+ _KEYSYM1_(9) \
+ _KEYSYM1_(COLON) \
+ _KEYSYM1_(SEMICOLON) \
+ _KEYSYM1_(LESS) \
+ _KEYSYM_(EQUALS,EQUAL) \
+ _KEYSYM1_(GREATER) \
+ _KEYSYM1_(QUESTION) \
+ _KEYSYM1_(AT) \
+ _KEYSYM1_(LEFTBRACKET) \
+ _KEYSYM1_(BACKSLASH) \
+ _KEYSYM1_(RIGHTBRACKET) \
+ _KEYSYM1_(CARET) \
+ _KEYSYM1_(UNDERSCORE) \
+ _KEYSYM1_(BACKQUOTE) \
+ _KEYSYM_(a,A) \
+ _KEYSYM_(b,B) \
+ _KEYSYM_(c,C) \
+ _KEYSYM_(d,D) \
+ _KEYSYM_(e,E) \
+ _KEYSYM_(f,F) \
+ _KEYSYM_(g,G) \
+ _KEYSYM_(h,H) \
+ _KEYSYM_(i,I) \
+ _KEYSYM_(j,J) \
+ _KEYSYM_(k,K) \
+ _KEYSYM_(l,L) \
+ _KEYSYM_(m,M) \
+ _KEYSYM_(n,N) \
+ _KEYSYM_(o,O) \
+ _KEYSYM_(p,P) \
+ _KEYSYM_(q,Q) \
+ _KEYSYM_(r,R) \
+ _KEYSYM_(s,S) \
+ _KEYSYM_(t,T) \
+ _KEYSYM_(u,U) \
+ _KEYSYM_(v,V) \
+ _KEYSYM_(w,W) \
+ _KEYSYM_(x,X) \
+ _KEYSYM_(y,Y) \
+ _KEYSYM_(z,Z) \
+ _KEYSYM1_(DELETE) \
+ _KEYSYM_(KP_PLUS,KEYPAD_PLUS) \
+ _KEYSYM_(KP_MINUS,KEYPAD_MINUS) \
+ _KEYSYM_(KP_MULTIPLY,KEYPAD_MULTIPLY) \
+ _KEYSYM_(KP_DIVIDE,KEYPAD_DIVIDE) \
+ _KEYSYM_(KP_ENTER,KEYPAD_ENTER) \
+ _KEYSYM_(KP_PERIOD,KEYPAD_PERIOD) \
+ _KEYSYM_(KP_EQUALS,KEYPAD_EQUALS) \
+ _KEYSYM_(KP1,KEYPAD_1) \
+ _KEYSYM_(KP2,KEYPAD_2) \
+ _KEYSYM_(KP3,KEYPAD_3) \
+ _KEYSYM_(KP4,KEYPAD_4) \
+ _KEYSYM_(KP5,KEYPAD_5) \
+ _KEYSYM_(KP6,KEYPAD_6) \
+ _KEYSYM_(KP7,KEYPAD_7) \
+ _KEYSYM_(KP8,KEYPAD_8) \
+ _KEYSYM_(KP9,KEYPAD_9) \
+ _KEYSYM_(KP0,KEYPAD_0) \
+ _KEYSYM1_(UP) \
+ _KEYSYM1_(DOWN) \
+ _KEYSYM1_(RIGHT) \
+ _KEYSYM1_(LEFT) \
+ _KEYSYM1_(INSERT) \
+ _KEYSYM1_(HOME) \
+ _KEYSYM1_(END) \
+ _KEYSYM1_(PAGEUP) \
+ _KEYSYM1_(PAGEDOWN) \
+ _KEYSYM1_(F1) \
+ _KEYSYM1_(F2) \
+ _KEYSYM1_(F3) \
+ _KEYSYM1_(F4) \
+ _KEYSYM1_(F5) \
+ _KEYSYM1_(F6) \
+ _KEYSYM1_(F7) \
+ _KEYSYM1_(F8) \
+ _KEYSYM1_(F9) \
+ _KEYSYM1_(F10) \
+ _KEYSYM1_(F11) \
+ _KEYSYM1_(F12) \
+ _KEYSYM1_(F13) \
+ _KEYSYM1_(F14) \
+ _KEYSYM1_(F15) \
+ _KEYSYM1_(SCROLLOCK) \
+ _KEYSYM1_(SYSREQ) \
+ _KEYSYM1_(PRINT) \
+ _KEYSYM1_(BREAK) \
+
+#define _KEYSYM_(x,y) { SDLK_##x, #y },
+static const struct { int _sym; const char* _str; } keysym_names[] =
+{
+ _KEYSYM_LIST
+ { 0, NULL }
+};
+#undef _KEYSYM_
+
+int
+skin_keysym_str_count( void )
+{
+ return sizeof(keysym_names)/sizeof(keysym_names[0])-1;
+}
+
+const char*
+skin_keysym_str( int index )
+{
+ if (index >= 0 && index < skin_keysym_str_count())
+ return keysym_names[index]._str;
+
+ return NULL;
+}
+
+const char*
+skin_key_symmod_to_str( int sym, int mod )
+{
+ static char temp[32];
+ char* p = temp;
+ char* end = p + sizeof(temp);
+ int nn;
+
+ if ((mod & KMOD_LCTRL) != 0) {
+ p = bufprint(p, end, "Ctrl-");
+ }
+ if ((mod & KMOD_RCTRL) != 0) {
+ p = bufprint(p, end, "RCtrl-");
+ }
+ if ((mod & KMOD_LSHIFT) != 0) {
+ p = bufprint(p, end, "Shift-");
+ }
+ if ((mod & KMOD_RSHIFT) != 0) {
+ p = bufprint(p, end, "RShift-");
+ }
+ if ((mod & KMOD_LALT) != 0) {
+ p = bufprint(p, end, "Alt-");
+ }
+ if ((mod & KMOD_RALT) != 0) {
+ p = bufprint(p, end, "RAlt-");
+ }
+ for (nn = 0; keysym_names[nn]._sym != 0; nn++) {
+ if (keysym_names[nn]._sym == sym) {
+ p = bufprint(p, end, "%s", keysym_names[nn]._str);
+ return temp;;
+ }
+ }
+
+ if (sym >= 32 && sym <= 127) {
+ p = bufprint(p, end, "%c", sym);
+ return temp;
+ }
+
+ return NULL;
+}
+
+
+int
+skin_key_symmod_from_str( const char* str, int *psym, int *pmod )
+{
+ int mod = 0;
+ int match = 1;
+ int nn;
+ const char* s0 = str;
+ static const struct { const char* prefix; int mod; } mods[] =
+ {
+ { "^", KMOD_LCTRL },
+ { "Ctrl", KMOD_LCTRL },
+ { "ctrl", KMOD_LCTRL },
+ { "RCtrl", KMOD_RCTRL },
+ { "rctrl", KMOD_RCTRL },
+ { "Alt", KMOD_LALT },
+ { "alt", KMOD_LALT },
+ { "RAlt", KMOD_RALT },
+ { "ralt", KMOD_RALT },
+ { "Shift", KMOD_LSHIFT },
+ { "shift", KMOD_LSHIFT },
+ { "RShift", KMOD_RSHIFT },
+ { "rshift", KMOD_RSHIFT },
+ { NULL, 0 }
+ };
+
+ while (match) {
+ match = 0;
+ for (nn = 0; mods[nn].prefix != NULL; nn++) {
+ const char* prefix = mods[nn].prefix;
+ int len = strlen(prefix);
+
+ if ( !memcmp(str, prefix, len) ) {
+ str += len;
+ match = 1;
+ mod |= mods[nn].mod;
+ if (str[0] == '-' && str[1] != 0)
+ str++;
+ break;
+ }
+ }
+ }
+
+ for (nn = 0; keysym_names[nn]._sym; nn++) {
+#ifdef _WIN32
+ if ( !stricmp(str, keysym_names[nn]._str) )
+#else
+ if ( !strcasecmp(str, keysym_names[nn]._str) )
+#endif
+ {
+ *psym = keysym_names[nn]._sym;
+ *pmod = mod;
+ return 0;
+ }
+ }
+
+ D("%s: can't find sym value for '%s' (mod=%d, str=%s)", __FUNCTION__, s0, mod, str);
+ return -1;
+}
+
+
+typedef struct {
+ int sym;
+ int mod;
+ SkinKeyCommand command;
+} SkinKeyItem;
+
+
+struct SkinKeyset {
+ int num_items;
+ int max_items;
+ SkinKeyItem* items;
+};
+
+
+static int
+skin_keyset_add( SkinKeyset* kset, int sym, int mod, SkinKeyCommand command )
+{
+ SkinKeyItem* item = kset->items;
+ SkinKeyItem* end = item + kset->num_items;
+ SkinKeyItem* first = NULL;
+ int count = 0;
+
+ D( "adding binding %s to %s", skin_key_command_to_str(command), skin_key_symmod_to_str(sym,mod));
+ for ( ; item < end; item++) {
+ if (item->command == command) {
+ if (!first)
+ first = item;
+ if (++count == SKIN_KEY_COMMAND_MAX_BINDINGS) {
+ /* replace the first (oldest) one in the list */
+ first->sym = sym;
+ first->mod = mod;
+ return 0;
+ }
+ continue;
+ }
+ if (item->sym == sym && item->mod == mod) {
+ /* replace a (sym,mod) binding */
+ item->command = command;
+ return 0;
+ }
+ }
+ if (kset->num_items >= kset->max_items) {
+ int old_size = kset->max_items;
+ int new_size = old_size + (old_size >> 1) + 4;
+ SkinKeyItem* new_items = realloc( kset->items, new_size*sizeof(SkinKeyItem) );
+ if (new_items == NULL) {
+ return -1;
+ }
+ kset->items = new_items;
+ kset->max_items = new_size;
+ }
+ item = kset->items + kset->num_items++;
+ item->command = command;
+ item->sym = sym;
+ item->mod = mod;
+ return 1;
+}
+
+
+SkinKeyset*
+skin_keyset_new ( AConfig* root )
+{
+ SkinKeyset* kset = calloc(1, sizeof(*kset));
+ AConfig* node = root->first_child;;
+
+ if (kset == NULL)
+ return NULL;
+
+ for ( ; node != NULL; node = node->next )
+ {
+ SkinKeyCommand command;
+ int sym, mod;
+ char* p;
+
+ command = skin_key_command_from_str( node->name, -1 );
+ if (command == SKIN_KEY_COMMAND_NONE) {
+ D( "ignoring unknown keyset command '%s'", node->name );
+ continue;
+ }
+ p = (char*)node->value;
+ while (*p) {
+ char* q = strpbrk( p, " \t,:" );
+ if (q == NULL)
+ q = p + strlen(p);
+
+ if (q > p) {
+ int len = q - p;
+ char keys[24];
+ if (len+1 >= (int)sizeof(keys)) {
+ D("key binding too long: '%s'", p);
+ }
+ else {
+ memcpy( keys, p, len );
+ keys[len] = 0;
+ if ( skin_key_symmod_from_str( keys, &sym, &mod ) < 0 ) {
+ D( "ignoring unknown keys '%s' for command '%s'",
+ keys, node->name );
+ } else {
+ skin_keyset_add( kset, sym, mod, command );
+ }
+ }
+ } else if (*q)
+ q += 1;
+
+ p = q;
+ }
+ }
+ return kset;
+}
+
+
+SkinKeyset*
+skin_keyset_new_from_text( const char* text )
+{
+ AConfig* root = aconfig_node("","");
+ char* str = strdup(text);
+ SkinKeyset* result;
+
+ D("kset new from:\n%s", text);
+ aconfig_load( root, str );
+ result = skin_keyset_new( root );
+ free(str);
+ D("kset done result=%p", result);
+ return result;
+}
+
+
+void
+skin_keyset_free( SkinKeyset* kset )
+{
+ if (kset) {
+ free(kset->items);
+ kset->items = NULL;
+ kset->num_items = 0;
+ kset->max_items = 0;
+ free(kset);
+ }
+}
+
+
+extern int
+skin_keyset_get_bindings( SkinKeyset* kset,
+ SkinKeyCommand command,
+ SkinKeyBinding* bindings )
+{
+ if (kset) {
+ int count = 0;
+ SkinKeyItem* item = kset->items;
+ SkinKeyItem* end = item + kset->num_items;
+
+ for ( ; item < end; item++ ) {
+ if (item->command == command) {
+ bindings->sym = item->sym;
+ bindings->mod = item->mod;
+ bindings ++;
+ if ( ++count >= SKIN_KEY_COMMAND_MAX_BINDINGS ) {
+ /* shouldn't happen, but be safe */
+ break;
+ }
+ }
+ }
+ return count;
+ }
+ return -1;
+}
+
+
+/* retrieve the command corresponding to a given (sym,mod) pair. returns SKIN_KEY_COMMAND_NONE if not found */
+SkinKeyCommand
+skin_keyset_get_command( SkinKeyset* kset, int sym, int mod )
+{
+ if (kset) {
+ SkinKeyItem* item = kset->items;
+ SkinKeyItem* end = item + kset->num_items;
+
+ for ( ; item < end; item++ ) {
+ if (item->sym == sym && item->mod == mod) {
+ return item->command;
+ }
+ }
+ }
+ return SKIN_KEY_COMMAND_NONE;
+}
+
+
+const char*
+skin_keyset_get_default( void )
+{
+ return
+ "BUTTON_CALL F3\n"
+ "BUTTON_HANGUP F4\n"
+ "BUTTON_HOME Home\n"
+ "BUTTON_BACK Escape\n"
+ "BUTTON_MENU F2, PageUp\n"
+ "BUTTON_STAR Shift-F2, PageDown\n"
+ "BUTTON_POWER F7\n"
+ "BUTTON_SEARCH F5\n"
+ "BUTTON_CAMERA Ctrl-Keypad_5, Ctrl-F3\n"
+ "BUTTON_VOLUME_UP Keypad_Plus, Ctrl-F5\n"
+ "BUTTON_VOLUME_DOWN Keypad_Minus, Ctrl-F6\n"
+
+ "TOGGLE_NETWORK F8\n"
+ "TOGGLE_TRACING F9\n"
+ "TOGGLE_FULLSCREEN Alt-Enter\n"
+
+ "BUTTON_DPAD_CENTER Keypad_5\n"
+ "BUTTON_DPAD_UP Keypad_8\n"
+ "BUTTON_DPAD_LEFT Keypad_4\n"
+ "BUTTON_DPAD_RIGHT Keypad_6\n"
+ "BUTTON_DPAD_DOWN Keypad_2\n"
+
+ "TOGGLE_TRACKBALL F6\n"
+ "SHOW_TRACKBALL Delete\n"
+
+ "CHANGE_LAYOUT_PREV Keypad_7, Ctrl-F11\n"
+ "CHANGE_LAYOUT_NEXT Keypad_9, Ctrl-F12\n"
+ "ONION_ALPHA_UP Keypad_Multiply\n"
+ "ONION_ALPHA_DOWN Keypad_Divide\n"
+ ;
+}
diff --git a/android/skin/keyset.h b/android/skin/keyset.h
new file mode 100644
index 0000000..d68d6a7
--- /dev/null
+++ b/android/skin/keyset.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_KEYSET_H_
+#define _ANDROID_SKIN_KEYSET_H_
+
+#include "android/config.h"
+
+/* A SkinKeySet maps keystrokes to specific commands. we have a few hard-coded
+ * keysets in the emulator binary, and the user can define its own if he wants
+ * to...
+ */
+typedef struct SkinKeyset SkinKeyset;
+
+#define SKIN_KEY_COMMAND_LIST \
+ _SKIN_KEY_COMMAND(NONE,"no key") \
+ _SKIN_KEY_COMMAND(BUTTON_HOME,"Home button") \
+ _SKIN_KEY_COMMAND(BUTTON_MENU,"Menu (Soft-Left) button") \
+ _SKIN_KEY_COMMAND(BUTTON_STAR,"Star (Soft-Right) button") \
+ _SKIN_KEY_COMMAND(BUTTON_BACK,"Back button") \
+ _SKIN_KEY_COMMAND(BUTTON_CALL,"Call/Dial button") \
+ _SKIN_KEY_COMMAND(BUTTON_HANGUP,"Hangup/EndCall button") \
+ _SKIN_KEY_COMMAND(BUTTON_POWER,"Power button") \
+ _SKIN_KEY_COMMAND(BUTTON_SEARCH,"Search button") \
+ _SKIN_KEY_COMMAND(BUTTON_VOLUME_UP,"Volume up button") \
+ _SKIN_KEY_COMMAND(BUTTON_VOLUME_DOWN,"Volume down button") \
+ _SKIN_KEY_COMMAND(BUTTON_CAMERA,"Camera button") \
+ _SKIN_KEY_COMMAND(CHANGE_LAYOUT_PREV,"switch to previous layout") \
+ _SKIN_KEY_COMMAND(CHANGE_LAYOUT_NEXT,"switch to next layout") \
+ _SKIN_KEY_COMMAND(TOGGLE_NETWORK,"toggle cell network on/off") \
+ _SKIN_KEY_COMMAND(TOGGLE_TRACING,"toggle code profiling") \
+ _SKIN_KEY_COMMAND(TOGGLE_FULLSCREEN,"toggle fullscreen mode") \
+ _SKIN_KEY_COMMAND(TOGGLE_TRACKBALL,"toggle trackball mode") \
+ _SKIN_KEY_COMMAND(SHOW_TRACKBALL,"show trackball") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_CENTER,"DPad center") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_LEFT,"DPad left") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_RIGHT,"DPad right") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_UP,"DPad up") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_DOWN,"DPad down") \
+ _SKIN_KEY_COMMAND(ONION_ALPHA_UP,"increase onion alpha") \
+ _SKIN_KEY_COMMAND(ONION_ALPHA_DOWN,"decrease onion alpha") \
+
+
+/* the list of commands in the emulator */
+#define _SKIN_KEY_COMMAND(x,y) SKIN_KEY_COMMAND_##x,
+typedef enum {
+ SKIN_KEY_COMMAND_LIST
+ SKIN_KEY_COMMAND_MAX // do not remove
+} SkinKeyCommand;
+#undef _SKIN_KEY_COMMAND
+
+/* retrieve the textual name of a given command, this is the command name without
+ * the "SKIN_KEY_COMMAND_" prefix. returns NULL if command is NONE or invalid
+ * the result is a static constant string that must not be freed
+ */
+extern const char* skin_key_command_to_str ( SkinKeyCommand command );
+
+/* convert a string into a SkinKeyCommand. returns SKIN_COMMAND_NONE if the string
+ * is unknown
+ */
+extern SkinKeyCommand skin_key_command_from_str( const char* str, int len );
+
+/* returns a short human-friendly description of the command */
+extern const char* skin_key_command_description( SkinKeyCommand cmd );
+
+/* returns the number of keysym string descriptors */
+extern int skin_keysym_str_count( void );
+
+/* return the n-th keysym string descriptor */
+extern const char* skin_keysym_str( int index );
+
+/* convert a (sym,mod) pair into a descriptive string. e.g. "Ctrl-K" or "Alt-A", etc..
+ * result is a static string that is overwritten on each call
+ */
+extern const char* skin_key_symmod_to_str ( int sym, int mod );
+
+/* convert a key binding description into a (sym,mod) pair. returns 0 on success, -1
+ * if the string cannot be parsed.
+ */
+extern int skin_key_symmod_from_str ( const char* str, int *psym, int *pmod );
+
+/* create a new keyset from a configuration tree node */
+extern SkinKeyset* skin_keyset_new ( AConfig* root );
+extern SkinKeyset* skin_keyset_new_from_text( const char* text );
+
+/* destroy a given keyset */
+extern void skin_keyset_free( SkinKeyset* kset );
+
+/* maximum number of key bindings per command. one command can be bound to several
+ * key bindings for convenience
+ */
+#define SKIN_KEY_COMMAND_MAX_BINDINGS 3
+
+/* a structure that describe a key binding */
+typedef struct {
+ int sym; // really a SDL key symbol
+ int mod; // really a SDL key modifier
+} SkinKeyBinding;
+
+/* return the number of keyboard bindings for a given command. results are placed in the 'bindings' array
+ * which must have at least SKIN_KEY_MAX_BINDINGS items */
+extern int skin_keyset_get_bindings( SkinKeyset* kset,
+ SkinKeyCommand command,
+ SkinKeyBinding* bindings );
+
+/* return the command for a given keypress - SKIN_KEY_COMMAND_NONE is returned if unknown */
+extern SkinKeyCommand skin_keyset_get_command( SkinKeyset* kset, int sym, int mod );
+
+extern const char* skin_keyset_get_default( void );
+
+/* in android_main.c */
+extern SkinKeyset* android_keyset;
+
+#endif /* _ANDROID_SKIN_KEYSET_H_ */
diff --git a/android/skin/rect.c b/android/skin/rect.c
new file mode 100644
index 0000000..93e8bc1
--- /dev/null
+++ b/android/skin/rect.c
@@ -0,0 +1,241 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/rect.h"
+#include <limits.h>
+
+#define SKIN_POS_INITIALIZER { 0, 0 }
+
+void
+skin_pos_rotate( SkinPos* dst, SkinPos* src, SkinRotation rotation )
+{
+ int x = src->x;
+ int y = src->y;
+
+ switch ( rotation & 3 ) {
+ case SKIN_ROTATION_0:
+ dst->x = x;
+ dst->y = y;
+ break;
+
+ case SKIN_ROTATION_90:
+ dst->x = -y;
+ dst->y = x;
+ break;
+
+ case SKIN_ROTATION_180:
+ dst->x = -x;
+ dst->y = -y;
+ break;
+
+ default:
+ dst->x = y;
+ dst->y = -x;
+ }
+}
+
+
+#define SKIN_SIZE_INITIALIZER { 0, 0 }
+
+int
+skin_size_contains( SkinSize* size, int x, int y )
+{
+ return ( (unsigned) x < (unsigned) size->w &&
+ (unsigned) y < (unsigned) size->h );
+}
+
+void
+skin_size_rotate( SkinSize* dst, SkinSize* src, SkinRotation rot )
+{
+ int w = src->w;
+ int h = src->h;
+
+ if ((rot & 1) != 0) {
+ dst->w = h;
+ dst->h = w;
+ } else {
+ dst->w = w;
+ dst->h = h;
+ }
+}
+
+/** SKIN RECTANGLES
+ **/
+#define SKIN_RECT_INITIALIZER { SKIN_POS_INITIALIZER, SKIN_SIZE_INITIALIZER }
+
+void
+skin_rect_init( SkinRect* r, int x, int y, int w, int h )
+{
+ if (w < 0 || h < 0)
+ x = y = w = h = 0;
+
+ r->pos.x = x;
+ r->pos.y = y;
+ r->size.w = w;
+ r->size.h = h;
+}
+
+
+void
+skin_rect_translate( SkinRect* r, int dx, int dy )
+{
+ r->pos.x += dx;
+ r->pos.y += dy;
+}
+
+
+void
+skin_rect_rotate( SkinRect* dst, SkinRect* src, SkinRotation rot )
+{
+ int x, y, w, h;
+
+ switch (rot & 3) {
+ case SKIN_ROTATION_90:
+ x = src->pos.x;
+ y = src->pos.y;
+ w = src->size.w;
+ h = src->size.h;
+ dst->pos.x = -(y + h);
+ dst->pos.y = x;
+ dst->size.w = h;
+ dst->size.h = w;
+ break;
+
+ case SKIN_ROTATION_180:
+ dst->pos.x = -(src->pos.x + src->size.w);
+ dst->pos.y = -(src->pos.y + src->size.h);
+ dst->size = src->size;
+ break;
+
+ case SKIN_ROTATION_270:
+ x = src->pos.x;
+ y = src->pos.y;
+ w = src->size.w;
+ h = src->size.h;
+ dst->pos.x = y;
+ dst->pos.y = -(x + w);
+ dst->size.w = h;
+ dst->size.h = w;
+ break;
+
+ default:
+ dst[0] = src[0];
+ }
+}
+
+
+int
+skin_rect_contains( SkinRect* r, int x, int y )
+{
+ return ( (unsigned)(x - r->pos.x) < (unsigned)r->size.w &&
+ (unsigned)(y - r->pos.y) < (unsigned)r->size.h );
+}
+
+SkinOverlap
+skin_rect_contains_rect( SkinRect *r1, SkinRect *r2 )
+{
+ SkinBox a, b;
+
+ skin_box_from_rect( &a, r1 );
+ skin_box_from_rect( &b, r2 );
+
+ if (a.x2 <= b.x1 || b.x2 <= a.x1 || a.y2 <= b.y1 || b.y2 <= a.y1) {
+ return SKIN_OUTSIDE;
+ }
+
+ if (b.x1 >= a.x1 && b.x2 <= a.x2 && b.y1 >= a.y1 && b.y2 <= a.y2) {
+ return SKIN_INSIDE;
+ }
+
+ return SKIN_OVERLAP;
+}
+
+
+int
+skin_rect_intersect( SkinRect* result, SkinRect* r1, SkinRect* r2 )
+{
+ SkinBox a, b, r;
+
+ skin_box_from_rect( &a, r1 );
+ skin_box_from_rect( &b, r2 );
+
+ if (a.x2 <= b.x1 || b.x2 <= a.x1 || a.y2 <= b.y1 || b.y2 <= a.y1) {
+ result->pos.x = result->pos.y = result->size.w = result->size.h = 0;
+ return 0;
+ }
+
+ r.x1 = (a.x1 > b.x1) ? a.x1 : b.x1;
+ r.x2 = (a.x2 < b.x2) ? a.x2 : b.x2;
+ r.y1 = (a.y1 > b.y1) ? a.y1 : b.y1;
+ r.y2 = (a.y2 < b.y2) ? a.y2 : b.y2;
+
+ skin_box_to_rect( &r, result );
+ return 1;
+}
+
+int
+skin_rect_equals( SkinRect* r1, SkinRect* r2 )
+{
+ return (r1->pos.x == r2->pos.x && r1->pos.y == r2->pos.y &&
+ r1->size.w == r2->size.w && r2->size.h == r2->size.h);
+}
+
+/** SKIN BOXES
+ **/
+void
+skin_box_minmax_init( SkinBox* box )
+{
+ box->x1 = box->y1 = INT_MAX;
+ box->x2 = box->y2 = INT_MIN;
+}
+
+void
+skin_box_minmax_update( SkinBox* a, SkinRect* r )
+{
+ SkinBox b[1];
+
+ skin_box_from_rect(b, r);
+
+ if (b->x1 < a->x1) a->x1 = b->x1;
+ if (b->y1 < a->y1) a->y1 = b->y1;
+ if (b->x2 > a->x2) a->x2 = b->x2;
+ if (b->y2 > a->y2) a->y2 = b->y2;
+}
+
+int
+skin_box_minmax_to_rect( SkinBox* box, SkinRect* r )
+{
+ if (box->x1 > box->x2) {
+ r->pos.x = r->pos.y = r->size.w = r->size.h = 0;
+ return 0;
+ }
+ skin_box_to_rect( box, r );
+ return 1;
+}
+
+void
+skin_box_from_rect( SkinBox* box, SkinRect* r )
+{
+ box->x1 = r->pos.x;
+ box->y1 = r->pos.y;
+ box->x2 = r->size.w + box->x1;
+ box->y2 = r->size.h + box->y1;
+}
+
+void
+skin_box_to_rect( SkinBox* box, SkinRect* r )
+{
+ r->pos.x = box->x1;
+ r->pos.y = box->y1;
+ r->size.w = box->x2 - box->x1;
+ r->size.h = box->y2 - box->y1;
+}
+
diff --git a/android/skin/rect.h b/android/skin/rect.h
new file mode 100644
index 0000000..757f888
--- /dev/null
+++ b/android/skin/rect.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_RECT_H
+#define _ANDROID_SKIN_RECT_H
+
+/** Rectangles
+ **/
+
+typedef enum {
+ SKIN_ROTATION_0,
+ SKIN_ROTATION_90,
+ SKIN_ROTATION_180,
+ SKIN_ROTATION_270
+} SkinRotation;
+
+typedef struct {
+ int x, y;
+} SkinPos;
+
+extern void skin_pos_rotate( SkinPos* dst, SkinPos* src, SkinRotation rot );
+
+typedef struct {
+ int w, h;
+} SkinSize;
+
+extern void skin_size_rotate( SkinSize* dst, SkinSize* src, SkinRotation rot );
+extern int skin_size_contains( SkinSize* size, int x, int y );
+
+
+typedef struct {
+ SkinPos pos;
+ SkinSize size;
+} SkinRect;
+
+extern void skin_rect_init ( SkinRect* r, int x, int y, int w, int h );
+extern void skin_rect_translate( SkinRect* r, int dx, int dy );
+extern void skin_rect_rotate ( SkinRect* dst, SkinRect* src, SkinRotation rotation );
+extern int skin_rect_contains ( SkinRect* r, int x, int y );
+extern int skin_rect_intersect( SkinRect* result, SkinRect* r1, SkinRect* r2 );
+extern int skin_rect_equals ( SkinRect* r1, SkinRect* r2 );
+
+typedef enum {
+ SKIN_OUTSIDE = 0,
+ SKIN_INSIDE = 1,
+ SKIN_OVERLAP = 2
+} SkinOverlap;
+
+extern SkinOverlap skin_rect_contains_rect( SkinRect *r1, SkinRect *r2 );
+
+typedef struct {
+ int x1, y1;
+ int x2, y2;
+} SkinBox;
+
+extern void skin_box_init( SkinBox* box, int x1, int y1, int x2, int y2 );
+extern void skin_box_minmax_init( SkinBox* box );
+extern void skin_box_minmax_update( SkinBox* box, SkinRect* rect );
+extern int skin_box_minmax_to_rect( SkinBox* box, SkinRect* rect );
+extern void skin_box_from_rect( SkinBox* box, SkinRect* rect );
+extern void skin_box_to_rect( SkinBox* box, SkinRect* rect );
+
+#endif /* _ANDROID_SKIN_RECT_H */
diff --git a/android/skin/region.c b/android/skin/region.c
new file mode 100644
index 0000000..a5f26a5
--- /dev/null
+++ b/android/skin/region.c
@@ -0,0 +1,1448 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/region.h"
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h> /* malloc/free */
+
+/*************************************************************************
+ *************************************************************************
+ ****
+ **** ASSERTION SUPPORT
+ ****
+ ****
+ ****/
+
+#ifdef UNIT_TEST
+#include <stdlib.h>
+#include <stdio.h>
+static void
+_rpanic(void)
+{
+ *((char*)(void*)0) = 1; /* should SEGFAULT */
+ /* put a breakpoint here */
+ exit(1);
+}
+
+#define RASSERT(cond) \
+ ({ if (!(cond)) { fprintf(stderr, "%s:%d:%s: assertion failed: %s", \
+ __FILE__, __LINE__, __FUNCTION__, #cond ); _rpanic(); } })
+
+#else
+#define RASSERT(cond) ((void)0)
+#endif
+
+
+/*************************************************************************
+ *************************************************************************
+ ****
+ **** IMPLEMENTATION DETAILS
+ ****
+ ****
+ ****/
+
+/* this implementation of regions encodes the the region's spans with the
+ following format:
+
+ region ::= yband+ YSENTINEL
+ yband ::= YTOP YBOTTOM scanline
+ scanline ::= span+ XSENTINEL
+ span ::= XLEFT XRIGHT
+
+ XSENTINEL ::= 0x7fff
+ YSENTINEL := 0x7fff
+
+ all values are sorted in increasing order, which means that:
+
+ - YTOP1 < YBOTTOM1 <= YTOP2 < YBOTTOM2 <= .... < YSENTINEL
+ - XLEFT1 < XRIGHT1 < XLEFT2 < XRIGHT2 < .... < XSENTINEL
+ (in a given scanline)
+*/
+
+/* convenience shortbuts */
+typedef SkinRegionRun Run;
+typedef SkinRegion Region;
+
+#define RUNS_RECT_COUNT 6 /* YTOP YBOT XLEFT XRIGHT XSENTINEL YSENTINEL */
+
+#define XSENTINEL SKIN_REGION_SENTINEL
+#define YSENTINEL SKIN_REGION_SENTINEL
+
+#define RUNS_EMPTY ((Run*)(void*)(-1))
+#define RUNS_RECT ((Run*)(void*)(0))
+
+static __inline__ int
+region_isEmpty( Region* r )
+{
+ return r->runs == RUNS_EMPTY;
+}
+
+static __inline__ int
+region_isRect( Region* r )
+{
+ return r->runs == RUNS_RECT;
+}
+
+static __inline__ int
+region_isComplex( Region* r )
+{
+ return r->runs != RUNS_EMPTY && r->runs != RUNS_RECT;
+}
+
+/** RunStore: ref-counted storage for runs
+ **/
+
+typedef struct {
+ int refcount;
+ int count;
+} RunStore;
+
+static void
+runstore_free( RunStore* s )
+{
+ free(s);
+}
+
+static RunStore*
+runstore_alloc( int count )
+{
+ RunStore* s = malloc( sizeof(*s) + sizeof(Run)*count );
+ RASSERT(s != NULL);
+ s->count = count;
+ s->refcount = 1;
+ return s;
+}
+
+static RunStore*
+runstore_edit( RunStore* s )
+{
+ RunStore* s2;
+
+ if (s->refcount == 1)
+ return s;
+
+ s2 = runstore_alloc( s->count );
+ if (s2) {
+ memcpy( s2, s, sizeof(*s) + s->count*sizeof(Run) );
+ s->refcount -= 1;
+ s2->refcount = 1;
+ }
+ return s2;
+}
+
+static void
+runstore_unrefp( RunStore* *ps )
+{
+ RunStore* s = *ps;
+ if (s != NULL) {
+ if (s->refcount <= 0)
+ runstore_free(s);
+ *ps = NULL;
+ }
+}
+
+static RunStore*
+runstore_ref( RunStore* s )
+{
+ if (s) s->refcount += 1;
+ return s;
+}
+
+static __inline__ RunStore*
+runstore_from_runs( Run* runs )
+{
+ RASSERT(runs != RUNS_EMPTY);
+ RASSERT(runs != RUNS_RECT);
+ return (RunStore*)runs - 1;
+}
+
+static __inline__ Run*
+runstore_to_runs( RunStore* s )
+{
+ RASSERT(s != NULL);
+ return (Run*)(s + 1);
+}
+
+static Run*
+region_edit( Region* r )
+{
+ RunStore* s;
+
+ RASSERT(region_isComplex(r));
+
+ s = runstore_from_runs(r->runs);
+ s = runstore_edit(s);
+ r->runs = runstore_to_runs(s);
+ return r->runs;
+}
+
+/** Run parsing
+ **/
+
+static Run*
+runs_next_scanline( Run* runs )
+{
+ RASSERT(runs[0] != YSENTINEL && runs[1] != YSENTINEL );
+ runs += 2;
+ do { runs += 1; } while (runs[-1] != XSENTINEL);
+ return runs;
+}
+
+static Run*
+runs_find_y( Run* runs, int y )
+{
+ do {
+ int ybot, ytop = runs[0];
+
+ if (y < ytop)
+ return NULL;
+
+ ybot = runs[1];
+ if (y < ybot)
+ return runs;
+
+ runs = runs_next_scanline( runs );
+ } while (runs[0] != YSENTINEL);
+
+ return NULL;
+}
+
+static void
+runs_set_rect( Run* runs, SkinRect* rect )
+{
+ runs[0] = rect->pos.y;
+ runs[1] = rect->pos.y + rect->size.h;
+ runs[2] = rect->pos.x;
+ runs[3] = rect->pos.x + rect->size.w;
+ runs[4] = XSENTINEL;
+ runs[5] = YSENTINEL;
+}
+
+static Run*
+runs_copy_scanline( Run* dst, Run* src )
+{
+ RASSERT(src[0] != YSENTINEL);
+ RASSERT(src[1] != YSENTINEL);
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 2;
+ dst += 2;
+ do { *dst++ = *src++; } while (src[-1] != XSENTINEL);
+ return dst;
+}
+
+static Run*
+runs_copy_scanline_adj( Run* dst, Run* src, int ytop, int ybot )
+{
+ Run* runs2 = runs_copy_scanline( dst, src );
+ dst[0] = (Run) ytop;
+ dst[1] = (Run) ybot;
+ return runs2;
+}
+
+static __inline__ Run*
+runs_add_span( Run* dst, int left, int right )
+{
+ dst[0] = (Run) left;
+ dst[1] = (Run) right;
+ return dst + 2;
+}
+
+static __inline__ int
+runs_get_count( Run* runs )
+{
+ RunStore* s = runstore_from_runs(runs);
+ return s->count;
+}
+
+
+static void
+runs_coalesce_band( Run* *psrc_spans, Run* *pdst_spans, SkinBox* minmax )
+{
+ Run* sspan = *psrc_spans;
+ Run* dspan = *pdst_spans;
+ int pleft = sspan[0];
+ int pright = sspan[1];
+ int xleft, xright;
+
+ RASSERT(pleft != XSENTINEL);
+ RASSERT(pright != XSENTINEL);
+ RASSERT(pleft < pright);
+
+ if (pleft < minmax->x1) minmax->x1 = pleft;
+
+ sspan += 2;
+ xleft = sspan[0];
+
+ while (xleft != XSENTINEL)
+ {
+ xright = sspan[1];
+ RASSERT(xright != XSENTINEL);
+ RASSERT(xleft < xright);
+
+ if (xleft == pright) {
+ pright = xright;
+ } else {
+ dspan[0] = (Run) pleft;
+ dspan[1] = (Run) pright;
+ dspan += 2;
+ }
+ sspan += 2;
+ xleft = sspan[0];
+ }
+ dspan[0] = (Run) pleft;
+ dspan[1] = (Run) pright;
+ dspan[2] = XSENTINEL;
+ dspan += 3;
+ sspan += 1; /* skip XSENTINEL */
+
+ if (pright > minmax->x2) minmax->x2 = pright;
+
+ *psrc_spans = sspan;
+ *pdst_spans = dspan;
+}
+
+
+static int
+runs_coalesce( Run* dst, Run* src, SkinBox* minmax )
+{
+ Run* prev = NULL;
+ Run* dst0 = dst;
+ int ytop = src[0];
+ int ybot;
+
+ while (ytop != YSENTINEL)
+ {
+ Run* sspan = src + 2;
+ Run* dspan = dst + 2;
+
+ ybot = src[1];
+ RASSERT( ytop < ybot );
+ RASSERT( ybot != YSENTINEL );
+ RASSERT( src[2] != XSENTINEL );
+
+ if (ytop < minmax->y1) minmax->y1 = ytop;
+ if (ybot > minmax->y2) minmax->y2 = ybot;
+
+ dst[0] = (Run) ytop;
+ dst[1] = (Run) ybot;
+
+ runs_coalesce_band( &sspan, &dspan, minmax );
+
+ if (prev && prev[1] == dst[0] && (dst-prev) == (dspan-dst) &&
+ !memcmp(prev+2, dst+2, (dspan-dst-2)*sizeof(Run)))
+ {
+ /* coalesce two identical bands */
+ prev[1] = dst[1];
+ }
+ else
+ {
+ prev = dst;
+ dst = dspan;
+ }
+ src = sspan;
+ ytop = src[0];
+ }
+ dst[0] = YSENTINEL;
+ return (dst + 1 - dst0);
+}
+
+/*************************************************************************
+ *************************************************************************
+ ****
+ **** PUBLIC API
+ ****
+ ****/
+
+void
+skin_region_init_empty( SkinRegion* r )
+{
+ /* empty region */
+ r->bounds.pos.x = r->bounds.pos.y = 0;
+ r->bounds.size.w = r->bounds.size.h = 0;
+ r->runs = RUNS_EMPTY;
+}
+
+void
+skin_region_init( SkinRegion* r, int x1, int y1, int x2, int y2 )
+{
+ if (x1 >= x2 || y1 >= y2) {
+ skin_region_init_empty(r);
+ return;
+ }
+ r->bounds.pos.x = x1;
+ r->bounds.pos.y = y1;
+ r->bounds.size.w = x2 - x1;
+ r->bounds.size.h = y2 - y1;
+ r->runs = RUNS_RECT;
+}
+
+void
+skin_region_init_rect( SkinRegion* r, SkinRect* rect )
+{
+ if (rect == NULL || rect->size.w <= 0 || rect->size.h <= 0) {
+ skin_region_init_empty(r);
+ return;
+ }
+ r->bounds = rect[0];
+ r->runs = RUNS_RECT;
+}
+
+void
+skin_region_init_box( SkinRegion* r, SkinBox* box )
+{
+ if (box == NULL || box->x1 >= box->x2 || box->y1 >= box->y2) {
+ skin_region_init_empty(r);
+ return;
+ }
+ r->bounds.pos.x = box->x1;
+ r->bounds.pos.y = box->y1;
+ r->bounds.size.w = box->x2 - box->x1;
+ r->bounds.size.h = box->y2 - box->y1;
+ r->runs = RUNS_RECT;
+}
+
+void
+skin_region_init_copy( SkinRegion* r, SkinRegion* src )
+{
+ if (src == NULL || region_isEmpty(src))
+ skin_region_init_empty(r);
+ else {
+ r[0] = src[0];
+ if (region_isComplex(src)) {
+ RunStore* s = runstore_from_runs(r->runs);
+ runstore_ref(s);
+ }
+ }
+}
+
+
+void
+skin_region_reset( SkinRegion* r )
+{
+ if (r != NULL) {
+ if (region_isComplex(r)) {
+ RunStore* s = runstore_from_runs(r->runs);
+ runstore_unrefp( &s );
+ }
+ skin_region_init_empty(r);
+ }
+}
+
+
+
+void
+skin_region_copy( SkinRegion* r, SkinRegion* src )
+{
+ skin_region_reset(r);
+ skin_region_init_copy(r, src);
+}
+
+
+int
+skin_region_equals( SkinRegion* r1, SkinRegion* r2 )
+{
+ Run *runs1, *runs2;
+ RunStore *store1, *store2;
+
+ if (r1 == r2)
+ return 1;
+
+ if (!skin_rect_equals( &r1->bounds, &r2->bounds ))
+ return 0;
+
+ runs1 = r1->runs;
+ runs2 = r2->runs;
+
+ if (runs1 == runs2) /* empties and rects */
+ return 1;
+
+ if ( !region_isComplex(r1) || !region_isComplex(r2) )
+ return 0;
+
+ store1 = runstore_from_runs(runs1);
+ store2 = runstore_from_runs(runs2);
+
+ if (store1->count == store2->count &&
+ !memcmp( (char*)runs1, (char*)runs2, store1->count*sizeof(Run) ) )
+ return 1;
+
+ return 0;
+}
+
+void
+skin_region_translate( SkinRegion* r, int dx, int dy )
+{
+ Run* runs;
+
+ if (region_isEmpty(r))
+ return;
+
+ skin_rect_translate( &r->bounds, dx, dy );
+ if (region_isRect(r))
+ return;
+
+ runs = region_edit(r);
+ while (runs[0] != YSENTINEL) {
+ int ytop = runs[0];
+ int ybot = runs[1];
+
+ RASSERT(ybot != YSENTINEL);
+ runs[0] = (Run)(ytop + dy);
+ runs[1] = (Run)(ybot + dy);
+ runs += 2;
+ while (runs[0] != XSENTINEL) {
+ int xleft = runs[0];
+ int xright = runs[1];
+ RASSERT(xright != YSENTINEL);
+ runs[0] = (Run)(xleft + dx);
+ runs[1] = (Run)(xright + dx);
+ runs += 2;
+ }
+ runs += 1;
+ }
+}
+
+void
+skin_region_get_bounds( SkinRegion* r, SkinRect* bounds )
+{
+ if (r != NULL) {
+ bounds[0] = r->bounds;
+ } else {
+ bounds->pos.x = bounds->pos.y = 0;
+ bounds->size.w = bounds->size.h = 0;
+ }
+}
+
+int
+skin_region_is_empty( SkinRegion* r )
+{
+ return region_isEmpty(r);
+}
+
+int
+skin_region_is_rect( SkinRegion* r )
+{
+ return region_isRect(r);
+}
+
+int
+skin_region_is_complex( SkinRegion* r )
+{
+ return region_isComplex(r);
+}
+
+void
+skin_region_swap( SkinRegion* r, SkinRegion* r2 )
+{
+ SkinRegion tmp;
+ tmp = r[0];
+ r[0] = r2[0];
+ r2[0] = tmp;
+}
+
+
+SkinOverlap
+skin_region_contains( SkinRegion* r, int x, int y )
+{
+ if (region_isEmpty(r))
+ return SKIN_OUTSIDE;
+ if (region_isRect(r)) {
+ return skin_rect_contains(&r->bounds,x,y);
+ } else {
+ Run* runs = runs_find_y( r->runs, y );
+ if (runs != NULL) {
+ runs += 2;
+ do {
+ int xright, xleft = runs[0];
+
+ if (x < xleft) // also x < xleft == XSENTINEL
+ break;
+ xright = runs[1];
+ if (xright == XSENTINEL)
+ break;
+ if (x < xright)
+ return SKIN_INSIDE;
+ runs += 2;
+ } while (runs[0] != XSENTINEL);
+ }
+ return SKIN_OUTSIDE;
+ }
+}
+
+
+SkinOverlap
+skin_region_contains_rect( SkinRegion* r, SkinRect* rect )
+{
+ SkinRegion r2[1];
+ skin_region_init_rect( r2, rect );
+ return skin_region_test_intersect( r, r2 );
+}
+
+
+SkinOverlap
+skin_region_contains_box( SkinRegion* r, SkinBox* b )
+{
+ SkinRegion r2[1];
+
+ skin_region_init_box( r2, b );
+ return skin_region_test_intersect( r, r2 );
+}
+
+
+
+#define FLAG_REGION_1 (1 << 0)
+#define FLAG_REGION_2 (1 << 1)
+#define FLAG_REGION_BOTH (1 << 2)
+
+SkinOverlap
+skin_region_test_intersect( SkinRegion* r1,
+ SkinRegion* r2 )
+{
+ Run *runs1, *runs2;
+ Run run2_tmp[ RUNS_RECT_COUNT ];
+ SkinRect r;
+
+ if (region_isEmpty(r1) || region_isEmpty(r2))
+ return SKIN_OUTSIDE;
+
+ if ( !skin_rect_intersect( &r, &r1->bounds, &r2->bounds) )
+ return SKIN_OUTSIDE;
+
+ if (region_isRect(r1)) {
+ if (region_isRect(r2)) {
+ return skin_rect_contains_rect(&r1->bounds, &r2->bounds);
+ } else {
+ SkinRegion* tmp = r1;
+ r1 = r2;
+ r2 = tmp;
+ }
+ }
+ /* here r1 is guaranteed to be complex, r2 is either rect of complex */
+ runs1 = r1->runs;
+ if (region_isRect(r2)) {
+ runs2 = run2_tmp;
+ runs_set_rect(runs2, &r2->bounds);
+ }
+ else {
+ runs2 = r2->runs;
+ }
+
+ {
+ int flags = 0;
+
+ while (runs1[0] != YSENTINEL && runs2[0] != YSENTINEL)
+ {
+ int ytop1 = runs1[0];
+ int ybot1 = runs1[1];
+ int ytop2 = runs2[0];
+ int ybot2 = runs2[1];
+
+ if (ybot1 <= ytop2)
+ {
+ /* band1 over band2 */
+ flags |= FLAG_REGION_1;
+ runs1 = runs_next_scanline( runs1 );
+ }
+ else if (ybot2 <= ytop1)
+ {
+ /* band2 over band1 */
+ flags |= FLAG_REGION_2;
+ runs2 = runs_next_scanline( runs2 );
+ }
+ else /* band1 and band2 overlap */
+ {
+ Run* span1;
+ Run* span2;
+ int ybot;
+
+ if (ytop1 < ytop2) {
+ flags |= FLAG_REGION_1;
+ ytop1 = ytop2;
+ } else if (ytop2 < ytop1) {
+ flags |= FLAG_REGION_2;
+ ytop2 = ytop1;
+ }
+
+ ybot = (ybot1 < ybot2) ? ybot1 : ybot2;
+
+ span1 = runs1 + 2;
+ span2 = runs2 + 2;
+
+ while (span1[0] != XSENTINEL && span2[0] != XSENTINEL)
+ {
+ int xleft1 = span1[0];
+ int xright1 = span1[1];
+ int xleft2 = span2[0];
+ int xright2 = span2[1];
+
+ RASSERT(xright1 != XSENTINEL);
+ RASSERT(xright2 != XSENTINEL);
+
+ if (xright1 <= xleft2) {
+ flags |= FLAG_REGION_1;
+ span1 += 2;
+ }
+ else if (xright2 <= xleft1) {
+ flags |= FLAG_REGION_2;
+ span2 += 2;
+ }
+ else {
+ int xright;
+
+ if (xleft1 < xleft2) {
+ flags |= FLAG_REGION_1;
+ xleft1 = xleft2;
+ } else if (xleft2 < xleft1) {
+ flags |= FLAG_REGION_2;
+ xleft2 = xleft1;
+ }
+
+ xright = (xright1 < xright2) ? xright1 : xright2;
+
+ flags |= FLAG_REGION_BOTH;
+
+ if (xright == xright1)
+ span1 += 2;
+ if (xright == xright2)
+ span2 += 2;
+ }
+ }
+
+ if (span1[0] != XSENTINEL) {
+ flags |= FLAG_REGION_1;
+ }
+
+ if (span2[0] != XSENTINEL) {
+ flags |= FLAG_REGION_2;
+ }
+
+ if (ybot == ybot1)
+ runs1 = runs_next_scanline( runs1 );
+
+ if (ybot == ybot2)
+ runs2 = runs_next_scanline( runs2 );
+ }
+ }
+
+ if (runs1[0] != YSENTINEL) {
+ flags |= FLAG_REGION_1;
+ }
+
+ if (runs2[0] != YSENTINEL) {
+ flags |= FLAG_REGION_2;
+ }
+
+ if ( !(flags & FLAG_REGION_BOTH) ) {
+ /* no intersection at all */
+ return SKIN_OUTSIDE;
+ }
+
+ if ( (flags & FLAG_REGION_2) != 0 ) {
+ /* intersection + overlap */
+ return SKIN_OVERLAP;
+ }
+
+ return SKIN_INSIDE;
+ }
+}
+
+typedef struct {
+ Run* runs1;
+ Run* runs2;
+ Run* runs_base;
+ Run* runs;
+ RunStore* store;
+ Region result[1];
+ Run runs1_rect[ RUNS_RECT_COUNT ];
+ Run runs2_rect[ RUNS_RECT_COUNT ];
+} RegionOperator;
+
+
+static void
+region_operator_init( RegionOperator* o,
+ Region* r1,
+ Region* r2 )
+{
+ int run1_count, run2_count;
+ int maxruns;
+
+ RASSERT( !region_isEmpty(r1) );
+ RASSERT( !region_isEmpty(r2) );
+
+ if (region_isRect(r1)) {
+ run1_count = RUNS_RECT_COUNT;
+ o->runs1 = o->runs1_rect;
+ runs_set_rect( o->runs1, &r1->bounds );
+ } else {
+ o->runs1 = r1->runs;
+ run1_count = runs_get_count(r1->runs);
+ }
+
+ if (region_isRect(r2)) {
+ run2_count = RUNS_RECT_COUNT;
+ o->runs2 = o->runs2_rect;
+ runs_set_rect( o->runs2, &r2->bounds );
+ } else {
+ o->runs2 = r2->runs;
+ run2_count = runs_get_count(r2->runs);
+ }
+
+ maxruns = run1_count < run2_count ? run2_count : run1_count;
+ o->store = runstore_alloc( 3*maxruns );
+ o->runs_base = runstore_to_runs(o->store);
+}
+
+
+static void
+region_operator_do( RegionOperator* o, int wanted )
+{
+ Run* runs1 = o->runs1;
+ Run* runs2 = o->runs2;
+ Run* runs = o->runs_base;
+ int ytop1 = runs1[0];
+ int ytop2 = runs2[0];
+
+ if (ytop1 != YSENTINEL && ytop2 != YSENTINEL)
+ {
+ int ybot1, ybot2;
+
+ while (ytop1 != YSENTINEL && ytop2 != YSENTINEL)
+ {
+ int ybot;
+
+ ybot1 = runs1[1];
+ ybot2 = runs2[1];
+
+ RASSERT(ybot1 != YSENTINEL);
+ RASSERT(ybot2 != YSENTINEL);
+
+ if (ybot1 <= ytop2) {
+ if (wanted & FLAG_REGION_1)
+ runs = runs_copy_scanline_adj( runs, runs1, ytop1, ybot1 );
+ runs1 = runs_next_scanline( runs1 );
+ ytop1 = runs1[0];
+ continue;
+ }
+
+ if (ybot2 <= ytop1) {
+ if (wanted & FLAG_REGION_2)
+ runs = runs_copy_scanline_adj( runs, runs2, ytop2, ybot2 );
+ runs2 = runs_next_scanline(runs2);
+ ytop2 = runs2[0];
+ continue;
+ }
+
+ if (ytop1 < ytop2) {
+ if (wanted & FLAG_REGION_1)
+ runs = runs_copy_scanline_adj( runs, runs1, ytop1, ytop2 );
+ ytop1 = ytop2;
+ }
+ else if (ytop2 < ytop1) {
+ if (wanted & FLAG_REGION_2)
+ runs = runs_copy_scanline_adj( runs, runs2, ytop2, ytop1 );
+ ytop2 = ytop1;
+ }
+
+ ybot = (ybot1 <= ybot2) ? ybot1 : ybot2;
+
+ runs[0] = (Run) ytop1;
+ runs[1] = (Run) ybot;
+
+ /* do the common band */
+ {
+ Run* span1 = runs1 + 2;
+ Run* span2 = runs2 + 2;
+ Run* span = runs + 2;
+ int xleft1 = span1[0];
+ int xleft2 = span2[0];
+ int xright1, xright2;
+
+ while (xleft1 != XSENTINEL && xleft2 != XSENTINEL)
+ {
+ int xright;
+
+ xright1 = span1[1];
+ xright2 = span2[1];
+
+ RASSERT(xright1 != XSENTINEL);
+ RASSERT(xright2 != XSENTINEL);
+
+ if (xright1 <= xleft2) {
+ if (wanted & FLAG_REGION_1)
+ span = runs_add_span( span, xleft1, xright1 );
+ span1 += 2;
+ xleft1 = span1[0];
+ continue;
+ }
+
+ if (xright2 <= xleft1) {
+ if (wanted & FLAG_REGION_2)
+ span = runs_add_span( span, xleft2, xright2 );
+ span2 += 2;
+ xleft2 = span2[0];
+ continue;
+ }
+
+ if (xleft1 < xleft2) {
+ if (wanted & FLAG_REGION_1)
+ span = runs_add_span( span, xleft1, xleft2 );
+ xleft1 = xleft2;
+ }
+
+ else if (xleft2 < xleft1) {
+ if (wanted & FLAG_REGION_2)
+ span = runs_add_span( span, xleft2, xleft1 );
+ xleft2 = xleft1;
+ }
+
+ xright = (xright1 <= xright2) ? xright1 : xright2;
+
+ if (wanted & FLAG_REGION_BOTH)
+ span = runs_add_span( span, xleft1, xright );
+
+ xleft1 = xleft2 = xright;
+
+ if (xright == xright1) {
+ span1 += 2;
+ xleft1 = span1[0];
+ }
+ if (xright == xright2) {
+ span2 += 2;
+ xleft2 = span2[0];
+ }
+ }
+
+ if (wanted & FLAG_REGION_1) {
+ while (xleft1 != XSENTINEL) {
+ RASSERT(span1[1] != XSENTINEL);
+ span[0] = (Run) xleft1;
+ span[1] = span1[1];
+ span += 2;
+ span1 += 2;
+ xleft1 = span1[0];
+ }
+ }
+
+ if (wanted & FLAG_REGION_2) {
+ while (xleft2 != XSENTINEL) {
+ RASSERT(span2[1] != XSENTINEL);
+ span[0] = (Run) xleft2;
+ span[1] = span2[1];
+ span += 2;
+ span2 += 2;
+ xleft2 = span2[0];
+ }
+ }
+
+ if (span > runs + 2) {
+ span[0] = XSENTINEL;
+ runs = span + 1;
+ }
+ }
+
+ ytop1 = ytop2 = ybot;
+
+ if (ybot == ybot1) {
+ runs1 = runs_next_scanline( runs1 );
+ ytop1 = runs1[0];
+ }
+ if (ybot == ybot2) {
+ runs2 = runs_next_scanline( runs2 );
+ ytop2 = runs2[0];
+ }
+ }
+ }
+
+ if ((wanted & FLAG_REGION_1) != 0) {
+ while (ytop1 != YSENTINEL) {
+ runs = runs_copy_scanline_adj( runs, runs1, ytop1, runs1[1] );
+ runs1 = runs_next_scanline(runs1);
+ ytop1 = runs1[0];
+ }
+ }
+
+ if ((wanted & FLAG_REGION_2) != 0) {
+ while (ytop2 != YSENTINEL) {
+ runs = runs_copy_scanline_adj( runs, runs2, ytop2, runs2[1] );
+ runs2 = runs_next_scanline(runs2);
+ ytop2 = runs2[0];
+ }
+ }
+
+ runs[0] = YSENTINEL;
+ o->runs = runs + 1;
+}
+
+/* returns 1 if the result is not empty */
+static int
+region_operator_done( RegionOperator* o )
+{
+ Run* src = o->runs;
+ int count;
+ SkinBox minmax;
+ RunStore* store;
+
+ if (src <= o->runs_base + 1) {
+ /* result is empty */
+ skin_region_init_empty( o->result );
+ return 0;
+ }
+
+ /* coalesce the temp runs in-place and compute the corresponding bounds */
+ minmax.x1 = minmax.y1 = INT_MAX;
+ minmax.x2 = minmax.y2 = INT_MIN;
+
+ count = runs_coalesce( o->runs_base, o->runs_base, &minmax );
+ if (count == 1) {
+ /* result is empty */
+ skin_region_init_empty( o->result );
+ }
+ else
+ {
+ skin_box_to_rect( &minmax, &o->result->bounds );
+ if (count == RUNS_RECT_COUNT) {
+ o->result->runs = RUNS_RECT;
+ }
+ else
+ {
+ /* result is complex */
+ store = runstore_alloc( count );
+ o->result->runs = runstore_to_runs(store);
+ memcpy( o->result->runs, o->runs_base, count*sizeof(Run) );
+ }
+ }
+
+ /* release temporary runstore */
+ runstore_unrefp( &o->store );
+
+ return region_isEmpty(o->result);
+}
+
+
+
+int
+skin_region_intersect( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r))
+ return 0;
+
+ if (region_isEmpty(r2))
+ return 1;
+
+ if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) {
+ skin_region_init_empty(r);
+ return 0;
+ }
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_BOTH );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+
+ return region_isEmpty( r );
+}
+
+
+/* performs r = (intersect r (region+_from_rect rect)), returns true iff
+ the resulting region is not empty */
+int
+skin_region_intersect_rect( SkinRegion* r, SkinRect* rect )
+{
+ Region r2[1];
+
+ skin_region_init_rect( r2, rect );
+ return skin_region_intersect( r, r2 );
+}
+
+/* performs r = (union r r2) */
+void
+skin_region_union( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r)) {
+ skin_region_copy(r, r2);
+ return;
+ }
+
+ if (region_isEmpty(r2))
+ return;
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_1|FLAG_REGION_2|FLAG_REGION_BOTH );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+}
+
+void
+skin_region_union_rect( SkinRegion* r, SkinRect* rect )
+{
+ Region r2[1];
+
+ skin_region_init_rect(r2, rect);
+ return skin_region_union( r, r2 );
+}
+
+/* performs r = (difference r r2) */
+void
+skin_region_substract( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r) || region_isEmpty(r2))
+ return;
+
+ if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) {
+ skin_region_init_empty(r);
+ return;
+ }
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_1 );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+}
+
+void
+skin_region_substract_rect( SkinRegion* r, SkinRect* rect )
+{
+ Region r2[1];
+
+ skin_region_init_rect(r2, rect);
+ return skin_region_substract( r, r2 );
+}
+
+/* performs r = (xor r r2) */
+void
+skin_region_xor( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r)) {
+ skin_region_copy(r, r2);
+ return;
+ }
+
+ if (region_isEmpty(r2))
+ return;
+
+ if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) {
+ skin_region_init_empty(r);
+ return;
+ }
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_1 );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+}
+
+
+void
+skin_region_iterator_init( SkinRegionIterator* iter,
+ SkinRegion* region )
+{
+ iter->region = region;
+ iter->band = NULL;
+ iter->span = NULL;
+}
+
+int
+skin_region_iterator_next( SkinRegionIterator* iter, SkinRect *rect )
+{
+ static const Run dummy[ 2 ] = { XSENTINEL, YSENTINEL };
+
+ Run* span = iter->span;
+ Run* band = iter->band;
+
+ if (span == NULL) {
+ Region* r = iter->region;
+ if (region_isEmpty(r))
+ return 0;
+ if (region_isRect(r)) {
+ rect[0] = r->bounds;
+ iter->span = (Run*) dummy;
+ return 1;
+ }
+ iter->band = band = r->runs;
+ iter->span = span = r->runs + 2;
+ }
+ else if (band == NULL)
+ return 0;
+
+ while (span[0] == XSENTINEL) {
+ band = span + 1;
+ if (band[0] == YSENTINEL || band[1] == YSENTINEL)
+ return 0;
+
+ iter->band = band;
+ iter->span = span = band + 2;
+ }
+
+ if (span[1] == XSENTINEL)
+ return 0;
+
+ rect->pos.y = band[0];
+ rect->pos.x = span[0];
+ rect->size.h = band[1] - band[0];
+ rect->size.w = span[1] - span[0];
+
+ iter->span = span + 2;
+ return 1;
+}
+
+int
+skin_region_iterator_next_box( SkinRegionIterator* iter, SkinBox *box )
+{
+ SkinRect rect;
+ int result = skin_region_iterator_next( iter, &rect );
+
+ if (result)
+ skin_box_from_rect( box, &rect );
+
+ return result;
+}
+
+#ifdef UNIT_TEST
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "skin_rect.c"
+
+static void
+panic(void)
+{
+ *((char*)0) = 1;
+ exit(0);
+}
+
+static void
+_expectCompare( Region* r, const SkinBox* boxes, int count )
+{
+ if (count == 0) {
+ if ( !skin_region_is_empty(r) ) {
+ printf( " result is not empty\n" );
+ panic();
+ }
+ }
+ else if (count == 1) {
+ SkinRect rect1, rect2;
+ if ( !skin_region_is_rect(r) ) {
+ printf( " result is not a rectangle\n" );
+ panic();
+ }
+ skin_region_get_bounds( r, &rect1 );
+ skin_box_to_rect( (SkinBox*)boxes, &rect2 );
+ if ( !skin_rect_equals( &rect1, &rect2 ) ) {
+ printf( " result is (%d,%d,%d,%d), expected (%d,%d,%d,%d)\n",
+ rect1.pos.x, rect1.pos.y,
+ rect1.pos.x + rect1.size.w, rect1.pos.y + rect1.size.h,
+ rect2.pos.x, rect2.pos.y,
+ rect2.pos.x + rect2.size.w, rect2.pos.y + rect2.size.h );
+ panic();
+ }
+ }
+ else {
+ SkinRegionIterator iter;
+ SkinBox b;
+ int n;
+
+ skin_region_iterator_init( &iter, r );
+ n = 0;
+ while (n < count) {
+ if ( !skin_region_iterator_next_box( &iter, &b ) ) {
+ printf( "missing region box (%d, %d, %d, %d)\n",
+ boxes->x1, boxes->y1, boxes->x2, boxes->y2 );
+ panic();
+ }
+
+ if (b.x1 != boxes->x1 || b.x2 != boxes->x2||
+ b.y1 != boxes->y1 || b.y2 != boxes->y2)
+ {
+ printf( "invalid region box (%d,%d,%d,%d) expecting (%d,%d,%d,%d)\n",
+ b.x1, b.y1, b.x2, b.y2,
+ boxes->x1, boxes->y1, boxes->x2, boxes->y2 );
+ panic();
+ }
+ boxes += 1;
+ n += 1;
+ }
+
+ if ( skin_region_iterator_next_box( &iter, &b ) ) {
+ printf( "excess region box (%d,%d,%d,%d)\n",
+ b.x1, b.y1, b.x2, b.y2 );
+ panic();
+ }
+ }
+}
+
+
+static void
+expectEmptyRegion( Region* r )
+{
+ printf( "expectEmptyRegion: " );
+ if (!skin_region_is_empty(r)) {
+ printf( "region not empty !!\n" );
+ panic();
+ }
+ printf( "ok\n" );
+}
+
+static void
+expectTestIntersect( Region* r1, Region* r2, SkinOverlap overlap )
+{
+ SkinOverlap result;
+ printf( "expectTestIntersect(%d): ", overlap );
+ result = skin_region_test_intersect(r1, r2);
+ if (result != overlap) {
+ printf( "bad result %d, expected %d\n", result, overlap );
+ panic();
+ }
+ printf( "ok\n" );
+}
+
+static void
+expectRectRegion( Region* r, int x1, int y1, int x2, int y2 )
+{
+ SkinRect rect;
+ SkinBox b;
+
+ printf( "expectRectRegion(%d,%d,%d,%d): ",x1,y1,x2,y2 );
+ if (!skin_region_is_rect(r)) {
+ printf( "region not rect !!\n" );
+ panic();
+ }
+
+ skin_region_get_bounds( r, &rect );
+ skin_box_from_rect( &b, &rect );
+
+ if (b.x1 != x1 || b.x2 != x2 || b.y1 != y1 || b.y2 != y2) {
+ printf( "rect region bounds are (%d,%d,%d,%d), expecting (%d,%d,%d,%d)\n",
+ b.x1, b.y1, b.x2, b.y2, x1, y1, x2, y2 );
+ panic();
+ }
+ printf( "ok\n" );
+}
+
+static void
+expectComplexRegion( Region* r, const SkinBox* boxes, int count )
+{
+ SkinRegionIterator iter;
+ SkinBox b;
+ int n;
+
+ printf( "expectComplexRegion(): " );
+ if (!skin_region_is_complex(r)) {
+ printf( "region is not complex !!\n" );
+ panic();
+ }
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+static void
+expectIntersect( Region* r1, Region* r2, const SkinBox* boxes, int count )
+{
+ SkinRegion r[1];
+
+ printf( "expectIntersect(%d): ", count );
+ skin_region_init_copy( r, r1 );
+ skin_region_intersect( r, r2 );
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+static void
+expectUnion( Region* r1, Region* r2, const SkinBox* boxes, int count )
+{
+ SkinRegion r[1];
+
+ printf( "expectUnion(%d): ", count );
+ skin_region_init_copy( r, r1 );
+ skin_region_union( r, r2 );
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+
+static void
+expectSubstract( Region* r1, Region* r2, const SkinBox* boxes, int count )
+{
+ SkinRegion r[1];
+
+ printf( "expectSubstract(%d): ", count );
+ skin_region_init_copy( r, r1 );
+ skin_region_substract( r, r2 );
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+
+int main( void )
+{
+ SkinRegion r[1], r2[1];
+
+ skin_region_init_empty( r );
+ expectEmptyRegion( r );
+
+ skin_region_init( r, 10, 20, 110, 120 );
+ expectRectRegion( r, 10, 20, 110, 120 );
+
+ skin_region_translate( r, 50, 80 );
+ expectRectRegion( r, 60, 100, 160, 200 );
+
+ skin_region_init( r, 10, 10, 40, 40 );
+ skin_region_init( r2, 20, 20, 50, 50 );
+ expectTestIntersect( r, r2, SKIN_OVERLAP );
+
+ skin_region_translate(r2, +20, + 20 );
+ expectTestIntersect( r, r2, SKIN_OUTSIDE );
+
+ skin_region_translate(r2, -30, -30 );
+ expectTestIntersect( r, r2, SKIN_INSIDE );
+
+ {
+ static const SkinBox result1[1] = {
+ { 20, 20, 40, 40 }
+ };
+ static const SkinBox result2[3] = {
+ { 10, 10, 40, 20 },
+ { 10, 20, 50, 40 },
+ { 20, 40, 50, 50 },
+ };
+ static const SkinBox result3[2] = {
+ { 10, 10, 40, 20 },
+ { 10, 20, 20, 40 },
+ };
+
+ skin_region_init( r, 10, 10, 40, 40 );
+ skin_region_init( r2, 20, 20, 50, 50 );
+ expectIntersect( r, r2, result1, 1 );
+ expectUnion( r, r2, result2, 3 );
+ expectSubstract( r, r2, result3, 2 );
+ }
+
+ return 0;
+}
+
+#endif /* UNIT_TEST */
diff --git a/android/skin/region.h b/android/skin/region.h
new file mode 100644
index 0000000..9ac4103
--- /dev/null
+++ b/android/skin/region.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_REGION_H
+#define _ANDROID_SKIN_REGION_H
+
+#include "android/skin/rect.h"
+
+typedef struct SkinRegion SkinRegion;
+
+extern void skin_region_init_empty( SkinRegion* r );
+extern void skin_region_init( SkinRegion* r, int x1, int y1, int x2, int y2 );
+extern void skin_region_init_rect( SkinRegion* r, SkinRect* rect );
+extern void skin_region_init_box( SkinRegion* r, SkinBox* box );
+extern void skin_region_init_copy( SkinRegion* r, SkinRegion* r2 );
+extern void skin_region_reset( SkinRegion* r );
+
+/* finalize region, then copy src into it */
+extern void skin_region_copy( SkinRegion* r, SkinRegion* src );
+
+/* compare two regions for equality */
+extern int skin_region_equals( SkinRegion* r1, SkinRegion* r2 );
+
+/* swap two regions */
+extern void skin_region_swap( SkinRegion* r, SkinRegion* r2 );
+
+extern int skin_region_is_empty( SkinRegion* r );
+extern int skin_region_is_rect( SkinRegion* r );
+extern int skin_region_is_complex( SkinRegion* r );
+extern void skin_region_get_bounds( SkinRegion* r, SkinRect* bounds );
+
+extern void skin_region_translate( SkinRegion* r, int dx, int dy );
+
+extern SkinOverlap skin_region_contains( SkinRegion* r, int x, int y );
+
+extern SkinOverlap skin_region_contains_rect( SkinRegion* r,
+ SkinRect* rect );
+
+extern SkinOverlap skin_region_contains_box( SkinRegion* r, SkinBox* b );
+
+/* returns overlap mode for "is r2 inside r1" */
+extern SkinOverlap skin_region_test_intersect( SkinRegion* r1,
+ SkinRegion* r2 );
+
+/* performs r = (intersect r r2), returns true if the resulting region
+ is not empty */
+extern int skin_region_intersect ( SkinRegion* r, SkinRegion* r2 );
+extern int skin_region_intersect_rect( SkinRegion* r, SkinRect* rect );
+
+/* performs r = (intersect r (region+_from_rect rect)), returns true iff
+ the resulting region is not empty */
+
+/* performs r = (union r r2) */
+extern void skin_region_union ( SkinRegion* r, SkinRegion* r2 );
+extern void skin_region_union_rect( SkinRegion* r, SkinRect* rect );
+
+/* performs r = (difference r r2) */
+extern void skin_region_substract ( SkinRegion* r, SkinRegion* r2 );
+extern void skin_region_substract_rect( SkinRegion* r, SkinRect* rect );
+
+/* performs r = (xor r r2) */
+extern void skin_region_xor( SkinRegion* r, SkinRegion* r2 );
+
+typedef struct SkinRegionIterator SkinRegionIterator;
+
+/* iterator */
+extern void skin_region_iterator_init( SkinRegionIterator* iter,
+ SkinRegion* r );
+
+extern int skin_region_iterator_next( SkinRegionIterator* iter,
+ SkinRect *rect );
+
+extern int skin_rection_iterator_next_box( SkinRegionIterator* iter,
+ SkinBox *box );
+
+/* the following should be considered private definitions. they're only here
+ to allow clients to allocate SkinRegion objects themselves... */
+
+typedef signed short SkinRegionRun;
+#define SKIN_REGION_SENTINEL 0x7fff
+
+struct SkinRegion
+{
+ SkinRect bounds;
+ SkinRegionRun* runs;
+};
+
+struct SkinRegionIterator
+{
+ SkinRegion* region;
+ SkinRegionRun* band;
+ SkinRegionRun* span;
+};
+
+#endif /* _ANDROID_SKIN_REGION_H */
diff --git a/android/skin/scaler.c b/android/skin/scaler.c
new file mode 100644
index 0000000..59e212f
--- /dev/null
+++ b/android/skin/scaler.c
@@ -0,0 +1,135 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/scaler.h"
+#include <stdint.h>
+#include <math.h>
+
+struct SkinScaler {
+ double scale;
+ double xdisp, ydisp;
+ double invscale;
+ int valid;
+};
+
+static SkinScaler _scaler0;
+
+SkinScaler*
+skin_scaler_create( void )
+{
+ _scaler0.scale = 1.0;
+ _scaler0.xdisp = 0.0;
+ _scaler0.ydisp = 0.0;
+ _scaler0.invscale = 1.0;
+ return &_scaler0;
+}
+
+/* change the scale of a given scaler. returns 0 on success, or -1 in case of
+ * problem (unsupported scale) */
+int
+skin_scaler_set( SkinScaler* scaler, double scale, double xdisp, double ydisp )
+{
+ /* right now, we only support scales in the 0.5 .. 1.0 range */
+ if (scale < 0.1)
+ scale = 0.1;
+ else if (scale > 6.0)
+ scale = 6.0;
+
+ scaler->scale = scale;
+ scaler->xdisp = xdisp;
+ scaler->ydisp = ydisp;
+ scaler->invscale = 1/scale;
+ scaler->valid = 1;
+
+ return 0;
+}
+
+void
+skin_scaler_free( SkinScaler* scaler )
+{
+ scaler=scaler;
+}
+
+typedef struct {
+ SDL_Rect rd; /* destination rectangle */
+ int sx, sy; /* source start position in 16.16 format */
+ int ix, iy; /* source increments in 16.16 format */
+ int src_pitch;
+ int src_w;
+ int src_h;
+ int dst_pitch;
+ uint8_t* dst_line;
+ uint8_t* src_line;
+ double scale;
+} ScaleOp;
+
+
+#define ARGB_SCALE_GENERIC scale_generic
+#define ARGB_SCALE_05_TO_10 scale_05_to_10
+#define ARGB_SCALE_UP_BILINEAR scale_up_bilinear
+#define ARGB_SCALE_UP_QUICK_4x4 scale_up_quick_4x4
+
+#include "android/skin/argb.h"
+
+
+void
+skin_scaler_scale( SkinScaler* scaler,
+ SDL_Surface* dst_surface,
+ SDL_Surface* src_surface,
+ int sx,
+ int sy,
+ int sw,
+ int sh )
+{
+ ScaleOp op;
+
+ if ( !scaler->valid )
+ return;
+
+ SDL_LockSurface( src_surface );
+ SDL_LockSurface( dst_surface );
+ {
+ op.scale = scaler->scale;
+ op.src_pitch = src_surface->pitch;
+ op.src_line = src_surface->pixels;
+ op.src_w = src_surface->w;
+ op.src_h = src_surface->h;
+ op.dst_pitch = dst_surface->pitch;
+ op.dst_line = dst_surface->pixels;
+
+ /* compute the destination rectangle */
+ op.rd.x = (int)(sx * scaler->scale + scaler->xdisp);
+ op.rd.y = (int)(sy * scaler->scale + scaler->ydisp);
+ op.rd.w = (int)(ceil((sx + sw) * scaler->scale + scaler->xdisp)) - op.rd.x;
+ op.rd.h = (int)(ceil((sy + sh) * scaler->scale + scaler->ydisp)) - op.rd.y;
+
+ /* compute the starting source position in 16.16 format
+ * and the corresponding increments */
+ op.sx = (int)((op.rd.x - scaler->xdisp) * scaler->invscale * 65536);
+ op.sy = (int)((op.rd.y - scaler->ydisp) * scaler->invscale * 65536);
+
+ op.ix = (int)( scaler->invscale * 65536 );
+ op.iy = op.ix;
+
+ op.dst_line += op.rd.x*4 + op.rd.y*op.dst_pitch;
+
+ if (op.scale >= 0.5 && op.scale <= 1.0)
+ scale_05_to_10( &op );
+ else if (op.scale > 1.0)
+ scale_up_bilinear( &op );
+ else
+ scale_generic( &op );
+ }
+ SDL_UnlockSurface( dst_surface );
+ SDL_UnlockSurface( src_surface );
+
+ SDL_UpdateRects( dst_surface, 1, &op.rd );
+}
diff --git a/android/skin/scaler.h b/android/skin/scaler.h
new file mode 100644
index 0000000..4e0ec5a
--- /dev/null
+++ b/android/skin/scaler.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_SCALER_H
+#define _ANDROID_SKIN_SCALER_H
+
+#include "android/skin/image.h"
+
+typedef struct SkinScaler SkinScaler;
+
+/* create a new image scaler. by default, it uses a scale of 1.0 */
+extern SkinScaler* skin_scaler_create( void );
+
+/* change the scale of a given scaler. returns 0 on success, or -1 in case of
+ * problem (unsupported scale) */
+extern int skin_scaler_set( SkinScaler* scaler,
+ double scale,
+ double xDisp,
+ double yDisp );
+
+extern void skin_scaler_free( SkinScaler* scaler );
+
+extern void skin_scaler_scale( SkinScaler* scaler,
+ SDL_Surface* dst,
+ SDL_Surface* src,
+ int sx,
+ int sy,
+ int sw,
+ int sh );
+
+#endif /* _ANDROID_SKIN_SCALER_H */
diff --git a/android/skin/surface.c b/android/skin/surface.c
new file mode 100644
index 0000000..4424bd8
--- /dev/null
+++ b/android/skin/surface.c
@@ -0,0 +1,613 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/surface.h"
+#include "android/skin/argb.h"
+#include <SDL.h>
+
+#define DEBUG 1
+
+#if DEBUG
+#include "android/utils/debug.h"
+#define D(...) VERBOSE_PRINT(surface,__VA_ARGS__)
+#else
+#define D(...) ((void)0)
+#endif
+
+struct SkinSurface {
+ int refcount;
+ uint32_t* pixels;
+ SDL_Surface* surface;
+ SkinSurfaceDoneFunc done_func;
+ void* done_user;
+};
+
+static void
+skin_surface_free( SkinSurface* s )
+{
+ if (s->done_func) {
+ s->done_func( s->done_user );
+ s->done_func = NULL;
+ }
+ if (s->surface) {
+ SDL_FreeSurface(s->surface);
+ s->surface = NULL;
+ }
+ free(s);
+}
+
+extern SkinSurface*
+skin_surface_ref( SkinSurface* surface )
+{
+ if (surface)
+ surface->refcount += 1;
+ return surface;
+}
+
+extern void
+skin_surface_unrefp( SkinSurface* *psurface )
+{
+ SkinSurface* surf = *psurface;
+ if (surf) {
+ if (--surf->refcount <= 0)
+ skin_surface_free(surf);
+ *psurface = NULL;
+ }
+}
+
+
+void
+skin_surface_set_done( SkinSurface* s, SkinSurfaceDoneFunc done_func, void* done_user )
+{
+ s->done_func = done_func;
+ s->done_user = done_user;
+}
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+# define ARGB32_R_MASK 0xff000000
+# define ARGB32_G_MASK 0x00ff0000
+# define ARGB32_B_MASK 0x0000ff00
+# define ARGB32_A_MASK 0x000000ff
+#else
+# define ARGB32_R_MASK 0x000000ff
+# define ARGB32_G_MASK 0x0000ff00
+# define ARGB32_B_MASK 0x00ff0000
+# define ARGB32_A_MASK 0xff000000
+#endif
+
+static SDL_Surface*
+_sdl_surface_create_rgb( int width,
+ int height,
+ int depth,
+ int flags )
+{
+ Uint32 rmask, gmask, bmask, amask;
+
+ if (depth == 8) {
+ rmask = gmask = bmask = 0;
+ amask = 0xff;
+ } else if (depth == 32) {
+ rmask = ARGB32_R_MASK;
+ gmask = ARGB32_G_MASK;
+ bmask = ARGB32_B_MASK;
+ amask = ARGB32_A_MASK;
+ } else
+ return NULL;
+
+ return SDL_CreateRGBSurface( flags, width, height, depth,
+ rmask, gmask, bmask, amask );
+}
+
+
+static SDL_Surface*
+_sdl_surface_create_rgb_from( int width,
+ int height,
+ int pitch,
+ void* pixels,
+ int depth )
+{
+ Uint32 rmask, gmask, bmask, amask;
+
+ if (depth == 8) {
+ rmask = gmask = bmask = 0;
+ amask = 0xff;
+ } else if (depth == 32) {
+ rmask = ARGB32_R_MASK;
+ gmask = ARGB32_G_MASK;
+ bmask = ARGB32_B_MASK;
+ amask = ARGB32_A_MASK;
+ } else
+ return NULL;
+
+ return SDL_CreateRGBSurfaceFrom( pixels, width, height, pitch, depth,
+ rmask, gmask, bmask, amask );
+}
+
+
+static SkinSurface*
+_skin_surface_create( SDL_Surface* surface,
+ void* pixels )
+{
+ SkinSurface* s = malloc(sizeof(*s));
+ if (s != NULL) {
+ s->refcount = 1;
+ s->pixels = pixels;
+ s->surface = surface;
+ s->done_func = NULL;
+ s->done_user = NULL;
+ }
+ else {
+ SDL_FreeSurface(surface);
+ free(pixels);
+ D( "not enough memory to allocate new skin surface !" );
+ }
+ return s;
+}
+
+
+SkinSurface*
+skin_surface_create_fast( int w, int h )
+{
+ SDL_Surface* surface;
+
+ surface = _sdl_surface_create_rgb( w, h, 32, SDL_HWSURFACE );
+ if (surface == NULL) {
+ surface = _sdl_surface_create_rgb( w, h, 32, SDL_SWSURFACE );
+ if (surface == NULL) {
+ D( "could not create fast %dx%d ARGB32 surface: %s",
+ w, h, SDL_GetError() );
+ return NULL;
+ }
+ }
+ return _skin_surface_create( surface, NULL );
+}
+
+
+SkinSurface*
+skin_surface_create_slow( int w, int h )
+{
+ SDL_Surface* surface;
+
+ surface = _sdl_surface_create_rgb( w, h, 32, SDL_SWSURFACE );
+ if (surface == NULL) {
+ D( "could not create slow %dx%d ARGB32 surface: %s",
+ w, h, SDL_GetError() );
+ return NULL;
+ }
+ return _skin_surface_create( surface, NULL );
+}
+
+
+SkinSurface*
+skin_surface_create_argb32_from(
+ int w,
+ int h,
+ int pitch,
+ uint32_t* pixels,
+ int do_copy )
+{
+ SDL_Surface* surface;
+ uint32_t* pixcopy = NULL;
+
+ if (do_copy) {
+ size_t size = h*pitch;
+ pixcopy = malloc( size );
+ if (pixcopy == NULL && size > 0) {
+ D( "not enough memory to create %dx%d ARGB32 surface",
+ w, h );
+ return NULL;
+ }
+ memcpy( pixcopy, pixels, size );
+ }
+
+ surface = _sdl_surface_create_rgb_from( w, h, pitch,
+ pixcopy ? pixcopy : pixels,
+ 32 );
+ if (surface == NULL) {
+ D( "could not create %dx%d slow ARGB32 surface: %s",
+ w, h, SDL_GetError() );
+ return NULL;
+ }
+ return _skin_surface_create( surface, pixcopy );
+}
+
+
+
+
+extern int
+skin_surface_lock( SkinSurface* s, SkinSurfacePixels *pix )
+{
+ if (!s || !s->surface) {
+ D( "error: trying to lock stale surface %p", s );
+ return -1;
+ }
+ if ( SDL_LockSurface( s->surface ) != 0 ) {
+ D( "could not lock surface %p: %s", s, SDL_GetError() );
+ return -1;
+ }
+ pix->w = s->surface->w;
+ pix->h = s->surface->h;
+ pix->pitch = s->surface->pitch;
+ pix->pixels = s->surface->pixels;
+ return 0;
+}
+
+/* unlock a slow surface that was previously locked */
+extern void
+skin_surface_unlock( SkinSurface* s )
+{
+ if (s && s->surface)
+ SDL_UnlockSurface( s->surface );
+}
+
+
+#if 0
+static uint32_t
+skin_surface_map_argb( SkinSurface* s, uint32_t c )
+{
+ if (s && s->surface) {
+ return SDL_MapRGBA( s->surface->format,
+ ((c) >> 16) & 255,
+ ((c) >> 8) & 255,
+ ((c) & 255),
+ ((c) >> 24) & 255 );
+ }
+ return 0x00000000;
+}
+#endif
+
+typedef struct {
+ int x;
+ int y;
+ int w;
+ int h;
+ int sx;
+ int sy;
+
+ uint8_t* dst_line;
+ int dst_pitch;
+ SDL_Surface* dst_lock;
+
+ uint8_t* src_line;
+ int src_pitch;
+ SDL_Surface* src_lock;
+ uint32_t src_color;
+
+} SkinBlit;
+
+
+static int
+skin_blit_init_fill( SkinBlit* blit,
+ SkinSurface* dst,
+ SkinRect* dst_rect,
+ uint32_t color )
+{
+ int x = dst_rect->pos.x;
+ int y = dst_rect->pos.y;
+ int w = dst_rect->size.w;
+ int h = dst_rect->size.h;
+ int delta;
+
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ delta = (x + w) - dst->surface->w;
+ if (delta > 0)
+ w -= delta;
+
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+ delta = (y + h) - dst->surface->h;
+ if (delta > 0)
+ h -= delta;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+
+ blit->x = x;
+ blit->y = y;
+ blit->w = w;
+ blit->h = h;
+
+ if ( !SDL_LockSurface(dst->surface) )
+ return 0;
+
+ blit->dst_lock = dst->surface;
+ blit->dst_pitch = dst->surface->pitch;
+ blit->dst_line = dst->surface->pixels + y*blit->dst_pitch;
+
+ blit->src_lock = NULL;
+ blit->src_color = color;
+
+ return 1;
+}
+
+static int
+skin_blit_init_blit( SkinBlit* blit,
+ SkinSurface* dst,
+ SkinPos* dst_pos,
+ SkinSurface* src,
+ SkinRect* src_rect )
+{
+ int x = dst_pos->x;
+ int y = dst_pos->y;
+ int sx = src_rect->pos.x;
+ int sy = src_rect->pos.y;
+ int w = src_rect->size.w;
+ int h = src_rect->size.h;
+ int delta;
+
+ if (x < 0) {
+ w += x;
+ sx -= x;
+ x = 0;
+ }
+ if (sx < 0) {
+ w += sx;
+ x -= sx;
+ sx = 0;
+ }
+
+ delta = (x + w) - dst->surface->w;
+ if (delta > 0)
+ w -= delta;
+
+ delta = (sx + w) - src->surface->w;
+ if (delta > 0)
+ w -= delta;
+
+ if (y < 0) {
+ h += y;
+ sy += y;
+ y = 0;
+ }
+ if (sy < 0) {
+ h += sy;
+ y -= sy;
+ sy = 0;
+ }
+ delta = (y + h) - dst->surface->h;
+ if (delta > 0)
+ h -= delta;
+
+ delta = (sy + h) - src->surface->h;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+
+ blit->x = x;
+ blit->y = y;
+ blit->w = w;
+ blit->h = h;
+
+ blit->sx = sx;
+ blit->sy = sy;
+
+ if ( !SDL_LockSurface(dst->surface) )
+ return 0;
+
+ blit->dst_lock = dst->surface;
+ blit->dst_pitch = dst->surface->pitch;
+ blit->dst_line = (uint8_t*) dst->surface->pixels + y*blit->dst_pitch;
+
+ if ( !SDL_LockSurface(src->surface) ) {
+ SDL_UnlockSurface(dst->surface);
+ return 0;
+ }
+
+ blit->src_lock = src->surface;
+ blit->src_pitch = src->surface->pitch;
+ blit->src_line = (uint8_t*) src->surface->pixels + sy*blit->src_pitch;
+
+ return 1;
+}
+
+static void
+skin_blit_done( SkinBlit* blit )
+{
+ if (blit->src_lock)
+ SDL_UnlockSurface( blit->src_lock );
+ if (blit->dst_lock)
+ SDL_UnlockSurface( blit->dst_lock );
+ ARGB_DONE;
+}
+
+typedef void (*SkinLineFillFunc)( uint32_t* dst, uint32_t color, int len );
+typedef void (*SkinLineBlitFunc)( uint32_t* dst, const uint32_t* src, int len );
+
+static void
+skin_line_fill_copy( uint32_t* dst, uint32_t color, int len )
+{
+ uint32_t* end = dst + len;
+
+ while (dst + 4 <= end) {
+ dst[0] = dst[1] = dst[2] = dst[3] = color;
+ dst += 4;
+ }
+ while (dst < end) {
+ dst[0] = color;
+ dst += 1;
+ }
+}
+
+static void
+skin_line_fill_srcover( uint32_t* dst, uint32_t color, int len )
+{
+ uint32_t* end = dst + len;
+ uint32_t alpha = (color >> 24);
+
+ if (alpha == 255)
+ {
+ skin_line_fill_copy(dst, color, len);
+ }
+ else
+ {
+ ARGB_DECL(src_c);
+ ARGB_DECL_ZERO();
+
+ alpha = 255 - alpha;
+ alpha += (alpha >> 7);
+
+ ARGB_UNPACK(src_c,color);
+
+ for ( ; dst < end; dst++ )
+ {
+ ARGB_DECL(dst_c);
+
+ ARGB_READ(dst_c,dst);
+ ARGB_MULSHIFT(dst_c,dst_c,alpha,8);
+ ARGB_ADD(dst_c,src_c);
+ ARGB_WRITE(dst_c,dst);
+ }
+ }
+}
+
+static void
+skin_line_fill_dstover( uint32_t* dst, uint32_t color, int len )
+{
+ uint32_t* end = dst + len;
+ ARGB_DECL(src_c);
+ ARGB_DECL_ZERO();
+
+ ARGB_UNPACK(src_c,color);
+
+ for ( ; dst < end; dst++ )
+ {
+ ARGB_DECL(dst_c);
+ ARGB_DECL(val);
+
+ uint32_t alpha;
+
+ ARGB_READ(dst_c,dst);
+ alpha = 256 - (dst[0] >> 24);
+ ARGB_MULSHIFT(val,src_c,alpha,8);
+ ARGB_ADD(val,dst_c);
+ ARGB_WRITE(val,dst);
+ }
+}
+
+extern void
+skin_surface_fill( SkinSurface* dst,
+ SkinRect* rect,
+ uint32_t argb_premul,
+ SkinBlitOp blitop )
+{
+ SkinLineFillFunc fill;
+ SkinBlit blit[1];
+
+ switch (blitop) {
+ case SKIN_BLIT_COPY: fill = skin_line_fill_copy; break;
+ case SKIN_BLIT_SRCOVER: fill = skin_line_fill_srcover; break;
+ case SKIN_BLIT_DSTOVER: fill = skin_line_fill_dstover; break;
+ default: return;
+ }
+
+ if ( skin_blit_init_fill( blit, dst, rect, argb_premul ) ) {
+ uint8_t* line = blit->dst_line;
+ int pitch = blit->dst_pitch;
+ uint8_t* end = line + pitch*blit->h;
+
+ for ( ; line != end; line += pitch )
+ fill( (uint32_t*)line + blit->x, argb_premul, blit->w );
+ }
+}
+
+
+static void
+skin_line_blit_copy( uint32_t* dst, const uint32_t* src, int len )
+{
+ memcpy( (char*)dst, (const char*)src, len*4 );
+}
+
+
+
+static void
+skin_line_blit_srcover( uint32_t* dst, const uint32_t* src, int len )
+{
+ uint32_t* end = dst + len;
+ ARGB_DECL_ZERO();
+
+ for ( ; dst < end; dst++ ) {
+ ARGB_DECL(s);
+ ARGB_DECL(d);
+ ARGB_DECL(v);
+ uint32_t alpha;
+
+ ARGB_READ(s,src);
+ alpha = (src[0] >> 24);
+ if (alpha > 0) {
+ ARGB_READ(d,dst);
+ alpha = 256 - alpha;
+ ARGB_MULSHIFT(v,d,alpha,8);
+ ARGB_ADD(v,d);
+ ARGB_WRITE(v,dst);
+ }
+ }
+}
+
+static void
+skin_line_blit_dstover( uint32_t* dst, const uint32_t* src, int len )
+{
+ uint32_t* end = dst + len;
+ ARGB_DECL_ZERO();
+
+ for ( ; dst < end; dst++ ) {
+ ARGB_DECL(s);
+ ARGB_DECL(d);
+ ARGB_DECL(v);
+ uint32_t alpha;
+
+ ARGB_READ(d,dst);
+ alpha = (dst[0] >> 24);
+ if (alpha < 255) {
+ ARGB_READ(s,src);
+ alpha = 256 - alpha;
+ ARGB_MULSHIFT(v,s,alpha,8);
+ ARGB_ADD(v,s);
+ ARGB_WRITE(v,dst);
+ }
+ }
+}
+
+
+extern void
+skin_surface_blit( SkinSurface* dst,
+ SkinPos* dst_pos,
+ SkinSurface* src,
+ SkinRect* src_rect,
+ SkinBlitOp blitop )
+{
+ SkinLineBlitFunc func;
+ SkinBlit blit[1];
+
+ switch (blitop) {
+ case SKIN_BLIT_COPY: func = skin_line_blit_copy; break;
+ case SKIN_BLIT_SRCOVER: func = skin_line_blit_srcover; break;
+ case SKIN_BLIT_DSTOVER: func = skin_line_blit_dstover; break;
+ default: return;
+ }
+
+ if ( skin_blit_init_blit( blit, dst, dst_pos, src, src_rect ) ) {
+ uint8_t* line = blit->dst_line;
+ uint8_t* sline = blit->src_line;
+ int pitch = blit->dst_pitch;
+ int spitch = blit->src_pitch;
+ uint8_t* end = line + pitch*blit->h;
+
+ for ( ; line != end; line += pitch, sline += spitch )
+ func( (uint32_t*)line + blit->x, (uint32_t*)sline + blit->sx, blit->w );
+
+ skin_blit_done(blit);
+ }
+}
diff --git a/android/skin/surface.h b/android/skin/surface.h
new file mode 100644
index 0000000..39ab439
--- /dev/null
+++ b/android/skin/surface.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_SURFACE_H
+#define _ANDROID_SKIN_SURFACE_H
+
+#include "android/skin/region.h"
+#include <stdint.h>
+
+/* a SkinSurface models a 32-bit ARGB pixel image that can be blitted to or from
+ */
+typedef struct SkinSurface SkinSurface;
+
+/* increment surface's reference count */
+extern SkinSurface* skin_surface_ref( SkinSurface* surface );
+
+/* decrement a surface's reference count. takes the surface's address as parameter.
+ it will be set to NULL on exit */
+extern void skin_surface_unrefp( SkinSurface* *psurface );
+
+/* sets a callback that will be called when the surface is destroyed.
+ * used NULL for done_func to disable it
+ */
+typedef void (*SkinSurfaceDoneFunc)( void* user );
+
+extern void skin_surface_set_done( SkinSurface* s, SkinSurfaceDoneFunc done_func, void* done_user );
+
+
+/* there are two kinds of surfaces:
+
+ - fast surfaces, whose content can be placed in video memory or
+ RLE-compressed for faster blitting and blending. the pixel format
+ used internally might be something very different from ARGB32.
+
+ - slow surfaces, whose content (pixel buffer) can be accessed and modified
+ with _lock()/_unlock() but may be blitted far slower since they reside in
+ system memory.
+*/
+
+/* create a 'fast' surface that contains a copy of an input ARGB32 pixmap */
+extern SkinSurface* skin_surface_create_fast( int w, int h );
+
+/* create an empty 'slow' surface containing an ARGB32 pixmap */
+extern SkinSurface* skin_surface_create_slow( int w, int h );
+
+/* create a 'slow' surface from a given pixel buffer. if 'do_copy' is TRUE, then
+ * the content of 'pixels' is copied into a heap-allocated buffer. otherwise
+ * the data will be used directly.
+ */
+extern SkinSurface* skin_surface_create_argb32_from(
+ int w,
+ int h,
+ int pitch,
+ uint32_t* pixels,
+ int do_copy );
+
+/* surface pixels information for slow surfaces */
+typedef struct {
+ int w;
+ int h;
+ int pitch;
+ uint32_t* pixels;
+} SkinSurfacePixels;
+
+/* lock a slow surface, and returns its pixel information.
+ returns 0 in case of success, -1 otherwise */
+extern int skin_surface_lock ( SkinSurface* s, SkinSurfacePixels *pix );
+
+/* unlock a slow surface that was previously locked */
+extern void skin_surface_unlock( SkinSurface* s );
+
+/* list of composition operators for the blit routine */
+typedef enum {
+ SKIN_BLIT_COPY = 0,
+ SKIN_BLIT_SRCOVER,
+ SKIN_BLIT_DSTOVER,
+} SkinBlitOp;
+
+
+/* blit a surface into another one */
+extern void skin_surface_blit( SkinSurface* dst,
+ SkinPos* dst_pos,
+ SkinSurface* src,
+ SkinRect* src_rect,
+ SkinBlitOp blitop );
+
+/* blit a colored rectangle into a destination surface */
+extern void skin_surface_fill( SkinSurface* dst,
+ SkinRect* rect,
+ uint32_t argb_premul,
+ SkinBlitOp blitop );
+
+#endif /* _ANDROID_SKIN_SURFACE_H */
diff --git a/android/skin/trackball.c b/android/skin/trackball.c
new file mode 100644
index 0000000..b18923a
--- /dev/null
+++ b/android/skin/trackball.c
@@ -0,0 +1,625 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/trackball.h"
+#include "android/skin/image.h"
+#include "android/utils/system.h"
+#include <math.h>
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** T R A C K B A L L *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+// a 3-d vector
+typedef double VectorRec[3];
+typedef double* Vector;
+
+/* define FIX16_IS_FLOAT to use floats for computations */
+#define FIX16_IS_FLOAT
+
+#ifdef FIX16_IS_FLOAT
+typedef float Fix16;
+#define FIX16_ONE 1.0
+#define FIX16_FROM_FLOAT(x) (x)
+#define FIX16_TO_FLOAT(x) (x)
+
+#else
+typedef int Fix16;
+
+#define FIX16_SHIFT 16
+#define FIX16_ONE (1 << FIX16_SHIFT)
+#define FIX16_FROM_FLOAT(x) (Fix16)((x) * FIX16_ONE)
+#define FIX16_TO_FLOAT(x) ((x)/(1.0*FIX16_ONE))
+
+#endif
+
+typedef Fix16 Fix16VectorRec[3];
+typedef Fix16* Fix16Vector;
+
+static Fix16
+fixedvector_len( Fix16Vector v )
+{
+ double x = FIX16_TO_FLOAT(v[0]);
+ double y = FIX16_TO_FLOAT(v[1]);
+ double z = FIX16_TO_FLOAT(v[2]);
+ double len = sqrt( x*x + y*y + z*z );
+
+ return FIX16_FROM_FLOAT(len);
+}
+
+static void
+fixedvector_from_vector( Fix16Vector f, Vector v )
+{
+ f[0] = FIX16_FROM_FLOAT(v[0]);
+ f[1] = FIX16_FROM_FLOAT(v[1]);
+ f[2] = FIX16_FROM_FLOAT(v[2]);
+}
+
+
+#ifdef FIX16_IS_FLOAT
+static double
+fixedvector_dot( Fix16Vector u, Fix16Vector v )
+{
+ return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
+}
+#else
+static Fix16
+fixedvector_dot( Fix16Vector u, Fix16Vector v )
+{
+ long long t;
+
+ t = (long long)u[0] * v[0] + (long long)u[1] * v[1] + (long long)u[2] * v[2];
+ return (Fix16)(t >> FIX16_SHIFT);
+}
+#endif
+
+static int
+norm( int dx, int dy )
+{
+ return (int) sqrt( dx*1.0*dx + dy*1.0*dy );
+}
+
+/*** ROTATOR: used to rotate the reference axis when mouse motion happens
+ ***/
+
+typedef struct
+{
+ VectorRec d;
+ VectorRec n;
+ double angle;
+
+} RotatorRec, *Rotator;
+
+
+#define ANGLE_FACTOR (M_PI/200)
+
+static void
+rotator_reset( Rotator rot, int dx, int dy )
+{
+ double len = sqrt( dx*dx + dy*dy );
+ double zx, zy;
+
+ if (len < 1e-3 ) {
+ zx = 1.;
+ zy = 0;
+ } else {
+ zx = dx / len;
+ zy = dy / len;
+ }
+ rot->d[0] = zx;
+ rot->d[1] = zy;
+ rot->d[2] = 0.;
+
+ rot->n[0] = -rot->d[1];
+ rot->n[1] = rot->d[0];
+ rot->n[2] = 0;
+
+ rot->angle = len * ANGLE_FACTOR;
+}
+
+static void
+rotator_apply( Rotator rot, double* vec )
+{
+ double d, n, z, d2, z2, cs, sn;
+
+ /* project on D, N, Z */
+ d = vec[0]*rot->d[0] + vec[1]*rot->d[1];
+ n = vec[0]*rot->n[0] + vec[1]*rot->n[1];
+ z = vec[2];
+
+ /* rotate on D, Z */
+ cs = cos( rot->angle );
+ sn = sin( rot->angle );
+
+ d2 = cs*d + sn*z;
+ z2 = -sn*d + cs*z;
+
+ /* project on X, Y, Z */
+ vec[0] = d2*rot->d[0] + n*rot->n[0];
+ vec[1] = d2*rot->d[1] + n*rot->n[1];
+ vec[2] = z2;
+}
+
+/*** TRACKBALL OBJECT
+ ***/
+typedef struct { int x, y, offset, alpha; Fix16VectorRec f; } SphereCoordRec, *SphereCoord;
+
+typedef struct SkinTrackBall
+{
+ int diameter;
+ unsigned* pixels;
+ SDL_Surface* surface;
+ VectorRec axes[3]; /* current ball axes */
+
+#define DOT_GRID 3 /* number of horizontal and vertical cells per side grid */
+#define DOT_CELLS 2 /* number of random dots per cell */
+#define DOT_MAX (6*DOT_GRID*DOT_GRID*DOT_CELLS) /* total number of dots */
+#define DOT_RANDOM_X 1007 /* horizontal random range in each cell */
+#define DOT_RANDOM_Y 1007 /* vertical random range in each cell */
+
+#define DOT_THRESHOLD FIX16_FROM_FLOAT(0.17)
+
+ Fix16VectorRec dots[ DOT_MAX ];
+
+ SphereCoordRec* sphere_map;
+ int sphere_count;
+
+ unsigned ball_color;
+ unsigned dot_color;
+ unsigned ring_color;
+
+ Uint32 ticks_last; /* ticks since last move */
+ int acc_x;
+ int acc_y;
+ int acc_threshold;
+ double acc_scale;
+
+ /* rotation applied to events send to the system */
+ SkinRotation rotation;
+
+} TrackBallRec, *TrackBall;
+
+
+/* The following constants are used to better mimic a real trackball.
+ *
+ * ACC_THRESHOLD is used to filter small ball movements out.
+ * If the length of the relative mouse motion is smaller than this
+ * constant, then no corresponding ball event will be sent to the
+ * system.
+ *
+ * ACC_SCALE is used to scale the relative mouse motion vector into
+ * the corresponding ball motion vector.
+ */
+#define ACC_THRESHOLD 20
+#define ACC_SCALE 0.2
+
+static void
+trackball_init( TrackBall ball, int diameter, int ring,
+ unsigned ball_color, unsigned dot_color,
+ unsigned ring_color )
+{
+ int diameter2 = diameter + ring*2;
+
+ memset( ball, 0, sizeof(*ball) );
+
+ ball->acc_threshold = ACC_THRESHOLD;
+ ball->acc_scale = ACC_SCALE;
+
+ /* init SDL surface */
+ ball->diameter = diameter2;
+ ball->ball_color = ball_color;
+ ball->dot_color = dot_color;
+ ball->ring_color = ring_color;
+
+ ball->rotation = SKIN_ROTATION_0;
+
+ ball->pixels = (unsigned*)calloc( diameter2*diameter2, sizeof(unsigned) );
+ ball->surface = sdl_surface_from_argb32( ball->pixels, diameter2, diameter2 );
+
+ /* init axes */
+ ball->axes[0][0] = 1.; ball->axes[0][1] = 0.; ball->axes[0][2] = 0.;
+ ball->axes[1][0] = 0.; ball->axes[1][1] = 1.; ball->axes[1][2] = 0.;
+ ball->axes[2][0] = 0.; ball->axes[2][1] = 0.; ball->axes[2][2] = 1.;
+
+ /* init dots */
+ {
+ int side, nn = 0;
+
+ for (side = 0; side < 6; side++) {
+ VectorRec origin, axis1, axis2;
+ int xx, yy;
+
+ switch (side) {
+ case 0:
+ origin[0] = -1; origin[1] = -1; origin[2] = +1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 1:
+ origin[0] = -1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 2:
+ origin[0] = +1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 0; axis1 [1] = 0; axis1 [2] = 1;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 3:
+ origin[0] = -1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 0; axis1 [1] = 0; axis1 [2] = 1;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 4:
+ origin[0] = -1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 0; axis2 [2] = 1;
+ break;
+ default:
+ origin[0] = -1; origin[1] = +1; origin[2] = -1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 0; axis2 [2] = 1;
+ }
+
+ for (xx = 0; xx < DOT_GRID; xx++) {
+ double tx = xx*(2./DOT_GRID);
+ for (yy = 0; yy < DOT_GRID; yy++) {
+ double ty = yy*(2./DOT_GRID);
+ double x0 = origin[0] + axis1[0]*tx + axis2[0]*ty;
+ double y0 = origin[1] + axis1[1]*tx + axis2[1]*ty;
+ double z0 = origin[2] + axis1[2]*tx + axis2[2]*ty;
+ int cc;
+ for (cc = 0; cc < DOT_CELLS; cc++) {
+ double h = (rand() % DOT_RANDOM_X)/((double)DOT_RANDOM_X*DOT_GRID/2);
+ double v = (rand() % DOT_RANDOM_Y)/((double)DOT_RANDOM_Y*DOT_GRID/2);
+ double x = x0 + axis1[0]*h + axis2[0]*v;
+ double y = y0 + axis1[1]*h + axis2[1]*v;
+ double z = z0 + axis1[2]*h + axis2[2]*v;
+ double invlen = 1/sqrt( x*x + y*y + z*z );
+
+ ball->dots[nn][0] = FIX16_FROM_FLOAT(x*invlen);
+ ball->dots[nn][1] = FIX16_FROM_FLOAT(y*invlen);
+ ball->dots[nn][2] = FIX16_FROM_FLOAT(z*invlen);
+ nn++;
+ }
+ }
+ }
+ }
+ }
+
+ /* init sphere */
+ {
+ int diameter2 = diameter + 2*ring;
+ double radius = diameter*0.5;
+ double radius2 = diameter2*0.5;
+ int xx, yy;
+ int empty = 0, total = 0;
+
+ ball->sphere_map = calloc( diameter2*diameter2, sizeof(SphereCoordRec) );
+
+ for (yy = 0; yy < diameter2; yy++) {
+ for (xx = 0; xx < diameter2; xx++) {
+ double x0 = xx - radius2;
+ double y0 = yy - radius2;
+ double r0 = sqrt( x0*x0 + y0*y0 );
+ SphereCoord coord = &ball->sphere_map[total];
+
+ if (r0 <= radius) { /* ball pixel */
+ double rx = x0/radius;
+ double ry = y0/radius;
+ double rz = sqrt( 1.0 - rx*rx - ry*ry );
+
+ coord->x = xx;
+ coord->y = yy;
+ coord->offset = xx + yy*diameter2;
+ coord->alpha = 256;
+ coord->f[0] = FIX16_FROM_FLOAT(rx);
+ coord->f[1] = FIX16_FROM_FLOAT(ry);
+ coord->f[2] = FIX16_FROM_FLOAT(rz);
+ if (r0 >= radius-1.) {
+ coord->alpha = 256*(radius - r0);
+ }
+ /* illumination model */
+ {
+#define LIGHT_X -2.0
+#define LIGHT_Y -2.5
+#define LIGHT_Z 5.0
+
+ double lx = LIGHT_X - rx;
+ double ly = LIGHT_Y - ry;
+ double lz = LIGHT_Z - rz;
+ double lir = 1/sqrt(lx*lx + ly*ly + lz*lz);
+ double cosphi = lir*(lx*rx + ly*ry + lz*rz);
+ double scale = 1.1*cosphi + 0.3;
+
+ if (scale < 0)
+ scale = 0;
+
+ coord->alpha = coord->alpha * scale;
+ }
+ total++;
+ } else if (r0 <= radius2) { /* ring pixel */
+ coord->x = xx;
+ coord->y = yy;
+ coord->offset = xx + yy*diameter2;
+ coord->alpha = 0;
+ if (r0 >= radius2-1.) {
+ coord->alpha = -256*(r0 - (radius2-1.));
+ }
+ total++;
+
+ } else /* outside pixel */
+ empty++;
+ }
+ }
+ ball->sphere_count = total;
+ }
+}
+
+static int
+trackball_contains( TrackBall ball, int x, int y )
+{
+ return ( (unsigned)(x) < (unsigned)ball->diameter &&
+ (unsigned)(y) < (unsigned)ball->diameter );
+}
+
+static void
+trackball_done( TrackBall ball )
+{
+ free( ball->sphere_map );
+ ball->sphere_map = NULL;
+ ball->sphere_count = 0;
+
+ if (ball->surface) {
+ SDL_FreeSurface( ball->surface );
+ ball->surface = NULL;
+ }
+
+ if (ball->pixels) {
+ free( ball->pixels );
+ ball->pixels = NULL;
+ }
+}
+
+/*** TRACKBALL SPHERE PIXELS
+ ***/
+static unsigned
+color_blend( unsigned from, unsigned to, int alpha )
+{
+ unsigned from_ag = (from >> 8) & 0x00ff00ff;
+ unsigned to_ag = (to >> 8) & 0x00ff00ff;
+ unsigned from_rb = from & 0x00ff00ff;
+ unsigned to_rb = to & 0x00ff00ff;
+ unsigned result_ag = (from_ag + (alpha*(to_ag - from_ag) >> 8)) & 0xff00ff;
+ unsigned result_rb = (from_rb + (alpha*(to_rb - from_rb) >> 8)) & 0xff00ff;
+
+ return (result_ag << 8) | result_rb;
+}
+
+static int
+trackball_move( TrackBall ball, int dx, int dy )
+{
+ RotatorRec rot[1];
+ Uint32 now = SDL_GetTicks();
+
+ ball->acc_x += dx;
+ ball->acc_y += dy;
+
+ if ( norm( ball->acc_x, ball->acc_y ) > ball->acc_threshold )
+ {
+ int ddx = ball->acc_x * ball->acc_scale;
+ int ddy = ball->acc_y * ball->acc_scale;
+ int ddt;
+
+ ball->acc_x = 0;
+ ball->acc_y = 0;
+
+ switch (ball->rotation) {
+ case SKIN_ROTATION_0:
+ break;
+
+ case SKIN_ROTATION_90:
+ ddt = ddx;
+ ddx = ddy;
+ ddy = -ddt;
+ break;
+
+ case SKIN_ROTATION_180:
+ ddx = -ddx;
+ ddy = -ddy;
+ break;
+
+ case SKIN_ROTATION_270:
+ ddt = ddx;
+ ddx = -ddy;
+ ddy = ddt;
+ break;
+ }
+
+ kbd_mouse_event(ddx, ddy, 1, 0);
+ }
+
+ rotator_reset( rot, dx, dy );
+ rotator_apply( rot, ball->axes[0] );
+ rotator_apply( rot, ball->axes[1] );
+ rotator_apply( rot, ball->axes[2] );
+
+ if ( ball->ticks_last == 0 )
+ ball->ticks_last = now;
+ else if ( now > ball->ticks_last + (1000/60) ) {
+ ball->ticks_last = now;
+ return 1;
+ }
+ return 0;
+}
+
+#define BACK_COLOR 0x00000000
+#define LIGHT_COLOR 0xffffffff
+
+static void
+trackball_refresh( TrackBall ball )
+{
+ int diameter = ball->diameter;
+ unsigned* pixels = ball->pixels;
+ Fix16VectorRec faxes[3];
+ Fix16 dot_threshold = DOT_THRESHOLD * diameter;
+ int nn;
+
+ SDL_LockSurface( ball->surface );
+
+ fixedvector_from_vector( (Fix16Vector)&faxes[0], (Vector)&ball->axes[0] );
+ fixedvector_from_vector( (Fix16Vector)&faxes[1], (Vector)&ball->axes[1] );
+ fixedvector_from_vector( (Fix16Vector)&faxes[2], (Vector)&ball->axes[2] );
+
+ for (nn = 0; nn < ball->sphere_count; nn++) {
+ SphereCoord coord = &ball->sphere_map[nn];
+ unsigned color = BACK_COLOR;
+
+ if (coord->alpha > 0) {
+ /* are we near one of the points ? */
+ Fix16 ax = fixedvector_dot( (Fix16Vector)&coord->f, (Fix16Vector)&faxes[0] );
+ Fix16 ay = fixedvector_dot( (Fix16Vector)&coord->f, (Fix16Vector)&faxes[1] );
+ Fix16 az = fixedvector_dot( (Fix16Vector)&coord->f, (Fix16Vector)&faxes[2] );
+
+ Fix16 best_dist = FIX16_ONE;
+ int pp;
+
+ color = ball->ball_color;
+
+ for (pp = 0; pp < DOT_MAX; pp++) {
+ Fix16VectorRec d;
+ Fix16 dist;
+
+ d[0] = ball->dots[pp][0] - ax;
+ d[1] = ball->dots[pp][1] - ay;
+ d[2] = ball->dots[pp][2] - az;
+
+ if (d[0] > dot_threshold || d[0] < -dot_threshold ||
+ d[1] > dot_threshold || d[1] < -dot_threshold ||
+ d[2] > dot_threshold || d[2] < -dot_threshold )
+ continue;
+
+ dist = fixedvector_len( (Fix16Vector)&d );
+
+ if (dist < best_dist)
+ best_dist = dist;
+ }
+ if (best_dist < DOT_THRESHOLD) {
+ int a = 256*(DOT_THRESHOLD - best_dist) / DOT_THRESHOLD;
+ color = color_blend( color, ball->dot_color, a );
+ }
+
+ if (coord->alpha < 256) {
+ int a = coord->alpha;
+ color = color_blend( ball->ring_color, color, a );
+ }
+ else if (coord->alpha > 256) {
+ int a = (coord->alpha - 256);
+ color = color_blend( color, LIGHT_COLOR, a );
+ }
+ }
+ else /* coord->alpha <= 0 */
+ {
+ color = ball->ring_color;
+
+ if (coord->alpha < 0) {
+ int a = -coord->alpha;
+ color = color_blend( color, BACK_COLOR, a );
+ }
+ }
+
+ pixels[coord->x + diameter*coord->y] = color;
+ }
+ SDL_UnlockSurface( ball->surface );
+}
+
+void
+trackball_draw( TrackBall ball, int x, int y, SDL_Surface* dst )
+{
+ SDL_Rect d;
+
+ d.x = x;
+ d.y = y;
+ d.w = ball->diameter;
+ d.h = ball->diameter;
+
+ SDL_BlitSurface( ball->surface, NULL, dst, &d );
+ SDL_UpdateRects( dst, 1, &d );
+}
+
+
+SkinTrackBall*
+skin_trackball_create ( SkinTrackBallParameters* params )
+{
+ TrackBall ball;
+
+ ANEW0(ball);
+ trackball_init( ball,
+ params->diameter,
+ params->ring,
+ params->ball_color,
+ params->dot_color,
+ params->ring_color );
+ return ball;
+}
+
+int
+skin_trackball_contains( SkinTrackBall* ball, int x, int y )
+{
+ return trackball_contains(ball, x, y);
+}
+
+int
+skin_trackball_move( SkinTrackBall* ball, int dx, int dy )
+{
+ return trackball_move(ball, dx, dy);
+}
+
+void
+skin_trackball_refresh ( SkinTrackBall* ball )
+{
+ trackball_refresh(ball);
+}
+
+void
+skin_trackball_draw( SkinTrackBall* ball, int x, int y, SDL_Surface* dst )
+{
+ trackball_draw(ball, x, y, dst);
+}
+
+void
+skin_trackball_destroy ( SkinTrackBall* ball )
+{
+ if (ball) {
+ trackball_done(ball);
+ AFREE(ball);
+ }
+}
+
+void
+skin_trackball_rect( SkinTrackBall* ball, SDL_Rect* rect )
+{
+ rect->x = 0;
+ rect->y = 0;
+ rect->w = ball->diameter;
+ rect->h = ball->diameter;
+}
+
+
+void
+skin_trackball_set_rotation( SkinTrackBall* ball, SkinRotation rotation )
+{
+ ball->rotation = rotation & 3;
+}
diff --git a/android/skin/trackball.h b/android/skin/trackball.h
new file mode 100644
index 0000000..06aa606
--- /dev/null
+++ b/android/skin/trackball.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_SKIN_TRACKBALL_H
+#define _ANDROID_SKIN_TRACKBALL_H
+
+#include <SDL.h>
+#include "android/skin/rect.h"
+
+typedef struct SkinTrackBall SkinTrackBall;
+
+typedef struct SkinTrackBallParameters
+{
+ int diameter;
+ int ring;
+ unsigned ball_color;
+ unsigned dot_color;
+ unsigned ring_color;
+}
+SkinTrackBallParameters;
+
+
+extern SkinTrackBall* skin_trackball_create ( SkinTrackBallParameters* params );
+extern void skin_trackball_rect ( SkinTrackBall* ball, SDL_Rect* rect );
+extern int skin_trackball_contains( SkinTrackBall* ball, int x, int y );
+extern int skin_trackball_move ( SkinTrackBall* ball, int dx, int dy );
+extern void skin_trackball_refresh ( SkinTrackBall* ball );
+extern void skin_trackball_draw ( SkinTrackBall* ball, int x, int y, SDL_Surface* dst );
+extern void skin_trackball_destroy ( SkinTrackBall* ball );
+
+/* this sets the rotation that will be applied to mouse events sent to the system */
+extern void skin_trackball_set_rotation( SkinTrackBall* ball, SkinRotation rotation);
+
+#endif /* END */
+
diff --git a/android/skin/window.c b/android/skin/window.c
new file mode 100644
index 0000000..6612ffe
--- /dev/null
+++ b/android/skin/window.c
@@ -0,0 +1,1516 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/skin/window.h"
+#include "android/skin/image.h"
+#include "android/skin/scaler.h"
+#include "android/charmap.h"
+#include "android/utils/debug.h"
+#include "android/utils/display.h"
+#include <SDL_syswm.h>
+#include "qemu-common.h"
+#include <math.h>
+
+#include "framebuffer.h"
+
+/* when shrinking, we reduce the pixel ratio by this fixed amount */
+#define SHRINK_SCALE 0.6
+
+/* maximum value of LCD brighness */
+#define LCD_BRIGHTNESS_MIN 0
+#define LCD_BRIGHTNESS_DEFAULT 128
+#define LCD_BRIGHTNESS_MAX 255
+
+typedef struct Background {
+ SkinImage* image;
+ SkinRect rect;
+ SkinPos origin;
+} Background;
+
+static void
+background_done( Background* back )
+{
+ skin_image_unref( &back->image );
+}
+
+static void
+background_init( Background* back, SkinBackground* sback, SkinLocation* loc, SkinRect* frame )
+{
+ SkinRect r;
+
+ back->image = skin_image_rotate( sback->image, loc->rotation );
+ skin_rect_rotate( &r, &sback->rect, loc->rotation );
+ r.pos.x += loc->anchor.x;
+ r.pos.y += loc->anchor.y;
+
+ back->origin = r.pos;
+ skin_rect_intersect( &back->rect, &r, frame );
+}
+
+static void
+background_redraw( Background* back, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &back->rect ) )
+ {
+ SDL_Rect rd, rs;
+
+ rd.x = r.pos.x;
+ rd.y = r.pos.y;
+ rd.w = r.size.w;
+ rd.h = r.size.h;
+
+ rs.x = r.pos.x - back->origin.x;
+ rs.y = r.pos.y - back->origin.y;
+ rs.w = r.size.w;
+ rs.h = r.size.h;
+
+ SDL_BlitSurface( skin_image_surface(back->image), &rs, surface, &rd );
+ //SDL_UpdateRects( surface, 1, &rd );
+ }
+}
+
+
+typedef struct ADisplay {
+ SkinRect rect;
+ SkinPos origin;
+ SkinRotation rotation;
+ SkinSize datasize; /* framebuffer size */
+ void* data; /* framebuffer pixels */
+ QFrameBuffer* qfbuff;
+ SkinImage* onion; /* onion image */
+ SkinRect onion_rect; /* onion rect, if any */
+ int brightness;
+} ADisplay;
+
+static void
+display_done( ADisplay* disp )
+{
+ disp->data = NULL;
+ disp->qfbuff = NULL;
+ skin_image_unref( &disp->onion );
+}
+
+static int
+display_init( ADisplay* disp, SkinDisplay* sdisp, SkinLocation* loc, SkinRect* frame )
+{
+ skin_rect_rotate( &disp->rect, &sdisp->rect, loc->rotation );
+ disp->rect.pos.x += loc->anchor.x;
+ disp->rect.pos.y += loc->anchor.y;
+
+ disp->rotation = (loc->rotation + sdisp->rotation) & 3;
+ switch (disp->rotation) {
+ case SKIN_ROTATION_0:
+ disp->origin = disp->rect.pos;
+ break;
+
+ case SKIN_ROTATION_90:
+ disp->origin.x = disp->rect.pos.x + disp->rect.size.w;
+ disp->origin.y = disp->rect.pos.y;
+ break;
+
+ case SKIN_ROTATION_180:
+ disp->origin.x = disp->rect.pos.x + disp->rect.size.w;
+ disp->origin.y = disp->rect.pos.y + disp->rect.size.h;
+ break;
+
+ default:
+ disp->origin.x = disp->rect.pos.x;
+ disp->origin.y = disp->rect.pos.y + disp->rect.size.h;
+ break;
+ }
+ skin_size_rotate( &disp->datasize, &sdisp->rect.size, sdisp->rotation );
+ skin_rect_intersect( &disp->rect, &disp->rect, frame );
+#if 0
+ fprintf(stderr, "... display_init rect.pos(%d,%d) rect.size(%d,%d) datasize(%d,%d)\n",
+ disp->rect.pos.x, disp->rect.pos.y,
+ disp->rect.size.w, disp->rect.size.h,
+ disp->datasize.w, disp->datasize.h);
+#endif
+ disp->qfbuff = sdisp->qfbuff;
+ disp->data = sdisp->qfbuff->pixels;
+ disp->onion = NULL;
+
+ disp->brightness = LCD_BRIGHTNESS_DEFAULT;
+
+ return (disp->data == NULL) ? -1 : 0;
+}
+
+static __inline__ uint32_t rgb565_to_argb32( uint32_t pix )
+{
+ uint32_t r = ((pix & 0xf800) << 8) | ((pix & 0xe000) << 3);
+ uint32_t g = ((pix & 0x07e0) << 5) | ((pix & 0x0600) >> 1);
+ uint32_t b = ((pix & 0x001f) << 3) | ((pix & 0x001c) >> 2);
+
+ return 0xff000000 | r | g | b;
+}
+
+
+static void
+display_set_onion( ADisplay* disp, SkinImage* onion, SkinRotation rotation, int blend )
+{
+ int onion_w, onion_h;
+ SkinRect* rect = &disp->rect;
+ SkinRect* orect = &disp->onion_rect;
+
+ rotation = (rotation + disp->rotation) & 3;
+
+ skin_image_unref( &disp->onion );
+ disp->onion = skin_image_clone_full( onion, rotation, blend );
+
+ onion_w = skin_image_w(disp->onion);
+ onion_h = skin_image_h(disp->onion);
+
+ switch (rotation) {
+ case SKIN_ROTATION_0:
+ orect->pos = rect->pos;
+ break;
+
+ case SKIN_ROTATION_90:
+ orect->pos.x = rect->pos.x + rect->size.w - onion_w;
+ orect->pos.y = rect->pos.y;
+ break;
+
+ case SKIN_ROTATION_180:
+ orect->pos.x = rect->pos.x + rect->size.w - onion_w;
+ orect->pos.y = rect->pos.y + rect->size.h - onion_h;
+ break;
+
+ default:
+ orect->pos.x = rect->pos.x;
+ orect->pos.y = rect->pos.y + rect->size.h - onion_h;
+ }
+ orect->size.w = onion_w;
+ orect->size.h = onion_h;
+}
+
+#define DOT_MATRIX 0
+
+#if DOT_MATRIX
+
+static void
+dotmatrix_dither_argb32( unsigned char* pixels, int x, int y, int w, int h, int pitch )
+{
+ static const unsigned dotmatrix_argb32[16] = {
+ 0x003f00, 0x00003f, 0x3f0000, 0x000000,
+ 0x3f3f3f, 0x000000, 0x3f3f3f, 0x000000,
+ 0x3f0000, 0x000000, 0x003f00, 0x00003f,
+ 0x3f3f3f, 0x000000, 0x3f3f3f, 0x000000
+ };
+
+ int yy = y & 3;
+
+ pixels += 4*x + y*pitch;
+
+ for ( ; h > 0; h-- ) {
+ unsigned* line = (unsigned*) pixels;
+ int nn, xx = x & 3;
+
+ for (nn = 0; nn < w; nn++) {
+ unsigned c = line[nn];
+
+ c = c - ((c >> 2) & dotmatrix_argb32[(yy << 2)|xx]);
+
+ xx = (xx + 1) & 3;
+ line[nn] = c;
+ }
+
+ yy = (yy + 1) & 3;
+ pixels += pitch;
+ }
+}
+
+#endif /* DOT_MATRIX */
+
+/* technical note about the lightness emulation
+ *
+ * we try to emulate something that looks like the Dream's
+ * non-linear LCD lightness, without going too dark or bright.
+ *
+ * the default lightness is around 105 (about 40%) and we prefer
+ * to keep full RGB colors at that setting, to not alleviate
+ * developers who will not understand why the emulator's colors
+ * look slightly too dark.
+ *
+ * we also want to implement a 'bright' mode by de-saturating
+ * colors towards bright white.
+ *
+ * All of this leads to the implementation below that looks like
+ * the following:
+ *
+ * if (level == MIN)
+ * screen is off
+ *
+ * if (level > MIN && level < LOW)
+ * interpolate towards black, with
+ * MINALPHA = 0.2
+ * alpha = MINALPHA + (1-MINALPHA)*(level-MIN)/(LOW-MIN)
+ *
+ * if (level >= LOW && level <= HIGH)
+ * keep full RGB colors
+ *
+ * if (level > HIGH)
+ * interpolate towards bright white, with
+ * MAXALPHA = 0.6
+ * alpha = MAXALPHA*(level-HIGH)/(MAX-HIGH)
+ *
+ * we probably want some sort of power law instead of interpolating
+ * linearly, but frankly, this is sufficient for most uses.
+ */
+
+#define LCD_BRIGHTNESS_LOW 80
+#define LCD_BRIGHTNESS_HIGH 180
+
+#define LCD_ALPHA_LOW_MIN 0.2
+#define LCD_ALPHA_HIGH_MAX 0.6
+
+/* treat as special value to turn screen off */
+#define LCD_BRIGHTNESS_OFF LCD_BRIGHTNESS_MIN
+
+static void
+lcd_brightness_argb32( unsigned char* pixels, SkinRect* r, int pitch, int brightness )
+{
+ const unsigned b_min = LCD_BRIGHTNESS_MIN;
+ const unsigned b_max = LCD_BRIGHTNESS_MAX;
+ const unsigned b_low = LCD_BRIGHTNESS_LOW;
+ const unsigned b_high = LCD_BRIGHTNESS_HIGH;
+
+ unsigned alpha = brightness;
+ int w = r->size.w;
+ int h = r->size.h;
+
+ if (alpha <= b_min)
+ alpha = b_min;
+ else if (alpha > b_max)
+ alpha = b_max;
+
+ pixels += 4*r->pos.x + r->pos.y*pitch;
+
+ if (alpha < b_low)
+ {
+ const unsigned alpha_min = (255*LCD_ALPHA_LOW_MIN);
+ const unsigned alpha_range = (255 - alpha_min);
+
+ alpha = alpha_min + ((alpha - b_min)*alpha_range) / (b_low - b_min);
+
+ for ( ; h > 0; h-- ) {
+ unsigned* line = (unsigned*) pixels;
+ int nn;
+
+ for (nn = 0; nn < w; nn++) {
+ unsigned c = line[nn];
+ unsigned ag = (c >> 8) & 0x00ff00ff;
+ unsigned rb = (c) & 0x00ff00ff;
+
+ ag = (ag*alpha) & 0xff00ff00;
+ rb = ((rb*alpha) >> 8) & 0x00ff00ff;
+
+ line[nn] = (unsigned)(ag | rb);
+ }
+ pixels += pitch;
+ }
+ }
+ else if (alpha > LCD_BRIGHTNESS_HIGH) /* 'superluminous' mode */
+ {
+ const unsigned alpha_max = (255*LCD_ALPHA_HIGH_MAX);
+ const unsigned alpha_range = (255-alpha_max);
+ unsigned ialpha;
+
+ alpha = ((alpha - b_high)*alpha_range) / (b_max - b_high);
+ ialpha = 255-alpha;
+
+ for ( ; h > 0; h-- ) {
+ unsigned* line = (unsigned*) pixels;
+ int nn;
+
+ for (nn = 0; nn < w; nn++) {
+ unsigned c = line[nn];
+ unsigned ag = (c >> 8) & 0x00ff00ff;
+ unsigned rb = (c) & 0x00ff00ff;
+
+ /* interpolate towards bright white, i.e. 0x00ffffff */
+ ag = ((ag*ialpha + 0x00ff00ff*alpha)) & 0xff00ff00;
+ rb = ((rb*ialpha + 0x00ff00ff*alpha) >> 8) & 0x00ff00ff;
+
+ line[nn] = (unsigned)(ag | rb);
+ }
+ pixels += pitch;
+ }
+ }
+}
+
+
+/* this is called when the LCD framebuffer is off */
+static void
+lcd_off_argb32( unsigned char* pixels, SkinRect* r, int pitch )
+{
+ int x = r->pos.x;
+ int y = r->pos.y;
+ int w = r->size.w;
+ int h = r->size.h;
+
+ pixels += 4*x + y*pitch;
+ for ( ; h > 0; h-- ) {
+ memset( pixels, 0, w*4 );
+ pixels += pitch;
+ }
+}
+
+
+static void
+display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &disp->rect ))
+ {
+ int x = r.pos.x - disp->rect.pos.x;
+ int y = r.pos.y - disp->rect.pos.y;
+ int w = r.size.w;
+ int h = r.size.h;
+ int disp_w = disp->rect.size.w;
+ int disp_h = disp->rect.size.h;
+ int dst_pitch = surface->pitch;
+ uint8_t* dst_line = (uint8_t*)surface->pixels + r.pos.x*4 + r.pos.y*dst_pitch;
+ int src_pitch = disp->datasize.w*2;
+ uint8_t* src_line = (uint8_t*)disp->data;
+ int yy, xx;
+#if 0
+ fprintf(stderr, "--- display redraw r.pos(%d,%d) r.size(%d,%d) "
+ "disp.pos(%d,%d) disp.size(%d,%d) datasize(%d,%d) rect.pos(%d,%d) rect.size(%d,%d)\n",
+ r.pos.x - disp->rect.pos.x, r.pos.y - disp->rect.pos.y, w, h, disp->rect.pos.x, disp->rect.pos.y,
+ disp->rect.size.w, disp->rect.size.h, disp->datasize.w, disp->datasize.h,
+ rect->pos.x, rect->pos.y, rect->size.w, rect->size.h );
+#endif
+ SDL_LockSurface( surface );
+
+ if (disp->brightness == LCD_BRIGHTNESS_OFF)
+ {
+ lcd_off_argb32( surface->pixels, &r, dst_pitch );
+ }
+ else
+ {
+ switch ( disp->rotation & 3 )
+ {
+ case ANDROID_ROTATION_0:
+ src_line += x*2 + y*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint16_t* src = (uint16_t*)src_line;
+
+ for (xx = 0; xx < w; xx++) {
+ dst[xx] = rgb565_to_argb32(src[xx]);
+ }
+ src_line += src_pitch;
+ dst_line += dst_pitch;
+ }
+ break;
+
+ case ANDROID_ROTATION_90:
+ src_line += y*2 + (disp_w - x - 1)*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint8_t* src = src_line;
+
+ for (xx = w; xx > 0; xx--)
+ {
+ dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+ src -= src_pitch;
+ dst += 1;
+ }
+ src_line += 2;
+ dst_line += dst_pitch;
+ }
+ break;
+
+ case ANDROID_ROTATION_180:
+ src_line += (disp_w -1 - x)*2 + (disp_h-1-y)*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint16_t* src = (uint16_t*)src_line;
+ uint32_t* dst = (uint32_t*)dst_line;
+
+ for (xx = w; xx > 0; xx--) {
+ dst[0] = rgb565_to_argb32(src[0]);
+ src -= 1;
+ dst += 1;
+ }
+
+ src_line -= src_pitch;
+ dst_line += dst_pitch;
+ }
+ break;
+
+ default: /* ANDROID_ROTATION_270 */
+ src_line += (disp_h-1-y)*2 + x*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint8_t* src = src_line;
+
+ for (xx = w; xx > 0; xx--) {
+ dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+ dst += 1;
+ src += src_pitch;
+ }
+ src_line -= 2;
+ dst_line += dst_pitch;
+ }
+ }
+#if DOT_MATRIX
+ dotmatrix_dither_argb32( surface->pixels, r.pos.x, r.pos.y, r.size.w, r.size.h, surface->pitch );
+#endif
+ /* apply lightness */
+ lcd_brightness_argb32( surface->pixels, &r, surface->pitch, disp->brightness );
+ }
+ SDL_UnlockSurface( surface );
+
+ /* Apply onion skin */
+ if (disp->onion != NULL) {
+ SkinRect r2;
+
+ if ( skin_rect_intersect( &r2, &r, &disp->onion_rect ) ) {
+ SDL_Rect rs, rd;
+
+ rd.x = r2.pos.x;
+ rd.y = r2.pos.y;
+ rd.w = r2.size.w;
+ rd.h = r2.size.h;
+
+ rs.x = rd.x - disp->onion_rect.pos.x;
+ rs.y = rd.y - disp->onion_rect.pos.y;
+ rs.w = rd.w;
+ rs.h = rd.h;
+
+ SDL_BlitSurface( skin_image_surface(disp->onion), &rs, surface, &rd );
+ }
+ }
+
+ SDL_UpdateRect( surface, r.pos.x, r.pos.y, w, h );
+ }
+}
+
+
+typedef struct Button {
+ SkinImage* image;
+ SkinRect rect;
+ SkinPos origin;
+ Background* background;
+ unsigned keycode;
+ int down;
+} Button;
+
+static void
+button_done( Button* button )
+{
+ skin_image_unref( &button->image );
+ button->background = NULL;
+}
+
+static void
+button_init( Button* button, SkinButton* sbutton, SkinLocation* loc, Background* back, SkinRect* frame )
+{
+ SkinRect r;
+
+ button->image = skin_image_rotate( sbutton->image, loc->rotation );
+ button->background = back;
+ button->keycode = sbutton->keycode;
+ button->down = 0;
+
+ skin_rect_rotate( &r, &sbutton->rect, loc->rotation );
+ r.pos.x += loc->anchor.x;
+ r.pos.y += loc->anchor.y;
+ button->origin = r.pos;
+ skin_rect_intersect( &button->rect, &r, frame );
+}
+
+static void
+button_redraw( Button* button, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &button->rect ))
+ {
+ if ( button->down && button->image != SKIN_IMAGE_NONE )
+ {
+ SDL_Rect rs, rd;
+
+ rs.x = r.pos.x - button->origin.x;
+ rs.y = r.pos.y - button->origin.y;
+ rs.w = r.size.w;
+ rs.h = r.size.h;
+
+ rd.x = r.pos.x;
+ rd.y = r.pos.y;
+ rd.w = r.size.w;
+ rd.h = r.size.h;
+
+ if (button->image != SKIN_IMAGE_NONE) {
+ SDL_BlitSurface( skin_image_surface(button->image), &rs, surface, &rd );
+ if (button->down > 1)
+ SDL_BlitSurface( skin_image_surface(button->image), &rs, surface, &rd );
+ }
+ }
+ }
+}
+
+
+typedef struct {
+ char tracking;
+ char inside;
+ SkinPos pos;
+ ADisplay* display;
+} FingerState;
+
+static void
+finger_state_reset( FingerState* finger )
+{
+ finger->tracking = 0;
+ finger->inside = 0;
+}
+
+typedef struct {
+ Button* pressed;
+ Button* hover;
+} ButtonState;
+
+static void
+button_state_reset( ButtonState* button )
+{
+ button->pressed = NULL;
+ button->hover = NULL;
+}
+
+typedef struct {
+ char tracking;
+ SkinTrackBall* ball;
+ SkinRect rect;
+ SkinWindow* window;
+} BallState;
+
+static void
+ball_state_reset( BallState* state, SkinWindow* window )
+{
+ state->tracking = 0;
+ state->ball = NULL;
+
+ state->rect.pos.x = 0;
+ state->rect.pos.y = 0;
+ state->rect.size.w = 0;
+ state->rect.size.h = 0;
+ state->window = window;
+}
+
+static void
+ball_state_redraw( BallState* state, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &state->rect ))
+ skin_trackball_draw( state->ball, 0, 0, surface );
+}
+
+static void
+ball_state_show( BallState* state, int enable )
+{
+ if (enable) {
+ if ( !state->tracking ) {
+ state->tracking = 1;
+ SDL_ShowCursor(0);
+ SDL_WM_GrabInput( SDL_GRAB_ON );
+ skin_trackball_refresh( state->ball );
+ skin_window_redraw( state->window, &state->rect );
+ }
+ } else {
+ if ( state->tracking ) {
+ state->tracking = 0;
+ SDL_WM_GrabInput( SDL_GRAB_OFF );
+ SDL_ShowCursor(1);
+ skin_window_redraw( state->window, &state->rect );
+ }
+ }
+}
+
+
+static void
+ball_state_set( BallState* state, SkinTrackBall* ball )
+{
+ ball_state_show( state, 0 );
+
+ state->ball = ball;
+ if (ball != NULL) {
+ SDL_Rect sr;
+
+ skin_trackball_rect( ball, &sr );
+ state->rect.pos.x = sr.x;
+ state->rect.pos.y = sr.y;
+ state->rect.size.w = sr.w;
+ state->rect.size.h = sr.h;
+ }
+}
+
+typedef struct Layout {
+ int num_buttons;
+ int num_backgrounds;
+ int num_displays;
+ unsigned color;
+ Button* buttons;
+ Background* backgrounds;
+ ADisplay* displays;
+ SkinRect rect;
+ SkinLayout* slayout;
+} Layout;
+
+#define LAYOUT_LOOP_BUTTONS(layout,button) \
+ do { \
+ Button* __button = (layout)->buttons; \
+ Button* __button_end = __button + (layout)->num_buttons; \
+ for ( ; __button < __button_end; __button ++ ) { \
+ Button* button = __button;
+
+#define LAYOUT_LOOP_END_BUTTONS \
+ } \
+ } while (0);
+
+#define LAYOUT_LOOP_DISPLAYS(layout,display) \
+ do { \
+ ADisplay* __display = (layout)->displays; \
+ ADisplay* __display_end = __display + (layout)->num_displays; \
+ for ( ; __display < __display_end; __display ++ ) { \
+ ADisplay* display = __display;
+
+#define LAYOUT_LOOP_END_DISPLAYS \
+ } \
+ } while (0);
+
+
+static void
+layout_done( Layout* layout )
+{
+ int nn;
+
+ for (nn = 0; nn < layout->num_buttons; nn++)
+ button_done( &layout->buttons[nn] );
+
+ for (nn = 0; nn < layout->num_backgrounds; nn++)
+ background_done( &layout->backgrounds[nn] );
+
+ for (nn = 0; nn < layout->num_displays; nn++)
+ display_done( &layout->displays[nn] );
+
+ qemu_free( layout->buttons );
+ layout->buttons = NULL;
+
+ qemu_free( layout->backgrounds );
+ layout->backgrounds = NULL;
+
+ qemu_free( layout->displays );
+ layout->displays = NULL;
+
+ layout->num_buttons = 0;
+ layout->num_backgrounds = 0;
+ layout->num_displays = 0;
+}
+
+static int
+layout_init( Layout* layout, SkinLayout* slayout )
+{
+ int n_buttons, n_backgrounds, n_displays;
+
+ /* first, count the number of elements of each kind */
+ n_buttons = 0;
+ n_backgrounds = 0;
+ n_displays = 0;
+
+ layout->color = slayout->color;
+ layout->slayout = slayout;
+
+ SKIN_LAYOUT_LOOP_LOCS(slayout,loc)
+ SkinPart* part = loc->part;
+
+ if ( part->background->valid )
+ n_backgrounds += 1;
+ if ( part->display->valid )
+ n_displays += 1;
+
+ SKIN_PART_LOOP_BUTTONS(part, sbutton)
+ n_buttons += 1;
+ sbutton=sbutton;
+ SKIN_PART_LOOP_END
+ SKIN_LAYOUT_LOOP_END
+
+ layout->num_buttons = n_buttons;
+ layout->num_backgrounds = n_backgrounds;
+ layout->num_displays = n_displays;
+
+ /* now allocate arrays, then populate them */
+ layout->buttons = qemu_mallocz( sizeof(Button) * n_buttons );
+ layout->backgrounds = qemu_mallocz( sizeof(Background) * n_backgrounds );
+ layout->displays = qemu_mallocz( sizeof(ADisplay) * n_displays );
+
+ if (layout->buttons == NULL && n_buttons > 0) goto Fail;
+ if (layout->backgrounds == NULL && n_backgrounds > 0) goto Fail;
+ if (layout->displays == NULL && n_displays > 0) goto Fail;
+
+ n_buttons = 0;
+ n_backgrounds = 0;
+ n_displays = 0;
+
+ layout->rect.pos.x = 0;
+ layout->rect.pos.y = 0;
+ layout->rect.size = slayout->size;
+
+ SKIN_LAYOUT_LOOP_LOCS(slayout,loc)
+ SkinPart* part = loc->part;
+ Background* back = NULL;
+
+ if ( part->background->valid ) {
+ back = layout->backgrounds + n_backgrounds;
+ background_init( back, part->background, loc, &layout->rect );
+ n_backgrounds += 1;
+ }
+ if ( part->display->valid ) {
+ ADisplay* disp = layout->displays + n_displays;
+ display_init( disp, part->display, loc, &layout->rect );
+ n_displays += 1;
+ }
+
+ SKIN_PART_LOOP_BUTTONS(part, sbutton)
+ Button* button = layout->buttons + n_buttons;
+ button_init( button, sbutton, loc, back, &layout->rect );
+ n_buttons += 1;
+ SKIN_PART_LOOP_END
+ SKIN_LAYOUT_LOOP_END
+
+ return 0;
+
+Fail:
+ layout_done(layout);
+ return -1;
+}
+
+struct SkinWindow {
+ SDL_Surface* surface;
+ Layout layout;
+ SkinPos pos;
+ FingerState finger;
+ ButtonState button;
+ BallState ball;
+ char enabled;
+ char fullscreen;
+ char no_display;
+
+ char enable_touch;
+ char enable_trackball;
+ char enable_dpad;
+ char enable_qwerty;
+
+ SkinImage* onion;
+ SkinRotation onion_rotation;
+ int onion_alpha;
+
+ int x_pos;
+ int y_pos;
+
+ SkinScaler* scaler;
+ int shrink;
+ double shrink_scale;
+ unsigned* shrink_pixels;
+ SDL_Surface* shrink_surface;
+
+ double effective_scale;
+ double effective_x;
+ double effective_y;
+};
+
+static void
+add_finger_event(unsigned x, unsigned y, unsigned state)
+{
+ //fprintf(stderr, "::: finger %d,%d %d\n", x, y, state);
+ kbd_mouse_event(x, y, 0, state);
+}
+
+static void
+skin_window_find_finger( SkinWindow* window,
+ int x,
+ int y )
+{
+ FingerState* finger = &window->finger;
+
+ /* find the display that contains this movement */
+ finger->display = NULL;
+ finger->inside = 0;
+
+ if (!window->enable_touch)
+ return;
+
+ LAYOUT_LOOP_DISPLAYS(&window->layout,disp)
+ if ( skin_rect_contains( &disp->rect, x, y ) ) {
+ finger->inside = 1;
+ finger->display = disp;
+ finger->pos.x = x - disp->origin.x;
+ finger->pos.y = y - disp->origin.y;
+
+ skin_pos_rotate( &finger->pos, &finger->pos, -disp->rotation );
+ break;
+ }
+ LAYOUT_LOOP_END_DISPLAYS
+}
+
+static void
+skin_window_move_mouse( SkinWindow* window,
+ int x,
+ int y )
+{
+ FingerState* finger = &window->finger;
+ ButtonState* button = &window->button;
+
+ if (finger->tracking) {
+ ADisplay* disp = finger->display;
+ char inside = 1;
+ int dx = x - disp->rect.pos.x;
+ int dy = y - disp->rect.pos.y;
+
+ if (dx < 0) {
+ dx = 0;
+ inside = 0;
+ }
+ else if (dx >= disp->rect.size.w) {
+ dx = disp->rect.size.w - 1;
+ inside = 0;
+ }
+ if (dy < 0) {
+ dy = 0;
+ inside = 0;
+ } else if (dy >= disp->rect.size.h) {
+ dy = disp->rect.size.h-1;
+ inside = 0;
+ }
+ finger->inside = inside;
+ finger->pos.x = dx + (disp->rect.pos.x - disp->origin.x);
+ finger->pos.y = dy + (disp->rect.pos.y - disp->origin.y);
+
+ skin_pos_rotate( &finger->pos, &finger->pos, -disp->rotation );
+ }
+
+ {
+ Button* hover = button->hover;
+
+ if (hover) {
+ if ( skin_rect_contains( &hover->rect, x, y ) )
+ return;
+
+ hover->down = 0;
+ skin_window_redraw( window, &hover->rect );
+ button->hover = NULL;
+ }
+
+ hover = NULL;
+ LAYOUT_LOOP_BUTTONS( &window->layout, butt )
+ if ( skin_rect_contains( &butt->rect, x, y ) ) {
+ hover = butt;
+ break;
+ }
+ LAYOUT_LOOP_END_BUTTONS
+
+ /* filter DPAD and QWERTY buttons right here */
+ if (hover != NULL) {
+ switch (hover->keycode) {
+ /* these correspond to the DPad */
+ case kKeyCodeDpadUp:
+ case kKeyCodeDpadDown:
+ case kKeyCodeDpadLeft:
+ case kKeyCodeDpadRight:
+ case kKeyCodeDpadCenter:
+ if (!window->enable_dpad)
+ hover = NULL;
+ break;
+
+ /* these correspond to non-qwerty buttons */
+ case kKeyCodeSoftLeft:
+ case kKeyCodeSoftRight:
+ case kKeyCodeVolumeUp:
+ case kKeyCodeVolumeDown:
+ case kKeyCodePower:
+ case kKeyCodeHome:
+ case kKeyCodeBack:
+ case kKeyCodeCall:
+ case kKeyCodeEndCall:
+ break;
+
+ /* all the rest is assumed to be qwerty */
+ default:
+ if (!window->enable_qwerty)
+ hover = NULL;
+ }
+ }
+
+ if (hover != NULL) {
+ hover->down = 1;
+ skin_window_redraw( window, &hover->rect );
+ button->hover = hover;
+ }
+ }
+}
+
+static void
+skin_window_trackball_press( SkinWindow* window, int down )
+{
+ send_key_event( kKeyCodeBtnMouse, down );
+}
+
+static void
+skin_window_trackball_move( SkinWindow* window, int xrel, int yrel )
+{
+ BallState* state = &window->ball;
+
+ if ( skin_trackball_move( state->ball, xrel, yrel ) ) {
+ skin_trackball_refresh( state->ball );
+ skin_window_redraw( window, &state->rect );
+ }
+}
+
+void
+skin_window_set_trackball( SkinWindow* window, SkinTrackBall* ball )
+{
+ BallState* state = &window->ball;
+
+ ball_state_set( state, ball );
+}
+
+void
+skin_window_show_trackball( SkinWindow* window, int enable )
+{
+ BallState* state = &window->ball;
+
+ if (state->ball != NULL && window->enable_trackball) {
+ ball_state_show(state, enable);
+ }
+}
+
+
+static int skin_window_reset_internal (SkinWindow*, SkinLayout*);
+
+SkinWindow*
+skin_window_create( SkinLayout* slayout, int x, int y, double scale, int no_display )
+{
+ SkinWindow* window = qemu_mallocz(sizeof(*window));
+
+ window->shrink_scale = scale;
+ window->shrink = (scale != 1.0);
+ window->scaler = skin_scaler_create();
+ window->no_display = no_display;
+
+ /* enable everything by default */
+ window->enable_touch = 1;
+ window->enable_trackball = 1;
+ window->enable_dpad = 1;
+ window->enable_qwerty = 1;
+
+ window->x_pos = x;
+ window->y_pos = y;
+
+ if (skin_window_reset_internal(window, slayout) < 0) {
+ skin_window_free( window );
+ return NULL;
+ }
+ //SDL_WM_SetCaption( "Android Emulator", "Android Emulator" );
+
+ SDL_WM_SetPos( x, y );
+ if ( !SDL_WM_IsFullyVisible( 1 ) ) {
+ dprint( "emulator window was out of view and was recentred\n" );
+ }
+
+ return window;
+}
+
+void
+skin_window_enable_touch( SkinWindow* window, int enabled )
+{
+ window->enable_touch = !!enabled;
+}
+
+void
+skin_window_enable_trackball( SkinWindow* window, int enabled )
+{
+ window->enable_trackball = !!enabled;
+}
+
+void
+skin_window_enable_dpad( SkinWindow* window, int enabled )
+{
+ window->enable_dpad = !!enabled;
+}
+
+void
+skin_window_enable_qwerty( SkinWindow* window, int enabled )
+{
+ window->enable_qwerty = !!enabled;
+}
+
+void
+skin_window_set_title( SkinWindow* window, const char* title )
+{
+ if (window && title)
+ SDL_WM_SetCaption( title, title );
+}
+
+static void
+skin_window_resize( SkinWindow* window )
+{
+ /* now resize window */
+ if (window->surface) {
+ SDL_FreeSurface(window->surface);
+ window->surface = NULL;
+ }
+
+ if (window->shrink_surface) {
+ SDL_FreeSurface(window->shrink_surface);
+ window->shrink_surface = NULL;
+ }
+
+ if (window->shrink_pixels) {
+ qemu_free(window->shrink_pixels);
+ window->shrink_pixels = NULL;
+ }
+
+ if ( !window->no_display ) {
+ int layout_w = window->layout.rect.size.w;
+ int layout_h = window->layout.rect.size.h;
+ int window_w = layout_w;
+ int window_h = layout_h;
+ int window_x = window->x_pos;
+ int window_y = window->y_pos;
+ int flags;
+ SDL_Surface* surface;
+ double scale = 1.0;
+ int fullscreen = window->fullscreen;
+
+ if (fullscreen) {
+ if (get_nearest_monitor_rect(&window_x, &window_y,
+ &window_w, &window_h) < 0) {
+ fullscreen = 0;
+ } else {
+ double x_scale = window_w * 1.0 / layout_w;
+ double y_scale = window_h * 1.0 / layout_h;
+
+ scale = (x_scale <= y_scale) ? x_scale : y_scale;
+ }
+ }
+ else if (window->shrink) {
+ scale = window->shrink_scale;
+ window_w = (int) ceil(layout_w*scale);
+ window_h = (int) ceil(layout_h*scale);
+ }
+
+ {
+ char temp[32];
+ sprintf(temp,"SDL_VIDEO_WINDOW_POS=%d,%d",window_x,window_y);
+ putenv(temp);
+ putenv("SDL_VIDEO_WINDOW_FORCE_VISIBLE=1");
+ }
+
+ flags = SDL_SWSURFACE;
+ if (fullscreen) {
+ flags |= SDL_FULLSCREEN;
+ }
+ surface = SDL_SetVideoMode( window_w, window_h, 32, flags );
+ if (surface == NULL) {
+ fprintf(stderr, "### Error: could not create or resize SDL window: %s\n", SDL_GetError() );
+ exit(1);
+ }
+
+ SDL_WM_SetPos( window_x, window_y );
+
+ window->effective_scale = scale;
+ window->effective_x = 0;
+ window->effective_y = 0;
+
+ if (fullscreen) {
+ window->effective_x = (window_w - layout_w*scale)*0.5;
+ window->effective_y = (window_h - layout_h*scale)*0.5;
+ }
+
+ if (scale == 1.0)
+ window->surface = surface;
+ else
+ {
+ window_w = (int) ceil(window_w / scale );
+ window_h = (int) ceil(window_h / scale );
+
+ window->shrink_surface = surface;
+ window->shrink_pixels = qemu_mallocz( window_w * window_h * 4 );
+ if (window->shrink_pixels == NULL) {
+ fprintf(stderr, "### Error: could not allocate memory for rescaling surface\n");
+ exit(1);
+ }
+ window->surface = sdl_surface_from_argb32( window->shrink_pixels, window_w, window_h );
+ if (window->surface == NULL) {
+ fprintf(stderr, "### Error: could not create or resize SDL window: %s\n", SDL_GetError() );
+ exit(1);
+ }
+ skin_scaler_set( window->scaler, scale, window->effective_x, window->effective_y );
+ }
+ }
+}
+
+static int
+skin_window_reset_internal ( SkinWindow* window, SkinLayout* slayout )
+{
+ Layout layout;
+ ADisplay* disp;
+
+ if ( layout_init( &layout, slayout ) < 0 )
+ return -1;
+
+ disp = window->layout.displays;
+
+ layout_done( &window->layout );
+ window->layout = layout;
+
+ disp = window->layout.displays;
+ if (disp != NULL && window->onion)
+ display_set_onion( disp,
+ window->onion,
+ window->onion_rotation,
+ window->onion_alpha );
+
+ skin_window_resize(window);
+
+ finger_state_reset( &window->finger );
+ button_state_reset( &window->button );
+ ball_state_reset( &window->ball, window );
+
+ skin_window_redraw( window, NULL );
+
+ if (slayout->event_type != 0) {
+ kbd_generic_event( slayout->event_type, slayout->event_code, slayout->event_value );
+ }
+
+ return 0;
+}
+
+int
+skin_window_reset ( SkinWindow* window, SkinLayout* slayout )
+{
+ if (!window->fullscreen) {
+ SDL_WM_GetPos(&window->x_pos, &window->y_pos);
+ }
+ return skin_window_reset_internal( window, slayout );
+}
+
+void
+skin_window_set_lcd_brightness( SkinWindow* window, int brightness )
+{
+ ADisplay* disp = window->layout.displays;
+
+ if (disp != NULL) {
+ disp->brightness = brightness;
+ skin_window_redraw( window, NULL );
+ }
+}
+
+void
+skin_window_free ( SkinWindow* window )
+{
+ if (window) {
+ if (window->surface) {
+ SDL_FreeSurface(window->surface);
+ window->surface = NULL;
+ }
+ if (window->shrink_surface) {
+ SDL_FreeSurface(window->shrink_surface);
+ window->shrink_surface = NULL;
+ }
+ if (window->shrink_pixels) {
+ qemu_free(window->shrink_pixels);
+ window->shrink_pixels = NULL;
+ }
+ if (window->onion) {
+ skin_image_unref( &window->onion );
+ window->onion_rotation = SKIN_ROTATION_0;
+ }
+ if (window->scaler) {
+ skin_scaler_free(window->scaler);
+ window->scaler = NULL;
+ }
+ layout_done( &window->layout );
+ qemu_free(window);
+ }
+}
+
+void
+skin_window_set_onion( SkinWindow* window,
+ SkinImage* onion,
+ SkinRotation onion_rotation,
+ int onion_alpha )
+{
+ ADisplay* disp;
+ SkinImage* old = window->onion;
+
+ window->onion = skin_image_ref(onion);
+ window->onion_rotation = onion_rotation;
+ window->onion_alpha = onion_alpha;
+
+ skin_image_unref( &old );
+
+ disp = window->layout.displays;
+
+ if (disp != NULL)
+ display_set_onion( disp, window->onion, onion_rotation, onion_alpha );
+}
+
+static void
+skin_window_update_shrink( SkinWindow* window, SkinRect* rect )
+{
+ skin_scaler_scale( window->scaler, window->shrink_surface, window->surface,
+ rect->pos.x, rect->pos.y, rect->size.w, rect->size.h );
+}
+
+void
+skin_window_set_scale( SkinWindow* window, double scale )
+{
+ window->shrink = (scale != 1.0);
+ window->shrink_scale = scale;
+
+ skin_window_resize( window );
+ skin_window_redraw( window, NULL );
+}
+
+void
+skin_window_redraw( SkinWindow* window, SkinRect* rect )
+{
+ if (window != NULL && window->surface != NULL) {
+ Layout* layout = &window->layout;
+
+ if (rect == NULL)
+ rect = &layout->rect;
+
+ {
+ SkinRect r;
+
+ if ( skin_rect_intersect( &r, rect, &layout->rect ) ) {
+ SDL_Rect rd;
+ rd.x = r.pos.x;
+ rd.y = r.pos.y;
+ rd.w = r.size.w;
+ rd.h = r.size.h;
+
+ SDL_FillRect( window->surface, &rd, layout->color );
+ }
+ }
+
+ {
+ Background* back = layout->backgrounds;
+ Background* end = back + layout->num_backgrounds;
+ for ( ; back < end; back++ )
+ background_redraw( back, rect, window->surface );
+ }
+
+ {
+ ADisplay* disp = layout->displays;
+ ADisplay* end = disp + layout->num_displays;
+ for ( ; disp < end; disp++ )
+ display_redraw( disp, rect, window->surface );
+ }
+
+ {
+ Button* button = layout->buttons;
+ Button* end = button + layout->num_buttons;
+ for ( ; button < end; button++ )
+ button_redraw( button, rect, window->surface );
+ }
+
+ if ( window->ball.tracking )
+ ball_state_redraw( &window->ball, rect, window->surface );
+
+ if (window->effective_scale != 1.0)
+ skin_window_update_shrink( window, rect );
+ else
+ {
+ SDL_Rect rd;
+ rd.x = rect->pos.x;
+ rd.y = rect->pos.y;
+ rd.w = rect->size.w;
+ rd.h = rect->size.h;
+
+ SDL_UpdateRects( window->surface, 1, &rd );
+ }
+ }
+}
+
+void
+skin_window_toggle_fullscreen( SkinWindow* window )
+{
+ if (window && window->surface) {
+ if (!window->fullscreen)
+ SDL_WM_GetPos( &window->x_pos, &window->y_pos );
+
+ window->fullscreen = !window->fullscreen;
+ skin_window_resize( window );
+ skin_window_redraw( window, NULL );
+ }
+}
+
+void
+skin_window_get_display( SkinWindow* window, ADisplayInfo *info )
+{
+ ADisplay* disp = window->layout.displays;
+
+ if (disp != NULL) {
+ info->width = disp->datasize.w;
+ info->height = disp->datasize.h;
+ info->rotation = disp->rotation;
+ info->data = disp->data;
+ } else {
+ info->width = 0;
+ info->height = 0;
+ info->rotation = SKIN_ROTATION_0;
+ info->data = NULL;
+ }
+}
+
+
+static void
+skin_window_map_to_scale( SkinWindow* window, int *x, int *y )
+{
+ *x = (*x - window->effective_x) / window->effective_scale;
+ *y = (*y - window->effective_y) / window->effective_scale;
+}
+
+void
+skin_window_process_event( SkinWindow* window, SDL_Event* ev )
+{
+ Button* button;
+ int mx, my;
+
+ if (!window->surface)
+ return;
+
+ switch (ev->type) {
+ case SDL_MOUSEBUTTONDOWN:
+ if ( window->ball.tracking ) {
+ skin_window_trackball_press( window, 1 );
+ break;
+ }
+
+ mx = ev->button.x;
+ my = ev->button.y;
+ skin_window_map_to_scale( window, &mx, &my );
+ skin_window_move_mouse( window, mx, my );
+ skin_window_find_finger( window, mx, my );
+#if 0
+ printf("down: x=%d y=%d fx=%d fy=%d fis=%d\n",
+ ev->button.x, ev->button.y, window->finger.pos.x,
+ window->finger.pos.y, window->finger.inside);
+#endif
+ if (window->finger.inside) {
+ window->finger.tracking = 1;
+ add_finger_event(window->finger.pos.x, window->finger.pos.y, 1);
+ } else {
+ window->button.pressed = NULL;
+ button = window->button.hover;
+ if(button) {
+ button->down += 1;
+ skin_window_redraw( window, &button->rect );
+ window->button.pressed = button;
+ if(button->keycode) {
+ send_key_event(button->keycode, 1);
+ }
+ }
+ }
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ if ( window->ball.tracking ) {
+ skin_window_trackball_press( window, 0 );
+ break;
+ }
+ button = window->button.pressed;
+ mx = ev->button.x;
+ my = ev->button.y;
+ skin_window_map_to_scale( window, &mx, &my );
+ if (button)
+ {
+ button->down = 0;
+ skin_window_redraw( window, &button->rect );
+ if(button->keycode) {
+ send_key_event(button->keycode, 0);
+ }
+ window->button.pressed = NULL;
+ window->button.hover = NULL;
+ skin_window_move_mouse( window, mx, my );
+ }
+ else if (window->finger.tracking)
+ {
+ skin_window_move_mouse( window, mx, my );
+ window->finger.tracking = 0;
+ add_finger_event( window->finger.pos.x, window->finger.pos.y, 0);
+ }
+ break;
+
+ case SDL_MOUSEMOTION:
+ if ( window->ball.tracking ) {
+ skin_window_trackball_move( window, ev->motion.xrel, ev->motion.yrel );
+ break;
+ }
+ mx = ev->button.x;
+ my = ev->button.y;
+ skin_window_map_to_scale( window, &mx, &my );
+ if ( !window->button.pressed )
+ {
+ skin_window_move_mouse( window, mx, my );
+ if ( window->finger.tracking ) {
+ add_finger_event( window->finger.pos.x, window->finger.pos.y, 1 );
+ }
+ }
+ break;
+ }
+}
+
+static ADisplay*
+skin_window_display( SkinWindow* window )
+{
+ return window->layout.displays;
+}
+
+void
+skin_window_update_display( SkinWindow* window, int x, int y, int w, int h )
+{
+ ADisplay* disp = skin_window_display(window);
+
+ if ( !window->surface )
+ return;
+
+ if (disp != NULL) {
+ SkinRect r;
+ r.pos.x = x;
+ r.pos.y = y;
+ r.size.w = w;
+ r.size.h = h;
+
+ skin_rect_rotate( &r, &r, disp->rotation );
+ r.pos.x += disp->origin.x;
+ r.pos.y += disp->origin.y;
+
+ if (window->effective_scale != 1.0)
+ skin_window_redraw( window, &r );
+ else
+ display_redraw( disp, &r, window->surface );
+ }
+}
diff --git a/android/skin/window.h b/android/skin/window.h
new file mode 100644
index 0000000..3e92e40
--- /dev/null
+++ b/android/skin/window.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _SKIN_WINDOW_H
+#define _SKIN_WINDOW_H
+
+#include "android/skin/file.h"
+#include "android/skin/trackball.h"
+#include <SDL.h>
+
+typedef struct SkinWindow SkinWindow;
+
+extern SkinWindow* skin_window_create( SkinLayout* layout,
+ int x,
+ int y,
+ double scale,
+ int no_display );
+
+extern void skin_window_enable_touch( SkinWindow* window, int enabled );
+extern void skin_window_enable_trackball( SkinWindow* window, int enabled );
+extern void skin_window_enable_dpad( SkinWindow* window, int enabled );
+extern void skin_window_enable_qwerty( SkinWindow* window, int enabled );
+
+extern int skin_window_reset ( SkinWindow* window, SkinLayout* layout );
+extern void skin_window_free ( SkinWindow* window );
+extern void skin_window_redraw( SkinWindow* window, SkinRect* rect );
+extern void skin_window_process_event( SkinWindow* window, SDL_Event* ev );
+
+extern void skin_window_set_onion( SkinWindow* window,
+ SkinImage* onion,
+ SkinRotation rotation,
+ int alpha );
+
+extern void skin_window_set_scale( SkinWindow* window,
+ double scale );
+
+extern void skin_window_set_title( SkinWindow* window,
+ const char* title );
+
+extern void skin_window_set_trackball( SkinWindow* window, SkinTrackBall* ball );
+extern void skin_window_show_trackball( SkinWindow* window, int enable );
+extern void skin_window_toggle_fullscreen( SkinWindow* window );
+
+/* change the brightness of the emulator LCD screen. 'brightness' will be clamped to 0..255 */
+extern void skin_window_set_lcd_brightness( SkinWindow* window, int brightness );
+
+typedef struct {
+ int width;
+ int height;
+ SkinRotation rotation;
+ void* data;
+} ADisplayInfo;
+
+extern void skin_window_get_display( SkinWindow* window, ADisplayInfo *info );
+extern void skin_window_update_display( SkinWindow* window, int x, int y, int w, int h );
+
+#endif /* _SKIN_WINDOW_H */
diff --git a/android/tools/gen-hw-config.py b/android/tools/gen-hw-config.py
new file mode 100755
index 0000000..928ccc5
--- /dev/null
+++ b/android/tools/gen-hw-config.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# this script is used to generate 'android/avd/hw-config.h' by
+# parsing 'android/avd/hardware-properties.ini'
+#
+#
+import sys, os, string, re
+
+# location of source file, relative to current program directory
+relativeSourcePath = "../avd/hardware-properties.ini"
+
+# location of target file, relative to current program directory
+relativeTargetPath = "../avd/hw-config-defs.h"
+
+def quoteStringForC(str):
+ """quote a string so it can be used in C"""
+ return '\\"'.join('"'+p+'"' for p in str.split('"'))
+
+# a dictionary that maps item types as they appear in the .ini
+# file into macro names in the generated C header
+#
+typesToMacros = {
+ 'integer': 'HWCFG_INT',
+ 'string': 'HWCFG_STRING',
+ 'boolean': 'HWCFG_BOOL',
+ 'diskSize': 'HWCFG_DISKSIZE',
+ 'double': 'HWCFG_DOUBLE'
+ }
+
+# the list of macro names
+macroNames = typesToMacros.values()
+
+# target program header
+targetHeader = """\
+/* this file is automatically generated from 'hardware-properties.ini'
+ * DO NOT EDIT IT. To re-generate it, use android/tools/gen-hw-config.py'
+ */"""
+
+# locate source and target
+programDir = os.path.dirname(sys.argv[0])
+sourceFile = os.path.normpath(os.path.join(programDir,relativeSourcePath))
+targetFile = os.path.normpath(os.path.join(programDir,relativeTargetPath))
+
+# parse the source file and record items
+# I would love to use Python's ConfigParser, but it doesn't
+# support files without sections, or multiply defined items
+#
+items = []
+lastItem = None
+
+class Item:
+ def __init__(self,name):
+ self.name = name
+ self.type = type
+ self.default = None
+ self.abstract = ""
+ self.description = ""
+
+ def add(self,key,val):
+ if key == 'type':
+ self.type = val
+ elif key == 'default':
+ self.default = val
+ elif key == 'abstract':
+ self.abstract = val
+ elif key == 'description':
+ self.description = val
+
+for line in open(sourceFile):
+ line = line.strip()
+ # ignore empty lines and comments
+ if len(line) == 0 or line[0] in ";#":
+ continue
+ key, value = line.split('=')
+
+ key = key.strip()
+ value = value.strip()
+
+ if key == 'name':
+ if lastItem: items.append(lastItem)
+ lastItem = Item(value)
+ else:
+ lastItem.add(key, value)
+
+if lastItem:
+ items.append(lastItem)
+
+
+print targetHeader
+
+# write guards to prevent bad compiles
+for m in macroNames:
+ print """\
+#ifndef %(macro)s
+#error %(macro)s not defined
+#endif""" % { 'macro':m }
+print ""
+
+for item in items:
+ if item.type == None:
+ sys.stderr.write("ignoring config item with no type '%s'\n" % item.name)
+ continue
+
+ if not typesToMacros.has_key(item.type):
+ sys.stderr.write("ignoring config item with unknown type '%s': '%s'\n" % \
+ (item.type, item.name))
+ continue
+
+ if item.default == None:
+ sys.stderr.write("ignoring config item with no default '%s' */" % item.name)
+ continue
+
+ # convert dots into underscores
+ varMacro = typesToMacros[item.type]
+ varNameStr = quoteStringForC(item.name)
+ varName = item.name.replace(".","_")
+ varDefault = item.default
+ varAbstract = quoteStringForC(item.abstract)
+ varDesc = quoteStringForC(item.description)
+
+ if item.type in [ 'string', 'boolean', 'diskSize' ]:
+ # quote default value for strings
+ varDefault = quoteStringForC(varDefault)
+
+ print "%s(\n %s,\n %s,\n %s,\n %s,\n %s)\n" % \
+ (varMacro,varName,varNameStr,varDefault,varAbstract,varDesc)
+
+
+for m in macroNames:
+ print "#undef %s" % m
+
+print "/* end of auto-generated file */"
diff --git a/android/user-config.c b/android/user-config.c
new file mode 100644
index 0000000..acd1a27
--- /dev/null
+++ b/android/user-config.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/user-config.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+#include "android/utils/system.h"
+#include "android/utils/path.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+#if 0 /* set to 1 for more debugging */
+# define DD(...) D(__VA_ARGS__)
+#else
+# define DD(...) ((void)0)
+#endif
+
+struct AUserConfig {
+ ABool changed;
+ int windowX;
+ int windowY;
+ uint64_t uuid;
+ char* iniPath;
+};
+
+/* Name of the user-config file */
+#define USER_CONFIG_FILE "emulator-user.ini"
+
+#define KEY_WINDOW_X "window.x"
+#define KEY_WINDOW_Y "window.y"
+#define KEY_UUID "uuid"
+
+#define DEFAULT_X 100
+#define DEFAULT_Y 100
+
+/* Create a new AUserConfig object from a given AvdInfo */
+AUserConfig*
+auserConfig_new( AvdInfo* info )
+{
+ AUserConfig* uc;
+ char inAndroidBuild = avdInfo_inAndroidBuild(info);
+ char needUUID = 1;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ char* parentPath;
+ IniFile* ini = NULL;
+
+ ANEW0(uc);
+
+ /* If we are in the Android build system, store the configuration
+ * in ~/.android/emulator-user.ini. otherwise, store it in the file
+ * emulator-user.ini in the AVD's content directory.
+ */
+ if (inAndroidBuild) {
+ p = bufprint_config_file(temp, end, USER_CONFIG_FILE);
+ } else {
+ p = bufprint(temp, end, "%s/%s", avdInfo_getContentPath(info),
+ USER_CONFIG_FILE);
+ }
+
+ /* handle the unexpected */
+ if (p >= end) {
+ /* Hmmm, something is weird, let's use a temporary file instead */
+ p = bufprint_temp_file(temp, end, USER_CONFIG_FILE);
+ if (p >= end) {
+ derror("Weird: Cannot create temporary user-config file?");
+ exit(2);
+ }
+ dwarning("Weird: Content path too long, using temporary user-config.");
+ }
+
+ uc->iniPath = ASTRDUP(temp);
+ DD("looking user-config in: %s", uc->iniPath);
+
+
+ /* ensure that the parent directory exists */
+ parentPath = path_parent(uc->iniPath, 1);
+ if (parentPath == NULL) {
+ derror("Weird: Can't find parent of user-config file: %s",
+ uc->iniPath);
+ exit(2);
+ }
+
+ if (!path_exists(parentPath)) {
+ if (!inAndroidBuild) {
+ derror("Weird: No content path for this AVD: %s", parentPath);
+ exit(2);
+ }
+ DD("creating missing directory: %s", parentPath);
+ if (path_mkdir_if_needed(parentPath, 0755) < 0) {
+ derror("Using empty user-config, can't create %s: %s",
+ parentPath, strerror(errno));
+ exit(2);
+ }
+ }
+
+ if (path_exists(uc->iniPath)) {
+ DD("reading user-config file");
+ ini = iniFile_newFromFile(uc->iniPath);
+ if (ini == NULL) {
+ dwarning("Can't read user-config file: %s\nUsing default values",
+ uc->iniPath);
+ }
+ }
+
+ if (ini != NULL) {
+ uc->windowX = iniFile_getInteger(ini, KEY_WINDOW_X, DEFAULT_X);
+ DD(" found %s = %d", KEY_WINDOW_X, uc->windowX);
+
+ uc->windowY = iniFile_getInteger(ini, KEY_WINDOW_Y, DEFAULT_Y);
+ DD(" found %s = %d", KEY_WINDOW_Y, uc->windowY);
+
+ if (iniFile_getValue(ini, KEY_UUID) != NULL) {
+ uc->uuid = (uint64_t) iniFile_getInt64(ini, KEY_UUID, 0LL);
+ needUUID = 0;
+ DD(" found %s = %lld", KEY_UUID, uc->uuid);
+ }
+
+ iniFile_free(ini);
+ }
+ else {
+ uc->windowX = DEFAULT_X;
+ uc->windowY = DEFAULT_Y;
+ uc->changed = 1;
+ }
+
+ /* Generate a 64-bit UUID if necessary. We simply take the
+ * current time, which avoids any privacy-related value.
+ */
+ if (needUUID) {
+ struct timeval tm;
+
+ gettimeofday( &tm, NULL );
+ uc->uuid = (uint64_t)tm.tv_sec*1000 + tm.tv_usec/1000;
+ uc->changed = 1;
+ DD(" Generated UUID = %lld", uc->uuid);
+ }
+
+ return uc;
+}
+
+
+uint64_t
+auserConfig_getUUID( AUserConfig* uconfig )
+{
+ return uconfig->uuid;
+}
+
+void
+auserConfig_getWindowPos( AUserConfig* uconfig, int *pX, int *pY )
+{
+ *pX = uconfig->windowX;
+ *pY = uconfig->windowY;
+}
+
+
+void
+auserConfig_setWindowPos( AUserConfig* uconfig, int x, int y )
+{
+ if (x != uconfig->windowX || y != uconfig->windowY) {
+ uconfig->windowX = x;
+ uconfig->windowY = y;
+ uconfig->changed = 1;
+ }
+}
+
+/* Save the user configuration back to the content directory.
+ * Should be used in an atexit() handler */
+void
+auserConfig_save( AUserConfig* uconfig )
+{
+ IniFile* ini;
+ char temp[256];
+
+ if (uconfig->changed == 0) {
+ D("User-config was not changed.");
+ return;
+ }
+
+ bufprint(temp, temp+sizeof(temp),
+ "%s = %d\n"
+ "%s = %d\n"
+ "%s = %lld\n",
+ KEY_WINDOW_X, uconfig->windowX,
+ KEY_WINDOW_Y, uconfig->windowY,
+ KEY_UUID, uconfig->uuid );
+
+ DD("Generated user-config file:\n%s", temp);
+
+ ini = iniFile_newFromMemory(temp, uconfig->iniPath);
+ if (ini == NULL) {
+ D("Weird: can't create user-config iniFile?");
+ return;
+ }
+ if (iniFile_saveToFile(ini, uconfig->iniPath) < 0) {
+ dwarning("could not save user configuration: %s: %s",
+ uconfig->iniPath, strerror(errno));
+ } else {
+ D("User configuration saved to %s", uconfig->iniPath);
+ }
+ iniFile_free(ini);
+}
diff --git a/android/user-config.h b/android/user-config.h
new file mode 100644
index 0000000..5fc6325
--- /dev/null
+++ b/android/user-config.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_USER_CONFIG_H
+#define _ANDROID_USER_CONFIG_H
+
+#include "android/avd/info.h"
+#include <stdint.h>
+
+/* a structure used to model the user-configuration settings
+ *
+ * At the moment, this is only used to store the last position
+ * of the emulator window and a unique 64-bit UUID. We might
+ * add more AVD-specific preferences here in the future.
+ *
+ * By definition, these settings should be optional and we
+ * should be able to work without them, unlike the AVD
+ * configuration information found in config.ini
+ */
+typedef struct AUserConfig AUserConfig;
+
+/* Create a new AUserConfig object from a given AvdInfo */
+AUserConfig* auserConfig_new( AvdInfo* info );
+
+/* Retrieve the unique UID for this AVD */
+uint64_t auserConfig_getUUID( AUserConfig* uconfig );
+
+/* Retrieve the stored window position for this AVD */
+void auserConfig_getWindowPos( AUserConfig* uconfig, int *pX, int *pY );
+
+/* Change the stored window position for this AVD */
+void auserConfig_setWindowPos( AUserConfig* uconfig, int x, int y );
+
+/* Save the user configuration back to the content directory.
+ * Should be used in an atexit() handler. This will effectively
+ * only save the user configuration to disk if its content
+ * has changed.
+ */
+void auserConfig_save( AUserConfig* uconfig );
+
+/* */
+
+#endif /* _ANDROID_USER_CONFIG_H */
diff --git a/android/utils/bufprint.c b/android/utils/bufprint.c
new file mode 100644
index 0000000..4309a4b
--- /dev/null
+++ b/android/utils/bufprint.c
@@ -0,0 +1,230 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "android/utils/bufprint.h"
+#include "android/utils/path.h"
+#include "android/utils/debug.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include "windows.h"
+# include "shlobj.h"
+#else
+# include <unistd.h>
+# include <sys/stat.h>
+#endif
+
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+
+/** USEFUL STRING BUFFER FUNCTIONS
+ **/
+
+char*
+vbufprint( char* buffer,
+ char* buffer_end,
+ const char* fmt,
+ va_list args )
+{
+ int len = vsnprintf( buffer, buffer_end - buffer, fmt, args );
+ if (len < 0 || buffer+len >= buffer_end) {
+ if (buffer < buffer_end)
+ buffer_end[-1] = 0;
+ return buffer_end;
+ }
+ return buffer + len;
+}
+
+char*
+bufprint(char* buffer, char* end, const char* fmt, ... )
+{
+ va_list args;
+ char* result;
+
+ va_start(args, fmt);
+ result = vbufprint(buffer, end, fmt, args);
+ va_end(args);
+ return result;
+}
+
+/** USEFUL DIRECTORY SUPPORT
+ **
+ ** bufprint_app_dir() returns the directory where the emulator binary is located
+ **
+ ** get_android_home() returns a user-specific directory where the emulator will
+ ** store its writable data (e.g. config files, profiles, etc...).
+ ** on Unix, this is $HOME/.android, on Windows, this is something like
+ ** "%USERPROFILE%/Local Settings/AppData/Android" on XP, and something different
+ ** on Vista.
+ **
+ ** both functions return a string that must be freed by the caller
+ **/
+
+#ifdef __linux__
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ char path[1024];
+ int len;
+ char* x;
+
+ len = readlink("/proc/self/exe", path, sizeof(path));
+ if (len <= 0 || len >= (int)sizeof(path)) goto Fail;
+ path[len] = 0;
+
+ x = strrchr(path, '/');
+ if (x == 0) goto Fail;
+ *x = 0;
+
+ return bufprint(buff, end, "%s", path);
+Fail:
+ fprintf(stderr,"cannot locate application directory\n");
+ exit(1);
+ return end;
+}
+
+#elif defined(__APPLE__)
+/* the following hack is needed in order to build with XCode 3.1
+ * don't ask me why, but it seems that there were changes in the
+ * GCC compiler that we don't have in our pre-compiled version
+ */
+#ifndef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ MAC_OS_X_VERSION_10_4
+#endif
+#import <Carbon/Carbon.h>
+#include <unistd.h>
+
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ ProcessSerialNumber psn;
+ CFDictionaryRef dict;
+ CFStringRef value;
+ char s[PATH_MAX];
+ char* x;
+
+ GetCurrentProcess(&psn);
+ dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
+ value = (CFStringRef)CFDictionaryGetValue(dict,
+ CFSTR("CFBundleExecutable"));
+ CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8);
+ x = strrchr(s, '/');
+ if (x == 0) goto fail;
+ *x = 0;
+
+ return bufprint(buff, end, "%s", s);
+fail:
+ fprintf(stderr,"cannot locate application directory\n");
+ exit(1);
+ return end;
+}
+#elif defined _WIN32
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ char appDir[MAX_PATH];
+ int len;
+ char* sep;
+
+ len = GetModuleFileName( 0, appDir, sizeof(appDir)-1 );
+ if (len == 0) {
+ fprintf(stderr, "PANIC CITY!!\n");
+ exit(1);
+ }
+ if (len >= (int)sizeof(appDir)) {
+ len = sizeof(appDir)-1;
+ appDir[len] = 0;
+ }
+
+ sep = strrchr(appDir, '\\');
+ if (sep)
+ *sep = 0;
+
+ return bufprint(buff, end, "%s", appDir);
+}
+#else
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ return bufprint(buff, end, ".");
+}
+#endif
+
+#define _ANDROID_PATH ".android"
+
+char*
+bufprint_config_path(char* buff, char* end)
+{
+#ifdef _WIN32
+ const char* home = getenv("ANDROID_SDK_HOME");
+ if (home != NULL) {
+ return bufprint(buff, end, "%s\\%s", home, _ANDROID_PATH );
+ } else {
+ char path[MAX_PATH];
+
+ SHGetFolderPath( NULL, CSIDL_PROFILE,
+ NULL, 0, path);
+
+ return bufprint(buff, end, "%s\\%s", path, _ANDROID_PATH );
+ }
+#else
+ const char* home = getenv("HOME");
+ if (home == NULL)
+ home = "/tmp";
+ return bufprint(buff, end, "%s/%s", home, _ANDROID_PATH );
+#endif
+}
+
+char*
+bufprint_config_file(char* buff, char* end, const char* suffix)
+{
+ char* p;
+ p = bufprint_config_path(buff, end);
+ p = bufprint(p, end, PATH_SEP "%s", suffix);
+ return p;
+}
+
+char*
+bufprint_temp_dir(char* buff, char* end)
+{
+#ifdef _WIN32
+ char path[MAX_PATH];
+ DWORD retval;
+
+ retval = GetTempPath( sizeof(path), path );
+ if (retval > sizeof(path) || retval == 0) {
+ D( "can't locate TEMP directory" );
+ strncpy(path, "C:\\Temp", sizeof(path) );
+ }
+ strncat( path, "\\AndroidEmulator", sizeof(path)-1 );
+ path_mkdir(path, 0744);
+
+ return bufprint(buff, end, "%s", path);
+#else
+ const char* tmppath = "/tmp/android";
+ mkdir(tmppath, 0744);
+ return bufprint(buff, end, "%s", tmppath );
+#endif
+}
+
+char*
+bufprint_temp_file(char* buff, char* end, const char* suffix)
+{
+ char* p;
+ p = bufprint_temp_dir(buff, end);
+ p = bufprint(p, end, PATH_SEP "%s", suffix);
+ return p;
+}
+
diff --git a/android/utils/bufprint.h b/android/utils/bufprint.h
new file mode 100644
index 0000000..32d64dc
--- /dev/null
+++ b/android/utils/bufprint.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#ifndef _ANDROID_UTILS_BUFPRINT_H
+#define _ANDROID_UTILS_BUFPRINT_H
+
+#include <stdarg.h>
+
+/** FORMATTED BUFFER PRINTING
+ **
+ ** bufprint() allows your to easily and safely append formatted string
+ ** content to a given bounded character buffer, in a way that is easier
+ ** to use than raw snprintf()
+ **
+ ** 'buffer' is the start position in the buffer,
+ ** 'buffend' is the end of the buffer, the function assumes (buffer <= buffend)
+ ** 'format' is a standard printf-style format string, followed by any number
+ ** of formatting arguments
+ **
+ ** the function returns the next position in the buffer if everything fits
+ ** in it. in case of overflow or formatting error, it will always return "buffend"
+ **
+ ** this allows you to chain several calls to bufprint() and only check for
+ ** overflow at the end, for exemple:
+ **
+ ** char buffer[1024];
+ ** char* p = buffer;
+ ** char* end = p + sizeof(buffer);
+ **
+ ** p = bufprint(p, end, "%s/%s", first, second);
+ ** p = bufprint(p, end, "/%s", third);
+ ** if (p >= end) ---> overflow
+ **
+ ** as a convenience, the appended string is zero-terminated if there is no overflow.
+ ** (this means that even if p >= end, the content of "buffer" is zero-terminated)
+ **
+ ** vbufprint() is a variant that accepts a va_list argument
+ **/
+
+extern char* vbufprint(char* buffer, char* buffend, const char* fmt, va_list args );
+extern char* bufprint (char* buffer, char* buffend, const char* fmt, ... );
+
+/** USEFUL DIRECTORY SUPPORT
+ **
+ ** bufprint_add_dir() appends the application's directory to a given bounded buffer
+ **
+ ** bufprint_config_path() appends the applications' user-specific configuration directory
+ ** to a bounded buffer. on Unix this is usually ~/.android, and something a bit more
+ ** complex on Windows
+ **
+ ** bufprint_config_file() appends the name of a file or directory relative to the
+ ** user-specific configuration directory to a bounded buffer. this really is equivalent
+ ** to concat-ing the config path + path separator + 'suffix'
+ **
+ ** bufprint_temp_dir() appends the temporary directory's path to a given bounded buffer
+ **
+ ** bufprint_temp_file() appens the name of a file or directory relative to the
+ ** temporary directory. equivalent to concat-ing the temp path + path separator + 'suffix'
+ **/
+
+extern char* bufprint_app_dir (char* buffer, char* buffend);
+extern char* bufprint_config_path(char* buffer, char* buffend);
+extern char* bufprint_config_file(char* buffer, char* buffend, const char* suffix);
+extern char* bufprint_temp_dir (char* buffer, char* buffend);
+extern char* bufprint_temp_file (char* buffer, char* buffend, const char* suffix);
+
+#endif /* _ANDROID_UTILS_BUFPRINT_H */
diff --git a/android/utils/debug.c b/android/utils/debug.c
new file mode 100644
index 0000000..32936d2
--- /dev/null
+++ b/android/utils/debug.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/debug.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+void
+dprint( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ fprintf( stdout, "emulator: ");
+ vfprintf( stdout, format, args );
+ fprintf( stdout, "\n" );
+ va_end( args );
+}
+
+void
+dprintn( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ vfprintf( stdout, format, args );
+ va_end( args );
+}
+
+void
+dprintnv( const char* format, va_list args )
+{
+ vfprintf( stdout, format, args );
+}
+
+
+void
+dwarning( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ dprintn( "emulator: WARNING: " );
+ dprintnv( format, args );
+ dprintn( "\n" );
+ va_end( args );
+}
+
+
+void
+derror( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ dprintn( "emulator: ERROR: " );
+ dprintnv( format, args );
+ dprintn( "\n" );
+ va_end( args );
+}
+
+/** STDOUT/STDERR REDIRECTION
+ **
+ ** allows you to shut temporarily shutdown stdout/stderr
+ ** this is useful to get rid of debug messages from ALSA and esd
+ ** on Linux.
+ **/
+static int stdio_disable_count;
+static int stdio_save_out_fd;
+static int stdio_save_err_fd;
+
+#ifdef _WIN32
+extern void
+stdio_disable( void )
+{
+ if (++stdio_disable_count == 1) {
+ int null_fd, out_fd, err_fd;
+ fflush(stdout);
+ out_fd = _fileno(stdout);
+ err_fd = _fileno(stderr);
+ stdio_save_out_fd = _dup(out_fd);
+ stdio_save_err_fd = _dup(err_fd);
+ null_fd = _open( "NUL", _O_WRONLY );
+ _dup2(null_fd, out_fd);
+ _dup2(null_fd, err_fd);
+ close(null_fd);
+ }
+}
+
+extern void
+stdio_enable( void )
+{
+ if (--stdio_disable_count == 0) {
+ int out_fd, err_fd;
+ fflush(stdout);
+ out_fd = _fileno(stdout);
+ err_fd = _fileno(stderr);
+ _dup2(stdio_save_out_fd, out_fd);
+ _dup2(stdio_save_err_fd, err_fd);
+ _close(stdio_save_out_fd);
+ _close(stdio_save_err_fd);
+ }
+}
+#else
+extern void
+stdio_disable( void )
+{
+ if (++stdio_disable_count == 1) {
+ int null_fd, out_fd, err_fd;
+ fflush(stdout);
+ out_fd = fileno(stdout);
+ err_fd = fileno(stderr);
+ stdio_save_out_fd = dup(out_fd);
+ stdio_save_err_fd = dup(err_fd);
+ null_fd = open( "/dev/null", O_WRONLY );
+ dup2(null_fd, out_fd);
+ dup2(null_fd, err_fd);
+ close(null_fd);
+ }
+}
+
+extern void
+stdio_enable( void )
+{
+ if (--stdio_disable_count == 0) {
+ int out_fd, err_fd;
+ fflush(stdout);
+ out_fd = fileno(stdout);
+ err_fd = fileno(stderr);
+ dup2(stdio_save_out_fd, out_fd);
+ dup2(stdio_save_err_fd, err_fd);
+ close(stdio_save_out_fd);
+ close(stdio_save_err_fd);
+ }
+}
+#endif
diff --git a/android/utils/debug.h b/android/utils/debug.h
new file mode 100644
index 0000000..fdf93c9
--- /dev/null
+++ b/android/utils/debug.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_DEBUG_H
+#define _ANDROID_UTILS_DEBUG_H
+
+#include <stdarg.h>
+
+#define VERBOSE_TAG_LIST \
+ _VERBOSE_TAG(init, "emulator initialization") \
+ _VERBOSE_TAG(console, "control console") \
+ _VERBOSE_TAG(modem, "emulated GSM modem") \
+ _VERBOSE_TAG(radio, "emulated GSM AT Command channel") \
+ _VERBOSE_TAG(keys, "key bindings & presses") \
+ _VERBOSE_TAG(slirp, "internal router/firewall") \
+ _VERBOSE_TAG(timezone, "host timezone detection" ) \
+ _VERBOSE_TAG(socket, "network sockets") \
+ _VERBOSE_TAG(proxy, "network proxy support") \
+ _VERBOSE_TAG(audio, "audio sub-system") \
+ _VERBOSE_TAG(audioin, "audio input backend") \
+ _VERBOSE_TAG(audioout, "audio output backend") \
+ _VERBOSE_TAG(surface, "video surface support") \
+ _VERBOSE_TAG(qemud, "qemud multiplexer daemon") \
+ _VERBOSE_TAG(gps, "emulated GPS") \
+ _VERBOSE_TAG(nand_limits, "nand/flash read/write thresholding") \
+ _VERBOSE_TAG(hw_control, "emulated power/flashlight/led/vibrator") \
+ _VERBOSE_TAG(avd_config, "android virtual device configuration") \
+
+#define _VERBOSE_TAG(x,y) VERBOSE_##x,
+typedef enum {
+ VERBOSE_TAG_LIST
+ VERBOSE_MAX /* do not remove */
+} VerboseTag;
+#undef _VERBOSE_TAG
+
+/* defined in android_main.c */
+extern unsigned long android_verbose;
+
+#define VERBOSE_ENABLE(tag) \
+ android_verbose |= (1 << VERBOSE_##tag)
+
+#define VERBOSE_DISABLE(tag) \
+ android_verbose &= (1 << VERBOSE_##tag)
+
+#define VERBOSE_CHECK(tag) \
+ ((android_verbose & (1 << VERBOSE_##tag)) != 0)
+
+#define VERBOSE_CHECK_ANY() \
+ (android_verbose != 0)
+
+#define VERBOSE_PRINT(tag,...) \
+ do { if (VERBOSE_CHECK(tag)) dprint(__VA_ARGS__); } while (0)
+
+/** DEBUG TRACE SUPPORT
+ **
+ ** debug messages can be sent by calling these function
+ **
+ ** 'dprint' prints the message, then appends a '\n\
+ ** 'dprintn' simply prints the message as is
+ ** 'dprintnv' allows you to use a va_list argument
+ ** 'dwarning' prints a warning message, then appends a '\n'
+ ** 'derror' prints a severe error message, then appends a '\n'
+ */
+
+extern void dprint( const char* format, ... );
+extern void dprintn( const char* format, ... );
+extern void dprintnv( const char* format, va_list args );
+extern void dwarning( const char* format, ... );
+extern void derror( const char* format, ... );
+
+/** STDOUT/STDERR REDIRECTION
+ **
+ ** allows you to shut temporarily shutdown stdout/stderr
+ ** this is useful to get rid of debug messages from ALSA and esd
+ ** on Linux.
+ **/
+
+extern void stdio_disable( void );
+extern void stdio_enable( void );
+
+/* */
+
+#endif /* _ANDROID_UTILS_DEBUG_H */
diff --git a/android/utils/dirscanner.c b/android/utils/dirscanner.c
new file mode 100644
index 0000000..fc63ef0
--- /dev/null
+++ b/android/utils/dirscanner.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/dirscanner.h"
+#include "android/utils/bufprint.h"
+#include "qemu-common.h"
+#include <stddef.h>
+
+#define DIRSCANNER_BASE \
+ char root[PATH_MAX]; \
+ int rootLen; \
+ char full[PATH_MAX]; \
+
+
+#if _WIN32
+
+#include <io.h>
+
+struct DirScanner {
+ DIRSCANNER_BASE
+ intptr_t findIndex1;
+ struct _finddata_t findData;
+};
+
+/* note: findIndex1 contains the find index + 1
+ * so a value of 0 means 'invalid'
+ */
+
+static int
+_dirScannerInit( DirScanner* s )
+{
+ char* p = s->root + s->rootLen;
+ char* end = s->root + sizeof s->root;
+ int ret;
+
+ /* create file spec by appending \* to root */
+ p = bufprint(p, end, "\\*");
+ if (p >= end)
+ return -1;
+
+ ret = _findfirst(s->root, &s->findData);
+
+ s->findIndex1 = ret+1;
+ return ret;
+}
+
+static void
+_dirScanner_done( DirScanner* s )
+{
+ if (s->findIndex1 > 0) {
+ _findclose(s->findIndex1-1);
+ s->findIndex1 = 0;
+ }
+}
+
+const char*
+dirScanner_next( DirScanner* s )
+{
+ char* ret = NULL;
+
+ if (!s || s->findIndex1 <= 0)
+ return NULL;
+
+ while (ret == NULL) {
+ ret = s->findData.name;
+
+ /* ignore special directories */
+ if (!strcmp(ret, ".") || !strcmp(ret, "..")) {
+ ret = NULL;
+ }
+ /* find next one */
+ if (_findnext(s->findIndex1-1, &s->findData) < 0) {
+ _dirScanner_done(s);
+ break;
+ }
+ }
+ return ret;
+}
+
+#else /* !_WIN32 */
+
+#include <dirent.h>
+struct DirScanner {
+ DIRSCANNER_BASE
+ DIR* dir;
+ struct dirent* entry;
+};
+
+static int
+_dirScannerInit( DirScanner* s )
+{
+ s->dir = opendir(s->root);
+
+ if (s->dir == NULL)
+ return -1;
+
+ s->entry = NULL;
+ return 0;
+}
+
+static void
+_dirScanner_done( DirScanner* s )
+{
+ if (s->dir) {
+ closedir(s->dir);
+ s->dir = NULL;
+ }
+}
+
+const char*
+dirScanner_next( DirScanner* s )
+{
+ char* ret = NULL;
+
+ if (!s || s->dir == NULL)
+ return NULL;
+
+ for (;;)
+ {
+ /* read new entry if needed */
+ s->entry = readdir(s->dir);
+ if (s->entry == NULL) {
+ _dirScanner_done(s);
+ break;
+ }
+
+ /* ignore special directories */
+ ret = s->entry->d_name;
+
+ if (!strcmp(ret,".") || !strcmp(ret,"..")) {
+ ret = NULL;
+ continue;
+ }
+ break;
+ }
+ return ret;
+}
+
+#endif /* !_WIN32 */
+
+DirScanner*
+dirScanner_new ( const char* rootPath )
+{
+ DirScanner* s = qemu_mallocz(sizeof *s);
+ char* p = s->root;
+ char* end = p + sizeof s->root;
+
+ p = bufprint(p, end, "%s", rootPath);
+ if (p >= end)
+ goto FAIL;
+
+ s->rootLen = (p - s->root);
+
+ if (_dirScannerInit(s) < 0)
+ goto FAIL;
+
+ return s;
+
+FAIL:
+ dirScanner_free(s);
+ return NULL;
+}
+
+
+void
+dirScanner_free( DirScanner* s )
+{
+ if (!s)
+ return;
+
+ _dirScanner_done(s);
+ qemu_free(s);
+}
+
+
+const char*
+dirScanner_nextFull( DirScanner* s )
+{
+ const char* name = dirScanner_next(s);
+ char* p;
+ char* end;
+
+ if (name == NULL)
+ return NULL;
+
+ p = s->full;
+ end = p + sizeof s->full;
+
+ p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name);
+ if (p >= end) {
+ /* ignore if the full name is too long */
+ return dirScanner_nextFull(s);
+ }
+ return s->full;
+}
diff --git a/android/utils/dirscanner.h b/android/utils/dirscanner.h
new file mode 100644
index 0000000..871b05e
--- /dev/null
+++ b/android/utils/dirscanner.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_DIR_H
+#define _ANDROID_UTILS_DIR_H
+
+/* simple utility to parse directories for files */
+/* needed because Unix and Windows don't use the same stuff */
+
+typedef struct DirScanner DirScanner;
+
+/* Create a new directory scanner object from a given rootPath.
+ * returns NULL in case of failure (error code in errno)
+ */
+DirScanner* dirScanner_new ( const char* rootPath );
+
+/* Destroy a given directory scanner. You must always call
+ * this function to release proper system resources.
+ */
+void dirScanner_free( DirScanner* s );
+
+/* Get the name of the next file from a directory scanner.
+ * Returns NULL when there is no more elements in the list.
+ *
+ * This is only the file name, use dirScanner_nextFull to
+ * get its full path.
+ *
+ * This will never return '.' and '..'.
+ *
+ * The returned string is owned by the scanner, and will
+ * change on the next call to this function or when the
+ * scanner is destroyed.
+ */
+const char* dirScanner_next( DirScanner* s );
+
+/* A variant of dirScanner_next() which returns the full path
+ * to the next directory element.
+ */
+const char* dirScanner_nextFull( DirScanner* s );
+
+/* */
+
+#endif /* _ANDROID_UTILS_DIR_H */
diff --git a/android/utils/display-quartz.m b/android/utils/display-quartz.m
new file mode 100644
index 0000000..594657e
--- /dev/null
+++ b/android/utils/display-quartz.m
@@ -0,0 +1,111 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+/* this is the Quartz-specific implementation of
+ * <android/utils/display.h>
+ */
+
+#include "android/utils/display.h"
+#include "android/utils/debug.h"
+
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+#include <stdio.h>
+#include <Cocoa/Cocoa.h>
+#include <Carbon/Carbon.h>
+#include <SDL_syswm.h>
+
+int
+get_monitor_resolution( int *px_dpi, int *py_dpi )
+{
+ fprintf(stderr, "emulator: FIXME: implement get_monitor_resolution on OS X\n" );
+ return -1;
+}
+
+int
+get_nearest_monitor_rect( int *x, int *y, int *width, int *height )
+{
+ SDL_SysWMinfo info;
+ NSWindow* window;
+
+ SDL_VERSION(&info.version);
+ if ( SDL_GetWMInfo(&info) < 0 ) {
+ D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+ return -1;
+ }
+ window = info.nsWindowPtr;
+ if (window == NULL) {
+ D( "%s: SDL_GetWMInfo() returned NULL NSWindow ptr",
+ __FUNCTION__ );
+ return -1;
+ }
+ else
+ {
+ NSRect frame = [ window frame ];
+ int fx1 = frame.origin.x;
+ int fy1 = frame.origin.y;
+ int fx2 = frame.size.width + fx1;
+ int fy2 = frame.size.height + fy1;
+ NSArray* screens = [ NSScreen screens ];
+ unsigned int count = [ screens count ];
+ int bestScreen = -1;
+ int bestArea = 0;
+
+ unsigned int n;
+ printf( "window frame (%d,%d) (%d,%d)\n", fx1, fy1, fx2, fy2 );
+
+ /* we need to compute which screen has the most window pixels */
+ for (n = 0; n < count; n++) {
+ NSScreen* screen = [ screens objectAtIndex: n ];
+ NSRect vis = [ screen visibleFrame ];
+ int vx1 = vis.origin.x;
+ int vy1 = vis.origin.y;
+ int vx2 = vis.size.width + vx1;
+ int vy2 = vis.size.height + vy1;
+ int cx1, cx2, cy1, cy2, cArea;
+
+ //printf( "screen %d/%d frame (%d,%d) (%d,%d)\n", n+1, count,
+ // vx1, vy1, vx2, vy2 );
+
+ if (fx1 >= vx2 || vx1 >= fx2 || fy1 >= vy2 || vy1 >= fy2)
+ continue;
+
+ cx1 = (fx1 < vx1) ? vx1 : fx1;
+ cx2 = (fx2 > vx2) ? vx2 : fx2;
+ cy1 = (fy1 < vy1) ? vy1 : fy1;
+ cy2 = (fy2 > vy2) ? vy2 : fy2;
+
+ if (cx1 >= cx2 || cy1 >= cy2)
+ continue;
+
+ cArea = (cx2-cx1)*(cy2-cy1);
+
+ if (bestScreen < 0 || cArea > bestArea) {
+ bestScreen = n;
+ bestArea = cArea;
+ }
+ }
+ if (bestScreen < 0)
+ bestScreen = 0;
+
+ {
+ NSScreen* screen = [ screens objectAtIndex: bestScreen ];
+ NSRect vis = [ screen visibleFrame ];
+
+ *x = vis.origin.x;
+ *y = vis.origin.y;
+ *width = vis.size.width;
+ *height = vis.size.height;
+ }
+ return 0;
+ }
+};
diff --git a/android/utils/display.c b/android/utils/display.c
new file mode 100644
index 0000000..e1ba507
--- /dev/null
+++ b/android/utils/display.c
@@ -0,0 +1,245 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "android/utils/display.h"
+#include "android/utils/debug.h"
+
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+/** HOST RESOLUTION SETTINGS
+ **
+ ** return the main monitor's DPI resolution according to the host device
+ ** beware: this is not always reliable or even obtainable.
+ **
+ ** returns 0 on success, or -1 in case of error (e.g. the system returns funky values)
+ **/
+
+/** NOTE: the following code assumes that we exclusively use X11 on Linux, and Quartz on OS X
+ **/
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <SDL_syswm.h>
+
+int
+get_monitor_resolution( int *px_dpi, int *py_dpi )
+{
+ HDC displayDC = CreateDC( "DISPLAY", NULL, NULL, NULL );
+ int xdpi, ydpi;
+
+ if (displayDC == NULL) {
+ D( "%s: could not get display DC\n", __FUNCTION__ );
+ return -1;
+ }
+ xdpi = GetDeviceCaps( displayDC, LOGPIXELSX );
+ ydpi = GetDeviceCaps( displayDC, LOGPIXELSY );
+
+ /* sanity checks */
+ if (xdpi < 20 || xdpi > 400 || ydpi < 20 || ydpi > 400) {
+ D( "%s: bad resolution: xpi=%d ydpi=%d", __FUNCTION__,
+ xdpi, ydpi );
+ return -1;
+ }
+
+ *px_dpi = xdpi;
+ *py_dpi = ydpi;
+ return 0;
+}
+
+int
+get_nearest_monitor_rect( int *x, int *y, int *width, int *height )
+{
+ SDL_SysWMinfo info;
+ HMONITOR monitor;
+ MONITORINFO monitorInfo;
+
+ SDL_VERSION(&info.version);
+
+ if ( !SDL_GetWMInfo(&info) ) {
+ D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+ return -1;
+ }
+
+ monitor = MonitorFromWindow( info.window, MONITOR_DEFAULTTONEAREST );
+ monitorInfo.cbSize = sizeof(monitorInfo);
+ GetMonitorInfo( monitor, &monitorInfo );
+
+ *x = monitorInfo.rcMonitor.left;
+ *y = monitorInfo.rcMonitor.top;
+ *width = monitorInfo.rcMonitor.right - *x;
+ *height = monitorInfo.rcMonitor.bottom - *y;
+
+ D("%s: found (x,y,w,h)=(%d,%d,%d,%d)", __FUNCTION__,
+ *x, *y, *width, *height);
+
+ return 0;
+}
+
+
+#elif defined __APPLE__
+
+/* the real implementation is in display-quartz.m, but
+ * unfortunately, the Android build system doesn't know
+ * how to build Objective-C sources, so provide stubs
+ * here instead.
+ *
+ * CONFIG_NO_COCOA is set by Makefile.android
+ */
+
+#ifdef CONFIG_NO_COCOA
+int
+get_monitor_resolution( int *px_dpi, int *py_dpi )
+{
+ return -1;
+}
+
+int
+get_nearest_monitor_rect( int *x, int *y, int *width, int *height )
+{
+ return -1;
+}
+#endif /* CONFIG_NO_COCOA */
+
+#else /* Linux and others */
+#include <SDL.h>
+#include <SDL_syswm.h>
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#define MM_PER_INCH 25.4
+
+#define DYNLINK_FUNCTIONS \
+ DYNLINK_FUNC(int,XDefaultScreen,(Display*)) \
+ DYNLINK_FUNC(int,XDisplayWidth,(Display*,int)) \
+ DYNLINK_FUNC(int,XDisplayWidthMM,(Display*,int)) \
+ DYNLINK_FUNC(int,XDisplayHeight,(Display*,int)) \
+ DYNLINK_FUNC(int,XDisplayHeightMM,(Display*,int)) \
+
+#define DYNLINK_FUNCTIONS_INIT \
+ x11_dynlink_init
+
+#include "dynlink.h"
+
+static int x11_lib_inited;
+static void* x11_lib;
+
+int
+x11_lib_init( void )
+{
+ if (!x11_lib_inited) {
+ x11_lib_inited = 1;
+
+ x11_lib = dlopen( "libX11.so", RTLD_NOW );
+
+ if (x11_lib == NULL) {
+ x11_lib = dlopen( "libX11.so.6", RTLD_NOW );
+ }
+ if (x11_lib == NULL) {
+ D("%s: Could not find libX11.so on this machine",
+ __FUNCTION__);
+ return -1;
+ }
+
+ if (x11_dynlink_init(x11_lib) < 0) {
+ D("%s: didn't find necessary symbols in libX11.so",
+ __FUNCTION__);
+ dlclose(x11_lib);
+ x11_lib = NULL;
+ }
+ }
+ return x11_lib ? 0 : -1;
+}
+
+
+int
+get_monitor_resolution( int *px_dpi, int *py_dpi )
+{
+ SDL_SysWMinfo info;
+ Display* display;
+ int screen;
+ int width, width_mm, height, height_mm, xdpi, ydpi;
+
+ SDL_VERSION(&info.version);
+
+ if ( !SDL_GetWMInfo(&info) ) {
+ D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+ return -1;
+ }
+
+ if (x11_lib_init() < 0)
+ return -1;
+
+ display = info.info.x11.display;
+ screen = FF(XDefaultScreen)(display);
+
+ width = FF(XDisplayWidth)(display, screen);
+ width_mm = FF(XDisplayWidthMM)(display, screen);
+ height = FF(XDisplayHeight)(display, screen);
+ height_mm = FF(XDisplayHeightMM)(display, screen);
+
+ if (width_mm <= 0 || height_mm <= 0) {
+ D( "%s: bad screen dimensions: width_mm = %d, height_mm = %d",
+ __FUNCTION__, width_mm, height_mm);
+ return -1;
+ }
+
+ D( "%s: found screen width=%d height=%d width_mm=%d height_mm=%d",
+ __FUNCTION__, width, height, width_mm, height_mm );
+
+ xdpi = width * MM_PER_INCH / width_mm;
+ ydpi = height * MM_PER_INCH / height_mm;
+
+ if (xdpi < 20 || xdpi > 400 || ydpi < 20 || ydpi > 400) {
+ D( "%s: bad resolution: xpi=%d ydpi=%d", __FUNCTION__,
+ xdpi, ydpi );
+ return -1;
+ }
+
+ *px_dpi = xdpi;
+ *py_dpi = ydpi;
+
+ return 0;
+}
+
+int
+get_nearest_monitor_rect( int *x, int *y, int *width, int *height )
+{
+ SDL_SysWMinfo info;
+ Display* display;
+ int screen;
+
+ SDL_VERSION(&info.version);
+
+ if ( !SDL_GetWMInfo(&info) ) {
+ D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+ return -1;
+ }
+
+ if (x11_lib_init() < 0)
+ return -1;
+
+ display = info.info.x11.display;
+ screen = FF(XDefaultScreen)(display);
+
+ *x = 0;
+ *y = 0;
+ *width = FF(XDisplayWidth)(display, screen);
+ *height = FF(XDisplayHeight)(display, screen);
+
+ D("%s: found (x,y,w,h)=(%d,%d,%d,%d)", __FUNCTION__,
+ *x, *y, *width, *height);
+
+ return 0;
+}
+
+#endif
diff --git a/android/utils/display.h b/android/utils/display.h
new file mode 100644
index 0000000..7254aca
--- /dev/null
+++ b/android/utils/display.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#ifndef _ANDROID_UTILS_DISPLAY_H
+#define _ANDROID_UTILS_DISPLAY_H
+
+/** HOST RESOLUTION SETTINGS
+ **
+ ** return the main monitor's DPI resolution according to the host device
+ ** beware: this is not always reliable or even obtainable.
+ **
+ ** returns 0 on success, or -1 in case of error (e.g. the system returns funky values)
+ **/
+extern int get_monitor_resolution( int *px_dpi, int *py_dpi );
+
+/** return the size in pixels of the nearest monitor for the current window.
+ ** this is used to implement full-screen presentation mode.
+ **/
+
+extern int get_nearest_monitor_rect( int *x, int *y, int *width, int *height );
+
+#endif /* _ANDROID_UTILS_DISPLAY_H */
diff --git a/android/utils/filelock.c b/android/utils/filelock.c
new file mode 100644
index 0000000..a8b18da
--- /dev/null
+++ b/android/utils/filelock.c
@@ -0,0 +1,414 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "android/utils/filelock.h"
+#include "android/utils/path.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
+#ifdef _WIN32
+# include <process.h>
+# include <windows.h>
+# include <tlhelp32.h>
+#else
+# include <sys/types.h>
+# include <unistd.h>
+# include <signal.h>
+#endif
+
+#define D(...) ((void)0)
+
+#ifndef CHECKED
+# ifdef _WIN32
+# define CHECKED(ret, call) (ret) = (call)
+# else
+# define CHECKED(ret, call) do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
+# endif
+#endif
+
+/** FILE LOCKS SUPPORT
+ **
+ ** a FileLock is useful to prevent several emulator instances from using the same
+ ** writable file (e.g. the userdata.img disk images).
+ **
+ ** create a FileLock object with filelock_create(), ithis function should return NULL
+ ** only if the corresponding file path could not be locked.
+ **
+ ** all file locks are automatically released and destroyed when the program exits.
+ ** the filelock_lock() function can also detect stale file locks that can linger
+ ** when the emulator crashes unexpectedly, and will happily clean them for you
+ **
+ ** here's how it works, three files are used:
+ ** file - the data file accessed by the emulator
+ ** lock - a lock file (file + '.lock')
+ ** temp - a temporary file make unique with mkstemp
+ **
+ ** when locking:
+ ** create 'temp' and store our pid in it
+ ** attemp to link 'lock' to 'temp'
+ ** if the link succeeds, we obtain the lock
+ ** unlink 'temp'
+ **
+ ** when unlocking:
+ ** unlink 'lock'
+ **
+ **
+ ** on Windows, 'lock' is a directory name. locking is equivalent to
+ ** creating it...
+ **
+ **/
+
+struct FileLock
+{
+ const char* file;
+ const char* lock;
+ char* temp;
+ int locked;
+ FileLock* next;
+};
+
+/* used to cleanup all locks at emulator exit */
+static FileLock* _all_filelocks;
+
+
+#define LOCK_NAME ".lock"
+#define TEMP_NAME ".tmp-XXXXXX"
+
+#ifdef _WIN32
+#define PIDFILE_NAME "pid"
+#endif
+
+/* returns 0 on success, -1 on failure */
+static int
+filelock_lock( FileLock* lock )
+{
+ int ret;
+#ifdef _WIN32
+ int pidfile_fd = -1;
+
+ ret = _mkdir( lock->lock );
+ if (ret < 0) {
+ if (errno == ENOENT) {
+ D( "could not access directory '%s', check path elements", lock->lock );
+ return -1;
+ } else if (errno != EEXIST) {
+ D( "_mkdir(%s): %s", lock->lock, strerror(errno) );
+ return -1;
+ }
+
+ /* if we get here, it's because the .lock directory already exists */
+ /* check to see if there is a pid file in it */
+ D("directory '%s' already exist, waiting a bit to ensure that no other emulator instance is starting", lock->lock );
+ {
+ int _sleep = 200;
+ int tries;
+
+ for ( tries = 4; tries > 0; tries-- )
+ {
+ pidfile_fd = open( lock->temp, O_RDONLY );
+
+ if (pidfile_fd >= 0)
+ break;
+
+ Sleep( _sleep );
+ _sleep *= 2;
+ }
+ }
+
+ if (pidfile_fd < 0) {
+ D( "no pid file in '%s', assuming stale directory", lock->lock );
+ }
+ else
+ {
+ /* read the pidfile, and check wether the corresponding process is still running */
+ char buf[16];
+ int len, lockpid;
+ HANDLE processSnapshot;
+ PROCESSENTRY32 pe32;
+ int is_locked = 0;
+
+ len = read( pidfile_fd, buf, sizeof(buf)-1 );
+ if (len < 0) {
+ D( "could not read pid file '%s'", lock->temp );
+ close( pidfile_fd );
+ return -1;
+ }
+ buf[len] = 0;
+ lockpid = atoi(buf);
+
+ /* PID 0 is the IDLE process, and 0 is returned in case of invalid input */
+ if (lockpid == 0)
+ lockpid = -1;
+
+ close( pidfile_fd );
+
+ pe32.dwSize = sizeof( PROCESSENTRY32 );
+ processSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
+
+ if ( processSnapshot == INVALID_HANDLE_VALUE ) {
+ D( "could not retrieve the list of currently active processes\n" );
+ is_locked = 1;
+ }
+ else if ( !Process32First( processSnapshot, &pe32 ) )
+ {
+ D( "could not retrieve first process id\n" );
+ CloseHandle( processSnapshot );
+ is_locked = 1;
+ }
+ else
+ {
+ do {
+ if (pe32.th32ProcessID == lockpid) {
+ is_locked = 1;
+ break;
+ }
+ } while (Process32Next( processSnapshot, &pe32 ) );
+
+ CloseHandle( processSnapshot );
+ }
+
+ if (is_locked) {
+ D( "the file '%s' is locked by process ID %d\n", lock->file, lockpid );
+ return -1;
+ }
+ }
+ }
+
+ /* write our PID into the pid file */
+ pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC );
+ if (pidfile_fd < 0) {
+ if (errno == EACCES) {
+ if ( path_delete_file( lock->temp ) < 0 ) {
+ D( "could not remove '%s': %s\n", lock->temp, strerror(errno) );
+ return -1;
+ }
+ pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC );
+ }
+ if (pidfile_fd < 0) {
+ D( "could not create '%s': %s\n", lock->temp, strerror(errno) );
+ return -1;
+ }
+ }
+
+ {
+ char buf[16];
+ sprintf( buf, "%ld", GetCurrentProcessId() );
+ ret = write( pidfile_fd, buf, strlen(buf) );
+ close(pidfile_fd);
+ if (ret < 0) {
+ D( "could not write PID to '%s'\n", lock->temp );
+ return -1;
+ }
+ }
+
+ lock->locked = 1;
+ return 0;
+#else
+ int temp_fd = -1;
+ int lock_fd = -1;
+ int rc, tries, _sleep;
+ FILE* f = NULL;
+ char pid[8];
+ struct stat st_temp;
+
+ strcpy( lock->temp, lock->file );
+ strcat( lock->temp, TEMP_NAME );
+ temp_fd = mkstemp( lock->temp );
+
+ if (temp_fd < 0) {
+ D("cannot create locking temp file '%s'", lock->temp );
+ goto Fail;
+ }
+
+ sprintf( pid, "%d", getpid() );
+ ret = write( temp_fd, pid, strlen(pid)+1 );
+ if (ret < 0) {
+ D( "cannot write to locking temp file '%s'", lock->temp);
+ goto Fail;
+ }
+ close( temp_fd );
+ temp_fd = -1;
+
+ CHECKED(rc, lstat( lock->temp, &st_temp ));
+ if (rc < 0) {
+ D( "can't properly stat our locking temp file '%s'", lock->temp );
+ goto Fail;
+ }
+
+ /* now attempt to link the temp file to the lock file */
+ _sleep = 0;
+ for ( tries = 4; tries > 0; tries-- )
+ {
+ struct stat st_lock;
+ int rc;
+
+ if (_sleep > 0) {
+ if (_sleep > 2000000) {
+ D( "cannot acquire lock file '%s'", lock->lock );
+ goto Fail;
+ }
+ usleep( _sleep );
+ }
+ _sleep += 200000;
+
+ /* the return value of link() is buggy on NFS */
+ CHECKED(rc, link( lock->temp, lock->lock ));
+
+ CHECKED(rc, lstat( lock->lock, &st_lock ));
+ if (rc == 0 &&
+ st_temp.st_rdev == st_lock.st_rdev &&
+ st_temp.st_ino == st_lock.st_ino )
+ {
+ /* SUCCESS */
+ lock->locked = 1;
+ CHECKED(rc, unlink( lock->temp ));
+ return 0;
+ }
+
+ /* if we get there, it means that the link() call failed */
+ /* check the lockfile to see if it is stale */
+ if (rc == 0) {
+ char buf[16];
+ time_t now;
+ int lockpid = 0;
+ int lockfd;
+ int stale = 2; /* means don't know */
+ struct stat st;
+
+ CHECKED(rc, time( &now));
+ st.st_mtime = now - 120;
+
+ CHECKED(lockfd, open( lock->lock,O_RDONLY ));
+ if ( lockfd >= 0 ) {
+ int len;
+
+ CHECKED(len, read( lockfd, buf, sizeof(buf)-1 ));
+ buf[len] = 0;
+ lockpid = atoi(buf);
+
+ CHECKED(rc, fstat( lockfd, &st ));
+ if (rc == 0)
+ now = st.st_atime;
+
+ CHECKED(rc, close(lockfd));
+ }
+ /* if there is a PID, check that it is still alive */
+ if (lockpid > 0) {
+ CHECKED(rc, kill( lockpid, 0 ));
+ if (rc == 0 || errno == EPERM) {
+ stale = 0;
+ } else if (rc < 0 && errno == ESRCH) {
+ stale = 1;
+ }
+ }
+ if (stale == 2) {
+ /* no pid, stale if the file is older than 1 minute */
+ stale = (now >= st.st_mtime + 60);
+ }
+
+ if (stale) {
+ D( "removing stale lockfile '%s'", lock->lock );
+ CHECKED(rc, unlink( lock->lock ));
+ _sleep = 0;
+ tries++;
+ }
+ }
+ }
+ D("file '%s' is already in use by another process", lock->file );
+
+Fail:
+ if (f)
+ fclose(f);
+
+ if (temp_fd >= 0) {
+ close(temp_fd);
+ }
+
+ if (lock_fd >= 0) {
+ close(lock_fd);
+ }
+
+ unlink( lock->lock );
+ unlink( lock->temp );
+ return -1;
+#endif
+}
+
+void
+filelock_release( FileLock* lock )
+{
+ if (lock->locked) {
+#ifdef _WIN32
+ path_delete_file( (char*)lock->temp );
+ rmdir( (char*)lock->lock );
+#else
+ unlink( (char*)lock->lock );
+#endif
+ lock->locked = 0;
+ }
+}
+
+static void
+filelock_atexit( void )
+{
+ FileLock* lock;
+
+ for (lock = _all_filelocks; lock != NULL; lock = lock->next)
+ filelock_release( lock );
+}
+
+/* create a file lock */
+FileLock*
+filelock_create( const char* file )
+{
+ int file_len = strlen(file);
+ int lock_len = file_len + sizeof(LOCK_NAME);
+#ifdef _WIN32
+ int temp_len = lock_len + 1 + sizeof(PIDFILE_NAME);
+#else
+ int temp_len = file_len + sizeof(TEMP_NAME);
+#endif
+ int total_len = sizeof(FileLock) + file_len + lock_len + temp_len + 3;
+
+ FileLock* lock = malloc(total_len);
+
+ lock->file = (const char*)(lock + 1);
+ memcpy( (char*)lock->file, file, file_len+1 );
+
+ lock->lock = lock->file + file_len + 1;
+ memcpy( (char*)lock->lock, file, file_len+1 );
+ strcat( (char*)lock->lock, LOCK_NAME );
+
+ lock->temp = (char*)lock->lock + lock_len + 1;
+#ifdef _WIN32
+ snprintf( (char*)lock->temp, temp_len, "%s\\" PIDFILE_NAME, lock->lock );
+#else
+ lock->temp[0] = 0;
+#endif
+ lock->locked = 0;
+
+ if (filelock_lock(lock) < 0) {
+ free(lock);
+ return NULL;
+ }
+
+ lock->next = _all_filelocks;
+ _all_filelocks = lock;
+
+ if (lock->next == NULL)
+ atexit( filelock_atexit );
+
+ return lock;
+}
diff --git a/android/utils/filelock.h b/android/utils/filelock.h
new file mode 100644
index 0000000..9bc86b5
--- /dev/null
+++ b/android/utils/filelock.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#ifndef _ANDROID_UTILS_FILELOCK_H
+#define _ANDROID_UTILS_FILELOCK_H
+
+/** FILE LOCKS SUPPORT
+ **
+ ** a FileLock is useful to prevent several emulator instances from using the same
+ ** writable file (e.g. the userdata.img disk images).
+ **
+ ** create a FileLock object with filelock_create(), the function will return
+ ** NULL only if the corresponding path is already locked by another emulator
+ ** of if the path is read-only.
+ **
+ ** note that 'path' can designate a non-existing path and that the lock creation
+ ** function can detect stale file locks that can longer when the emulator
+ ** crashes unexpectedly, and will happily clean them for you.
+ **
+ ** you can call filelock_release() to release a file lock explicitely. otherwise
+ ** all file locks are automatically released when the program exits.
+ **/
+
+typedef struct FileLock FileLock;
+
+extern FileLock* filelock_create ( const char* path );
+extern void filelock_release( FileLock* lock );
+
+#endif /* _ANDROID_UTILS_FILELOCK_H */
diff --git a/android/utils/ini.c b/android/utils/ini.c
new file mode 100644
index 0000000..95bb4e3
--- /dev/null
+++ b/android/utils/ini.c
@@ -0,0 +1,416 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/ini.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include "android/utils/debug.h"
+#include "android/utils/system.h" /* for ASTRDUP */
+#include "android/utils/bufprint.h"
+#include "osdep.h"
+
+/* W() is used to print warnings, D() to print debugging info */
+#define W(...) dwarning(__VA_ARGS__)
+#define D(...) VERBOSE_PRINT(avd_config,__VA_ARGS__)
+
+/* a simple .ini file parser and container for Android
+ * no sections support. see android/utils/ini.h for
+ * more details on the supported file format.
+ */
+typedef struct {
+ char* key;
+ char* value;
+} IniPair;
+
+struct IniFile {
+ int numPairs;
+ int maxPairs;
+ IniPair* pairs;
+};
+
+void
+iniFile_free( IniFile* i )
+{
+ int nn;
+ for (nn = 0; nn < i->numPairs; nn++) {
+ AFREE(i->pairs[nn].key);
+ i->pairs[nn].key = NULL;
+ i->pairs[nn].value = NULL;
+ }
+ AFREE(i->pairs);
+ AFREE(i);
+}
+
+static IniFile*
+iniFile_alloc( void )
+{
+ IniFile* i;
+
+ ANEW0(i);
+ return i;
+}
+
+static void
+iniFile_addPair( IniFile* i, const char* key, int keyLen,
+ const char* value, int valueLen )
+{
+ IniPair* pair;
+
+ if (i->numPairs >= i->maxPairs) {
+ int oldMax = i->maxPairs;
+ int newMax = oldMax + (oldMax >> 1) + 4;
+
+ AARRAY_RENEW(i->pairs, newMax);
+ i->maxPairs = newMax;
+ }
+
+ pair = i->pairs + i->numPairs;
+
+ AARRAY_NEW(pair->key, keyLen + valueLen + 2);
+ memcpy(pair->key, key, keyLen);
+ pair->key[keyLen] = 0;
+
+ pair->value = pair->key + keyLen + 1;
+ memcpy(pair->value, value, valueLen);
+ pair->value[valueLen] = 0;
+
+ i->numPairs += 1;
+}
+
+const char*
+iniFile_getValue( IniFile* i, const char* key )
+{
+ if (i && key) {
+ int nn;
+
+ for (nn = 0; nn < i->numPairs; nn++) {
+ if (!strcmp(i->pairs[nn].key,key))
+ return i->pairs[nn].value;
+ }
+ }
+ return NULL;
+}
+
+int
+iniFile_getPairCount( IniFile* i )
+{
+ return i ? i->numPairs : 0;
+}
+
+void
+iniFile_getPair( IniFile* i,
+ int index,
+ const char* *pKey,
+ const char* *pValue )
+{
+ const char* key = NULL;
+ const char* value = NULL;
+
+ if (i && index >= 0 && index < i->numPairs) {
+ key = i->pairs[index].key;
+ value = i->pairs[index].value;
+ }
+ *pKey = key;
+ *pValue = value;
+}
+
+/* NOTE: we avoid using <ctype.h> functions to avoid locale-specific
+ * behaviour that can be the source of strange bugs.
+ */
+
+static const char*
+skipSpaces( const char* p )
+{
+ while (*p == ' ' || *p == '\t')
+ p ++;
+ return p;
+}
+
+static const char*
+skipToEOL( const char* p )
+{
+ while (*p && (*p != '\n' && *p != '\r'))
+ p ++;
+
+ if (*p) {
+ p ++;
+ if (p[-1] == '\r' && p[0] == '\n')
+ p ++;
+ }
+ return p;
+}
+
+static int
+isKeyStartChar( int c )
+{
+ return ((unsigned)(c-'a') < 26 ||
+ (unsigned)(c-'A') < 26 ||
+ c == '_');
+}
+
+static int
+isKeyChar( int c )
+{
+ return isKeyStartChar(c) || ((unsigned)(c-'0') < 10) || (c == '.') || (c == '-');
+}
+
+IniFile*
+iniFile_newFromMemory( const char* text, const char* fileName )
+{
+ const char* p = text;
+ IniFile* ini = iniFile_alloc();
+ int lineno = 0;
+
+ if (!fileName)
+ fileName = "<memoryFile>";
+
+ D("%s: parsing as .ini file", fileName);
+
+ while (*p) {
+ const char* key;
+ int keyLen;
+ const char* value;
+ int valueLen;
+
+ lineno += 1;
+
+ /* skip leading whitespace */
+ p = skipSpaces(p);
+
+ /* skip comments and empty lines */
+ if (*p == 0 || *p == ';' || *p == '#' || *p == '\n' || *p == '\r') {
+ p = skipToEOL(p);
+ continue;
+ }
+
+ /* check the key name */
+ key = p++;
+ if (!isKeyStartChar(*key)) {
+ p = skipToEOL(p);
+ W("%4d: key name doesn't start with valid character. line ignored",
+ lineno);
+ continue;
+ }
+
+ while (isKeyChar(*p))
+ p++;
+
+ keyLen = p - key;
+ p = skipSpaces(p);
+
+ /* check the equal */
+ if (*p != '=') {
+ W("%4d: missing expected assignment operator (=). line ignored",
+ lineno);
+ p = skipToEOL(p);
+ continue;
+ }
+ p += 1;
+
+ /* skip spaces before the value */
+ p = skipSpaces(p);
+ value = p;
+
+ /* find the value */
+ while (*p && (*p != '\n' && *p != '\r'))
+ p += 1;
+
+ /* remove trailing spaces */
+ while (p > value && (p[-1] == ' ' || p[-1] == '\t'))
+ p --;
+
+ valueLen = p - value;
+
+ iniFile_addPair(ini, key, keyLen, value, valueLen);
+ D("%4d: KEY='%.*s' VALUE='%.*s'", lineno,
+ keyLen, key, valueLen, value);
+
+ p = skipToEOL(p);
+ }
+
+ D("%s: parsing finished", fileName);
+
+ return ini;
+}
+
+IniFile*
+iniFile_newFromFile( const char* filepath )
+{
+ FILE* fp = fopen(filepath, "rt");
+ char* text;
+ long size;
+ IniFile* ini = NULL;
+
+ if (fp == NULL) {
+ D("could not open .ini file: %s: %s",
+ filepath, strerror(errno));
+ return NULL;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ /* avoid reading a very large file that was passed by mistake
+ * this threshold is quite liberal.
+ */
+#define MAX_INI_FILE_SIZE 655360
+
+ if (size < 0 || size > MAX_INI_FILE_SIZE) {
+ W("hardware configuration file '%s' too large (%ld bytes)",
+ filepath, size);
+ goto EXIT;
+ }
+
+ /* read the file, add a sentinel at the end of it */
+ AARRAY_NEW(text, size+1);
+ fread(text, 1, size, fp);
+ text[size] = 0;
+
+ ini = iniFile_newFromMemory(text, filepath);
+ AFREE(text);
+
+EXIT:
+ fclose(fp);
+ return ini;
+}
+
+int
+iniFile_saveToFile( IniFile* f, const char* filepath )
+{
+ FILE* fp = fopen(filepath, "wt");
+ IniPair* pair = f->pairs;
+ IniPair* pairEnd = pair + f->numPairs;
+ int result = 0;
+
+ if (fp == NULL) {
+ D("could not create .ini file: %s: %s",
+ filepath, strerror(errno));
+ return -1;
+ }
+
+ for ( ; pair < pairEnd; pair++ ) {
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ p = bufprint(temp, end, "%s = %s\n", pair->key, pair->value);
+ if (fwrite(temp, p - temp, 1, fp) != 1) {
+ result = -1;
+ break;
+ }
+ }
+
+ fclose(fp);
+ return result;
+}
+
+char*
+iniFile_getString( IniFile* f, const char* key )
+{
+ const char* val = iniFile_getValue(f, key);
+
+ if (!val)
+ return NULL;
+
+ return ASTRDUP(val);
+}
+
+int
+iniFile_getInteger( IniFile* f, const char* key, int defaultValue )
+{
+ const char* valueStr = iniFile_getValue(f, key);
+ int value = defaultValue;
+
+ if (valueStr != NULL) {
+ char* end;
+ long l = strtol(valueStr, &end, 10);
+ if (end != NULL && end[0] == 0 && (int)l == l)
+ value = l;
+ }
+ return value;
+}
+
+double
+iniFile_getDouble( IniFile* f, const char* key, double defaultValue )
+{
+ const char* valueStr = iniFile_getValue(f, key);
+ double value = defaultValue;
+
+ if (valueStr != NULL) {
+ char* end;
+ double d = strtod(valueStr, &end);
+ if (end != NULL && end[0] == 0)
+ value = d;
+ }
+ return value;
+}
+
+int
+iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue )
+{
+ const char* value = iniFile_getValue(f, key);
+
+ if (!value)
+ value = defaultValue;
+
+ if (!strcmp(value,"1") ||
+ !strcmp(value,"yes") ||
+ !strcmp(value,"YES") ||
+ !strcmp(value,"true") ||
+ !strcmp(value,"TRUE"))
+ {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int64_t
+iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue )
+{
+ const char* valStr = iniFile_getValue(f, key);
+ int64_t value = 0;
+
+ if (!valStr)
+ valStr = defaultValue;
+
+ if (valStr != NULL) {
+ char* end;
+
+ value = strtoll(valStr, &end, 10);
+ if (*end == 'k' || *end == 'K')
+ value *= 1024ULL;
+ else if (*end == 'm' || *end == 'M')
+ value *= 1024*1024ULL;
+ else if (*end == 'g' || *end == 'G')
+ value *= 1024*1024*1024ULL;
+ }
+ return value;
+}
+
+int64_t
+iniFile_getInt64( IniFile* f, const char* key, int64_t defaultValue )
+{
+ const char* valStr = iniFile_getValue(f, key);
+ int64_t value = defaultValue;
+
+ if (valStr != NULL) {
+ char* end;
+ int64_t d;
+
+ d = strtoll(valStr, &end, 10);
+ if (end != NULL && end[0] == 0)
+ value = d;
+ }
+ return value;
+}
+
diff --git a/android/utils/ini.h b/android/utils/ini.h
new file mode 100644
index 0000000..a176bfe
--- /dev/null
+++ b/android/utils/ini.h
@@ -0,0 +1,131 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_INI_H
+#define _ANDROID_UTILS_INI_H
+
+#include <stdint.h>
+
+/* the emulator supports a simple .ini file format for its configuration
+ * files. Here's the BNF for it:
+ *
+ * file := <line>*
+ * line := <comment> | <LF> | <assignment>
+ * comment := (';'|'#') <noLF>* <LF>
+ * assignment := <space>* <keyName> <space>* '=' <space>* <valueString> <space>* <LF>
+ * keyName := <keyNameStartChar> <keyNameChar>*
+ * keyNameStartChar := [A-Za-z_]
+ * keyNameChar := [A-Za-z0-9_.-]
+ * valueString := <noLF>*
+ * space := ' ' | '\t'
+ * LF := '\r\n' | '\n' | '\r'
+ * noLF := [^<LF>]
+ *
+ * Or, in English:
+ *
+ * - no support for sections
+ * - empty lines are ignored, as well as lines beginning with ';' or '#'
+ * - lines must be of the form: "<keyName> = <value>"
+ * - key names must start with a letter or an underscore
+ * - other key name characters can be letters, digits, underscores, dots or dashes
+ *
+ * - leading and trailing space are allowed and ignored before/after the key name
+ * and before/after the value
+ *
+ * - there is no restriction on the value, except that it can't contain
+ * leading/trailing space/tab characters or newline/charfeed characters
+ *
+ * - empty values are possible, and will be stored as an empty string.
+ * - any badly formatted line is discarded (and will print a warning)
+ *
+ */
+
+/* an opaque structure used to model an .ini configuration file */
+typedef struct IniFile IniFile;
+
+/* creates a new IniFile object from a config file loaded in memory.
+ * 'fileName' is only used when writing a warning to stderr in case
+ * of badly formed output
+ */
+IniFile* iniFile_newFromMemory( const char* text, const char* fileName );
+
+/* creates a new IniFile object from a file path,
+ * returns NULL if the file cannot be opened.
+ */
+IniFile* iniFile_newFromFile( const char* filePath);
+
+/* try to write an IniFile into a given file.
+ * returns 0 on success, -1 on error (see errno for error code)
+ */
+int iniFile_saveToFile( IniFile* f, const char* filePath );
+
+/* free an IniFile object */
+void iniFile_free( IniFile* f );
+
+/* returns the number of (key.value) pairs in an IniFile */
+int iniFile_getPairCount( IniFile* f );
+
+/* return a specific (key,value) pair from an IniFile.
+ * if the index is not correct, both '*pKey' and '*pValue' will be
+ * set to NULL.
+ *
+ * you should probably use iniFile_getValue() and its variants instead
+ */
+void iniFile_getPair( IniFile* f,
+ int index,
+ const char* *pKey,
+ const char* *pValue );
+
+/* returns the value of a given key from an IniFile.
+ * NULL if the key is not assigned in the corresponding configuration file
+ */
+const char* iniFile_getValue( IniFile* f, const char* key );
+
+/* returns a copy of the value of a given key, or NULL
+ */
+char* iniFile_getString( IniFile* f, const char* key );
+
+/* returns an integer value, or a default in case the value string is
+ * missing or badly formatted
+ */
+int iniFile_getInteger( IniFile* f, const char* key, int defaultValue );
+
+/* returns a 64-bit integer value, or a default in case the value string is
+ * missing or badly formatted
+ */
+int64_t iniFile_getInt64( IniFile* f, const char* key, int64_t defaultValue );
+
+/* returns a double value, or a default in case the value string is
+ * missing or badly formatted
+ */
+double iniFile_getDouble( IniFile* f, const char* key, double defaultValue );
+
+/* returns a copy of a given key's value, if any, or NULL if it is missing
+ * caller must call free() to release it */
+char* iniFile_getString( IniFile* f, const char* key );
+
+/* parses a key value as a boolean. Accepted values are "1", "0", "yes", "YES",
+ * "no" and "NO". Returns either 1 or 0.
+ * note that the default value must be provided as a string too
+ */
+int iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue );
+
+/* parses a key value as a disk size. this means it can be an integer followed
+ * by a suffix that can be one of "mMkKgG" which correspond to KiB, MiB and GiB
+ * multipliers.
+ *
+ * NOTE: we consider that 1K = 1024, not 1000.
+ */
+int64_t iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue );
+
+/* */
+
+#endif /* _ANDROID_UTILS_INI_H */
diff --git a/android/utils/misc.c b/android/utils/misc.c
new file mode 100644
index 0000000..818ab78
--- /dev/null
+++ b/android/utils/misc.c
@@ -0,0 +1,193 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "android/utils/misc.h"
+#include "android/utils/stralloc.h"
+#include "android/utils/debug.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void
+print_tabular( const char** strings, int count,
+ const char* prefix, int width )
+{
+ int nrows, ncols, r, c, n, maxw = 0;
+
+ for (n = 0; n < count; n++) {
+ int len = strlen(strings[n]);
+ if (len > maxw)
+ maxw = len;
+ }
+ maxw += 2;
+ ncols = width/maxw;
+ nrows = (count + ncols-1)/ncols;
+
+ for (r = 0; r < nrows; r++) {
+ printf( "%s", prefix );
+ for (c = 0; c < ncols; c++) {
+ int index = c*nrows + r;
+ if (index >= count) {
+ break;
+ }
+ printf( "%-*s", maxw, strings[index] );
+ }
+ printf( "\n" );
+ }
+}
+
+extern void
+string_translate_char( char* str, char from, char to )
+{
+ char* p = str;
+ while (p != NULL && (p = strchr(p, from)) != NULL)
+ *p++ = to;
+}
+
+extern void
+buffer_translate_char( char* buff,
+ unsigned buffLen,
+ const char* src,
+ char fromChar,
+ char toChar )
+{
+ int len = strlen(src);
+
+ if (len >= buffLen)
+ len = buffLen-1;
+
+ memcpy(buff, src, len);
+ buff[len] = 0;
+
+ string_translate_char( buff, fromChar, toChar );
+}
+
+
+/** TEMP CHAR STRINGS
+ **
+ ** implement a circular ring of temporary string buffers
+ **/
+
+typedef struct Temptring {
+ struct TempString* next;
+ char* buffer;
+ int size;
+} TempString;
+
+#define MAX_TEMP_STRINGS 16
+
+static TempString _temp_strings[ MAX_TEMP_STRINGS ];
+static int _temp_string_n;
+
+extern char*
+tempstr_get( int size )
+{
+ TempString* t = &_temp_strings[_temp_string_n];
+
+ if ( ++_temp_string_n >= MAX_TEMP_STRINGS )
+ _temp_string_n = 0;
+
+ size += 1; /* reserve 1 char for terminating zero */
+
+ if (t->size < size) {
+ t->buffer = realloc( t->buffer, size );
+ if (t->buffer == NULL) {
+ derror( "%s: could not allocate %d bytes",
+ __FUNCTION__, size );
+ exit(1);
+ }
+ t->size = size;
+ }
+ return t->buffer;
+}
+
+extern char*
+tempstr_format( const char* fmt, ... )
+{
+ va_list args;
+ char* result;
+ STRALLOC_DEFINE(s);
+ va_start(args, fmt);
+ stralloc_formatv(s, fmt, args);
+ va_end(args);
+ result = stralloc_to_tempstr(s);
+ stralloc_reset(s);
+ return result;
+}
+
+/** QUOTING
+ **
+ ** dumps a human-readable version of a string. this replaces
+ ** newlines with \n, etc...
+ **/
+
+extern const char*
+quote_bytes( const char* str, int len )
+{
+ STRALLOC_DEFINE(s);
+ char* q;
+
+ stralloc_add_quote_bytes( s, str, len );
+ q = stralloc_to_tempstr( s );
+ stralloc_reset(s);
+ return q;
+}
+
+extern const char*
+quote_str( const char* str )
+{
+ int len = strlen(str);
+ return quote_bytes( str, len );
+}
+
+/** HEXADECIMAL CHARACTER SEQUENCES
+ **/
+
+static int
+hexdigit( int c )
+{
+ unsigned d;
+
+ d = (unsigned)(c - '0');
+ if (d < 10) return d;
+
+ d = (unsigned)(c - 'a');
+ if (d < 6) return d+10;
+
+ d = (unsigned)(c - 'A');
+ if (d < 6) return d+10;
+
+ return -1;
+}
+
+int
+hex2int( const uint8_t* hex, int len )
+{
+ int result = 0;
+ while (len > 0) {
+ int c = hexdigit(*hex++);
+ if (c < 0)
+ return -1;
+
+ result = (result << 4) | c;
+ len --;
+ }
+ return result;
+}
+
+void
+int2hex( uint8_t* hex, int len, int val )
+{
+ static const uint8_t hexchars[16] = "0123456789abcdef";
+ while ( --len >= 0 )
+ *hex++ = hexchars[(val >> (len*4)) & 15];
+}
diff --git a/android/utils/misc.h b/android/utils/misc.h
new file mode 100644
index 0000000..0db1e28
--- /dev/null
+++ b/android/utils/misc.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_MISC_H
+#define _ANDROID_UTILS_MISC_H
+
+#include <stdint.h>
+
+/** TABULAR OUTPUT
+ **
+ ** prints a list of strings in row/column format
+ **
+ **/
+
+extern void print_tabular( const char** strings, int count,
+ const char* prefix, int width );
+
+/** CHARACTER TRANSLATION
+ **
+ ** converts one character into another in strings
+ **/
+
+extern void buffer_translate_char( char* buff,
+ unsigned buffLen,
+ const char* src,
+ char fromChar,
+ char toChar );
+
+extern void string_translate_char( char* str, char from, char to );
+
+/** TEMP CHAR STRINGS
+ **
+ ** implement a circular ring of temporary string buffers
+ **/
+
+extern char* tempstr_get( int size );
+extern char* tempstr_format( const char* fmt, ... );
+
+/** QUOTING
+ **
+ ** dumps a human-readable version of a string. this replaces
+ ** newlines with \n, etc...
+ **/
+
+extern const char* quote_bytes( const char* str, int len );
+extern const char* quote_str( const char* str );
+
+/** DECIMAL AND HEXADECIMAL CHARACTER SEQUENCES
+ **/
+
+/* decodes a sequence of 'len' hexadecimal chars from 'hex' into
+ * an integer. returns -1 in case of error (i.e. badly formed chars)
+ */
+extern int hex2int( const uint8_t* hex, int len );
+
+/* encodes an integer 'val' into 'len' hexadecimal charaters into 'hex' */
+extern void int2hex( uint8_t* hex, int len, int val );
+
+#endif /* _ANDROID_UTILS_MISC_H */
diff --git a/android/utils/path.c b/android/utils/path.c
new file mode 100644
index 0000000..b15b6de
--- /dev/null
+++ b/android/utils/path.c
@@ -0,0 +1,559 @@
+/* Copyright (C) 2007-2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/path.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef _WIN32
+#include <process.h>
+#include <shlobj.h>
+#include <tlhelp32.h>
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <limits.h>
+#include <winbase.h>
+#else
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+#endif
+
+#define D(...) ((void)0)
+
+#ifndef CHECKED
+# ifdef _WIN32
+# define CHECKED(ret, call) (ret) = (call)
+# else
+# define CHECKED(ret, call) do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
+# endif
+#endif
+
+/** PATH HANDLING ROUTINES
+ **
+ ** path_parent() can be used to return the n-level parent of a given directory
+ ** this understands . and .. when encountered in the input path
+ **/
+
+static __inline__ int
+ispathsep(int c)
+{
+#ifdef _WIN32
+ return (c == '/' || c == '\\');
+#else
+ return (c == '/');
+#endif
+}
+
+char*
+path_parent( const char* path, int levels )
+{
+ const char* end = path + strlen(path);
+ char* result;
+
+ while (levels > 0) {
+ const char* base;
+
+ /* trim any trailing path separator */
+ while (end > path && ispathsep(end[-1]))
+ end--;
+
+ base = end;
+ while (base > path && !ispathsep(base[-1]))
+ base--;
+
+ if (base <= path) /* we can't go that far */
+ return NULL;
+
+ if (end == base+1 && base[0] == '.')
+ goto Next;
+
+ if (end == base+2 && base[0] == '.' && base[1] == '.') {
+ levels += 1;
+ goto Next;
+ }
+
+ levels -= 1;
+
+ Next:
+ end = base - 1;
+ }
+ result = malloc( end-path+1 );
+ if (result != NULL) {
+ memcpy( result, path, end-path );
+ result[end-path] = 0;
+ }
+ return result;
+}
+
+static char*
+substring_dup( const char* start, const char* end )
+{
+ int len = end - start;
+ char* result = android_alloc(len+1);
+ memcpy(result, start, len);
+ result[len] = 0;
+ return result;
+}
+
+int
+path_split( const char* path, char* *pdirname, char* *pbasename )
+{
+ const char* end = path + strlen(path);
+ const char* last;
+ char* basename;
+
+ /* prepare for errors */
+ if (pdirname)
+ *pdirname = NULL;
+ if (pbasename)
+ *pbasename = NULL;
+
+ /* handle empty path case */
+ if (end == path) {
+ return -1;
+ }
+
+ /* strip trailing path separators */
+ while (end > path && ispathsep(end[-1]))
+ end -= 1;
+
+ /* handle "/" and degenerate cases like "////" */
+ if (end == path) {
+ return -1;
+ }
+
+ /* find last separator */
+ last = end;
+ while (last > path && !ispathsep(last[-1]))
+ last -= 1;
+
+ /* handle cases where there is no path separator */
+ if (last == path) {
+ if (pdirname)
+ *pdirname = ASTRDUP(".");
+ if (pbasename)
+ *pbasename = substring_dup(path,end);
+ return 0;
+ }
+
+ /* handle "/foo" */
+ if (last == path+1) {
+ if (pdirname)
+ *pdirname = ASTRDUP("/");
+ if (pbasename)
+ *pbasename = substring_dup(path+1,end);
+ return 0;
+ }
+
+ /* compute basename */
+ basename = substring_dup(last,end);
+ if (strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0) {
+ AFREE(basename);
+ return -1;
+ }
+
+ if (pbasename)
+ *pbasename = basename;
+ else {
+ AFREE(basename);
+ }
+
+ /* compute dirname */
+ if (pdirname != NULL)
+ *pdirname = substring_dup(path,last-1);
+
+ return 0;
+}
+
+char*
+path_basename( const char* path )
+{
+ char* basename;
+
+ if (path_split(path, NULL, &basename) < 0)
+ return NULL;
+
+ return basename;
+}
+
+char*
+path_dirname( const char* path )
+{
+ char* dirname;
+
+ if (path_split(path, &dirname, NULL) < 0)
+ return NULL;
+
+ return dirname;
+}
+
+
+
+
+
+/** MISC FILE AND DIRECTORY HANDLING
+ **/
+
+ABool
+path_exists( const char* path )
+{
+ int ret;
+ CHECKED(ret, access(path, F_OK));
+ return (ret == 0) || (errno != ENOENT);
+}
+
+/* checks that a path points to a regular file */
+ABool
+path_is_regular( const char* path )
+{
+ int ret;
+ struct stat st;
+
+ CHECKED(ret, stat(path, &st));
+ if (ret < 0)
+ return 0;
+
+ return S_ISREG(st.st_mode);
+}
+
+
+/* checks that a path points to a directory */
+ABool
+path_is_dir( const char* path )
+{
+ int ret;
+ struct stat st;
+
+ CHECKED(ret, stat(path, &st));
+ if (ret < 0)
+ return 0;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* checks that one can read/write a given (regular) file */
+ABool
+path_can_read( const char* path )
+{
+ int ret;
+ CHECKED(ret, access(path, R_OK));
+ return (ret == 0);
+}
+
+ABool
+path_can_write( const char* path )
+{
+ int ret;
+ CHECKED(ret, access(path, R_OK));
+ return (ret == 0);
+}
+
+/* try to make a directory. returns 0 on success, -1 on failure
+ * (error code in errno) */
+APosixStatus
+path_mkdir( const char* path, int mode )
+{
+#ifdef _WIN32
+ (void)mode;
+ return _mkdir(path);
+#else
+ int ret;
+ CHECKED(ret, mkdir(path, mode));
+ return ret;
+#endif
+}
+
+static APosixStatus
+path_mkdir_recursive( char* path, unsigned len, int mode )
+{
+ char old_c;
+ int ret;
+ unsigned len2;
+
+ /* get rid of trailing separators */
+ while (len > 0 && ispathsep(path[len-1]))
+ len -= 1;
+
+ if (len == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* check that the parent exists, 'len2' is the length of
+ * the parent part of the path */
+ len2 = len-1;
+ while (len2 > 0 && !ispathsep(path[len2-1]))
+ len2 -= 1;
+
+ if (len2 > 0) {
+ old_c = path[len2];
+ path[len2] = 0;
+ ret = 0;
+ if ( !path_exists(path) ) {
+ /* the parent doesn't exist, so try to create it */
+ ret = path_mkdir_recursive( path, len2, mode );
+ }
+ path[len2] = old_c;
+
+ if (ret < 0)
+ return ret;
+ }
+
+ /* at this point, we now the parent exists */
+ old_c = path[len];
+ path[len] = 0;
+ ret = path_mkdir( path, mode );
+ path[len] = old_c;
+
+ return ret;
+}
+
+/* ensure that a given directory exists, create it if not,
+ 0 on success, -1 on failure (error code in errno) */
+APosixStatus
+path_mkdir_if_needed( const char* path, int mode )
+{
+ int ret = 0;
+
+ if (!path_exists(path)) {
+ ret = path_mkdir(path, mode);
+
+ if (ret < 0 && errno == ENOENT) {
+ char temp[MAX_PATH];
+ unsigned len = (unsigned)strlen(path);
+
+ if (len > sizeof(temp)-1) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy( temp, path, len );
+ temp[len] = 0;
+
+ return path_mkdir_recursive(temp, len, mode);
+ }
+ }
+ return ret;
+}
+
+/* return the size of a given file in '*psize'. returns 0 on
+ * success, -1 on failure (error code in errno) */
+APosixStatus
+path_get_size( const char* path, uint64_t *psize )
+{
+#ifdef _WIN32
+ /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */
+ /* do not use OpenFile() because it has strange search behaviour that could */
+ /* result in getting the size of a different file */
+ LARGE_INTEGER size;
+ HANDLE file = CreateFile( /* lpFilename */ path,
+ /* dwDesiredAccess */ GENERIC_READ,
+ /* dwSharedMode */ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ /* lpSecurityAttributes */ NULL,
+ /* dwCreationDisposition */ OPEN_EXISTING,
+ /* dwFlagsAndAttributes */ 0,
+ /* hTemplateFile */ NULL );
+ if (file == INVALID_HANDLE_VALUE) {
+ /* ok, just to play fair */
+ errno = ENOENT;
+ return -1;
+ }
+ if (!GetFileSizeEx(file, &size)) {
+ /* maybe we tried to get the size of a pipe or something like that ? */
+ *psize = 0;
+ }
+ else {
+ *psize = (uint64_t) size.QuadPart;
+ }
+ CloseHandle(file);
+ return 0;
+#else
+ int ret;
+ struct stat st;
+
+ CHECKED(ret, stat(path, &st));
+ if (ret == 0) {
+ *psize = (uint64_t) st.st_size;
+ }
+ return ret;
+#endif
+}
+
+
+ABool
+path_is_absolute( const char* path )
+{
+#ifdef _WIN32
+ if (path == NULL)
+ return 0;
+
+ if (path[0] == '/' || path[0] == '\\')
+ return 1;
+
+ /* 'C:' is always considered to be absolute
+ * even if used with a relative path like C:foo which
+ * is different from C:\foo
+ */
+ if (path[0] != 0 && path[1] == ':')
+ return 1;
+
+ return 0;
+#else
+ return (path != NULL && path[0] == '/');
+#endif
+}
+
+
+/** OTHER FILE UTILITIES
+ **
+ ** path_empty_file() creates an empty file at a given path location.
+ ** if the file already exists, it is truncated without warning
+ **
+ ** path_copy_file() copies one file into another.
+ **
+ ** both functions return 0 on success, and -1 on error
+ **/
+
+APosixStatus
+path_empty_file( const char* path )
+{
+#ifdef _WIN32
+ int fd = _creat( path, S_IWRITE );
+#else
+ /* on Unix, only allow the owner to read/write, since the file *
+ * may contain some personal data we don't want to see exposed */
+ int fd = creat(path, S_IRUSR | S_IWUSR);
+#endif
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ return -1;
+}
+
+APosixStatus
+path_copy_file( const char* dest, const char* source )
+{
+ int fd, fs, result = -1;
+
+ /* if the destination doesn't exist, create it */
+ if ( access(source, F_OK) < 0 ||
+ path_empty_file(dest) < 0) {
+ return -1;
+ }
+
+#ifdef _WIN32
+ fd = _open(dest, _O_RDWR | _O_BINARY);
+ fs = _open(source, _O_RDONLY | _O_BINARY);
+#else
+ fd = creat(dest, S_IRUSR | S_IWUSR);
+ fs = open(source, S_IREAD);
+#endif
+ if (fs >= 0 && fd >= 0) {
+ char buf[4096];
+ ssize_t total = 0;
+ ssize_t n;
+ result = 0; /* success */
+ while ((n = read(fs, buf, 4096)) > 0) {
+ if (write(fd, buf, n) != n) {
+ /* write failed. Make it return -1 so that an
+ * empty file be created. */
+ D("Failed to copy '%s' to '%s': %s (%d)",
+ source, dest, strerror(errno), errno);
+ result = -1;
+ break;
+ }
+ total += n;
+ }
+ }
+
+ if (fs >= 0) {
+ close(fs);
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+ return result;
+}
+
+
+APosixStatus
+path_delete_file( const char* path )
+{
+#ifdef _WIN32
+ int ret = _unlink( path );
+ if (ret == -1 && errno == EACCES) {
+ /* a first call to _unlink will fail if the file is set read-only */
+ /* we can however try to change its mode first and call unlink */
+ /* again... */
+ ret = _chmod( path, _S_IREAD | _S_IWRITE );
+ if (ret == 0)
+ ret = _unlink( path );
+ }
+ return ret;
+#else
+ return unlink(path);
+#endif
+}
+
+
+void*
+path_load_file(const char *fn, size_t *pSize)
+{
+ char* data;
+ int sz;
+ int fd;
+
+ if (pSize)
+ *pSize = 0;
+
+ data = NULL;
+
+ fd = open(fn, O_BINARY | O_RDONLY);
+ if(fd < 0) return NULL;
+
+ do {
+ sz = lseek(fd, 0, SEEK_END);
+ if(sz < 0) break;
+
+ if (pSize)
+ *pSize = (size_t) sz;
+
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ break;
+
+ data = (char*) malloc(sz + 1);
+ if(data == NULL) break;
+
+ if (read(fd, data, sz) != sz)
+ break;
+
+ close(fd);
+ data[sz] = 0;
+
+ return data;
+ } while (0);
+
+ close(fd);
+
+ if(data != NULL)
+ free(data);
+
+ return NULL;
+}
+
diff --git a/android/utils/path.h b/android/utils/path.h
new file mode 100644
index 0000000..e822834
--- /dev/null
+++ b/android/utils/path.h
@@ -0,0 +1,152 @@
+/* Copyright (C) 2007-2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_PATH_H
+#define _ANDROID_UTILS_PATH_H
+
+#include <android/utils/system.h>
+#include <stdint.h> /* for uint64_t */
+
+/** MISC FILE AND DIRECTORY HANDLING
+ **/
+
+/* O_BINARY is required in the MS C library to avoid opening file
+ * in text mode (the default, ahhhhh)
+ */
+#if !defined(_WIN32) && !defined(O_BINARY)
+# define O_BINARY 0
+#endif
+
+/* define PATH_SEP as a string containing the directory separateor */
+#ifdef _WIN32
+# define PATH_SEP "\\"
+#else
+# define PATH_SEP "/"
+#endif
+
+/* get MAX_PATH, note that PATH_MAX is set to 260 on Windows for
+ * stupid backwards-compatibility reason, though any 32-bit version
+ * of the OS handles much much longer paths
+ */
+#ifdef _WIN32
+# undef MAX_PATH
+# define MAX_PATH 1024
+# undef PATH_MAX
+# define PATH_MAX MAX_PATH
+#else
+# include <limits.h>
+# define MAX_PATH PATH_MAX
+#endif
+
+/* checks that a given file exists */
+extern ABool path_exists( const char* path );
+
+/* checks that a path points to a regular file */
+extern ABool path_is_regular( const char* path );
+
+/* checks that a path points to a directory */
+extern ABool path_is_dir( const char* path );
+
+/* checks that a path is absolute or not */
+extern ABool path_is_absolute( const char* path );
+
+/* checks that one can read/write a given (regular) file */
+extern ABool path_can_read( const char* path );
+extern ABool path_can_write( const char* path );
+
+/* try to make a directory */
+extern APosixStatus path_mkdir( const char* path, int mode );
+
+/* ensure that a given directory exists, create it if not,
+ 0 on success, -1 on error */
+extern APosixStatus path_mkdir_if_needed( const char* path, int mode );
+
+/* return the size of a given file in '*psize'. returns 0 on
+ * success, -1 on failure (error code in errno) */
+extern APosixStatus path_get_size( const char* path, uint64_t *psize );
+
+/* path_parent() can be used to return the n-level parent of a given directory
+ * this understands . and .. when encountered in the input path.
+ *
+ * the returned string must be freed by the caller.
+ */
+extern char* path_parent( const char* path, int levels );
+
+/* split a path into a (dirname,basename) pair. the result strings must be freed
+ * by the caller. Return 0 on success, or -1 on error. Error conditions include
+ * the following:
+ * - 'path' is empty
+ * - 'path' is "/" or degenerate cases like "////"
+ * - basename is "." or ".."
+ *
+ * if there is no directory separator in path, *dirname will be set to "."
+ * if the path is of type "/foo", then *dirname will be set to "/"
+ *
+ * pdirname can be NULL if you don't want the directory name
+ * pbasename can be NULL if you don't want the base name
+ */
+extern int path_split( const char* path, char* *pdirname, char* *pbasename );
+
+/* a convenience function to retrieve the directory name as returned by
+ * path_split(). Returns NULL if path_split() returns an error.
+ * the result string must be freed by the caller
+ */
+extern char* path_dirname( const char* path );
+
+/* a convenience function to retrieve the base name as returned by
+ * path_split(). Returns NULL if path_split() returns an error.
+ * the result must be freed by the caller.
+ */
+extern char* path_basename( const char* path );
+
+/** OTHER FILE UTILITIES
+ **
+ ** path_empty_file() creates an empty file at a given path location.
+ ** if the file already exists, it is truncated without warning
+ **
+ ** path_copy_file() copies one file into another.
+ **
+ ** unlink_file() is equivalent to unlink() on Unix, on Windows,
+ ** it will handle the case where _unlink() fails because the file is
+ ** read-only by trying to change its access rights then calling _unlink()
+ ** again.
+ **
+ ** these functions return 0 on success, and -1 on error
+ **
+ ** load_text_file() reads a file into a heap-allocated memory block,
+ ** and appends a 0 to it. the caller must free it
+ **/
+
+/* creates an empty file at a given location. If the file already
+ * exists, it is truncated without warning. returns 0 on success,
+ * or -1 on failure.
+ */
+extern APosixStatus path_empty_file( const char* path );
+
+/* copies on file into another one. 0 on success, -1 on failure
+ * (error code in errno). Does not work on directories */
+extern APosixStatus path_copy_file( const char* dest, const char* source );
+
+/* unlink/delete a given file. Note that on Win32, this will
+ * fail if the program has an opened handle to the file
+ */
+extern APosixStatus path_delete_file( const char* path );
+
+/* try to load a given file into a heap-allocated block.
+ * if 'pSize' is not NULL, this will set the file's size in '*pSize'
+ * note that this actually zero-terminates the file for convenience.
+ * In case of failure, NULL is returned and the error code is in errno
+ */
+extern void* path_load_file( const char* path, size_t *pSize );
+
+/* */
+
+#endif /* _ANDROID_UTILS_PATH_H */
diff --git a/android/utils/reflist.c b/android/utils/reflist.c
new file mode 100644
index 0000000..bc604cd
--- /dev/null
+++ b/android/utils/reflist.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/reflist.h"
+#include <stdlib.h>
+#include <string.h>
+
+void
+areflist_setEmpty(ARefList* l)
+{
+ if (l->iteration > 0) {
+ /* deferred empty, set all items to NULL
+ * to stop iterations */
+ void** items = areflist_items(l);
+ memset(items, 0, l->count*sizeof(items[0]));
+ l->iteration |= 1;
+ } else {
+ /* direct empty */
+ if (l->max > 1) {
+ free(l->u.items);
+ l->max = 1;
+ }
+ }
+ l->count = 0;
+}
+
+int
+areflist_indexOf(ARefList* l, void* item)
+{
+ if (item) {
+ void** items = (l->max == 1) ? &l->u.item0 : l->u.items;
+ void** end = items + l->count;
+ void** ii = items;
+
+ for ( ; ii < end; ii += 1 )
+ if (*ii == item)
+ return (ii - items);
+ }
+ return -1;
+}
+
+static void
+areflist_grow(ARefList* l, int count)
+{
+ int newcount = l->count + count;
+ if (newcount > l->max) {
+ int oldmax = l->max == 1 ? 0 : l->max;
+ int newmax = oldmax;
+ void** olditems = l->max == 1 ? NULL : l->u.items;
+ void** newitems;
+
+ while (oldmax < newcount)
+ oldmax += (oldmax >> 1) + 4;
+
+ newitems = realloc(olditems, newmax*sizeof(newitems[0]));
+
+ l->u.items = newitems;
+ l->max = (uint16_t) newmax;
+ }
+}
+
+
+void
+areflist_add(ARefList* l, void* item)
+{
+ if (item) {
+ void** items;
+
+ if (l->count >= l->max) {
+ areflist_grow(l, 1);
+ }
+ items = areflist_items(l);
+ items[l->count] = item;
+ l->count += 1;
+ }
+}
+
+void*
+areflist_pop(ARefList* l)
+{
+ void* item = NULL;
+ void** items = areflist_items(l);
+
+ if (l->count > 0) {
+ if (l->iteration > 0) {
+ /* deferred deletion */
+ int nn;
+ for (nn = l->count-1; nn > 0; nn--) {
+ item = items[nn];
+ if (item != NULL) {
+ l->count -= 1;
+ return item;
+ }
+ }
+ } else {
+ /* normal pop */
+ item = items[--l->count];
+ if (l->count <= 0 && l->max > 1) {
+ free(l->u.items);
+ l->max = 1;
+ }
+ }
+ }
+ return item;
+}
+
+ABool
+areflist_del(ARefList* l, void* item)
+{
+ if (item) {
+ int index = areflist_indexOf(l, item);
+ if (index >= 0) {
+ void** items = areflist_items(l);
+
+ if (l->iteration > 0) {
+ /* deferred deletion */
+ items[index] = NULL;
+ l->iteration |= 1;
+ } else {
+ /* direct deletion */
+ if (l->max > 1) {
+ memmove(items + index, items + index + 1, l->count - index - 1);
+ if (--l->count == 0) {
+ free(l->u.items);
+ l->max = 1;
+ }
+ } else {
+ l->u.item0 = NULL;
+ l->count = 0;
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+_areflist_remove_deferred(ARefList* l)
+{
+ if (l->iteration & 1) {
+ /* remove all NULL elements from the array */
+ void** items = areflist_items(l);
+ int rr = 0;
+ int ww = 0;
+ for ( ; rr < l->count; rr++ ) {
+ if (items[rr] != NULL)
+ items[ww++] = items[rr];
+ }
+ l->count = (int16_t) ww;
+
+ /* if the list is empty, release its array */
+ if (l->count == 0 && l->max > 1) {
+ free(l->u.items);
+ l->max = 1;
+ }
+ }
+ l->iteration = 0;
+}
+
+void
+areflist_copy(ARefList* dst, ARefList* src)
+{
+ dst[0] = src[0];
+
+ if (src->max > 1) {
+ dst->u.items = malloc( dst->count*sizeof(void*) );
+ dst->max = dst->count;
+ }
+}
+
+void*
+areflist_get(ARefList* l, int n)
+{
+ if ((unsigned)n >= (unsigned)l->count)
+ return NULL;
+
+ if (l->max == 1)
+ return l->u.item0;
+
+ return l->u.items[n];
+}
+
+void**
+areflist_at(ARefList* l, int n)
+{
+ void** items;
+
+ if ((unsigned)n >= (unsigned)l->count)
+ return NULL;
+
+ items = (l->max == 1) ? &l->u.item0 : l->u.items;
+
+ return items + n;
+}
diff --git a/android/utils/reflist.h b/android/utils/reflist.h
new file mode 100644
index 0000000..dffaef8
--- /dev/null
+++ b/android/utils/reflist.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_REFLIST_H
+#define _ANDROID_UTILS_REFLIST_H
+
+#include "android/utils/system.h"
+
+/* definitions for a smart list of references to generic objects.
+ * supports safe deletion and addition while they are being iterated
+ * with AREFLIST_FOREACH() macro
+ */
+
+typedef struct ARefList {
+ uint16_t count, max;
+ uint16_t iteration;
+ union {
+ struct ARefList* next;
+ void* item0;
+ void** items;
+ } u;
+} ARefList;
+
+AINLINED void
+areflist_init(ARefList* l)
+{
+ l->count = 0;
+ l->max = 1;
+ l->iteration = 0;
+}
+
+void areflist_setEmpty(ARefList* l);
+
+AINLINED void
+areflist_done(ARefList* l)
+{
+ areflist_setEmpty(l);
+}
+
+AINLINED ABool
+areflist_isEmpty(ARefList* l)
+{
+ return (l->count == 0);
+}
+
+int areflist_indexOf(ARefList* l, void* item);
+
+AINLINED ABool
+areflist_has(ARefList* l, void* item)
+{
+ return areflist_indexOf(l, item) >= 0;
+}
+
+/* if 'item' is not NULL, append it to the list. An item
+ * can be added several times to a list */
+void areflist_add(ARefList* l, void* item);
+
+/* if 'item' is not NULL, try to remove it from the list */
+/* returns TRUE iff the item was found in the list */
+ABool areflist_del(ARefList* l, void* item);
+
+AINLINED void
+areflist_push(ARefList* l, void* item)
+{
+ areflist_add(l, item);
+}
+
+void* areflist_pop(ARefList* l);
+
+AINLINED void**
+areflist_items(ARefList* l)
+{
+ return (l->max == 1) ? &l->u.item0 : l->u.items;
+}
+
+AINLINED int
+areflist_count(ARefList* l)
+{
+ return l->count;
+}
+
+/* return a pointer to the n-th list array entry,
+ or NULL in case of invalid index */
+void** areflist_at(ARefList* l, int n);
+
+/* return the n-th array entry, or NULL in case of invalid index */
+void* areflist_get(ARefList* l, int n);
+
+/* used internally */
+void _areflist_remove_deferred(ARefList* l);
+
+#define AREFLIST_FOREACH(list_,item_,statement_) \
+ ({ ARefList* _reflist = (list_); \
+ int _reflist_i = 0; \
+ int _reflist_n = _reflist->count; \
+ _reflist->iteration += 2; \
+ for ( ; _reflist_i < _reflist_n; _reflist_i++ ) { \
+ void** __reflist_at = areflist_at(_reflist, _reflist_i); \
+ void* item_ = *__reflist_at; \
+ if (item_ != NULL) { \
+ statement_; \
+ } \
+ } \
+ _reflist->iteration -= 2; \
+ if (_reflist->iteration == 1) \
+ _areflist_remove_deferred(_reflist); \
+ })
+
+/* use this to delete the currently iterated element */
+#define AREFLIST_DEL_ITERATED() \
+ ({ *_reflist_at = NULL; \
+ _reflist->iteration |= 1; })
+
+/* use this to replace the currently iterated element */
+#define AREFLIST_SET_ITERATED(item) \
+ ({ *_reflist_at = (item); \
+ if (item == NULL) _reflist->iteration |= 1; })
+
+void areflist_copy(ARefList* dst, ARefList* src);
+
+#endif /* _ANDROID_UTILS_REFLIST_H */
diff --git a/android/utils/stralloc.c b/android/utils/stralloc.c
new file mode 100644
index 0000000..2a924e4
--- /dev/null
+++ b/android/utils/stralloc.c
@@ -0,0 +1,300 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "android/utils/stralloc.h"
+#include "android/utils/debug.h"
+#include "android/utils/misc.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+extern void
+stralloc_tabular( stralloc_t* out,
+ const char** strings, int count,
+ const char* prefix, int width )
+{
+ int nrows, ncols, r, c, n, maxw = 0;
+
+ for (n = 0; n < count; n++) {
+ int len = strlen(strings[n]);
+ if (len > maxw)
+ maxw = len;
+ }
+ maxw += 2;
+ ncols = width/maxw;
+ nrows = (count + ncols-1)/ncols;
+
+ for (r = 0; r < nrows; r++) {
+ stralloc_add_str( out, prefix );
+ for (c = 0; c < ncols; c++) {
+ int index = c*nrows + r;
+ if (index >= count) {
+ break;
+ }
+ stralloc_add_format( out, "%-*s", maxw, strings[index] );
+ }
+ stralloc_add_str( out, "\n" );
+ }
+}
+
+/** DYNAMIC STRINGS
+ **/
+
+extern void
+stralloc_reset( stralloc_t* s )
+{
+ free(s->s);
+ s->s = NULL;
+ s->n = 0;
+ s->a = 0;
+}
+
+extern void
+stralloc_ready( stralloc_t* s, unsigned int len )
+{
+ unsigned old_max = s->a;
+ unsigned new_max = old_max;
+
+ while (new_max < len) {
+ unsigned new_max2 = new_max + (new_max >> 1) + 16;
+ if (new_max2 < new_max)
+ new_max2 = UINT_MAX;
+ new_max = new_max2;
+ }
+
+ s->s = realloc( s->s, new_max );
+ if (s->s == NULL) {
+ derror( "%s: not enough memory to reallocate %ld bytes",
+ __FUNCTION__, new_max );
+ exit(1);
+ }
+ s->a = new_max;
+}
+
+extern void
+stralloc_readyplus( stralloc_t* s, unsigned int len )
+{
+ unsigned len2 = s->n + len;
+
+ if (len2 < s->n) { /* overflow ? */
+ derror("%s: trying to grow by too many bytes: %ld",
+ __FUNCTION__, len);
+ exit(1);
+ }
+ stralloc_ready( s, len2 );
+}
+
+extern void
+stralloc_copy( stralloc_t* s, stralloc_t* from )
+{
+ stralloc_ready(s, from->n);
+ memcpy( s->s, from->s, from->n );
+ s->n = from->n;
+}
+
+extern void
+stralloc_append( stralloc_t* s, stralloc_t* from )
+{
+ stralloc_readyplus( s, from->n );
+ memcpy( s->s + s->n, from->s, from->n );
+ s->n += from->n;
+}
+
+extern void
+stralloc_add_c( stralloc_t* s, int c )
+{
+ stralloc_add_bytes( s, (char*)&c, 1 );
+}
+
+extern void
+stralloc_add_str( stralloc_t* s, const char* str )
+{
+ stralloc_add_bytes( s, str, strlen(str) );
+}
+
+extern void
+stralloc_add_bytes( stralloc_t* s, const void* from, unsigned len )
+{
+ stralloc_readyplus( s, len );
+ memcpy( s->s + s->n, from, len );
+ s->n += len;
+}
+
+extern char*
+stralloc_cstr( stralloc_t* s )
+{
+ stralloc_readyplus( s, 1 );
+ s->s[s->n] = 0;
+ return s->s;
+}
+
+extern char*
+stralloc_to_tempstr( stralloc_t* s )
+{
+ char* q = tempstr_get( s->n );
+
+ memcpy( q, s->s, s->n );
+ q[s->n] = 0;
+ return q;
+}
+
+extern void
+stralloc_formatv( stralloc_t* s, const char* fmt, va_list args )
+{
+ stralloc_reset(s);
+ stralloc_ready(s,10);
+
+ while (1) {
+ int n;
+ va_list args2;
+
+ va_copy(args2, args);
+ n = vsnprintf( s->s, s->a, fmt, args2 );
+ va_end(args2);
+
+ /* funky old C libraries returns -1 when truncation occurs */
+ if (n > -1 && n < s->a) {
+ s->n = n;
+ break;
+ }
+ if (n > -1) { /* we now precisely what we need */
+ stralloc_ready( s, n+1 );
+ } else {
+ stralloc_ready( s, s->a*2 );
+ }
+ }
+}
+
+
+extern void
+stralloc_format( stralloc_t* s, const char* fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ stralloc_formatv(s, fmt, args);
+ va_end(args);
+}
+
+extern void
+stralloc_add_formatv( stralloc_t* s, const char* fmt, va_list args )
+{
+ STRALLOC_DEFINE(s2);
+ stralloc_formatv(s2, fmt, args);
+ stralloc_append( s, s2 );
+ stralloc_reset( s2 );
+}
+
+extern void
+stralloc_add_format( stralloc_t* s, const char* fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ stralloc_add_formatv( s, fmt, args );
+ va_end(args);
+}
+
+extern void
+stralloc_add_quote_c( stralloc_t* s, int c )
+{
+ stralloc_add_quote_bytes( s, (char*)&c, 1 );
+}
+
+extern void
+stralloc_add_quote_str( stralloc_t* s, const char* str )
+{
+ stralloc_add_quote_bytes( s, str, strlen(str) );
+}
+
+extern void
+stralloc_add_quote_bytes( stralloc_t* s, const void* from, unsigned len )
+{
+ uint8_t* p = (uint8_t*) from;
+ uint8_t* end = p + len;
+
+ for ( ; p < end; p++ ) {
+ int c = p[0];
+
+ if (c == '\\') {
+ stralloc_add_str( s, "\\\\" );
+ } else if (c >= ' ' && c < 128) {
+ stralloc_add_c( s, c );
+ } else if (c == '\n') {
+ stralloc_add_str( s, "\\n" );
+ } else if (c == '\t') {
+ stralloc_add_str( s, "\\t" );
+ } else if (c == '\r') {
+ stralloc_add_str( s, "\\r" );
+ } else {
+ stralloc_add_format( s, "\\x%02x", c );
+ }
+ }
+}
+
+extern void
+stralloc_add_hex( stralloc_t* s, unsigned value, int num_digits )
+{
+ const char hexdigits[16] = "0123456789abcdef";
+ int nn;
+
+ if (num_digits <= 0)
+ return;
+
+ stralloc_readyplus(s, num_digits);
+ for (nn = num_digits-1; nn >= 0; nn--) {
+ s->s[s->n+nn] = hexdigits[value & 15];
+ value >>= 4;
+ }
+ s->n += num_digits;
+}
+
+extern void
+stralloc_add_hexdump( stralloc_t* s, void* base, int size, const char* prefix )
+{
+ uint8_t* p = (uint8_t*)base;
+ const int max_count = 16;
+ int prefix_len = strlen(prefix);
+
+ while (size > 0) {
+ int count = size > max_count ? max_count : size;
+ int count2;
+ int n;
+
+ stralloc_add_bytes( s, prefix, prefix_len );
+ stralloc_add_hex( s, p[0], 2 );
+
+ for (n = 1; n < count; n++) {
+ stralloc_add_c( s, ' ' );
+ stralloc_add_hex( s, p[n], 2 );
+ }
+
+ count2 = 4 + 3*(max_count - count);
+ stralloc_readyplus( s, count2 );
+ memset( s->s + s->n, ' ', count2 );
+ s->n += count2;
+
+ stralloc_readyplus(s, count+1);
+ for (n = 0; n < count; n++) {
+ int c = p[n];
+
+ if (c < 32 || c > 127)
+ c = '.';
+
+ s->s[s->n++] = c;
+ }
+ s->s[s->n++] = '\n';
+
+ size -= count;
+ p += count;
+ }
+}
+
diff --git a/android/utils/stralloc.h b/android/utils/stralloc.h
new file mode 100644
index 0000000..4d17060
--- /dev/null
+++ b/android/utils/stralloc.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#ifndef _ANDROID_UTILS_STRALLOC_H
+#define _ANDROID_UTILS_STRALLOC_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+/** DYNAMIC STRINGS
+ **/
+
+typedef struct {
+ char* s;
+ unsigned n;
+ unsigned a;
+} stralloc_t;
+
+#define STRALLOC_INIT { NULL, 0, 0 }
+#define STRALLOC_DEFINE(s) stralloc_t s[1] = { STRALLOC_INIT }
+
+extern void stralloc_reset( stralloc_t* s );
+extern void stralloc_ready( stralloc_t* s, unsigned len );
+extern void stralloc_readyplus( stralloc_t* s, unsigned len );
+
+extern void stralloc_copy( stralloc_t* s, stralloc_t* from );
+extern void stralloc_append( stralloc_t* s, stralloc_t* from );
+
+extern void stralloc_add_c( stralloc_t* s, int c );
+extern void stralloc_add_str( stralloc_t* s, const char* str );
+extern void stralloc_add_bytes( stralloc_t* s, const void* from, unsigned len );
+
+extern char* stralloc_cstr( stralloc_t* s );
+
+extern void stralloc_format( stralloc_t* s, const char* fmt, ... );
+extern void stralloc_formatv( stralloc_t* s, const char* fmt, va_list args );
+extern void stralloc_add_format( stralloc_t* s, const char* fmt, ... );
+
+extern void stralloc_add_quote_c( stralloc_t* s, int c );
+extern void stralloc_add_quote_str( stralloc_t* s, const char* str );
+extern void stralloc_add_quote_bytes( stralloc_t* s, const void* from, unsigned len );
+
+extern void stralloc_add_hex( stralloc_t* s, unsigned value, int num_digits );
+extern void stralloc_add_hexdump( stralloc_t* s, void* base, int size, const char* prefix );
+
+extern void stralloc_tabular( stralloc_t* s, const char** strings, int count,
+ const char* prefix, int width );
+
+extern char* stralloc_to_tempstr( stralloc_t* s );
+
+#endif /* ANDROID_UTILS_STRALLOC_H */
diff --git a/android/utils/system.c b/android/utils/system.c
new file mode 100644
index 0000000..e09fd6b
--- /dev/null
+++ b/android/utils/system.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/system.h"
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h> /* for Sleep */
+#else
+# include <unistd.h> /* for usleep */
+#endif
+
+void*
+android_alloc( size_t size )
+{
+ void* block;
+
+ if (size == 0)
+ return NULL;
+
+ block = malloc(size);
+ if (block != NULL)
+ return block;
+
+ fprintf(stderr, "PANIC: not enough memory\n");
+ exit(1);
+ return NULL;
+}
+
+void*
+android_alloc0( size_t size )
+{
+ void* block;
+
+ if (size == 0)
+ return NULL;
+
+ block = calloc(1, size);
+ if (block != NULL)
+ return block;
+
+ fprintf(stderr, "PANIC: not enough memory\n");
+ exit(1);
+ return NULL;
+}
+
+void*
+android_realloc( void* block, size_t size )
+{
+ void* block2;
+
+ if (size == 0) {
+ free(block);
+ return NULL;
+ }
+ block2 = realloc(block, size);
+ if (block2 != NULL)
+ return block2;
+
+ fprintf(stderr, "PANIC: not enough memory to reallocate %d bytes\n", size);
+ exit(1);
+ return NULL;
+}
+
+void
+android_free( void* block )
+{
+ if (block)
+ free(block);
+}
+
+char*
+android_strdup( const char* str )
+{
+ int len;
+ char* copy;
+
+ if (str == NULL)
+ return NULL;
+
+ len = strlen(str);
+ copy = malloc(len+1);
+ memcpy(copy, str, len);
+ copy[len] = 0;
+
+ return copy;
+}
+
+#ifdef _WIN32
+char*
+win32_strsep(char** pline, const char* delim)
+{
+ char* line = *pline;
+ char* p = line;
+
+ if (p == NULL)
+ return NULL;
+
+ for (;;) {
+ int c = *p++;
+ const char* q = delim;
+
+ if (c == 0) {
+ p = NULL;
+ break;
+ }
+
+ while (*q) {
+ if (*q == c) {
+ p[-1] = 0;
+ goto Exit;
+ }
+ q++;
+ }
+ }
+Exit:
+ *pline = p;
+ return line;
+}
+#endif
+
+
+void
+disable_sigalrm( signal_state_t *state )
+{
+#ifdef _WIN32
+ (void)state;
+#else
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask (SIG_BLOCK, &set, &state->old);
+#endif
+}
+
+void
+restore_sigalrm( signal_state_t *state )
+{
+#ifdef _WIN32
+ (void)state;
+#else
+ pthread_sigmask (SIG_SETMASK, &state->old, NULL);
+#endif
+}
+
+void
+sleep_ms( int timeout_ms )
+{
+#ifdef _WIN32
+ if (timeout_ms <= 0)
+ return;
+
+ Sleep( timeout_ms );
+#else
+ if (timeout_ms <= 0)
+ return;
+
+ BEGIN_NOSIGALRM
+ usleep( timeout_ms*1000 );
+ END_NOSIGALRM
+#endif
+}
diff --git a/android/utils/system.h b/android/utils/system.h
new file mode 100644
index 0000000..804aa7d
--- /dev/null
+++ b/android/utils/system.h
@@ -0,0 +1,161 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_SYSTEM_H
+#define _ANDROID_UTILS_SYSTEM_H
+
+#include <string.h>
+#include <stdint.h>
+
+/* the following functions perform 'checked allocations', i.e.
+ * they abort if there is not enough memory.
+ */
+
+/* checked malloc, only returns NULL if size is 0 */
+void* android_alloc( size_t size );
+
+/* checked calloc, only returns NULL if size is 0 */
+void* android_alloc0( size_t size );
+
+/* checked realloc, only returns NULL if size if 0 */
+void* android_realloc( void* block, size_t size );
+
+/* free memory block */
+void android_free( void* block );
+
+/* convenience macros */
+
+#define AZERO(p) memset((char*)(p),0,sizeof(*(p)))
+#define ANEW(p) (p = android_alloc(sizeof(*p)))
+#define ANEW0(p) (p = android_alloc0(sizeof(*p)))
+#define AFREE(p) android_free(p)
+
+#define AMEM_ZERO(dst,size) memset((char*)(dst), 0, (size_t)(size))
+#define AMEM_COPY(dst,src,size) memcpy((char*)(dst),(const char*)(src),(size_t)(size))
+#define AMEM_MOVE(dst,src,size) memmove((char*)(dst),(const char*)(src),(size_t)(size))
+
+#define AARRAY_NEW(p,count) ((p) = android_alloc(sizeof(*p)*(count)))
+#define AARRAY_NEW0(p,count) ((p) = android_alloc0(sizeof(*p)*(count)))
+
+#define AARRAY_RENEW(p,count) ((p) = android_realloc((p),sizeof(*(p))*(count)))
+
+#define AARRAY_COPY(dst,src,count) AMEM_COPY(dst,src,(count)*sizeof((dst)[0]))
+#define AARRAY_MOVE(dst,src,count) AMEM_MOVE(dst,src,(count)*sizeof((dst)[0]))
+#define AARRAY_ZERO(dst,count) AMEM_ZERO(dst,(count)*sizeof((dst)[0]))
+
+#define AARRAY_STATIC_LEN(a) (sizeof((a))/sizeof((a)[0]))
+
+#define AINLINED static __inline__
+
+/* unlike strdup(), this accepts NULL as valid input (and will return NULL then) */
+char* android_strdup(const char* src);
+
+#define ASTRDUP(str) android_strdup(str)
+
+/* used for functions that return a Posix-style status code, i.e.
+ * 0 means success, -1 means failure with the error code in 'errno'
+ */
+typedef int APosixStatus;
+
+/* used for functions that return or accept a boolean type */
+typedef int ABool;
+
+/** Stringification macro
+ **/
+#ifndef STRINGIFY
+#define _STRINGIFY(x) #x
+#define STRINGIFY(x) _STRINGIFY(x)
+#endif
+
+/** Concatenation macros
+ **/
+#ifndef GLUE
+#define _GLUE(x,y) x##y
+#define GLUE(x,y) _GLUE(x,y)
+
+#define _GLUE3(x,y,z) x##y##z
+#define GLUE3(x,y,z) _GLUE3(x,y,z)
+#endif
+
+/** Handle strsep() on Win32
+ **/
+#ifdef _WIN32
+# undef strsep
+# define strsep win32_strsep
+extern char* win32_strsep(char** pline, const char* delim);
+#endif
+
+/** Handle strcasecmp on Windows
+ **/
+#ifdef _WIN32
+# define strcasecmp stricmp
+#endif
+
+/** EINTR HANDLING
+ **
+ ** since QEMU uses SIGALRM pretty extensively, having a system call returning
+ ** EINTR on Unix happens very frequently. provide a simple macro to guard against
+ ** this.
+ **/
+
+#ifdef _WIN32
+# define CHECKED(ret, call) (ret) = (call)
+#else
+# define CHECKED(ret, call) do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
+#endif
+
+/** SIGNAL HANDLING
+ **
+ ** the following can be used to block SIGALRM for a given period of time.
+ ** use with caution, the QEMU execution loop uses SIGALRM extensively
+ **
+ **/
+#ifdef _WIN32
+typedef struct { int dumy; } signal_state_t;
+#else
+#include <signal.h>
+typedef struct { sigset_t old; } signal_state_t;
+#endif
+
+extern void disable_sigalrm( signal_state_t *state );
+extern void restore_sigalrm( signal_state_t *state );
+
+#ifdef _WIN32
+
+#define BEGIN_NOSIGALRM \
+ {
+
+#define END_NOSIGALRM \
+ }
+
+#else /* !WIN32 */
+
+#define BEGIN_NOSIGALRM \
+ { signal_state_t __sigalrm_state; \
+ disable_sigalrm( &__sigalrm_state );
+
+#define END_NOSIGALRM \
+ restore_sigalrm( &__sigalrm_state ); \
+ }
+
+#endif /* !WIN32 */
+
+/** TIME HANDLING
+ **
+ ** sleep for a given time in milliseconds. note: this uses
+ ** disable_sigalrm()/restore_sigalrm()
+ **/
+
+extern void sleep_ms( int timeout );
+
+/* */
+
+#endif /* _ANDROID_UTILS_SYSTEM_H */
diff --git a/android/utils/tempfile.c b/android/utils/tempfile.c
new file mode 100644
index 0000000..6374c12
--- /dev/null
+++ b/android/utils/tempfile.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "android/utils/tempfile.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#define D(...) ((void)0)
+
+/** TEMP FILE SUPPORT
+ **
+ ** simple interface to create an empty temporary file on the system.
+ **
+ ** create the file with tempfile_create(), which returns a reference to a TempFile
+ ** object, or NULL if your system is so weird it doesn't have a temporary directory.
+ **
+ ** you can then call tempfile_path() to retrieve the TempFile's real path to open
+ ** it. the returned path is owned by the TempFile object and should not be freed.
+ **
+ ** all temporary files are destroyed when the program quits, unless you explicitely
+ ** close them before that with tempfile_close()
+ **/
+
+struct TempFile
+{
+ const char* name;
+ TempFile* next;
+};
+
+static void tempfile_atexit();
+static TempFile* _all_tempfiles;
+
+TempFile*
+tempfile_create( void )
+{
+ TempFile* tempfile;
+ const char* tempname = NULL;
+
+#ifdef _WIN32
+ char temp_namebuff[MAX_PATH];
+ char temp_dir[MAX_PATH];
+ char *p = temp_dir, *end = p + sizeof(temp_dir);
+ UINT retval;
+
+ p = bufprint_temp_dir( p, end );
+ if (p >= end) {
+ D( "TEMP directory path is too long" );
+ return NULL;
+ }
+
+ retval = GetTempFileName(temp_dir, "TMP", 0, temp_namebuff);
+ if (retval == 0) {
+ D( "can't create temporary file in '%s'", temp_dir );
+ return NULL;
+ }
+
+ tempname = temp_namebuff;
+#else
+#define TEMPLATE "/tmp/.android-emulator-XXXXXX"
+ int tempfd = -1;
+ char template[512];
+ char *p = template, *end = p + sizeof(template);
+
+ p = bufprint_temp_file( p, end, "emulator-XXXXXX" );
+ if (p >= end) {
+ D( "Xcannot create temporary file in /tmp/android !!" );
+ return NULL;
+ }
+
+ D( "template: %s", template );
+ tempfd = mkstemp( template );
+ if (tempfd < 0) {
+ D("cannot create temporary file in /tmp/android !!");
+ return NULL;
+ }
+ close(tempfd);
+ tempname = template;
+#endif
+ tempfile = malloc( sizeof(*tempfile) + strlen(tempname) + 1 );
+ tempfile->name = (char*)(tempfile + 1);
+ strcpy( (char*)tempfile->name, tempname );
+
+ tempfile->next = _all_tempfiles;
+ _all_tempfiles = tempfile;
+
+ if ( !tempfile->next ) {
+ atexit( tempfile_atexit );
+ }
+
+ return tempfile;
+}
+
+const char*
+tempfile_path(TempFile* temp)
+{
+ return temp ? temp->name : NULL;
+}
+
+void
+tempfile_close(TempFile* tempfile)
+{
+#ifdef _WIN32
+ DeleteFile(tempfile->name);
+#else
+ unlink(tempfile->name);
+#endif
+}
+
+/** TEMP FILE CLEANUP
+ **
+ **/
+
+/* we don't expect to use many temporary files */
+#define MAX_ATEXIT_FDS 16
+
+typedef struct {
+ int count;
+ int fds[ MAX_ATEXIT_FDS ];
+} AtExitFds;
+
+static void
+atexit_fds_add( AtExitFds* t, int fd )
+{
+ if (t->count < MAX_ATEXIT_FDS)
+ t->fds[t->count++] = fd;
+ else {
+ dwarning("%s: over %d calls. Program exit may not cleanup all temporary files",
+ __FUNCTION__, MAX_ATEXIT_FDS);
+ }
+}
+
+static void
+atexit_fds_del( AtExitFds* t, int fd )
+{
+ int nn;
+ for (nn = 0; nn < t->count; nn++)
+ if (t->fds[nn] == fd) {
+ /* move the last element to the current position */
+ t->count -= 1;
+ t->fds[nn] = t->fds[t->count];
+ break;
+ }
+}
+
+static void
+atexit_fds_close_all( AtExitFds* t )
+{
+ int nn;
+ for (nn = 0; nn < t->count; nn++)
+ close(t->fds[nn]);
+}
+
+static AtExitFds _atexit_fds[1];
+
+void
+atexit_close_fd(int fd)
+{
+ if (fd >= 0)
+ atexit_fds_add(_atexit_fds, fd);
+}
+
+void
+atexit_close_fd_remove(int fd)
+{
+ if (fd >= 0)
+ atexit_fds_del(_atexit_fds, fd);
+}
+
+static void
+tempfile_atexit( void )
+{
+ TempFile* tempfile;
+
+ atexit_fds_close_all( _atexit_fds );
+
+ for (tempfile = _all_tempfiles; tempfile; tempfile = tempfile->next)
+ tempfile_close(tempfile);
+}
diff --git a/android/utils/tempfile.h b/android/utils/tempfile.h
new file mode 100644
index 0000000..4264a84
--- /dev/null
+++ b/android/utils/tempfile.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#ifndef _ANDROID_UTILS_TEMPFILE_H
+#define _ANDROID_UTILS_TEMPFILE_H
+
+/** TEMP FILE SUPPORT
+ **
+ ** simple interface to create an empty temporary file on the system.
+ **
+ ** create the file with tempfile_create(), which returns a reference to a TempFile
+ ** object, or NULL if your system is so weird it doesn't have a temporary directory.
+ **
+ ** you can then call tempfile_path() to retrieve the TempFile's real path to open
+ ** it. the returned path is owned by the TempFile object and should not be freed.
+ **
+ ** all temporary files are destroyed when the program quits, unless you explicitely
+ ** close them before that with tempfile_close()
+ **/
+
+typedef struct TempFile TempFile;
+
+extern TempFile* tempfile_create( void );
+extern const char* tempfile_path( TempFile* temp );
+extern void tempfile_close( TempFile* temp );
+
+/** TEMP FILE CLEANUP
+ **
+ ** We delete all temporary files in atexit()-registered callbacks.
+ ** however, the Win32 DeleteFile is unable to remove a file unless
+ ** all HANDLEs to it are closed in the terminating process.
+ **
+ ** Call 'atexit_close_fd' on a newly open-ed file descriptor to indicate
+ ** that you want it closed in atexit() time. You should always call
+ ** this function unless you're certain that the corresponding file
+ ** cannot be temporary.
+ **
+ ** Call 'atexit_close_fd_remove' before explicitely closing a 'fd'
+ **/
+extern void atexit_close_fd(int fd);
+extern void atexit_close_fd_remove(int fd);
+
+#endif /* _ANDROID_UTILS_TEMPFILE_H */
diff --git a/android/utils/timezone.c b/android/utils/timezone.c
new file mode 100644
index 0000000..b5588a3
--- /dev/null
+++ b/android/utils/timezone.c
@@ -0,0 +1,721 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/debug.h"
+#include "android/utils/timezone.h"
+#include "android/utils/bufprint.h"
+#include "android/android.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "qemu-common.h"
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(timezone)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(...) do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0)
+#else
+# define D(...) ((void)0)
+#endif
+
+
+
+static const char* get_zoneinfo_timezone( void ); /* forward */
+
+static char android_timezone0[256];
+static const char* android_timezone;
+static int android_timezone_init;
+
+static int
+check_timezone_is_zoneinfo(const char* tz)
+{
+ const char* slash1 = NULL, *slash2 = NULL;
+
+ if (tz == NULL)
+ return 0;
+
+ /* the name must be of the form Area/Location or Area/Location/SubLocation */
+ slash1 = strchr( tz, '/' );
+ if (slash1 == NULL || slash1[1] == 0)
+ return 0;
+
+ slash2 = strchr( slash1+1, '/');
+ if (slash2 != NULL) {
+ if (slash2[1] == 0 || strchr(slash2+1, '/') != NULL)
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+timezone_set( const char* tzname )
+{
+ int len;
+
+ if ( !check_timezone_is_zoneinfo(tzname) )
+ return -1;
+
+ len = strlen(tzname);
+ if (len > sizeof(android_timezone0)-1)
+ return -1;
+
+ strcpy( android_timezone0, tzname );
+ android_timezone = android_timezone0;
+ android_timezone_init = 1;
+
+ return 0;
+}
+
+
+char*
+bufprint_zoneinfo_timezone( char* p, char* end )
+{
+ const char* tz = get_zoneinfo_timezone();
+
+ if (tz == NULL || !check_timezone_is_zoneinfo(tz))
+ return bufprint(p, end, "Unknown/Unknown");
+ else
+ return bufprint(p, end, "%s", tz);
+}
+
+/* on OS X, the timezone directory is always /usr/share/zoneinfo
+ * this makes things easy.
+ */
+#ifdef __APPLE__
+
+#include <unistd.h>
+#include <limits.h>
+#define LOCALTIME_FILE "/etc/localtime"
+#define ZONEINFO_DIR "/usr/share/zoneinfo/"
+static const char*
+get_zoneinfo_timezone( void )
+{
+ if (!android_timezone_init) {
+ const char* tz = getenv("TZ");
+ char buff[PATH_MAX+1];
+
+ android_timezone_init = 1;
+ if (tz == NULL) {
+ int len = readlink(LOCALTIME_FILE, buff, sizeof(buff));
+ if (len < 0) {
+ dprint( "### WARNING: Could not read %s, something is very wrong on your system",
+ LOCALTIME_FILE);
+ return NULL;
+ }
+
+ buff[len] = 0;
+ D("%s: %s points to %s\n", __FUNCTION__, LOCALTIME_FILE, buff);
+ if ( memcmp(buff, ZONEINFO_DIR, sizeof(ZONEINFO_DIR)-1) ) {
+ dprint( "### WARNING: %s does not point to %s, can't determine zoneinfo timezone name",
+ LOCALTIME_FILE, ZONEINFO_DIR );
+ return NULL;
+ }
+ tz = buff + sizeof(ZONEINFO_DIR)-1;
+ if ( !check_timezone_is_zoneinfo(tz) ) {
+ dprint( "### WARNING: %s does not point to zoneinfo-compatible timezone name\n", LOCALTIME_FILE );
+ return NULL;
+ }
+ }
+ pstrcpy( android_timezone0, sizeof(android_timezone0), tz );
+ android_timezone = android_timezone0;
+ }
+ D( "found timezone %s", android_timezone );
+ return android_timezone;
+}
+
+#endif /* __APPLE__ */
+
+/* on Linux, with glibc2, the zoneinfo directory can be changed with TZDIR environment variable
+ * but should be /usr/share/zoneinfo by default. /etc/localtime is not guaranteed to exist on
+ * all platforms, so if it doesn't, try $TZDIR/localtime, then /usr/share/zoneinfo/locatime
+ * ugly, isn't it ?
+ *
+ * besides, modern Linux distribution don't make /etc/localtime a symlink but a straight copy of
+ * the original timezone file. the only way to know which zoneinfo name to retrieve is to compare
+ * it with all files in $TZDIR (at least those that match Area/Location or Area/Location/SubLocation
+ */
+#ifdef __linux__
+
+#include <unistd.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#define ZONEINFO_DIR "/usr/share/zoneinfo/"
+#define LOCALTIME_FILE1 "/etc/localtime"
+
+typedef struct {
+ const char* localtime;
+ struct stat localtime_st;
+ char* path_end;
+ char* path_root;
+ char path[ PATH_MAX ];
+} ScanDataRec;
+
+static int
+compare_timezone_to_localtime( ScanDataRec* scan,
+ const char* path )
+{
+ struct stat st;
+ int fd1, fd2, result = 0;
+
+ D( "%s: comparing %s:", __FUNCTION__, path );
+
+ if ( stat( path, &st ) < 0 ) {
+ D( " can't stat: %s\n", strerror(errno) );
+ return 0;
+ }
+
+ if ( st.st_size != scan->localtime_st.st_size ) {
+ D( " size mistmatch (%lld != %lld)\n", st.st_size, scan->localtime_st.st_size );
+ return 0;
+ }
+
+ fd1 = open( scan->localtime, O_RDONLY );
+ if (fd1 < 0) {
+ D(" can't open %s: %s\n", scan->localtime, strerror(errno) );
+ return 0;
+ }
+ fd2 = open( path, O_RDONLY );
+ if (fd2 < 0) {
+ D(" can't open %s: %s\n", path, strerror(errno) );
+ close(fd1);
+ return 0;
+ }
+ do {
+ off_t nn;
+
+ for (nn = 0; nn < st.st_size; nn++) {
+ char temp[2];
+ int ret;
+
+ do { ret = read(fd1, &temp[0], 1); } while (ret < 0 && errno == EINTR);
+ if (ret < 0) break;
+
+ do { ret = read(fd2, &temp[1], 1); } while (ret < 0 && errno == EINTR);
+ if (ret < 0) break;
+
+ if (temp[0] != temp[1])
+ break;
+ }
+
+ result = (nn == st.st_size);
+
+ } while (0);
+
+ D( result ? " MATCH\n" : "no match\n" );
+
+ close(fd2);
+ close(fd1);
+
+ return result;
+}
+
+static const char*
+scan_timezone_dir( ScanDataRec* scan,
+ char* top,
+ int depth )
+{
+ DIR* d = opendir( scan->path );
+ const char* result = NULL;
+
+ D( "%s: entering '%s\n", __FUNCTION__, scan->path );
+ if (d != NULL) {
+ struct dirent* ent;
+ while ((ent = readdir(d)) != NULL) {
+ struct stat ent_st;
+ char* p = top;
+
+ if (ent->d_name[0] == '.') /* avoid hidden and special files */
+ continue;
+
+ p = bufprint( p, scan->path_end, "/%s", ent->d_name );
+ if (p >= scan->path_end)
+ continue;
+
+ //D( "%s: scanning '%s'\n", __FUNCTION__, scan->path );
+
+ if ( stat( scan->path, &ent_st ) < 0 )
+ continue;
+
+ if ( S_ISDIR(ent_st.st_mode) && depth < 2 )
+ {
+ //D( "%s: directory '%s'\n", __FUNCTION__, scan->path );
+ result = scan_timezone_dir( scan, p, depth + 1 );
+ if (result != NULL)
+ break;
+ }
+ else if ( S_ISREG(ent_st.st_mode) && (depth >= 1 && depth <= 2) )
+ {
+ char* name = scan->path_root + 1;
+
+ if ( check_timezone_is_zoneinfo( name ) )
+ {
+ if (compare_timezone_to_localtime( scan, scan->path ))
+ {
+ result = strdup( name );
+ D( "%s: found '%s'\n", __FUNCTION__, result );
+ break;
+ }
+ }
+ else
+ {
+ //D( "%s: ignoring '%s'\n", __FUNCTION__, scan->path );
+ }
+ }
+ }
+ closedir(d);
+ }
+ return result;
+}
+
+static const char*
+get_zoneinfo_timezone( void )
+{
+ if (!android_timezone_init)
+ {
+ const char* tz = getenv( "TZ" );
+
+ android_timezone_init = 1;
+
+ if ( tz != NULL && !check_timezone_is_zoneinfo(tz) ) {
+ D( "%s: ignoring non zoneinfo formatted TZ environment variable: '%s'\n",
+ __FUNCTION__, tz );
+ tz = NULL;
+ }
+
+ if (tz == NULL) {
+ char* tzdir = NULL;
+ int tzdirlen = 0;
+ char* localtime = NULL;
+ int len;
+ char temp[ PATH_MAX ];
+
+ /* determine the correct timezone directory */
+ {
+ const char* env = getenv("TZDIR");
+ const char* zoneinfo_dir = ZONEINFO_DIR;
+
+ if (env == NULL)
+ env = zoneinfo_dir;
+
+ if ( access( env, R_OK ) != 0 ) {
+ if ( env == zoneinfo_dir ) {
+ fprintf( stderr,
+ "### WARNING: could not find %s directory. unable to determine host timezone\n", env );
+ } else {
+ D( "%s: TZDIR does not point to valid directory, using %s instead\n",
+ __FUNCTION__, zoneinfo_dir );
+ env = zoneinfo_dir;
+ }
+ return NULL;
+ }
+ tzdir = strdup(env);
+ }
+
+ /* remove trailing slash, if any */
+ len = strlen(tzdir);
+ if (len > 0 && tzdir[len-1] == '/') {
+ tzdir[len-1] = 0;
+ len -= 1;
+ }
+ tzdirlen = len;
+ D( "%s: found timezone dir as %s\n", __FUNCTION__, tzdir );
+
+ /* try to find the localtime file */
+ localtime = LOCALTIME_FILE1;
+ if ( access( localtime, R_OK ) != 0 ) {
+ char *p = temp, *end = p + sizeof(temp);
+
+ p = bufprint( p, end, "%s/%s", tzdir, "localtime" );
+ if (p >= end || access( temp, R_OK ) != 0 ) {
+ fprintf( stderr, "### WARNING: could not find %s or %s. unable to determine host timezone\n",
+ LOCALTIME_FILE1, temp );
+ goto Exit;
+ }
+ localtime = temp;
+ }
+ localtime = strdup(localtime);
+ D( "%s: found localtime file as %s\n", __FUNCTION__, localtime );
+
+#if 1
+ /* if the localtime file is a link, make a quick check */
+ len = readlink( localtime, temp, sizeof(temp)-1 );
+ if (len >= 0 && len > tzdirlen + 2) {
+ temp[len] = 0;
+
+ /* verify that the link points to tzdir/<something> where <something> is a valid zoneinfo name */
+ if ( !memcmp( temp, tzdir, tzdirlen ) && temp[tzdirlen] == '/' ) {
+ if ( check_timezone_is_zoneinfo( temp + tzdirlen + 1 ) ) {
+ /* we have it ! */
+ tz = temp + tzdirlen + 1;
+ D( "%s: found zoneinfo timezone %s from %s symlink\n", __FUNCTION__, tz, localtime );
+ goto Exit;
+ }
+ D( "%s: %s link points to non-zoneinfo filename %s, comparing contents\n",
+ __FUNCTION__, localtime, temp );
+ }
+ }
+#endif
+
+ /* otherwise, parse all files under tzdir and see if we have something that looks like it */
+ {
+ ScanDataRec scan[1];
+
+ if ( stat( localtime, &scan->localtime_st ) < 0 ) {
+ fprintf( stderr, "### WARNING: can't access '%s', unable to determine host timezone\n",
+ localtime );
+ goto Exit;
+ }
+
+ scan->localtime = localtime;
+ scan->path_end = scan->path + sizeof(scan->path);
+ scan->path_root = bufprint( scan->path, scan->path_end, "%s", tzdir );
+
+ tz = scan_timezone_dir( scan, scan->path_root, 0 );
+ }
+
+ Exit:
+ if (tzdir)
+ free(tzdir);
+ if (localtime)
+ free(localtime);
+
+ if (tz == NULL)
+ return NULL;
+
+ pstrcpy( android_timezone0, sizeof(android_timezone0), tz );
+ android_timezone = android_timezone0;
+ }
+ D( "found timezone %s\n", android_timezone );
+ }
+ return android_timezone;
+}
+
+#endif /* __linux__ */
+
+
+/* on Windows, we need to translate the Windows timezone into a ZoneInfo one */
+#ifdef _WIN32
+#include <time.h>
+
+typedef struct {
+ const char* win_name;
+ const char* zoneinfo_name;
+} Win32Timezone;
+
+/* table generated from http://unicode.org/cldr/data/diff/supplemental/windows_tzid.html */
+static const Win32Timezone _win32_timezones[] = {
+ { "AUS Central Standard Time" , "Australia/Darwin" },
+ { "AUS Eastern Standard Time" , "Australia/Sydney" },
+ { "Acre Standard Time" , "America/Rio_Branco" },
+ { "Afghanistan Standard Time" , "Asia/Kabul" },
+ { "Africa_Central Standard Time" , "Africa/Kigali" },
+ { "Africa_Eastern Standard Time" , "Africa/Kampala" },
+ { "Africa_FarWestern Standard Time" , "Africa/El_Aaiun" },
+ { "Africa_Southern Standard Time" , "Africa/Johannesburg" },
+ { "Africa_Western Standard Time" , "Africa/Niamey" },
+ { "Aktyubinsk Standard Time" , "Asia/Aqtobe" },
+ { "Alaska Standard Time" , "America/Juneau" },
+ { "Alaska_Hawaii Standard Time" , "America/Anchorage" },
+ { "Alaskan Standard Time" , "America/Anchorage" },
+ { "Almaty Standard Time" , "Asia/Almaty" },
+ { "Amazon Standard Time" , "America/Manaus" },
+ { "America_Central Standard Time" , "America/Winnipeg" },
+ { "America_Eastern Standard Time" , "America/Panama" },
+ { "America_Mountain Standard Time" , "America/Edmonton" },
+ { "America_Pacific Standard Time" , "America/Vancouver" },
+ { "Anadyr Standard Time" , "Asia/Anadyr" },
+ { "Aqtau Standard Time" , "Asia/Aqtau" },
+ { "Aqtobe Standard Time" , "Asia/Aqtobe" },
+ { "Arab Standard Time" , "Asia/Riyadh" },
+ { "Arabian Standard Time" , "Asia/Bahrain" },
+ { "Arabic Standard Time" , "Asia/Baghdad" },
+ { "Argentina Standard Time" , "America/Buenos_Aires" },
+ { "Argentina_Western Standard Time" , "America/Mendoza" },
+ { "Armenia Standard Time" , "Asia/Yerevan" },
+ { "Ashkhabad Standard Time" , "Asia/Ashgabat" },
+ { "Atlantic Standard Time" , "America/Curacao" },
+ { "Australia_Central Standard Time" , "Australia/Adelaide" },
+ { "Australia_CentralWestern Standard Time", "Australia/Eucla" },
+ { "Australia_Eastern Standard Time" , "Australia/Sydney" },
+ { "Australia_Western Standard Time" , "Australia/Perth" },
+ { "Azerbaijan Standard Time" , "Asia/Baku" },
+ { "Azores Standard Time" , "Atlantic/Azores" },
+ { "Baku Standard Time" , "Asia/Baku" },
+ { "Bangladesh Standard Time" , "Asia/Dhaka" },
+ { "Bering Standard Time" , "America/Adak" },
+ { "Bhutan Standard Time" , "Asia/Thimphu" },
+ { "Bolivia Standard Time" , "America/La_Paz" },
+ { "Borneo Standard Time" , "Asia/Kuching" },
+ { "Brasilia Standard Time" , "America/Sao_Paulo" },
+ { "British Standard Time" , "Europe/London" },
+ { "Brunei Standard Time" , "Asia/Brunei" },
+ { "Canada Central Standard Time" , "America/Regina" },
+ { "Cape Verde Standard Time" , "Atlantic/Cape_Verde" },
+ { "Cape_Verde Standard Time" , "Atlantic/Cape_Verde" },
+ { "Caucasus Standard Time" , "Asia/Yerevan" },
+ { "Cen. Australia Standard Time" , "Australia/Adelaide" },
+ { "Central Standard Time" , "America/Chicago" },
+ { "Central America Standard Time" , "America/Guatemala" },
+ { "Central Asia Standard Time" , "Asia/Dhaka" },
+ { "Central Brazilian Standard Time" , "America/Manaus" },
+ { "Central Europe Standard Time" , "Europe/Prague" },
+ { "Central European Standard Time" , "Europe/Warsaw" },
+ { "Central Pacific Standard Time" , "Pacific/Guadalcanal" },
+ { "Central Standard Time (Mexico)" , "America/Mexico_City" },
+ { "Chamorro Standard Time" , "Pacific/Guam" },
+ { "Changbai Standard Time" , "Asia/Harbin" },
+ { "Chatham Standard Time" , "Pacific/Chatham" },
+ { "Chile Standard Time" , "America/Santiago" },
+ { "China Standard Time" , "Asia/Taipei" },
+ { "Choibalsan Standard Time" , "Asia/Choibalsan" },
+ { "Christmas Standard Time" , "Indian/Christmas" },
+ { "Cocos Standard Time" , "Indian/Cocos" },
+ { "Colombia Standard Time" , "America/Bogota" },
+ { "Cook Standard Time" , "Pacific/Rarotonga" },
+ { "Cuba Standard Time" , "America/Havana" },
+ { "Dacca Standard Time" , "Asia/Dhaka" },
+ { "Dateline Standard Time" , "Pacific/Kwajalein" },
+ { "Davis Standard Time" , "Antarctica/Davis" },
+ { "Dominican Standard Time" , "America/Santo_Domingo" },
+ { "DumontDUrville Standard Time" , "Antarctica/DumontDUrville" },
+ { "Dushanbe Standard Time" , "Asia/Dushanbe" },
+ { "Dutch_Guiana Standard Time" , "America/Paramaribo" },
+ { "E. Africa Standard Time" , "Africa/Nairobi" },
+ { "E. Australia Standard Time" , "Australia/Brisbane" },
+ { "E. Europe Standard Time" , "Europe/Minsk" },
+ { "E. South America Standard Time" , "America/Sao_Paulo" },
+ { "East_Timor Standard Time" , "Asia/Dili" },
+ { "Easter Standard Time" , "Pacific/Easter" },
+ { "Eastern Standard Time" , "America/New_York" },
+ { "Ecuador Standard Time" , "America/Guayaquil" },
+ { "Egypt Standard Time" , "Africa/Cairo" },
+ { "Ekaterinburg Standard Time" , "Asia/Yekaterinburg" },
+ { "Europe_Central Standard Time" , "Europe/Oslo" },
+ { "Europe_Eastern Standard Time" , "Europe/Vilnius" },
+ { "Europe_Western Standard Time" , "Atlantic/Canary" },
+ { "FLE Standard Time" , "Europe/Helsinki" },
+ { "Falkland Standard Time" , "Atlantic/Stanley" },
+ { "Fiji Standard Time" , "Pacific/Fiji" },
+ { "French_Guiana Standard Time" , "America/Cayenne" },
+ { "French_Southern Standard Time" , "Indian/Kerguelen" },
+ { "Frunze Standard Time" , "Asia/Bishkek" },
+ { "GMT Standard Time" , "Europe/Dublin" },
+ { "GTB Standard Time" , "Europe/Istanbul" },
+ { "Galapagos Standard Time" , "Pacific/Galapagos" },
+ { "Gambier Standard Time" , "Pacific/Gambier" },
+ { "Georgia Standard Time" , "Asia/Tbilisi" },
+ { "Georgian Standard Time" , "Asia/Tbilisi" },
+ { "Gilbert_Islands Standard Time" , "Pacific/Tarawa" },
+ { "Goose_Bay Standard Time" , "America/Goose_Bay" },
+ { "Greenland Standard Time" , "America/Godthab" },
+ { "Greenland_Central Standard Time" , "America/Scoresbysund" },
+ { "Greenland_Eastern Standard Time" , "America/Scoresbysund" },
+ { "Greenland_Western Standard Time" , "America/Godthab" },
+ { "Greenwich Standard Time" , "Africa/Casablanca" },
+ { "Guam Standard Time" , "Pacific/Guam" },
+ { "Gulf Standard Time" , "Asia/Muscat" },
+ { "Guyana Standard Time" , "America/Guyana" },
+ { "Hawaii_Aleutian Standard Time" , "Pacific/Honolulu" },
+ { "Hawaiian Standard Time" , "Pacific/Honolulu" },
+ { "Hong_Kong Standard Time" , "Asia/Hong_Kong" },
+ { "Hovd Standard Time" , "Asia/Hovd" },
+ { "India Standard Time" , "Asia/Calcutta" },
+ { "Indian_Ocean Standard Time" , "Indian/Chagos" },
+ { "Indochina Standard Time" , "Asia/Vientiane" },
+ { "Indonesia_Central Standard Time" , "Asia/Makassar" },
+ { "Indonesia_Eastern Standard Time" , "Asia/Jayapura" },
+ { "Indonesia_Western Standard Time" , "Asia/Jakarta" },
+ { "Iran Standard Time" , "Asia/Tehran" },
+ { "Irish Standard Time" , "Europe/Dublin" },
+ { "Irkutsk Standard Time" , "Asia/Irkutsk" },
+ { "Israel Standard Time" , "Asia/Jerusalem" },
+ { "Japan Standard Time" , "Asia/Tokyo" },
+ { "Jordan Standard Time" , "Asia/Amman" },
+ { "Kamchatka Standard Time" , "Asia/Kamchatka" },
+ { "Karachi Standard Time" , "Asia/Karachi" },
+ { "Kashgar Standard Time" , "Asia/Kashgar" },
+ { "Kazakhstan_Eastern Standard Time" , "Asia/Almaty" },
+ { "Kazakhstan_Western Standard Time" , "Asia/Aqtobe" },
+ { "Kizilorda Standard Time" , "Asia/Qyzylorda" },
+ { "Korea Standard Time" , "Asia/Seoul" },
+ { "Kosrae Standard Time" , "Pacific/Kosrae" },
+ { "Krasnoyarsk Standard Time" , "Asia/Krasnoyarsk" },
+ { "Kuybyshev Standard Time" , "Europe/Samara" },
+ { "Kwajalein Standard Time" , "Pacific/Kwajalein" },
+ { "Kyrgystan Standard Time" , "Asia/Bishkek" },
+ { "Lanka Standard Time" , "Asia/Colombo" },
+ { "Liberia Standard Time" , "Africa/Monrovia" },
+ { "Line_Islands Standard Time" , "Pacific/Kiritimati" },
+ { "Long_Shu Standard Time" , "Asia/Chongqing" },
+ { "Lord_Howe Standard Time" , "Australia/Lord_Howe" },
+ { "Macau Standard Time" , "Asia/Macau" },
+ { "Magadan Standard Time" , "Asia/Magadan" },
+ { "Malaya Standard Time" , "Asia/Kuala_Lumpur" },
+ { "Malaysia Standard Time" , "Asia/Kuching" },
+ { "Maldives Standard Time" , "Indian/Maldives" },
+ { "Marquesas Standard Time" , "Pacific/Marquesas" },
+ { "Marshall_Islands Standard Time" , "Pacific/Majuro" },
+ { "Mauritius Standard Time" , "Indian/Mauritius" },
+ { "Mawson Standard Time" , "Antarctica/Mawson" },
+ { "Mexico Standard Time" , "America/Mexico_City" },
+ { "Mexico Standard Time 2 Standard Time" , "America/Chihuahua" },
+ { "Mid-Atlantic Standard Time" , "America/Noronha" },
+ { "Middle East Standard Time" , "Asia/Beirut" },
+ { "Mongolia Standard Time" , "Asia/Ulaanbaatar" },
+ { "Montevideo Standard Time" , "America/Montevideo" },
+ { "Moscow Standard Time" , "Europe/Moscow" },
+ { "Mountain Standard Time" , "America/Denver" },
+ { "Mountain Standard Time (Mexico)" , "America/Chihuahua" },
+ { "Myanmar Standard Time" , "Asia/Rangoon" },
+ { "N. Central Asia Standard Time" , "Asia/Novosibirsk" },
+ { "Namibia Standard Time" , "Africa/Windhoek" },
+ { "Nauru Standard Time" , "Pacific/Nauru" },
+ { "Nepal Standard Time" , "Asia/Katmandu" },
+ { "New Zealand Standard Time" , "Pacific/Auckland" },
+ { "New_Caledonia Standard Time" , "Pacific/Noumea" },
+ { "New_Zealand Standard Time" , "Pacific/Auckland" },
+ { "Newfoundland Standard Time" , "America/St_Johns" },
+ { "Niue Standard Time" , "Pacific/Niue" },
+ { "Norfolk Standard Time" , "Pacific/Norfolk" },
+ { "Noronha Standard Time" , "America/Noronha" },
+ { "North Asia Standard Time" , "Asia/Krasnoyarsk" },
+ { "North Asia East Standard Time" , "Asia/Ulaanbaatar" },
+ { "North_Mariana Standard Time" , "Pacific/Saipan" },
+ { "Novosibirsk Standard Time" , "Asia/Novosibirsk" },
+ { "Omsk Standard Time" , "Asia/Omsk" },
+ { "Oral Standard Time" , "Asia/Oral" },
+ { "Pacific Standard Time" , "America/Los_Angeles" },
+ { "Pacific SA Standard Time" , "America/Santiago" },
+ { "Pacific Standard Time (Mexico)" , "America/Tijuana" },
+ { "Pakistan Standard Time" , "Asia/Karachi" },
+ { "Palau Standard Time" , "Pacific/Palau" },
+ { "Papua_New_Guinea Standard Time" , "Pacific/Port_Moresby" },
+ { "Paraguay Standard Time" , "America/Asuncion" },
+ { "Peru Standard Time" , "America/Lima" },
+ { "Philippines Standard Time" , "Asia/Manila" },
+ { "Phoenix_Islands Standard Time" , "Pacific/Enderbury" },
+ { "Pierre_Miquelon Standard Time" , "America/Miquelon" },
+ { "Pitcairn Standard Time" , "Pacific/Pitcairn" },
+ { "Ponape Standard Time" , "Pacific/Ponape" },
+ { "Qyzylorda Standard Time" , "Asia/Qyzylorda" },
+ { "Reunion Standard Time" , "Indian/Reunion" },
+ { "Romance Standard Time" , "Europe/Paris" },
+ { "Rothera Standard Time" , "Antarctica/Rothera" },
+ { "Russian Standard Time" , "Europe/Moscow" },
+ { "SA Eastern Standard Time" , "America/Buenos_Aires" },
+ { "SA Pacific Standard Time" , "America/Bogota" },
+ { "SA Western Standard Time" , "America/Caracas" },
+ { "SE Asia Standard Time" , "Asia/Bangkok" },
+ { "Sakhalin Standard Time" , "Asia/Sakhalin" },
+ { "Samara Standard Time" , "Europe/Samara" },
+ { "Samarkand Standard Time" , "Asia/Samarkand" },
+ { "Samoa Standard Time" , "Pacific/Apia" },
+ { "Seychelles Standard Time" , "Indian/Mahe" },
+ { "Shevchenko Standard Time" , "Asia/Aqtau" },
+ { "Singapore Standard Time" , "Asia/Singapore" },
+ { "Solomon Standard Time" , "Pacific/Guadalcanal" },
+ { "South Africa Standard Time" , "Africa/Johannesburg" },
+ { "South_Georgia Standard Time" , "Atlantic/South_Georgia" },
+ { "Sri Lanka Standard Time" , "Asia/Colombo" },
+ { "Suriname Standard Time" , "America/Paramaribo" },
+ { "Sverdlovsk Standard Time" , "Asia/Yekaterinburg" },
+ { "Syowa Standard Time" , "Antarctica/Syowa" },
+ { "Tahiti Standard Time" , "Pacific/Tahiti" },
+ { "Taipei Standard Time" , "Asia/Taipei" },
+ { "Tajikistan Standard Time" , "Asia/Dushanbe" },
+ { "Tashkent Standard Time" , "Asia/Tashkent" },
+ { "Tasmania Standard Time" , "Australia/Hobart" },
+ { "Tbilisi Standard Time" , "Asia/Tbilisi" },
+ { "Tokelau Standard Time" , "Pacific/Fakaofo" },
+ { "Tokyo Standard Time" , "Asia/Tokyo" },
+ { "Tonga Standard Time" , "Pacific/Tongatapu" },
+ { "Truk Standard Time" , "Pacific/Truk" },
+ { "Turkey Standard Time" , "Europe/Istanbul" },
+ { "Turkmenistan Standard Time" , "Asia/Ashgabat" },
+ { "Tuvalu Standard Time" , "Pacific/Funafuti" },
+ { "US Eastern Standard Time" , "America/Indianapolis" },
+ { "US Mountain Standard Time" , "America/Phoenix" },
+ { "Uralsk Standard Time" , "Asia/Oral" },
+ { "Uruguay Standard Time" , "America/Montevideo" },
+ { "Urumqi Standard Time" , "Asia/Urumqi" },
+ { "Uzbekistan Standard Time" , "Asia/Tashkent" },
+ { "Vanuatu Standard Time" , "Pacific/Efate" },
+ { "Venezuela Standard Time" , "America/Caracas" },
+ { "Vladivostok Standard Time" , "Asia/Vladivostok" },
+ { "Volgograd Standard Time" , "Europe/Volgograd" },
+ { "Vostok Standard Time" , "Antarctica/Vostok" },
+ { "W. Australia Standard Time" , "Australia/Perth" },
+ { "W. Central Africa Standard Time" , "Africa/Lagos" },
+ { "W. Europe Standard Time" , "Europe/Berlin" },
+ { "Wake Standard Time" , "Pacific/Wake" },
+ { "Wallis Standard Time" , "Pacific/Wallis" },
+ { "West Asia Standard Time" , "Asia/Karachi" },
+ { "West Pacific Standard Time" , "Pacific/Guam" },
+ { "Yakutsk Standard Time" , "Asia/Yakutsk" },
+ { "Yekaterinburg Standard Time" , "Asia/Yekaterinburg" },
+ { "Yerevan Standard Time" , "Asia/Yerevan" },
+ { "Yukon Standard Time" , "America/Yakutat" },
+ { NULL, NULL }
+};
+
+static const char*
+get_zoneinfo_timezone( void )
+{
+ if (!android_timezone_init)
+ {
+ char tzname[128];
+ time_t t = time(NULL);
+ struct tm* tm = localtime(&t);
+ const Win32Timezone* win32tz = _win32_timezones;
+
+ android_timezone_init = 1;
+
+ if (!tm) {
+ D("%s: could not determine current date/time\n", __FUNCTION__);
+ return NULL;
+ }
+
+ memset(tzname, 0, sizeof(tzname));
+ strftime(tzname, sizeof(tzname) - 1, "%Z", tm);
+
+ for (win32tz = _win32_timezones; win32tz->win_name != NULL; win32tz++)
+ if ( !strcmp(win32tz->win_name, tzname) ) {
+ android_timezone = win32tz->zoneinfo_name;
+ goto Exit;
+ }
+
+#if 0 /* TODO */
+ /* we didn't find it, this may come from localized versions of Windows. we're going to explore the registry,
+ * as the code in Postgresql does...
+ */
+#endif
+ D( "%s: could not determine current timezone\n", __FUNCTION__ );
+ return NULL;
+ }
+Exit:
+ D( "emulator: found timezone %s\n", android_timezone );
+ return android_timezone;
+}
+
+#endif /* _WIN32 */
+
diff --git a/android/utils/timezone.h b/android/utils/timezone.h
new file mode 100644
index 0000000..bf5f731
--- /dev/null
+++ b/android/utils/timezone.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_TIMEZONE_H
+#define _ANDROID_UTILS_TIMEZONE_H
+
+/* try to set the default host timezone, returns 0 on success, or -1 if
+ * 'tzname' is not in zoneinfo format (e.g. Area/Location)
+ */
+extern int timezone_set( const char* tzname );
+
+/* append the current host "zoneinfo" timezone name to a given buffer. note
+ * that this is something like "America/Los_Angeles", and not the human-friendly "PST"
+ * this is required by the Android emulated system...
+ *
+ * the implementation of this function is really tricky and is OS-dependent
+ * on Unix systems, it needs to cater to the TZ environment variable, uhhh
+ *
+ * if TZ is defined to something like "CET" or "PST", this will return the name "Unknown/Unknown"
+ */
+extern char* bufprint_zoneinfo_timezone( char* buffer, char* end );
+
+#endif /* _ANDROID_UTILS_TIMEZONE_H */