From bb6e704ab011a497ac8c735afc0fd4c52a1425ce Mon Sep 17 00:00:00 2001 From: Jakob Stendahl Date: Tue, 9 Jan 2018 15:01:04 +0100 Subject: Added old project --- love2dToAPK/tools/icon.png | Bin 0 -> 10129 bytes love2dToAPK/tools/startAnt.bat | 12 + love2dToAPK/tools/tools/adb/AdbWinApi.dll | Bin 0 -> 97792 bytes love2dToAPK/tools/tools/adb/AdbWinUsbApi.dll | Bin 0 -> 62976 bytes love2dToAPK/tools/tools/adb/NOTICE.txt | 6260 ++ love2dToAPK/tools/tools/adb/adb.exe | Bin 0 -> 1656320 bytes love2dToAPK/tools/tools/adb/api/annotations.zip | Bin 0 -> 140715 bytes love2dToAPK/tools/tools/adb/api/api-versions.xml | 75120 +++++++++++++++++++ love2dToAPK/tools/tools/adb/dmtracedump.exe | Bin 0 -> 145920 bytes love2dToAPK/tools/tools/adb/etc1tool.exe | Bin 0 -> 333824 bytes love2dToAPK/tools/tools/adb/fastboot.exe | Bin 0 -> 851456 bytes love2dToAPK/tools/tools/adb/hprof-conv.exe | Bin 0 -> 43008 bytes love2dToAPK/tools/tools/adb/lib64/libc++.so | Bin 0 -> 1272189 bytes love2dToAPK/tools/tools/adb/libwinpthread-1.dll | Bin 0 -> 210625 bytes love2dToAPK/tools/tools/adb/mke2fs.exe | Bin 0 -> 1034240 bytes love2dToAPK/tools/tools/adb/source.properties | 3 + love2dToAPK/tools/tools/adb/sqlite3.exe | Bin 0 -> 793600 bytes love2dToAPK/tools/tools/adb/systrace/NOTICE | 205 + .../tools/tools/adb/systrace/UPSTREAM_REVISION | 1 + .../catapult/common/battor/battor/__init__.py | 27 + .../battor/battor/battor_binary_dependencies.json | 114 + .../catapult/common/battor/battor/battor_error.py | 8 + .../common/battor/battor/battor_wrapper.py | 420 + .../battor/battor/battor_wrapper_devicetest.py | 106 + .../battor/battor/battor_wrapper_unittest.py | 365 + .../adb/systrace/catapult/common/eslint/LICENSE | 20 + .../adb/systrace/catapult/common/eslint/README.md | 5 + .../catapult/common/eslint/eslint/__init__.py | 68 + .../catapult/common/eslint/eslint/smoke_test.py | 36 + .../common/eslint/rules/catapult-camelcase.js | 154 + .../common/eslint/tests/catapult-camelcase.js | 324 + .../adb/systrace/catapult/common/lab/commits.py | 101 + .../adb/systrace/catapult/common/lab/hardware.py | 93 + .../catapult/common/lab/keychain_unlock.sh | 15 + .../common/node_runner/node_runner/__init__.py | 4 + .../node_runner/node_runner/node_binaries.json | 53 + .../common/node_runner/node_runner/node_util.py | 60 + .../common/node_runner/node_runner/package.json | 22 + .../catapult/common/py_trace_event/README.txt | 7 + .../py_trace_event/py_trace_event/__init__.py | 9 + .../common/py_trace_event/py_trace_event/run_tests | 163 + .../common/py_trace_event/py_trace_event/setup.py | 12 + .../py_trace_event/py_trace_event/trace_event.py | 266 + .../py_trace_event/trace_event_impl/__init__.py | 7 + .../py_trace_event/trace_event_impl/decorators.py | 87 + .../trace_event_impl/decorators_test.py | 62 + .../py_trace_event/trace_event_impl/log.py | 179 + .../py_trace_event/trace_event_impl/log_io_test.py | 50 + .../py_trace_event/trace_event_impl/meta_class.py | 16 + .../trace_event_impl/multiprocessing_shim.py | 92 + .../trace_event_impl/parsed_trace_events.py | 98 + .../py_trace_event/trace_event_impl/trace_test.py | 48 + .../py_trace_event/trace_event_unittest.py | 423 + .../py_trace_event/py_trace_event/trace_time.py | 234 + .../py_trace_event/trace_time_unittest.py | 123 + .../systrace/catapult/common/py_utils/PRESUBMIT.py | 31 + .../catapult/common/py_utils/py_utils/__init__.py | 140 + .../common/py_utils/py_utils/binary_manager.py | 61 + .../py_utils/py_utils/binary_manager_unittest.py | 214 + .../common/py_utils/py_utils/chrome_binaries.json | 86 + .../common/py_utils/py_utils/cloud_storage.py | 461 + .../py_utils/py_utils/cloud_storage_global_lock.py | 5 + .../py_utils/py_utils/cloud_storage_unittest.py | 284 + .../common/py_utils/py_utils/contextlib_ext.py | 33 + .../py_utils/py_utils/contextlib_ext_unittest.py | 34 + .../common/py_utils/py_utils/dependency_util.py | 49 + .../catapult/common/py_utils/py_utils/lock.py | 117 + .../common/py_utils/py_utils/lock_unittest.py | 165 + .../common/py_utils/py_utils/py_utils_unittest.py | 55 + .../common/py_utils/py_utils/refactor/__init__.py | 28 + .../py_utils/refactor/annotated_symbol/__init__.py | 71 + .../refactor/annotated_symbol/base_symbol.py | 36 + .../refactor/annotated_symbol/class_definition.py | 51 + .../annotated_symbol/function_definition.py | 51 + .../refactor/annotated_symbol/import_statement.py | 322 + .../refactor/annotated_symbol/reference.py | 75 + .../common/py_utils/py_utils/refactor/module.py | 39 + .../py_utils/py_utils/refactor/offset_token.py | 115 + .../common/py_utils/py_utils/refactor/snippet.py | 244 + .../py_utils/py_utils/refactor_util/__init__.py | 0 .../common/py_utils/py_utils/refactor_util/move.py | 116 + .../common/py_utils/py_utils/shell_util.py | 40 + .../common/py_utils/py_utils/tempfile_ext.py | 25 + .../py_utils/py_utils/tempfile_ext_unittest.py | 39 + .../common/py_utils/py_utils/test_data/foo.txt | 1 + .../catapult/common/py_utils/py_utils/xvfb.py | 29 + .../catapult/dependency_manager/PRESUBMIT.py | 32 + .../dependency_manager/__init__.py | 43 + .../dependency_manager/archive_info.py | 80 + .../dependency_manager/base_config.py | 388 + .../dependency_manager/base_config_unittest.py | 1525 + .../dependency_manager/cloud_storage_info.py | 110 + .../cloud_storage_info_unittest.py | 233 + .../dependency_manager/dependency_info.py | 128 + .../dependency_manager/dependency_info_unittest.py | 234 + .../dependency_manager_unittest.py | 527 + .../dependency_manager/dependency_manager_util.py | 103 + .../dependency_manager_util_unittest.py | 193 + .../dependency_manager/exceptions.py | 52 + .../dependency_manager/local_path_info.py | 40 + .../dependency_manager/manager.py | 247 + .../dependency_manager/uploader.py | 108 + .../dependency_manager/uploader_unittest.py | 91 + .../systrace/catapult/dependency_manager/pylintrc | 68 + .../tools/adb/systrace/catapult/devil/PRESUBMIT.py | 81 + .../tools/adb/systrace/catapult/devil/README.md | 37 + .../adb/systrace/catapult/devil/devil/__init__.py | 7 + .../catapult/devil/devil/android/__init__.py | 3 + .../catapult/devil/devil/android/apk_helper.py | 164 + .../devil/devil/android/apk_helper_test.py | 169 + .../catapult/devil/devil/android/app_ui.py | 243 + .../catapult/devil/devil/android/app_ui_test.py | 191 + .../catapult/devil/devil/android/battery_utils.py | 711 + .../devil/devil/android/battery_utils_test.py | 694 + .../devil/devil/android/constants/__init__.py | 3 + .../devil/devil/android/constants/chrome.py | 57 + .../devil/devil/android/constants/file_system.py | 5 + .../catapult/devil/devil/android/decorators.py | 176 + .../devil/devil/android/decorators_test.py | 332 + .../devil/devil/android/device_blacklist.py | 80 + .../devil/devil/android/device_blacklist_test.py | 38 + .../catapult/devil/devil/android/device_errors.py | 196 + .../devil/devil/android/device_errors_test.py | 72 + .../catapult/devil/devil/android/device_list.py | 52 + .../catapult/devil/devil/android/device_signal.py | 41 + .../devil/devil/android/device_temp_file.py | 63 + .../devil/devil/android/device_test_case.py | 54 + .../catapult/devil/devil/android/device_utils.py | 2654 + .../devil/devil/android/device_utils_devicetest.py | 238 + .../devil/devil/android/device_utils_test.py | 2908 + .../catapult/devil/devil/android/fastboot_utils.py | 256 + .../devil/devil/android/fastboot_utils_test.py | 375 + .../catapult/devil/devil/android/flag_changer.py | 300 + .../devil/devil/android/flag_changer_devicetest.py | 88 + .../devil/devil/android/flag_changer_test.py | 135 + .../catapult/devil/devil/android/forwarder.py | 467 + .../devil/devil/android/install_commands.py | 57 + .../catapult/devil/devil/android/logcat_monitor.py | 255 + .../devil/devil/android/logcat_monitor_test.py | 230 + .../catapult/devil/devil/android/md5sum.py | 120 + .../catapult/devil/devil/android/md5sum_test.py | 237 + .../catapult/devil/devil/android/perf/__init__.py | 3 + .../devil/devil/android/perf/cache_control.py | 15 + .../devil/devil/android/perf/perf_control.py | 210 + .../devil/android/perf/perf_control_devicetest.py | 38 + .../devil/android/perf/surface_stats_collector.py | 186 + .../devil/devil/android/perf/thermal_throttle.py | 135 + .../systrace/catapult/devil/devil/android/ports.py | 178 + .../catapult/devil/devil/android/sdk/__init__.py | 6 + .../catapult/devil/devil/android/sdk/aapt.py | 43 + .../android/sdk/adb_compatibility_devicetest.py | 230 + .../devil/devil/android/sdk/adb_wrapper.py | 923 + .../devil/android/sdk/adb_wrapper_devicetest.py | 122 + .../devil/devil/android/sdk/adb_wrapper_test.py | 59 + .../devil/devil/android/sdk/build_tools.py | 51 + .../catapult/devil/devil/android/sdk/dexdump.py | 31 + .../catapult/devil/devil/android/sdk/fastboot.py | 98 + .../devil/devil/android/sdk/gce_adb_wrapper.py | 154 + .../catapult/devil/devil/android/sdk/intent.py | 129 + .../catapult/devil/devil/android/sdk/keyevent.py | 63 + .../devil/devil/android/sdk/shared_prefs.py | 420 + .../devil/devil/android/sdk/shared_prefs_test.py | 171 + .../devil/devil/android/sdk/split_select.py | 63 + .../push_directory/push_directory_contents.txt | 1 + .../devil/android/sdk/test/data/push_file.txt | 1 + .../devil/devil/android/sdk/version_codes.py | 20 + .../catapult/devil/devil/android/settings.py | 283 + .../catapult/devil/devil/android/tools/__init__.py | 3 + .../devil/devil/android/tools/adb_run_shell_cmd.py | 61 + .../catapult/devil/devil/android/tools/cpufreq.py | 87 + .../devil/devil/android/tools/device_monitor.py | 232 + .../devil/android/tools/device_monitor_test.py | 168 + .../devil/devil/android/tools/device_recovery.py | 211 + .../devil/devil/android/tools/device_status.py | 316 + .../devil/devil/android/tools/flash_device.py | 70 + .../catapult/devil/devil/android/tools/keyboard.py | 129 + .../devil/devil/android/tools/provision_devices.py | 663 + .../devil/devil/android/tools/screenshot.py | 59 + .../devil/devil/android/tools/script_common.py | 29 + .../devil/android/tools/script_common_test.py | 58 + .../devil/devil/android/tools/video_recorder.py | 175 + .../devil/devil/android/tools/wait_for_devices.py | 50 + .../devil/devil/android/valgrind_tools/__init__.py | 21 + .../devil/android/valgrind_tools/base_tool.py | 53 + .../systrace/catapult/devil/devil/base_error.py | 24 + .../catapult/devil/devil/constants/__init__.py | 3 + .../catapult/devil/devil/constants/exit_codes.py | 9 + .../catapult/devil/devil/devil_dependencies.json | 127 + .../adb/systrace/catapult/devil/devil/devil_env.py | 194 + .../catapult/devil/devil/devil_env_test.py | 63 + .../catapult/devil/devil/utils/__init__.py | 23 + .../devil/devil/utils/battor_device_mapping.py | 309 + .../catapult/devil/devil/utils/cmd_helper.py | 451 + .../catapult/devil/devil/utils/cmd_helper_test.py | 264 + .../catapult/devil/devil/utils/file_utils.py | 31 + .../catapult/devil/devil/utils/find_usb_devices.py | 538 + .../devil/devil/utils/find_usb_devices_test.py | 379 + .../catapult/devil/devil/utils/geometry.py | 75 + .../catapult/devil/devil/utils/geometry_test.py | 61 + .../catapult/devil/devil/utils/host_utils.py | 16 + .../catapult/devil/devil/utils/lazy/__init__.py | 5 + .../devil/devil/utils/lazy/weak_constant.py | 29 + .../systrace/catapult/devil/devil/utils/lsusb.py | 174 + .../catapult/devil/devil/utils/lsusb_test.py | 250 + .../catapult/devil/devil/utils/markdown.py | 320 + .../catapult/devil/devil/utils/markdown_test.py | 121 + .../catapult/devil/devil/utils/mock_calls.py | 180 + .../catapult/devil/devil/utils/mock_calls_test.py | 173 + .../catapult/devil/devil/utils/parallelizer.py | 238 + .../devil/devil/utils/parallelizer_test.py | 162 + .../catapult/devil/devil/utils/reraiser_thread.py | 228 + .../devil/devil/utils/reraiser_thread_unittest.py | 117 + .../catapult/devil/devil/utils/reset_usb.py | 111 + .../catapult/devil/devil/utils/run_tests_helper.py | 44 + .../catapult/devil/devil/utils/signal_handler.py | 48 + .../devil/utils/test/data/test_serial_map.json | 1 + .../catapult/devil/devil/utils/timeout_retry.py | 175 + .../devil/devil/utils/timeout_retry_unittest.py | 79 + .../catapult/devil/devil/utils/update_mapping.py | 47 + .../catapult/devil/devil/utils/usb_hubs.py | 184 + .../catapult/devil/devil/utils/watchdog_timer.py | 47 + .../catapult/devil/devil/utils/zip_utils.py | 33 + .../systrace/catapult/devil/docs/adb_wrapper.md | 388 + .../catapult/devil/docs/device_blacklist.md | 59 + .../systrace/catapult/devil/docs/device_utils.md | 1041 + .../adb/systrace/catapult/devil/docs/markdown.md | 139 + .../catapult/devil/docs/persistent_device_list.md | 41 + .../tools/adb/systrace/catapult/devil/pylintrc | 68 + .../adb/systrace/catapult/systrace/PRESUBMIT.py | 36 + .../tools/adb/systrace/catapult/systrace/README.md | 10 + .../catapult/systrace/atrace_helper/README.md | 29 + .../systrace/atrace_helper/jni/Application.mk | 7 + .../systrace/atrace_helper/jni/file_utils.cc | 96 + .../systrace/atrace_helper/jni/file_utils.h | 53 + .../catapult/systrace/atrace_helper/jni/logging.h | 28 + .../catapult/systrace/atrace_helper/jni/main.cc | 198 + .../systrace/atrace_helper/jni/process_info.cc | 102 + .../systrace/atrace_helper/jni/process_info.h | 71 + .../atrace_helper/jni/process_memory_stats.cc | 132 + .../atrace_helper/jni/process_memory_stats.h | 68 + .../catapult/systrace/profile_chrome/__init__.py | 13 + .../profile_chrome/chrome_startup_tracing_agent.py | 123 + .../chrome_startup_tracing_agent_unittest.py | 28 + .../profile_chrome/chrome_tracing_agent.py | 214 + .../chrome_tracing_agent_unittest.py | 51 + .../systrace/profile_chrome/ddms_tracing_agent.py | 97 + .../profile_chrome/ddms_tracing_agent_unittest.py | 24 + .../systrace/profile_chrome/fake_agent_1.py | 69 + .../systrace/profile_chrome/fake_agent_2.py | 68 + .../catapult/systrace/profile_chrome/flags.py | 16 + .../catapult/systrace/profile_chrome/main.py | 160 + .../systrace/profile_chrome/perf_tracing_agent.py | 253 + .../profile_chrome/perf_tracing_agent_unittest.py | 39 + .../catapult/systrace/profile_chrome/profiler.py | 108 + .../systrace/profile_chrome/profiler_unittest.py | 58 + .../catapult/systrace/profile_chrome/run_tests | 3 + .../systrace/profile_chrome/third_party/COPYING | 339 + .../profile_chrome/third_party/README.chromium | 15 + .../profile_chrome/third_party/perf_to_tracing.py | 248 + .../catapult/systrace/profile_chrome/ui.py | 27 + .../catapult/systrace/profile_chrome/util.py | 35 + .../tools/adb/systrace/catapult/systrace/pylintrc | 67 + .../systrace/catapult/systrace/systrace/AUTHORS | 12 + .../systrace/catapult/systrace/systrace/LICENSE | 27 + .../systrace/catapult/systrace/systrace/README.md | 16 + .../catapult/systrace/systrace/__init__.py | 28 + .../catapult/systrace/systrace/decorators.py | 41 + .../catapult/systrace/systrace/monitor_unittest.py | 52 + .../catapult/systrace/systrace/output_generator.py | 189 + .../systrace/systrace/output_generator_unittest.py | 123 + .../catapult/systrace/systrace/prefix.html | 70 + .../catapult/systrace/systrace/run_systrace.py | 199 + .../catapult/systrace/systrace/suffix.html | 2 + .../catapult/systrace/systrace/systrace_runner.py | 70 + .../systrace/systrace/systrace_trace_viewer.html | 9630 +++ .../systrace/systrace/test_data/atrace_data | 127 + .../systrace/systrace/test_data/atrace_data_raw | 128 + .../systrace/test_data/atrace_data_stripped | 127 + .../systrace/test_data/atrace_extracted_tgids | 1 + .../systrace/test_data/atrace_extracted_threads | 1 + .../systrace/systrace/test_data/atrace_fixed_tgids | 127 + .../systrace/test_data/atrace_missing_tgids | 127 + .../systrace/systrace/test_data/atrace_procfs_dump | 1156 + .../systrace/test_data/battor_test_data.txt | 16 + .../systrace/test_data/compressed_atrace_data.txt | 5 + .../test_data/decompressed_atrace_data.txt | 1053 + .../profile-chrome_systrace_perf_chrome_data | 1 + .../catapult/systrace/systrace/trace_result.py | 17 + .../systrace/systrace/tracing_agents/__init__.py | 91 + .../systrace/tracing_agents/agents_unittest.py | 50 + .../tracing_agents/android_process_data_agent.py | 89 + .../systrace/tracing_agents/atrace_agent.py | 451 + .../tracing_agents/atrace_agent_unittest.py | 132 + .../tracing_agents/atrace_from_file_agent.py | 81 + .../atrace_from_file_agent_unittest.py | 59 + .../systrace/tracing_agents/battor_trace_agent.py | 165 + .../tracing_agents/battor_trace_agent_unittest.py | 182 + .../systrace/tracing_agents/ftrace_agent.py | 257 + .../tracing_agents/ftrace_agent_unittest.py | 143 + .../systrace/systrace/tracing_agents/walt_agent.py | 120 + .../systrace/tracing_agents/walt_agent_unittest.py | 51 + .../systrace/systrace/tracing_controller.py | 306 + .../systrace/update_systrace_trace_viewer.py | 119 + .../systrace/catapult/systrace/systrace/util.py | 211 + .../catapult/systrace/systrace/util_unittest.py | 30 + .../catapult/third_party/pyserial/LICENSE.txt | 61 + .../catapult/third_party/pyserial/README.chromium | 19 + .../third_party/pyserial/linux-product_info.patch | 19 + .../third_party/pyserial/serial/__init__.py | 79 + .../third_party/pyserial/serial/rfc2217.py | 1323 + .../third_party/pyserial/serial/serialcli.py | 273 + .../third_party/pyserial/serial/serialjava.py | 262 + .../third_party/pyserial/serial/serialposix.py | 703 + .../third_party/pyserial/serial/serialutil.py | 551 + .../third_party/pyserial/serial/serialwin32.py | 461 + .../third_party/pyserial/serial/sermsdos.py | 200 + .../third_party/pyserial/serial/tools/__init__.py | 0 .../pyserial/serial/tools/list_ports.py | 103 + .../pyserial/serial/tools/list_ports_linux.py | 151 + .../pyserial/serial/tools/list_ports_osx.py | 208 + .../pyserial/serial/tools/list_ports_posix.py | 101 + .../pyserial/serial/tools/list_ports_windows.py | 240 + .../third_party/pyserial/serial/tools/miniterm.py | 694 + .../pyserial/serial/urlhandler/__init__.py | 0 .../pyserial/serial/urlhandler/protocol_hwgrep.py | 45 + .../pyserial/serial/urlhandler/protocol_loop.py | 265 + .../pyserial/serial/urlhandler/protocol_rfc2217.py | 11 + .../pyserial/serial/urlhandler/protocol_socket.py | 274 + .../catapult/third_party/pyserial/serial/win32.py | 320 + .../systrace/catapult/third_party/zipfile/LICENSE | 255 + .../catapult/third_party/zipfile/README.chromium | 16 + .../catapult/third_party/zipfile/zipfile_2_7_13.py | 1543 + .../systrace/catapult/tracing/tracing/__init__.py | 6 + .../tracing/tracing/trace_data/__init__.py | 4 + .../tracing/tracing/trace_data/trace_data.py | 339 + .../tracing/trace_data/trace_data_unittest.py | 103 + .../systrace/catapult/tracing/tracing_project.py | 196 + love2dToAPK/tools/tools/adb/systrace/systrace.py | 49 + .../android-win/build-tools/19.1.0/NOTICE.txt | 195 + .../tools/android-win/build-tools/19.1.0/aapt.exe | Bin 0 -> 852992 bytes .../tools/android-win/build-tools/19.1.0/aidl.exe | Bin 0 -> 277504 bytes .../android-win/build-tools/19.1.0/bcc_compat.exe | Bin 0 -> 120832 bytes .../android-win/build-tools/19.1.0/dexdump.exe | Bin 0 -> 128512 bytes .../tools/android-win/build-tools/19.1.0/dx.bat | 88 + .../android-win/build-tools/19.1.0/lib/dx.jar | Bin 0 -> 901345 bytes .../android-win/build-tools/19.1.0/libbcc.dll | Bin 0 -> 321536 bytes .../android-win/build-tools/19.1.0/libbcinfo.dll | Bin 0 -> 674304 bytes .../renderscript/clang-include/CMakeLists.txt | 108 + .../19.1.0/renderscript/clang-include/LICENSE.TXT | 63 + .../19.1.0/renderscript/clang-include/altivec.h | 11856 +++ .../19.1.0/renderscript/clang-include/ammintrin.h | 68 + .../19.1.0/renderscript/clang-include/avx2intrin.h | 1206 + .../19.1.0/renderscript/clang-include/avxintrin.h | 1224 + .../19.1.0/renderscript/clang-include/bmi2intrin.h | 94 + .../19.1.0/renderscript/clang-include/bmiintrin.h | 115 + .../19.1.0/renderscript/clang-include/cpuid.h | 156 + .../19.1.0/renderscript/clang-include/emmintrin.h | 1431 + .../19.1.0/renderscript/clang-include/f16cintrin.h | 58 + .../19.1.0/renderscript/clang-include/float.h | 124 + .../19.1.0/renderscript/clang-include/fma4intrin.h | 231 + .../19.1.0/renderscript/clang-include/fmaintrin.h | 229 + .../19.1.0/renderscript/clang-include/immintrin.h | 114 + .../19.1.0/renderscript/clang-include/iso646.h | 43 + .../19.1.0/renderscript/clang-include/limits.h | 117 + .../renderscript/clang-include/lzcntintrin.h | 55 + .../19.1.0/renderscript/clang-include/mm3dnow.h | 162 + .../19.1.0/renderscript/clang-include/mm_malloc.h | 75 + .../19.1.0/renderscript/clang-include/mmintrin.h | 503 + .../19.1.0/renderscript/clang-include/module.map | 156 + .../19.1.0/renderscript/clang-include/nmmintrin.h | 35 + .../19.1.0/renderscript/clang-include/pmmintrin.h | 117 + .../renderscript/clang-include/popcntintrin.h | 45 + .../renderscript/clang-include/prfchwintrin.h | 39 + .../renderscript/clang-include/rdseedintrin.h | 52 + .../19.1.0/renderscript/clang-include/rtmintrin.h | 54 + .../19.1.0/renderscript/clang-include/smmintrin.h | 467 + .../19.1.0/renderscript/clang-include/stdalign.h | 35 + .../19.1.0/renderscript/clang-include/stdarg.h | 50 + .../19.1.0/renderscript/clang-include/stdbool.h | 44 + .../19.1.0/renderscript/clang-include/stddef.h | 102 + .../19.1.0/renderscript/clang-include/stdint.h | 708 + .../renderscript/clang-include/stdnoreturn.h | 30 + .../19.1.0/renderscript/clang-include/tgmath.h | 1374 + .../19.1.0/renderscript/clang-include/tmmintrin.h | 225 + .../19.1.0/renderscript/clang-include/unwind.h | 133 + .../19.1.0/renderscript/clang-include/varargs.h | 26 + .../19.1.0/renderscript/clang-include/wmmintrin.h | 42 + .../19.1.0/renderscript/clang-include/x86intrin.h | 75 + .../19.1.0/renderscript/clang-include/xmmintrin.h | 1001 + .../19.1.0/renderscript/clang-include/xopintrin.h | 804 + .../19.1.0/renderscript/include/rs_allocation.rsh | 378 + .../19.1.0/renderscript/include/rs_atomic.rsh | 250 + .../19.1.0/renderscript/include/rs_cl.rsh | 1120 + .../19.1.0/renderscript/include/rs_core.rsh | 189 + .../19.1.0/renderscript/include/rs_debug.rsh | 267 + .../19.1.0/renderscript/include/rs_element.rsh | 143 + .../19.1.0/renderscript/include/rs_graphics.rsh | 421 + .../19.1.0/renderscript/include/rs_math.rsh | 251 + .../19.1.0/renderscript/include/rs_matrix.rsh | 378 + .../19.1.0/renderscript/include/rs_mesh.rsh | 88 + .../19.1.0/renderscript/include/rs_object.rsh | 220 + .../19.1.0/renderscript/include/rs_program.rsh | 118 + .../19.1.0/renderscript/include/rs_quaternion.rsh | 253 + .../19.1.0/renderscript/include/rs_sampler.rsh | 77 + .../19.1.0/renderscript/include/rs_time.rsh | 111 + .../19.1.0/renderscript/include/rs_types.rsh | 628 + .../renderscript/lib/bc/armeabi-v7a/libclcore.bc | Bin 0 -> 174112 bytes .../19.1.0/renderscript/lib/bc/mips/libclcore.bc | Bin 0 -> 174112 bytes .../lib/intermediates/armeabi-v7a/libc.so | Bin 0 -> 306404 bytes .../lib/intermediates/armeabi-v7a/libcompiler_rt.a | Bin 0 -> 284572 bytes .../lib/intermediates/armeabi-v7a/libm.so | Bin 0 -> 103692 bytes .../renderscript/lib/intermediates/mips/libc.so | Bin 0 -> 545564 bytes .../lib/intermediates/mips/libcompiler_rt.a | Bin 0 -> 399274 bytes .../renderscript/lib/intermediates/mips/libm.so | Bin 0 -> 136844 bytes .../lib/packaged/armeabi-v7a/libRSSupport.so | Bin 0 -> 338204 bytes .../lib/packaged/armeabi-v7a/librsjni.so | Bin 0 -> 22564 bytes .../renderscript/lib/packaged/mips/libRSSupport.so | Bin 0 -> 536800 bytes .../renderscript/lib/packaged/mips/librsjni.so | Bin 0 -> 71912 bytes .../19.1.0/renderscript/lib/renderscript-v8.jar | Bin 0 -> 136431 bytes .../build-tools/19.1.0/source.properties | 7 + .../android-win/build-tools/19.1.0/zipalign.exe | Bin 0 -> 166400 bytes .../tools/android-win/platform-tools/AdbWinApi.dll | Bin 0 -> 96256 bytes .../android-win/platform-tools/AdbWinUsbApi.dll | Bin 0 -> 60928 bytes .../tools/android-win/platform-tools/NOTICE.txt | 15551 ++++ .../tools/tools/android-win/platform-tools/adb.exe | Bin 0 -> 1011200 bytes .../platform-tools/api/api-versions.xml | 57543 ++++++++++++++ .../android-win/platform-tools/dmtracedump.exe | Bin 0 -> 73728 bytes .../tools/android-win/platform-tools/etc1tool.exe | Bin 0 -> 338944 bytes .../tools/android-win/platform-tools/fastboot.exe | Bin 0 -> 196608 bytes .../android-win/platform-tools/hprof-conv.exe | Bin 0 -> 43008 bytes .../android-win/platform-tools/source.properties | 7 + .../tools/android-win/platform-tools/sqlite3.exe | Bin 0 -> 700928 bytes .../android-win/platform-tools/systrace/AUTHORS | 12 + .../android-win/platform-tools/systrace/LICENSE | 27 + .../android-win/platform-tools/systrace/NOTICE | 205 + .../platform-tools/systrace/UPSTREAM_REVISION | 1 + .../platform-tools/systrace/prefix.html | 38 + .../android-win/platform-tools/systrace/script.js | 546 + .../android-win/platform-tools/systrace/style.css | 1 + .../platform-tools/systrace/suffix.html | 5 + .../platform-tools/systrace/systrace-legacy.py | 251 + .../platform-tools/systrace/systrace.py | 313 + .../android-win/platforms/android-19/android.jar | Bin 0 -> 21841425 bytes .../android-win/platforms/android-19/build.prop | 54 + .../platforms/android-19/framework.aidl | 57 + .../platforms/android-19/sdk.properties | 5 + .../platforms/android-19/source.properties | 12 + .../platforms/android-19/uiautomator.jar | Bin 0 -> 10081 bytes .../tools/tools/android-win/tools/NOTICE.txt | 15749 ++++ .../tools/tools/android-win/tools/android.bat | 85 + .../tools/tools/android-win/tools/ant/NOTICE | 190 + .../tools/tools/android-win/tools/ant/build.xml | 1534 + .../tools/tools/android-win/tools/ant/uibuild.xml | 260 + .../tools/apps/SdkController/.classpath | 8 + .../android-win/tools/apps/SdkController/.project | 34 + .../.settings/org.eclipse.jdt.core.prefs | 12 + .../tools/apps/SdkController/AndroidManifest.xml | 44 + .../tools/apps/SdkController/Implementation.txt | 85 + .../android-win/tools/apps/SdkController/NOTICE | 190 + .../apps/SdkController/assets/intro_help.html | 42 + .../tools/apps/SdkController/proguard-project.txt | 20 + .../tools/apps/SdkController/project.properties | 14 + .../res/drawable-hdpi/ic_launcher.png | Bin 0 -> 9397 bytes .../res/drawable-ldpi/ic_launcher.png | Bin 0 -> 2729 bytes .../res/drawable-mdpi/ic_launcher.png | Bin 0 -> 5237 bytes .../res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 14383 bytes .../apps/SdkController/res/layout-land/sensors.xml | 168 + .../tools/apps/SdkController/res/layout/main.xml | 116 + .../apps/SdkController/res/layout/multitouch.xml | 32 + .../apps/SdkController/res/layout/sensor_row.xml | 42 + .../apps/SdkController/res/layout/sensors.xml | 130 + .../SdkController/res/values-v11/styles_v11.xml | 26 + .../apps/SdkController/res/values/strings.xml | 48 + .../tools/apps/SdkController/res/values/styles.xml | 26 + .../activities/BaseBindingActivity.java | 159 + .../sdkcontroller/activities/MainActivity.java | 208 + .../activities/MultiTouchActivity.java | 388 + .../sdkcontroller/activities/SensorActivity.java | 338 + .../sdkcontroller/handlers/MultiTouchChannel.java | 173 + .../sdkcontroller/handlers/SensorChannel.java | 675 + .../android/tools/sdkcontroller/lib/Channel.java | 795 + .../tools/sdkcontroller/lib/Connection.java | 412 + .../tools/sdkcontroller/lib/ProtocolConstants.java | 146 + .../android/tools/sdkcontroller/lib/Socket.java | 213 + .../sdkcontroller/service/ControllerService.java | 319 + .../tools/sdkcontroller/utils/ApiHelper.java | 57 + .../tools/sdkcontroller/utils/ApiHelper_11.java | 36 + .../tools/sdkcontroller/views/MultiTouchView.java | 232 + love2dToAPK/tools/tools/android-win/tools/ddms.bat | 74 + .../tools/tools/android-win/tools/draw9patch.bat | 46 + .../tools/android-win/tools/hierarchyviewer.bat | 75 + love2dToAPK/tools/tools/android-win/tools/jobb.bat | 51 + .../tools/tools/android-win/tools/lib/android.el | 131 + .../android-win/tools/lib/annotations-12.0.jar | Bin 0 -> 20195 bytes .../tools/android-win/tools/lib/annotations.jar | Bin 0 -> 4220 bytes .../tools/android-win/tools/lib/ant-tasks.jar | Bin 0 -> 102368 bytes .../tools/android-win/tools/lib/archquery.jar | Bin 0 -> 1462 bytes .../tools/android-win/tools/lib/asm-5.0.3.jar | Bin 0 -> 53231 bytes .../android-win/tools/lib/asm-analysis-5.0.3.jar | Bin 0 -> 20443 bytes .../tools/android-win/tools/lib/asm-tree-5.0.3.jar | Bin 0 -> 29036 bytes .../tools/android-win/tools/lib/asset-studio.jar | Bin 0 -> 842447 bytes .../tools/android-win/tools/lib/build.template | 92 + .../android-win/tools/lib/build_gradle.template | 21 + .../tools/android-win/tools/lib/builder-model.jar | Bin 0 -> 20359 bytes .../android-win/tools/lib/cglib-nodep-3.1.jar | Bin 0 -> 331202 bytes .../tools/android-win/tools/lib/chimpchat.jar | Bin 0 -> 52629 bytes .../tools/tools/android-win/tools/lib/common.jar | Bin 0 -> 87532 bytes .../android-win/tools/lib/commons-codec-1.4.jar | Bin 0 -> 58160 bytes .../tools/lib/commons-compress-1.8.1.jar | Bin 0 -> 365552 bytes .../tools/lib/commons-logging-1.1.1.jar | Bin 0 -> 60686 bytes .../tools/tools/android-win/tools/lib/ddmlib.jar | Bin 0 -> 290394 bytes .../tools/tools/android-win/tools/lib/ddms.jar | Bin 0 -> 124370 bytes .../tools/tools/android-win/tools/lib/ddmuilib.jar | Bin 0 -> 597108 bytes .../tools/tools/android-win/tools/lib/devices.xml | 595 + .../tools/android-win/tools/lib/draw9patch.jar | Bin 0 -> 70529 bytes .../tools/tools/android-win/tools/lib/dvlib.jar | Bin 0 -> 19963 bytes .../tools/android-win/tools/lib/easymock-3.3.jar | Bin 0 -> 126613 bytes .../tools/android-win/tools/lib/ecj-4.4.2.jar | Bin 0 -> 2310271 bytes .../tools/tools/android-win/tools/lib/emma.jar | Bin 0 -> 428218 bytes .../tools/tools/android-win/tools/lib/emma_ant.jar | Bin 0 -> 38232 bytes .../tools/android-win/tools/lib/emma_device.jar | Bin 0 -> 447350 bytes .../tools/tools/android-win/tools/lib/fat32lib.jar | Bin 0 -> 71904 bytes .../tools/android-win/tools/lib/find_java.bat | 68 + .../tools/android-win/tools/lib/find_java32.exe | Bin 0 -> 726124 bytes .../tools/android-win/tools/lib/find_java64.exe | Bin 0 -> 954370 bytes .../tools/android-win/tools/lib/gson-2.2.4.jar | Bin 0 -> 190432 bytes .../tools/android-win/tools/lib/guava-17.0.jar | Bin 0 -> 2243036 bytes .../android-win/tools/lib/hamcrest-core-1.3.jar | Bin 0 -> 45024 bytes .../android-win/tools/lib/hierarchyviewer2.jar | Bin 0 -> 32695 bytes .../android-win/tools/lib/hierarchyviewer2lib.jar | Bin 0 -> 407189 bytes .../android-win/tools/lib/httpclient-4.1.1.jar | Bin 0 -> 351132 bytes .../tools/android-win/tools/lib/httpcore-4.1.jar | Bin 0 -> 181041 bytes .../tools/android-win/tools/lib/httpmime-4.1.jar | Bin 0 -> 26813 bytes .../tools/android-win/tools/lib/jcommon-1.0.12.jar | Bin 0 -> 309245 bytes .../android-win/tools/lib/jfreechart-1.0.9.jar | Bin 0 -> 1291498 bytes .../android-win/tools/lib/jfreechart-swt-1.0.9.jar | Bin 0 -> 73010 bytes .../tools/tools/android-win/tools/lib/jobb.jar | Bin 0 -> 36332 bytes .../tools/android-win/tools/lib/jsilver-1.0.0.jar | Bin 0 -> 545459 bytes .../tools/android-win/tools/lib/junit-4.12.jar | Bin 0 -> 314932 bytes .../tools/android-win/tools/lib/kxml2-2.3.0.jar | Bin 0 -> 43858 bytes .../tools/android-win/tools/lib/layoutlib-api.jar | Bin 0 -> 82562 bytes .../tools/lib/libemugl_test_shared_library.dll | Bin 0 -> 195307 bytes .../tools/tools/android-win/tools/lib/lint-api.jar | Bin 0 -> 192626 bytes .../tools/android-win/tools/lib/lint-checks.jar | Bin 0 -> 668803 bytes .../tools/android-win/tools/lib/lint-tests.jar | Bin 0 -> 20889 bytes .../tools/tools/android-win/tools/lib/lint.jar | Bin 0 -> 136089 bytes .../android-win/tools/lib/lombok-ast-0.2.3.jar | Bin 0 -> 720633 bytes .../android-win/tools/lib/manifest-merger.jar | Bin 0 -> 171833 bytes .../tools/android-win/tools/lib/monkeyrunner.jar | Bin 0 -> 101761 bytes .../tools/android-win/tools/lib/ninepatch.jar | Bin 0 -> 11485 bytes .../tools/android-win/tools/lib/objenesis-2.1.jar | Bin 0 -> 41755 bytes .../tools/lib/org-eclipse-core-commands-3.6.0.jar | Bin 0 -> 107209 bytes .../tools/lib/org-eclipse-equinox-common-3.6.0.jar | Bin 0 -> 101958 bytes .../tools/lib/org-eclipse-jface-3.6.2.jar | Bin 0 -> 1069483 bytes .../tools/android-win/tools/lib/osgi-4.0.0.jar | Bin 0 -> 1831843 bytes .../tools/android-win/tools/lib/pc-bios/bios.bin | Bin 0 -> 131072 bytes .../tools/lib/pc-bios/vgabios-cirrus.bin | Bin 0 -> 35840 bytes .../tools/tools/android-win/tools/lib/plugin.prop | 3 + .../android-win/tools/lib/proguard-project.txt | 20 + .../tools/tools/android-win/tools/lib/rule-api.jar | Bin 0 -> 39674 bytes .../tools/android-win/tools/lib/screenshot2.jar | Bin 0 -> 5389 bytes .../tools/android-win/tools/lib/sdk-common.jar | Bin 0 -> 448287 bytes .../tools/tools/android-win/tools/lib/sdklib.jar | Bin 0 -> 734357 bytes .../tools/android-win/tools/lib/sdkmanager.jar | Bin 0 -> 30978 bytes .../tools/tools/android-win/tools/lib/sdkstats.jar | Bin 0 -> 16833 bytes .../tools/tools/android-win/tools/lib/sdkuilib.jar | Bin 0 -> 482727 bytes .../tools/android-win/tools/lib/swtmenubar.jar | Bin 0 -> 18580 bytes .../tools/android-win/tools/lib/traceview.jar | Bin 0 -> 137241 bytes .../android-win/tools/lib/uiautomatorviewer.jar | Bin 0 -> 67649 bytes .../tools/android-win/tools/lib/uibuild.template | 92 + love2dToAPK/tools/tools/android-win/tools/lint.bat | 58 + .../tools/tools/android-win/tools/mksdcard.exe | Bin 0 -> 230163 bytes .../tools/tools/android-win/tools/monitor.bat | 32 + .../tools/tools/android-win/tools/monkeyrunner.bat | 63 + .../tools/tools/android-win/tools/proguard/README | 41 + .../android-win/tools/proguard/ant/task.properties | 2 + .../tools/proguard/examples/android.pro | 149 + .../proguard/examples/annotations/examples.pro | 60 + .../examples/annotations/examples/Applet.java | 22 + .../examples/annotations/examples/Application.java | 20 + .../examples/annotations/examples/Bean.java | 56 + .../annotations/examples/NativeCallBack.java | 44 + .../examples/annotations/lib/annotations.jar | Bin 0 -> 6123 bytes .../examples/annotations/lib/annotations.pro | 118 + .../annotations/src/proguard/annotation/Keep.java | 18 + .../src/proguard/annotation/KeepApplication.java | 18 + .../proguard/annotation/KeepClassMemberNames.java | 18 + .../src/proguard/annotation/KeepClassMembers.java | 18 + .../proguard/annotation/KeepGettersSetters.java | 18 + .../proguard/annotation/KeepImplementations.java | 18 + .../src/proguard/annotation/KeepName.java | 18 + .../annotation/KeepPublicClassMemberNames.java | 18 + .../annotation/KeepPublicClassMembers.java | 18 + .../annotation/KeepPublicGettersSetters.java | 18 + .../annotation/KeepPublicImplementations.java | 18 + .../KeepPublicProtectedClassMemberNames.java | 18 + .../KeepPublicProtectedClassMembers.java | 19 + .../tools/proguard/examples/ant/android-8.xml | 177 + .../tools/proguard/examples/ant/applets.xml | 88 + .../tools/proguard/examples/ant/applications1.xml | 15 + .../tools/proguard/examples/ant/applications2.xml | 74 + .../tools/proguard/examples/ant/applications3.xml | 98 + .../tools/proguard/examples/ant/library.xml | 102 + .../tools/proguard/examples/ant/midlets.xml | 52 + .../tools/proguard/examples/ant/proguard.xml | 78 + .../tools/proguard/examples/ant/servlets.xml | 88 + .../tools/proguard/examples/applets.pro | 69 + .../tools/proguard/examples/applications.pro | 75 + .../proguard/examples/dictionaries/compact.txt | 18 + .../proguard/examples/dictionaries/keywords.txt | 58 + .../proguard/examples/dictionaries/shakespeare.txt | 23 + .../proguard/examples/dictionaries/windows.txt | 209 + .../tools/proguard/examples/library.pro | 79 + .../tools/proguard/examples/midlets.pro | 67 + .../tools/proguard/examples/proguard.pro | 57 + .../tools/proguard/examples/proguardall.pro | 62 + .../tools/proguard/examples/proguardgui.pro | 50 + .../tools/proguard/examples/retrace.pro | 43 + .../android-win/tools/proguard/examples/scala.pro | 132 + .../tools/proguard/examples/servlets.pro | 70 + .../android-win/tools/proguard/lib/proguard.jar | Bin 0 -> 716008 bytes .../android-win/tools/proguard/lib/proguardgui.jar | Bin 0 -> 138390 bytes .../android-win/tools/proguard/lib/retrace.jar | Bin 0 -> 6894 bytes .../tools/android-win/tools/proguard/license.html | 49 + .../tools/proguard/proguard-android-optimize.txt | 64 + .../tools/proguard/proguard-android.txt | 57 + .../tools/proguard/proguard-project.txt | 20 + .../tools/android-win/tools/source.properties | 3 + .../android-win/tools/support/annotations.jar | Bin 0 -> 1351 bytes .../tools/android-win/tools/support/typos-de.txt | 2219 + .../tools/android-win/tools/support/typos-en.txt | 4576 ++ .../tools/android-win/tools/support/typos-es.txt | 733 + .../tools/android-win/tools/support/typos-hu.txt | 431 + .../tools/android-win/tools/support/typos-it.txt | 665 + .../tools/android-win/tools/support/typos-nb.txt | 449 + .../tools/android-win/tools/support/typos-pt.txt | 1647 + .../tools/android-win/tools/support/typos-tr.txt | 604 + .../activities/BlankActivity/globals.xml.ftl | 11 + .../activities/BlankActivity/recipe.xml.ftl | 28 + .../BlankActivity/root/AndroidManifest.xml.ftl | 24 + .../root/res/layout/activity_simple.xml.ftl | 16 + .../BlankActivity/root/res/menu/main.xml.ftl | 9 + .../root/res/values-w820dp/dimens.xml | 6 + .../BlankActivity/root/res/values/dimens.xml.ftl | 5 + .../BlankActivity/root/res/values/strings.xml.ftl | 9 + .../root/src/app_package/SimpleActivity.java.ftl | 35 + .../activities/BlankActivity/template.xml | 71 + .../BlankActivity/template_blank_activity.png | Bin 0 -> 3264 bytes .../BlankActivityWithFragment/globals.xml.ftl | 11 + .../BlankActivityWithFragment/recipe.xml.ftl | 31 + .../root/AndroidManifest.xml.ftl | 24 + .../res/layout/activity_fragment_container.xml.ftl | 7 + .../root/res/layout/fragment_simple.xml.ftl | 16 + .../root/res/menu/main.xml.ftl | 9 + .../root/res/values-w820dp/dimens.xml | 6 + .../root/res/values/dimens.xml.ftl | 5 + .../root/res/values/strings.xml.ftl | 7 + .../root/src/app_package/SimpleActivity.java.ftl | 32 + .../root/src/app_package/include_fragment.java.ftl | 15 + .../src/app_package/include_options_menu.java.ftl | 19 + .../BlankActivityWithFragment/template.xml | 80 + .../template_blank_activity_fragment.png | Bin 0 -> 4983 bytes .../activities/EmptyActivity/globals.xml.ftl | 7 + .../activities/EmptyActivity/recipe.xml.ftl | 17 + .../EmptyActivity/root/AndroidManifest.xml.ftl | 20 + .../root/res/layout/activity_simple.xml | 12 + .../EmptyActivity/root/res/values/strings.xml.ftl | 6 + .../root/src/app_package/SimpleActivity.java.ftl | 15 + .../activities/EmptyActivity/template.xml | 63 + .../EmptyActivity/template_blank_activity.png | Bin 0 -> 3264 bytes .../activities/FullscreenActivity/globals.xml.ftl | 9 + .../activities/FullscreenActivity/recipe.xml.ftl | 32 + .../root/AndroidManifest.xml.ftl | 26 + .../root/res/layout/activity_fullscreen.xml.ftl | 46 + .../root/res/values-v11/styles.xml | 15 + .../FullscreenActivity/root/res/values/attrs.xml | 12 + .../FullscreenActivity/root/res/values/colors.xml | 5 + .../root/res/values/strings.xml.ftl | 9 + .../FullscreenActivity/root/res/values/styles.xml | 22 + .../src/app_package/FullscreenActivity.java.ftl | 198 + .../src/app_package/util/SystemUiHider.java.ftl | 172 + .../app_package/util/SystemUiHiderBase.java.ftl | 63 + .../util/SystemUiHiderHoneycomb.java.ftl | 133 + .../activities/FullscreenActivity/template.xml | 68 + .../template_fullscreen_activity.png | Bin 0 -> 16885 bytes .../activities/LoginActivity/globals.xml.ftl | 10 + .../activities/LoginActivity/recipe.xml.ftl | 28 + .../LoginActivity/root/AndroidManifest.xml.ftl | 37 + .../root/res/layout/activity_login.xml.ftl | 108 + .../LoginActivity/root/res/values/dimens.xml | 5 + .../LoginActivity/root/res/values/strings.xml.ftl | 17 + .../root/src/app_package/LoginActivity.java.ftl | 449 + .../root/src/app_package/PlusBaseActivity.java.ftl | 282 + .../activities/LoginActivity/template.xml | 68 + .../LoginActivity/template_login_activity.png | Bin 0 -> 5939 bytes .../activities/MasterDetailFlow/globals.xml.ftl | 14 + .../activities/MasterDetailFlow/recipe.xml.ftl | 37 + .../MasterDetailFlow/root/AndroidManifest.xml.ftl | 31 + .../res/layout/activity_content_detail.xml.ftl | 7 + .../root/res/layout/activity_content_list.xml.ftl | 10 + .../res/layout/activity_content_twopane.xml.ftl | 38 + .../res/layout/fragment_content_detail.xml.ftl | 9 + .../root/res/values-large/refs.xml.ftl | 10 + .../root/res/values-sw600dp/refs.xml.ftl | 11 + .../root/res/values/strings.xml.ftl | 6 + .../src/app_package/ContentDetailActivity.java.ftl | 78 + .../src/app_package/ContentDetailFragment.java.ftl | 62 + .../src/app_package/ContentListActivity.java.ftl | 106 + .../src/app_package/ContentListFragment.java.ftl | 152 + .../src/app_package/dummy/DummyContent.java.ftl | 55 + .../activities/MasterDetailFlow/template.xml | 68 + .../MasterDetailFlow/template_master_detail.png | Bin 0 -> 7173 bytes .../NavigationDrawerActivity/globals.xml.ftl | 12 + .../NavigationDrawerActivity/recipe.xml.ftl | 49 + .../root/AndroidManifest.xml.ftl | 24 + .../NavigationDrawerActivity/root/build.gradle.ftl | 7 + .../root/res/drawable-hdpi/drawer_shadow.9.png | Bin 0 -> 161 bytes .../root/res/drawable-hdpi/ic_drawer.png | Bin 0 -> 2829 bytes .../root/res/drawable-mdpi/drawer_shadow.9.png | Bin 0 -> 142 bytes .../root/res/drawable-mdpi/ic_drawer.png | Bin 0 -> 2820 bytes .../root/res/drawable-xhdpi/drawer_shadow.9.png | Bin 0 -> 174 bytes .../root/res/drawable-xhdpi/ic_drawer.png | Bin 0 -> 2836 bytes .../root/res/drawable-xxhdpi/drawer_shadow.9.png | Bin 0 -> 208 bytes .../root/res/drawable-xxhdpi/ic_drawer.png | Bin 0 -> 202 bytes .../root/res/layout/activity_drawer.xml.ftl | 31 + .../res/layout/fragment_navigation_drawer.xml.ftl | 9 + .../root/res/layout/fragment_simple.xml.ftl | 16 + .../root/res/menu/global.xml.ftl | 7 + .../root/res/menu/main.xml.ftl | 12 + .../root/res/values-w820dp/dimens.xml | 6 + .../root/res/values/dimens.xml.ftl | 9 + .../root/res/values/strings.xml.ftl | 17 + .../root/src/app_package/DrawerActivity.java.ftl | 84 + .../app_package/NavigationDrawerFragment.java.ftl | 282 + .../root/src/app_package/include_fragment.java.ftl | 43 + .../src/app_package/include_options_menu.java.ftl | 25 + .../NavigationDrawerActivity/template.xml | 87 + .../template_blank_activity_drawer.png | Bin 0 -> 2631 bytes .../activities/SettingsActivity/globals.xml.ftl | 9 + .../activities/SettingsActivity/recipe.xml.ftl | 24 + .../SettingsActivity/root/AndroidManifest.xml.ftl | 18 + .../root/res/values/strings.xml.ftl | 61 + .../root/res/xml/pref_data_sync.xml | 21 + .../SettingsActivity/root/res/xml/pref_general.xml | 33 + .../root/res/xml/pref_headers.xml.ftl | 17 + .../root/res/xml/pref_notification.xml | 27 + .../root/src/app_package/SettingsActivity.java.ftl | 296 + .../activities/SettingsActivity/template.xml | 56 + .../template_settings_activity.png | Bin 0 -> 6260 bytes .../activities/TabbedActivity/globals.xml.ftl | 12 + .../activities/TabbedActivity/recipe.xml.ftl | 47 + .../TabbedActivity/root/AndroidManifest.xml.ftl | 24 + .../res/layout/activity_fragment_container.xml.ftl | 7 + .../root/res/layout/activity_pager.xml.ftl | 6 + .../root/res/layout/fragment_simple.xml.ftl | 16 + .../TabbedActivity/root/res/menu/main.xml.ftl | 9 + .../root/res/values-w820dp/dimens.xml | 6 + .../TabbedActivity/root/res/values/dimens.xml.ftl | 5 + .../TabbedActivity/root/res/values/strings.xml.ftl | 14 + .../root/src/app_package/DropdownActivity.java.ftl | 86 + .../src/app_package/TabsAndPagerActivity.java.ftl | 139 + .../root/src/app_package/include_fragment.java.ftl | 36 + .../src/app_package/include_options_menu.java.ftl | 19 + .../activities/TabbedActivity/template.xml | 95 + .../template_blank_activity_dropdown.png | Bin 0 -> 3824 bytes .../template_blank_activity_pager.png | Bin 0 -> 2600 bytes .../template_blank_activity_tabs.png | Bin 0 -> 3732 bytes .../templates/gradle/utils/dependencies.gradle.ftl | 7 + .../wrapper/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../tools/templates/gradle/wrapper/gradlew | 164 + .../tools/templates/gradle/wrapper/gradlew.bat | 90 + .../tools/templates/other/AidlFile/recipe.xml.ftl | 7 + .../root/src/app_package/interface.aidl.ftl | 13 + .../tools/templates/other/AidlFile/template.xml | 21 + .../templates/other/AidlFolder/recipe.xml.ftl | 12 + .../other/AidlFolder/root/build.gradle.ftl | 1 + .../tools/templates/other/AidlFolder/template.xml | 30 + .../templates/other/AndroidManifest/recipe.xml.ftl | 14 + .../AndroidManifest/root/AndroidManifest.xml.ftl | 8 + .../other/AndroidManifest/root/build.gradle.ftl | 3 + .../templates/other/AndroidManifest/template.xml | 30 + .../templates/other/AppWidget/globals.xml.ftl | 8 + .../tools/templates/other/AppWidget/recipe.xml.ftl | 35 + .../other/AppWidget/root/AndroidManifest.xml.ftl | 25 + .../drawable-nodpi/example_appwidget_preview.png | Bin 0 -> 3522 bytes .../other/AppWidget/root/res/layout/appwidget.xml | 21 + .../root/res/layout/appwidget_configure.xml | 27 + .../other/AppWidget/root/res/values-v14/dimens.xml | 10 + .../other/AppWidget/root/res/values/dimens.xml | 10 + .../AppWidget/root/res/values/strings.xml.ftl | 8 + .../AppWidget/root/res/xml/appwidget_info.xml.ftl | 27 + .../root/src/app_package/AppWidget.java.ftl | 63 + .../AppWidgetConfigureActivity.java.ftl | 101 + .../tools/templates/other/AppWidget/template.xml | 148 + .../other/AppWidget/thumbs/template_widget_1x1.png | Bin 0 -> 2960 bytes .../AppWidget/thumbs/template_widget_1x1_h.png | Bin 0 -> 3750 bytes .../AppWidget/thumbs/template_widget_1x1_v.png | Bin 0 -> 3787 bytes .../AppWidget/thumbs/template_widget_1x1_vh.png | Bin 0 -> 4004 bytes .../other/AppWidget/thumbs/template_widget_1x2.png | Bin 0 -> 3010 bytes .../AppWidget/thumbs/template_widget_1x2_h.png | Bin 0 -> 3771 bytes .../AppWidget/thumbs/template_widget_1x2_v.png | Bin 0 -> 3835 bytes .../AppWidget/thumbs/template_widget_1x2_vh.png | Bin 0 -> 4065 bytes .../other/AppWidget/thumbs/template_widget_1x3.png | Bin 0 -> 3058 bytes .../AppWidget/thumbs/template_widget_1x3_h.png | Bin 0 -> 3830 bytes .../AppWidget/thumbs/template_widget_1x3_v.png | Bin 0 -> 3880 bytes .../AppWidget/thumbs/template_widget_1x3_vh.png | Bin 0 -> 4120 bytes .../other/AppWidget/thumbs/template_widget_1x4.png | Bin 0 -> 3114 bytes .../AppWidget/thumbs/template_widget_1x4_h.png | Bin 0 -> 3880 bytes .../AppWidget/thumbs/template_widget_1x4_v.png | Bin 0 -> 3944 bytes .../AppWidget/thumbs/template_widget_1x4_vh.png | Bin 0 -> 4178 bytes .../other/AppWidget/thumbs/template_widget_2x1.png | Bin 0 -> 2973 bytes .../AppWidget/thumbs/template_widget_2x1_h.png | Bin 0 -> 3765 bytes .../AppWidget/thumbs/template_widget_2x1_v.png | Bin 0 -> 3794 bytes .../AppWidget/thumbs/template_widget_2x1_vh.png | Bin 0 -> 4020 bytes .../other/AppWidget/thumbs/template_widget_2x2.png | Bin 0 -> 3023 bytes .../AppWidget/thumbs/template_widget_2x2_h.png | Bin 0 -> 3784 bytes .../AppWidget/thumbs/template_widget_2x2_v.png | Bin 0 -> 3842 bytes .../AppWidget/thumbs/template_widget_2x2_vh.png | Bin 0 -> 4062 bytes .../other/AppWidget/thumbs/template_widget_2x3.png | Bin 0 -> 3047 bytes .../AppWidget/thumbs/template_widget_2x3_h.png | Bin 0 -> 3849 bytes .../AppWidget/thumbs/template_widget_2x3_v.png | Bin 0 -> 3890 bytes .../AppWidget/thumbs/template_widget_2x3_vh.png | Bin 0 -> 4133 bytes .../other/AppWidget/thumbs/template_widget_2x4.png | Bin 0 -> 3071 bytes .../AppWidget/thumbs/template_widget_2x4_h.png | Bin 0 -> 3888 bytes .../AppWidget/thumbs/template_widget_2x4_v.png | Bin 0 -> 3946 bytes .../AppWidget/thumbs/template_widget_2x4_vh.png | Bin 0 -> 4168 bytes .../other/AppWidget/thumbs/template_widget_3x1.png | Bin 0 -> 2950 bytes .../AppWidget/thumbs/template_widget_3x1_h.png | Bin 0 -> 3728 bytes .../AppWidget/thumbs/template_widget_3x1_v.png | Bin 0 -> 3777 bytes .../AppWidget/thumbs/template_widget_3x1_vh.png | Bin 0 -> 3987 bytes .../other/AppWidget/thumbs/template_widget_3x2.png | Bin 0 -> 2995 bytes .../AppWidget/thumbs/template_widget_3x2_h.png | Bin 0 -> 3747 bytes .../AppWidget/thumbs/template_widget_3x2_v.png | Bin 0 -> 3811 bytes .../AppWidget/thumbs/template_widget_3x2_vh.png | Bin 0 -> 4045 bytes .../other/AppWidget/thumbs/template_widget_3x3.png | Bin 0 -> 3035 bytes .../AppWidget/thumbs/template_widget_3x3_h.png | Bin 0 -> 3790 bytes .../AppWidget/thumbs/template_widget_3x3_v.png | Bin 0 -> 3844 bytes .../AppWidget/thumbs/template_widget_3x3_vh.png | Bin 0 -> 4080 bytes .../other/AppWidget/thumbs/template_widget_3x4.png | Bin 0 -> 3051 bytes .../AppWidget/thumbs/template_widget_3x4_h.png | Bin 0 -> 3819 bytes .../AppWidget/thumbs/template_widget_3x4_v.png | Bin 0 -> 3887 bytes .../AppWidget/thumbs/template_widget_3x4_vh.png | Bin 0 -> 4120 bytes .../other/AppWidget/thumbs/template_widget_4x1.png | Bin 0 -> 2925 bytes .../AppWidget/thumbs/template_widget_4x1_h.png | Bin 0 -> 3710 bytes .../AppWidget/thumbs/template_widget_4x1_v.png | Bin 0 -> 3747 bytes .../AppWidget/thumbs/template_widget_4x1_vh.png | Bin 0 -> 3973 bytes .../other/AppWidget/thumbs/template_widget_4x2.png | Bin 0 -> 2931 bytes .../AppWidget/thumbs/template_widget_4x2_h.png | Bin 0 -> 3667 bytes .../AppWidget/thumbs/template_widget_4x2_v.png | Bin 0 -> 3730 bytes .../AppWidget/thumbs/template_widget_4x2_vh.png | Bin 0 -> 3960 bytes .../other/AppWidget/thumbs/template_widget_4x3.png | Bin 0 -> 2934 bytes .../AppWidget/thumbs/template_widget_4x3_h.png | Bin 0 -> 3696 bytes .../AppWidget/thumbs/template_widget_4x3_v.png | Bin 0 -> 3723 bytes .../AppWidget/thumbs/template_widget_4x3_vh.png | Bin 0 -> 3994 bytes .../other/AppWidget/thumbs/template_widget_4x4.png | Bin 0 -> 2938 bytes .../AppWidget/thumbs/template_widget_4x4_h.png | Bin 0 -> 3639 bytes .../AppWidget/thumbs/template_widget_4x4_v.png | Bin 0 -> 3717 bytes .../AppWidget/thumbs/template_widget_4x4_vh.png | Bin 0 -> 3932 bytes .../templates/other/AssetsFolder/recipe.xml.ftl | 12 + .../other/AssetsFolder/root/build.gradle.ftl | 1 + .../templates/other/AssetsFolder/template.xml | 30 + .../templates/other/BlankFragment/globals.xml.ftl | 7 + .../templates/other/BlankFragment/recipe.xml.ftl | 19 + .../root/res/layout/fragment_blank.xml.ftl | 13 + .../BlankFragment/root/res/values/strings.xml | 6 + .../root/src/app_package/BlankFragment.java.ftl | 130 + .../templates/other/BlankFragment/template.xml | 60 + .../BlankFragment/template_blank_fragment.png | Bin 0 -> 5266 bytes .../other/BroadcastReceiver/globals.xml.ftl | 6 + .../other/BroadcastReceiver/recipe.xml.ftl | 8 + .../BroadcastReceiver/root/AndroidManifest.xml.ftl | 10 + .../src/app_package/BroadcastReceiver.java.ftl | 17 + .../templates/other/BroadcastReceiver/template.xml | 32 + .../other/ContentProvider/globals.xml.ftl | 6 + .../templates/other/ContentProvider/recipe.xml.ftl | 8 + .../ContentProvider/root/AndroidManifest.xml.ftl | 11 + .../root/src/app_package/ContentProvider.java.ftl | 50 + .../templates/other/ContentProvider/template.xml | 40 + .../templates/other/CustomView/globals.xml.ftl | 6 + .../templates/other/CustomView/recipe.xml.ftl | 13 + .../CustomView/root/res/layout/sample.xml.ftl | 22 + .../other/CustomView/root/res/values/attrs.xml.ftl | 8 + .../root/src/app_package/CustomView.java.ftl | 182 + .../tools/templates/other/CustomView/template.xml | 28 + .../tools/templates/other/Daydream/globals.xml.ftl | 11 + .../tools/templates/other/Daydream/recipe.xml.ftl | 28 + .../other/Daydream/root/AndroidManifest.xml.ftl | 28 + .../other/Daydream/root/res/layout-v17/dream.xml | 13 + .../other/Daydream/root/res/values/strings.xml.ftl | 7 + .../other/Daydream/root/res/xml/dream_prefs.xml | 9 + .../other/Daydream/root/res/xml/xml_dream.xml.ftl | 3 + .../root/src/app_package/DreamService.java.ftl | 141 + .../root/src/app_package/SettingsActivity.java.ftl | 37 + .../tools/templates/other/Daydream/template.xml | 47 + .../templates/other/IntentService/globals.xml.ftl | 6 + .../templates/other/IntentService/recipe.xml.ftl | 8 + .../IntentService/root/AndroidManifest.xml.ftl | 9 + .../root/src/app_package/IntentService.java.ftl | 106 + .../templates/other/IntentService/template.xml | 29 + .../templates/other/JavaFolder/recipe.xml.ftl | 12 + .../other/JavaFolder/root/build.gradle.ftl | 1 + .../tools/templates/other/JavaFolder/template.xml | 30 + .../tools/templates/other/JniFolder/recipe.xml.ftl | 12 + .../other/JniFolder/root/build.gradle.ftl | 1 + .../tools/templates/other/JniFolder/template.xml | 30 + .../other/LayoutResourceFile/recipe.xml.ftl | 7 + .../LayoutResourceFile/root/res/layout.xml.ftl | 6 + .../other/LayoutResourceFile/template.xml | 29 + .../templates/other/ListFragment/globals.xml.ftl | 11 + .../templates/other/ListFragment/recipe.xml.ftl | 28 + .../ListFragment/root/res/layout/fragment_grid.xml | 20 + .../ListFragment/root/res/layout/fragment_list.xml | 19 + .../root/res/values-large/refs_lrg.xml.ftl | 12 + .../root/res/values-sw600dp/refs_lrg.xml.ftl | 12 + .../ListFragment/root/res/values/refs.xml.ftl | 12 + .../ListFragment/root/res/values/refs_lrg.xml.ftl | 12 + .../root/src/app_package/ListFragment.java.ftl | 195 + .../src/app_package/dummy/DummyContent.java.ftl | 55 + .../templates/other/ListFragment/template.xml | 52 + .../other/ListFragment/templates_list_fragment.png | Bin 0 -> 7293 bytes .../templates/other/Notification/globals.xml.ftl | 10 + .../templates/other/Notification/recipe.xml.ftl | 31 + .../Notification/root/AndroidManifest.xml.ftl | 5 + .../res/drawable-hdpi/ic_action_stat_reply.png | Bin 0 -> 1480 bytes .../res/drawable-hdpi/ic_action_stat_share.png | Bin 0 -> 1606 bytes .../res/drawable-mdpi/ic_action_stat_reply.png | Bin 0 -> 1314 bytes .../res/drawable-mdpi/ic_action_stat_share.png | Bin 0 -> 1341 bytes .../res/drawable-nodpi/example_picture_large.png | Bin 0 -> 5834 bytes .../res/drawable-nodpi/example_picture_small.png | Bin 0 -> 1885 bytes .../res/drawable-xhdpi/ic_action_stat_reply.png | Bin 0 -> 1692 bytes .../res/drawable-xhdpi/ic_action_stat_share.png | Bin 0 -> 1780 bytes .../Notification/root/res/values/strings.xml.ftl | 13 + .../src/app_package/NotificationHelper.java.ftl | 206 + .../templates/other/Notification/template.xml | 58 + .../Notification/template_notification_list.png | Bin 0 -> 7306 bytes .../template_notification_list_actions.png | Bin 0 -> 7850 bytes .../Notification/template_notification_none.png | Bin 0 -> 4146 bytes .../template_notification_none_actions.png | Bin 0 -> 5904 bytes .../Notification/template_notification_picture.png | Bin 0 -> 6308 bytes .../template_notification_picture_actions.png | Bin 0 -> 6749 bytes .../Notification/template_notification_text.png | Bin 0 -> 6695 bytes .../template_notification_text_actions.png | Bin 0 -> 7073 bytes .../other/PlusOneFragment/globals.xml.ftl | 5 + .../templates/other/PlusOneFragment/recipe.xml.ftl | 20 + .../PlusOneFragment/root/AndroidManifest.xml.ftl | 6 + .../root/res/layout/fragment_plus_one.xml.ftl | 15 + .../root/src/app_package/PlusOneFragment.java.ftl | 146 + .../templates/other/PlusOneFragment/template.xml | 45 + .../PlusOneFragment/templates_plusone_fragment.png | Bin 0 -> 6178 bytes .../tools/templates/other/ResFolder/recipe.xml.ftl | 12 + .../other/ResFolder/root/build.gradle.ftl | 1 + .../tools/templates/other/ResFolder/template.xml | 30 + .../templates/other/ResourcesFolder/recipe.xml.ftl | 12 + .../other/ResourcesFolder/root/build.gradle.ftl | 1 + .../templates/other/ResourcesFolder/template.xml | 30 + .../tools/templates/other/RsFolder/recipe.xml.ftl | 12 + .../templates/other/RsFolder/root/build.gradle.ftl | 1 + .../tools/templates/other/RsFolder/template.xml | 30 + .../tools/templates/other/Service/globals.xml.ftl | 6 + .../tools/templates/other/Service/recipe.xml.ftl | 8 + .../other/Service/root/AndroidManifest.xml.ftl | 10 + .../Service/root/src/app_package/Service.java.ftl | 16 + .../tools/templates/other/Service/template.xml | 34 + .../other/ValueResourceFile/recipe.xml.ftl | 7 + .../ValueResourceFile/root/res/values.xml.ftl | 3 + .../templates/other/ValueResourceFile/template.xml | 21 + .../projects/NewAndroidApplication/globals.xml.ftl | 12 + .../projects/NewAndroidApplication/recipe.xml.ftl | 27 + .../root/AndroidManifest.xml.ftl | 15 + .../NewAndroidApplication/root/build.gradle.ftl | 35 + .../root/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 9397 bytes .../root/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 5237 bytes .../root/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 14383 bytes .../root/res/values-v11/styles_hc.xml.ftl | 13 + .../root/res/values-v14/styles_ics.xml.ftl | 14 + .../root/res/values/strings.xml.ftl | 3 + .../root/res/values/styles.xml.ftl | 22 + .../NewAndroidApplication/root/settings.gradle.ftl | 1 + .../projects/NewAndroidApplication/template.xml | 82 + .../NewAndroidApplication/template_new_project.png | Bin 0 -> 12408 bytes .../projects/NewAndroidLibrary/globals.xml.ftl | 12 + .../projects/NewAndroidLibrary/recipe.xml.ftl | 27 + .../NewAndroidLibrary/root/AndroidManifest.xml.ftl | 15 + .../NewAndroidLibrary/root/build.gradle.ftl | 35 + .../root/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 9397 bytes .../root/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 5237 bytes .../root/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 14383 bytes .../root/res/values-v11/styles_hc.xml.ftl | 13 + .../root/res/values-v14/styles_ics.xml.ftl | 14 + .../root/res/values/strings.xml.ftl | 3 + .../root/res/values/styles.xml.ftl | 22 + .../NewAndroidLibrary/root/settings.gradle.ftl | 1 + .../projects/NewAndroidLibrary/template.xml | 82 + .../NewAndroidLibrary/template_new_project.png | Bin 0 -> 12408 bytes .../projects/NewJavaLibrary/globals.xml.ftl | 6 + .../projects/NewJavaLibrary/recipe.xml.ftl | 5 + .../projects/NewJavaLibrary/root/build.gradle.ftl | 1 + .../NewJavaLibrary/root/settings.gradle.ftl | 1 + .../root/src/library_package/Placeholder.java.ftl | 4 + .../templates/projects/NewJavaLibrary/template.xml | 38 + .../NewJavaLibrary/template_new_project.png | Bin 0 -> 12408 bytes .../tools/tools/android-win/tools/traceview.bat | 65 + .../tools/android-win/tools/uiautomatorviewer.bat | 66 + love2dToAPK/tools/tools/ant/CONTRIBUTORS | 417 + love2dToAPK/tools/tools/ant/INSTALL | 2 + love2dToAPK/tools/tools/ant/KEYS | 1497 + love2dToAPK/tools/tools/ant/LICENSE | 272 + love2dToAPK/tools/tools/ant/NOTICE | 9 + love2dToAPK/tools/tools/ant/README | 97 + love2dToAPK/tools/tools/ant/WHATSNEW | 6263 ++ love2dToAPK/tools/tools/ant/contributors.xml | 1671 + love2dToAPK/tools/tools/ant/etc/ant-bootstrap.jar | Bin 0 -> 21191 bytes love2dToAPK/tools/tools/ant/etc/changelog.xsl | 148 + .../checkstyle/checkstyle-frames-sortby-check.xsl | 367 + .../tools/ant/etc/checkstyle/checkstyle-frames.xsl | 299 + .../tools/ant/etc/checkstyle/checkstyle-text.xsl | 34 + .../tools/ant/etc/checkstyle/checkstyle-xdoc.xsl | 130 + .../tools/tools/ant/etc/coverage-frames.xsl | 487 + love2dToAPK/tools/tools/ant/etc/jdepend-frames.xsl | 485 + love2dToAPK/tools/tools/ant/etc/jdepend.xsl | 276 + .../tools/tools/ant/etc/junit-frames-xalan1.xsl | 745 + love2dToAPK/tools/tools/ant/etc/junit-frames.xsl | 972 + love2dToAPK/tools/tools/ant/etc/junit-noframes.xsl | 513 + love2dToAPK/tools/tools/ant/etc/log.xsl | 203 + love2dToAPK/tools/tools/ant/etc/maudit-frames.xsl | 502 + .../tools/tools/ant/etc/mmetrics-frames.xsl | 1023 + love2dToAPK/tools/tools/ant/etc/tagdiff.xsl | 179 + love2dToAPK/tools/tools/ant/fetch.xml | 335 + love2dToAPK/tools/tools/ant/get-m2.xml | 121 + love2dToAPK/tools/tools/ant/lib/README | 3 + love2dToAPK/tools/tools/ant/lib/ant-antlr.jar | Bin 0 -> 11608 bytes love2dToAPK/tools/tools/ant/lib/ant-antlr.pom | 75 + .../tools/tools/ant/lib/ant-apache-bcel.jar | Bin 0 -> 15113 bytes .../tools/tools/ant/lib/ant-apache-bcel.pom | 71 + love2dToAPK/tools/tools/ant/lib/ant-apache-bsf.jar | Bin 0 -> 9787 bytes love2dToAPK/tools/tools/ant/lib/ant-apache-bsf.pom | 74 + .../tools/tools/ant/lib/ant-apache-log4j.jar | Bin 0 -> 8635 bytes .../tools/tools/ant/lib/ant-apache-log4j.pom | 69 + love2dToAPK/tools/tools/ant/lib/ant-apache-oro.jar | Bin 0 -> 9748 bytes love2dToAPK/tools/tools/ant/lib/ant-apache-oro.pom | 74 + .../tools/tools/ant/lib/ant-apache-regexp.jar | Bin 0 -> 9611 bytes .../tools/tools/ant/lib/ant-apache-regexp.pom | 70 + .../tools/tools/ant/lib/ant-apache-resolver.jar | Bin 0 -> 9680 bytes .../tools/tools/ant/lib/ant-apache-resolver.pom | 69 + .../tools/tools/ant/lib/ant-apache-xalan2.jar | Bin 0 -> 8142 bytes .../tools/tools/ant/lib/ant-apache-xalan2.pom | 94 + .../tools/tools/ant/lib/ant-commons-logging.jar | Bin 0 -> 9762 bytes .../tools/tools/ant/lib/ant-commons-logging.pom | 70 + .../tools/tools/ant/lib/ant-commons-net.jar | Bin 0 -> 91364 bytes .../tools/tools/ant/lib/ant-commons-net.pom | 75 + love2dToAPK/tools/tools/ant/lib/ant-jai.jar | Bin 0 -> 28264 bytes love2dToAPK/tools/tools/ant/lib/ant-jai.pom | 85 + love2dToAPK/tools/tools/ant/lib/ant-javamail.jar | Bin 0 -> 13841 bytes love2dToAPK/tools/tools/ant/lib/ant-javamail.pom | 78 + love2dToAPK/tools/tools/ant/lib/ant-jdepend.jar | Bin 0 -> 13869 bytes love2dToAPK/tools/tools/ant/lib/ant-jdepend.pom | 72 + love2dToAPK/tools/tools/ant/lib/ant-jmf.jar | Bin 0 -> 12316 bytes love2dToAPK/tools/tools/ant/lib/ant-jmf.pom | 65 + love2dToAPK/tools/tools/ant/lib/ant-jsch.jar | Bin 0 -> 47689 bytes love2dToAPK/tools/tools/ant/lib/ant-jsch.pom | 74 + love2dToAPK/tools/tools/ant/lib/ant-junit.jar | Bin 0 -> 118491 bytes love2dToAPK/tools/tools/ant/lib/ant-junit.pom | 101 + love2dToAPK/tools/tools/ant/lib/ant-junit4.jar | Bin 0 -> 13104 bytes love2dToAPK/tools/tools/ant/lib/ant-junit4.pom | 71 + love2dToAPK/tools/tools/ant/lib/ant-launcher.jar | Bin 0 -> 18392 bytes love2dToAPK/tools/tools/ant/lib/ant-launcher.pom | 57 + love2dToAPK/tools/tools/ant/lib/ant-netrexx.jar | Bin 0 -> 16316 bytes love2dToAPK/tools/tools/ant/lib/ant-netrexx.pom | 98 + love2dToAPK/tools/tools/ant/lib/ant-parent.pom | 151 + love2dToAPK/tools/tools/ant/lib/ant-swing.jar | Bin 0 -> 13316 bytes love2dToAPK/tools/tools/ant/lib/ant-swing.pom | 66 + love2dToAPK/tools/tools/ant/lib/ant-testutil.jar | Bin 0 -> 26975 bytes love2dToAPK/tools/tools/ant/lib/ant-testutil.pom | 74 + love2dToAPK/tools/tools/ant/lib/ant.jar | Bin 0 -> 2029794 bytes love2dToAPK/tools/tools/ant/lib/ant.pom | 225 + .../tools/tools/ant/lib/libraries.properties | 65 + love2dToAPK/tools/tools/ant/patch.xml | 48 + love2dToAPK/tools/tools/jdk-win/COPYRIGHT | 69 + love2dToAPK/tools/tools/jdk-win/LICENSE | 1 + love2dToAPK/tools/tools/jdk-win/README.html | 9 + .../jdk-win/THIRDPARTYLICENSEREADME-JAVAFX.txt | 1531 + .../tools/jdk-win/THIRDPARTYLICENSEREADME.txt | 3605 + .../tools/jdk-win/include/classfile_constants.h | 560 + love2dToAPK/tools/tools/jdk-win/include/jawt.h | 299 + .../tools/tools/jdk-win/include/jdwpTransport.h | 254 + love2dToAPK/tools/tools/jdk-win/include/jni.h | 1960 + love2dToAPK/tools/tools/jdk-win/include/jvmti.h | 2534 + .../tools/tools/jdk-win/include/jvmticmlr.h | 115 + .../include/win32/bridge/AccessBridgeCallbacks.h | 76 + .../include/win32/bridge/AccessBridgeCalls.c | 1111 + .../include/win32/bridge/AccessBridgeCalls.h | 686 + .../include/win32/bridge/AccessBridgePackages.h | 2195 + .../tools/tools/jdk-win/include/win32/jawt_md.h | 59 + .../tools/tools/jdk-win/include/win32/jni_md.h | 37 + love2dToAPK/tools/tools/jdk-win/jre/COPYRIGHT | 69 + love2dToAPK/tools/tools/jdk-win/jre/LICENSE | 1 + love2dToAPK/tools/tools/jdk-win/jre/README.txt | 1 + .../jdk-win/jre/THIRDPARTYLICENSEREADME-JAVAFX.txt | 1531 + .../tools/jdk-win/jre/THIRDPARTYLICENSEREADME.txt | 3605 + love2dToAPK/tools/tools/jdk-win/jre/Welcome.html | 28 + .../tools/jdk-win/jre/lib/accessibility.properties | 6 + .../tools/jdk-win/jre/lib/calendars.properties | 60 + .../tools/tools/jdk-win/jre/lib/charsets.jar | Bin 0 -> 3086224 bytes love2dToAPK/tools/tools/jdk-win/jre/lib/classlist | 2378 + .../tools/tools/jdk-win/jre/lib/cmm/CIEXYZ.pf | Bin 0 -> 51236 bytes .../tools/tools/jdk-win/jre/lib/cmm/GRAY.pf | Bin 0 -> 632 bytes .../tools/tools/jdk-win/jre/lib/cmm/LINEAR_RGB.pf | Bin 0 -> 1044 bytes .../tools/tools/jdk-win/jre/lib/cmm/PYCC.pf | Bin 0 -> 274474 bytes .../tools/tools/jdk-win/jre/lib/cmm/sRGB.pf | Bin 0 -> 3144 bytes .../tools/jdk-win/jre/lib/content-types.properties | 276 + .../tools/tools/jdk-win/jre/lib/currency.data | Bin 0 -> 4074 bytes love2dToAPK/tools/tools/jdk-win/jre/lib/deploy.jar | Bin 0 -> 4791488 bytes .../tools/jdk-win/jre/lib/ext/access-bridge.jar | Bin 0 -> 187715 bytes .../tools/tools/jdk-win/jre/lib/ext/cldrdata.jar | Bin 0 -> 3860522 bytes .../tools/tools/jdk-win/jre/lib/ext/dnsns.jar | Bin 0 -> 8286 bytes .../tools/tools/jdk-win/jre/lib/ext/jaccess.jar | Bin 0 -> 44115 bytes .../tools/tools/jdk-win/jre/lib/ext/jfxrt.jar | Bin 0 -> 18131395 bytes .../tools/tools/jdk-win/jre/lib/ext/localedata.jar | Bin 0 -> 2248141 bytes .../tools/tools/jdk-win/jre/lib/ext/meta-index | 71 + .../tools/tools/jdk-win/jre/lib/ext/nashorn.jar | Bin 0 -> 2008813 bytes .../tools/tools/jdk-win/jre/lib/ext/sunec.jar | Bin 0 -> 39773 bytes .../tools/jdk-win/jre/lib/ext/sunjce_provider.jar | Bin 0 -> 278075 bytes .../tools/tools/jdk-win/jre/lib/ext/sunmscapi.jar | Bin 0 -> 32654 bytes .../tools/tools/jdk-win/jre/lib/ext/sunpkcs11.jar | Bin 0 -> 249387 bytes .../tools/tools/jdk-win/jre/lib/ext/zipfs.jar | Bin 0 -> 68837 bytes .../tools/jdk-win/jre/lib/flavormap.properties | 77 + .../tools/tools/jdk-win/jre/lib/fontconfig.bfc | Bin 0 -> 3670 bytes .../jdk-win/jre/lib/fontconfig.properties.src | 300 + .../jre/lib/hijrah-config-umalqura.properties | 369 + .../tools/tools/jdk-win/jre/lib/i386/jvm.cfg | 34 + .../tools/tools/jdk-win/jre/lib/javafx.properties | 1 + love2dToAPK/tools/tools/jdk-win/jre/lib/javaws.jar | Bin 0 -> 920936 bytes love2dToAPK/tools/tools/jdk-win/jre/lib/jce.jar | Bin 0 -> 114708 bytes love2dToAPK/tools/tools/jdk-win/jre/lib/jfr.jar | Bin 0 -> 555272 bytes .../tools/tools/jdk-win/jre/lib/jfr/default.jfc | 556 + .../tools/tools/jdk-win/jre/lib/jfr/profile.jfc | 556 + love2dToAPK/tools/tools/jdk-win/jre/lib/jfxswt.jar | Bin 0 -> 33795 bytes love2dToAPK/tools/tools/jdk-win/jre/lib/jsse.jar | Bin 0 -> 620257 bytes .../tools/tools/jdk-win/jre/lib/jvm.hprof.txt | 86 + .../tools/tools/jdk-win/jre/lib/logging.properties | 59 + .../tools/jdk-win/jre/lib/management-agent.jar | Bin 0 -> 381 bytes .../jdk-win/jre/lib/management/jmxremote.access | 79 + .../jre/lib/management/jmxremote.password.template | 64 + .../jre/lib/management/management.properties | 318 + .../jdk-win/jre/lib/management/snmp.acl.template | 110 + love2dToAPK/tools/tools/jdk-win/jre/lib/meta-index | 92 + .../tools/tools/jdk-win/jre/lib/net.properties | 74 + love2dToAPK/tools/tools/jdk-win/jre/lib/plugin.jar | Bin 0 -> 1922576 bytes .../tools/jdk-win/jre/lib/psfont.properties.ja | 119 + .../tools/jdk-win/jre/lib/psfontj2d.properties | 323 + .../tools/tools/jdk-win/jre/lib/resources.jar | Bin 0 -> 3487757 bytes love2dToAPK/tools/tools/jdk-win/jre/lib/rt.jar | Bin 0 -> 63191979 bytes .../jdk-win/jre/lib/security/US_export_policy.jar | Bin 0 -> 3026 bytes .../tools/tools/jdk-win/jre/lib/security/blacklist | 95 + .../jdk-win/jre/lib/security/blacklisted.certs | 19 + .../tools/tools/jdk-win/jre/lib/security/cacerts | Bin 0 -> 98626 bytes .../tools/jdk-win/jre/lib/security/java.policy | 49 + .../tools/jdk-win/jre/lib/security/java.security | 528 + .../tools/jdk-win/jre/lib/security/javaws.policy | 5 + .../jdk-win/jre/lib/security/local_policy.jar | Bin 0 -> 3527 bytes .../jdk-win/jre/lib/security/trusted.libraries | 0 .../tools/tools/jdk-win/jre/lib/sound.properties | 39 + love2dToAPK/tools/tools/jdk-win/jre/lib/tzdb.dat | Bin 0 -> 102385 bytes love2dToAPK/tools/tools/jdk-win/jre/lib/tzmappings | 202 + love2dToAPK/tools/tools/jdk-win/lib/ant-javafx.jar | Bin 0 -> 1646460 bytes love2dToAPK/tools/tools/jdk-win/lib/ct.sym | Bin 0 -> 17364173 bytes love2dToAPK/tools/tools/jdk-win/lib/dt.jar | Bin 0 -> 163019 bytes love2dToAPK/tools/tools/jdk-win/lib/ir.idl | 778 + love2dToAPK/tools/tools/jdk-win/lib/javafx-mx.jar | Bin 0 -> 36037 bytes love2dToAPK/tools/tools/jdk-win/lib/jawt.lib | Bin 0 -> 1688 bytes love2dToAPK/tools/tools/jdk-win/lib/jconsole.jar | Bin 0 -> 407734 bytes love2dToAPK/tools/tools/jdk-win/lib/jvm.lib | Bin 0 -> 751824 bytes love2dToAPK/tools/tools/jdk-win/lib/orb.idl | 47 + love2dToAPK/tools/tools/jdk-win/lib/packager.jar | Bin 0 -> 4573 bytes love2dToAPK/tools/tools/jdk-win/lib/sa-jdi.jar | Bin 0 -> 2268285 bytes love2dToAPK/tools/tools/jdk-win/lib/tools.jar | Bin 0 -> 18173747 bytes love2dToAPK/tools/tools/jdk-win/release | 6 + .../tools/tools/love-android-sdl2/.classpath | 9 + love2dToAPK/tools/tools/love-android-sdl2/.project | 53 + .../tools/love-android-sdl2/AndroidManifest.xml | 71 + .../tools/tools/love-android-sdl2/README.md | 140 + .../tools/tools/love-android-sdl2/ant.properties | 17 + .../tools/tools/love-android-sdl2/assets/game.love | Bin 0 -> 1512 bytes .../tools/tools/love-android-sdl2/build.properties | 17 + .../tools/tools/love-android-sdl2/build.xml | 93 + .../tools/love-android-sdl2/default.properties | 11 + .../tools/tools/love-android-sdl2/gen/R.java.d | 4 + .../gen/love/to/android/BuildConfig.java | 6 + .../love-android-sdl2/gen/love/to/android/R.java | 16 + .../gen/love/to/android1219203756/BuildConfig.java | 6 + .../gen/love/to/android1219203756/R.java | 16 + .../gen/love/to/android1220074642/BuildConfig.java | 6 + .../gen/love/to/android1220074642/R.java | 16 + .../libs/armeabi-v7a/libgnustl_shared.so | Bin 0 -> 804492 bytes .../love-android-sdl2/libs/armeabi-v7a/liblove.so | Bin 0 -> 3309304 bytes .../libs/armeabi-v7a/libmpg123.so | Bin 0 -> 120888 bytes .../libs/armeabi-v7a/libopenal.so | Bin 0 -> 251528 bytes .../libs/armeabi/libgnustl_shared.so | Bin 0 -> 808580 bytes .../love-android-sdl2/libs/armeabi/liblove.so | Bin 0 -> 3464936 bytes .../love-android-sdl2/libs/armeabi/libmpg123.so | Bin 0 -> 141348 bytes .../love-android-sdl2/libs/armeabi/libopenal.so | Bin 0 -> 272000 bytes .../love-android-sdl2/original/AndroidManifest.xml | 71 + .../original/love/to/android/LtaActivity.java | 4 + .../tools/love-android-sdl2/project.properties | 14 + .../res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 10129 bytes .../src/love/to/android/LtaActivity.java | 4 + .../src/org/libsdl/app/SDLActivity.java | 1676 + .../src/org/love2d/android/DownloadActivity.java | 24 + .../src/org/love2d/android/DownloadService.java | 96 + .../src/org/love2d/android/GameActivity.java | 253 + love2dToAPK/tools/tools/love-old-win/DevIL.dll | Bin 0 -> 1024512 bytes love2dToAPK/tools/tools/love-old-win/OpenAL32.dll | Bin 0 -> 316928 bytes love2dToAPK/tools/tools/love-old-win/SDL2.dll | Bin 0 -> 814592 bytes love2dToAPK/tools/tools/love-old-win/changes.txt | 831 + love2dToAPK/tools/tools/love-old-win/game.ico | Bin 0 -> 33093 bytes love2dToAPK/tools/tools/love-old-win/license.txt | 979 + love2dToAPK/tools/tools/love-old-win/love.dll | Bin 0 -> 2984448 bytes love2dToAPK/tools/tools/love-old-win/love.exe | Bin 0 -> 47616 bytes love2dToAPK/tools/tools/love-old-win/love.ico | Bin 0 -> 35492 bytes love2dToAPK/tools/tools/love-old-win/lua51.dll | Bin 0 -> 348672 bytes love2dToAPK/tools/tools/love-old-win/mpg123.dll | Bin 0 -> 138752 bytes love2dToAPK/tools/tools/love-old-win/msvcp120.dll | Bin 0 -> 455328 bytes love2dToAPK/tools/tools/love-old-win/msvcr120.dll | Bin 0 -> 970912 bytes love2dToAPK/tools/tools/love-old-win/readme.txt | 74 + love2dToAPK/tools/tools/love-win/OpenAL32.dll | Bin 0 -> 390656 bytes love2dToAPK/tools/tools/love-win/SDL2.dll | Bin 0 -> 808448 bytes love2dToAPK/tools/tools/love-win/changes.txt | 1031 + love2dToAPK/tools/tools/love-win/game.ico | Bin 0 -> 370070 bytes love2dToAPK/tools/tools/love-win/license.txt | 977 + love2dToAPK/tools/tools/love-win/love.dll | Bin 0 -> 2379776 bytes love2dToAPK/tools/tools/love-win/love.exe | Bin 0 -> 380928 bytes love2dToAPK/tools/tools/love-win/love.ico | Bin 0 -> 370070 bytes love2dToAPK/tools/tools/love-win/lua51.dll | Bin 0 -> 349184 bytes love2dToAPK/tools/tools/love-win/mpg123.dll | Bin 0 -> 143360 bytes love2dToAPK/tools/tools/love-win/msvcp120.dll | Bin 0 -> 455328 bytes love2dToAPK/tools/tools/love-win/msvcr120.dll | Bin 0 -> 970912 bytes love2dToAPK/tools/tools/love-win/readme.txt | 96 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/ABOUT-NLS | 1111 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/AUTHORS | 5 + .../contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/BUGS | 133 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/COPYING | 676 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/ChangeLog | 3185 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/INSTALL | 236 + .../contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/NEWS | 502 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/README | 13 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/README-alpha | 8 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/README.boot | 23 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/THANKS | 54 + .../sed/4.2.1/sed-4.2.1/sed-4.2.1-src/po/ChangeLog | 53 + .../sed-4.2.1-src/testsuite/bug-regex10.c | 65 + .../sed-4.2.1-src/testsuite/bug-regex11.c | 143 + .../sed-4.2.1-src/testsuite/bug-regex12.c | 81 + .../sed-4.2.1-src/testsuite/bug-regex13.c | 111 + .../sed-4.2.1-src/testsuite/bug-regex14.c | 62 + .../sed-4.2.1-src/testsuite/bug-regex15.c | 53 + .../sed-4.2.1-src/testsuite/bug-regex16.c | 39 + .../sed-4.2.1-src/testsuite/bug-regex21.c | 53 + .../sed-4.2.1-src/testsuite/bug-regex27.c | 65 + .../sed-4.2.1-src/testsuite/bug-regex28.c | 76 + .../sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex7.c | 96 + .../sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex8.c | 88 + .../sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex9.c | 75 + .../tools/tools/zbstudio-old-win/CHANGELOG.md | 2364 + love2dToAPK/tools/tools/zbstudio-old-win/LICENSE | 237 + love2dToAPK/tools/tools/zbstudio-old-win/README.md | 113 + .../tools/tools/zbstudio-old-win/api/cg/stdlib.lua | 205 + .../tools/tools/zbstudio-old-win/api/glsl/std.lua | 277 + .../tools/zbstudio-old-win/api/lua/baselib.lua | 1238 + .../tools/zbstudio-old-win/api/lua/love2d.lua | 6566 ++ .../tools/zbstudio-old-win/api/lua/luajit2.lua | 52 + .../tools/zbstudio-old-win/api/lua/wxwidgets.lua | 24 + .../tools/zbstudio-old-win/api/opencl/std.lua | 278 + .../tools/tools/zbstudio-old-win/cfg/estrela.lua | 19 + .../tools/tools/zbstudio-old-win/cfg/i18n/cn.lua | 344 + .../tools/tools/zbstudio-old-win/cfg/i18n/de.lua | 345 + .../tools/tools/zbstudio-old-win/cfg/i18n/en.lua | 7 + .../tools/tools/zbstudio-old-win/cfg/i18n/eo.lua | 346 + .../tools/tools/zbstudio-old-win/cfg/i18n/es.lua | 346 + .../tools/tools/zbstudio-old-win/cfg/i18n/fr.lua | 345 + .../tools/tools/zbstudio-old-win/cfg/i18n/it.lua | 345 + .../tools/zbstudio-old-win/cfg/i18n/pt-br.lua | 347 + .../tools/tools/zbstudio-old-win/cfg/i18n/ru.lua | 345 + .../tools/zbstudio-old-win/cfg/scheme-picker.lua | 28 + .../tools/tools/zbstudio-old-win/cfg/tomorrow.lua | 311 + .../tools/zbstudio-old-win/cfg/user-sample.lua | 170 + .../tools/tools/zbstudio-old-win/cfg/user.lua | 56 + .../tools/zbstudio-old-win/cfg/xcode-keys.lua | 73 + .../tools/zbstudio-old-win/interpreters/love2d.lua | 61 + .../zbstudio-old-win/interpreters/luabase.lua | 101 + .../tools/zbstudio-old-win/interpreters/luadeb.lua | 2 + .../zbstudio-old-win/interpreters/luadeb52.lua | 2 + .../zbstudio-old-win/interpreters/luadeb53.lua | 4 + .../tools/zbstudio-old-win/lualibs/copas/copas.lua | 636 + .../zbstudio-old-win/lualibs/coxpcall/coxpcall.lua | 68 + .../tools/zbstudio-old-win/lualibs/dist/config.lua | 112 + .../zbstudio-old-win/lualibs/dist/constraints.lua | 271 + .../zbstudio-old-win/lualibs/dist/depends.lua | 770 + .../tools/zbstudio-old-win/lualibs/dist/git.lua | 306 + .../tools/zbstudio-old-win/lualibs/dist/init.lua | 349 + .../tools/zbstudio-old-win/lualibs/dist/logger.lua | 64 + .../zbstudio-old-win/lualibs/dist/manifest.lua | 248 + .../zbstudio-old-win/lualibs/dist/package.lua | 596 + .../tools/zbstudio-old-win/lualibs/dist/sys.lua | 386 + .../tools/zbstudio-old-win/lualibs/dist/utils.lua | 151 + .../tools/tools/zbstudio-old-win/lualibs/git.lua | 5 + .../tools/zbstudio-old-win/lualibs/git/objects.lua | 121 + .../tools/zbstudio-old-win/lualibs/git/pack.lua | 316 + .../zbstudio-old-win/lualibs/git/protocol.lua | 188 + .../tools/zbstudio-old-win/lualibs/git/repo.lua | 283 + .../tools/zbstudio-old-win/lualibs/git/util.lua | 233 + .../tools/tools/zbstudio-old-win/lualibs/ltn12.lua | 298 + .../zbstudio-old-win/lualibs/lua_lexer_loose.lua | 212 + .../zbstudio-old-win/lualibs/lua_parser_loose.lua | 337 + .../tools/zbstudio-old-win/lualibs/luadist.lua | 746 + .../zbstudio-old-win/lualibs/luainspect/ast.lua | 915 + .../lualibs/luainspect/compat_env.lua | 390 + .../zbstudio-old-win/lualibs/luainspect/dump.lua | 90 + .../lualibs/luainspect/globals.lua | 222 + .../zbstudio-old-win/lualibs/luainspect/init.lua | 1454 + .../lualibs/luainspect/signatures.lua | 433 + .../lualibs/luainspect/typecheck.lua | 40 + .../zbstudio-old-win/lualibs/luainspect/types.lua | 130 + .../zbstudio-old-win/lualibs/metalua/compiler.lua | 162 + .../lualibs/metalua/compiler/parser.lua | 42 + .../metalua/compiler/parser/annot/generator.lua | 48 + .../metalua/compiler/parser/annot/grammar.lua | 112 + .../lualibs/metalua/compiler/parser/common.lua | 27 + .../lualibs/metalua/compiler/parser/expr.lua | 213 + .../lualibs/metalua/compiler/parser/ext.lua | 96 + .../lualibs/metalua/compiler/parser/lexer.lua | 44 + .../lualibs/metalua/compiler/parser/meta.lua | 138 + .../lualibs/metalua/compiler/parser/misc.lua | 147 + .../lualibs/metalua/compiler/parser/stat.lua | 283 + .../lualibs/metalua/compiler/parser/table.lua | 77 + .../lualibs/metalua/grammar/generator.lua | 832 + .../lualibs/metalua/grammar/lexer.lua | 678 + .../zbstudio-old-win/lualibs/metalua/pprint.lua | 295 + .../tools/tools/zbstudio-old-win/lualibs/mime.lua | 90 + .../zbstudio-old-win/lualibs/mobdebug/mobdebug.lua | 1609 + .../tools/tools/zbstudio-old-win/lualibs/sha2.lua | 239 + .../tools/zbstudio-old-win/lualibs/socket.lua | 165 + .../tools/zbstudio-old-win/lualibs/socket/ftp.lua | 285 + .../zbstudio-old-win/lualibs/socket/headers.lua | 104 + .../tools/zbstudio-old-win/lualibs/socket/http.lua | 354 + .../tools/zbstudio-old-win/lualibs/socket/smtp.lua | 256 + .../tools/zbstudio-old-win/lualibs/socket/tp.lua | 126 + .../tools/zbstudio-old-win/lualibs/socket/url.lua | 307 + .../tools/tools/zbstudio-old-win/lualibs/ssl.lua | 93 + .../tools/zbstudio-old-win/lualibs/ssl/https.lua | 138 + .../tools/zbstudio-old-win/lualibs/testwell.lua | 315 + .../tools/tools/zbstudio-old-win/spec/lua.lua | 284 + .../tools/tools/zbstudio-old-win/spec/text.lua | 9 + .../tools/tools/zbstudio-old-win/src/defs.lua | 332 + .../zbstudio-old-win/src/editor/autocomplete.lua | 652 + .../zbstudio-old-win/src/editor/commandbar.lua | 359 + .../tools/zbstudio-old-win/src/editor/commands.lua | 1054 + .../tools/zbstudio-old-win/src/editor/debugger.lua | 1696 + .../tools/zbstudio-old-win/src/editor/editor.lua | 1619 + .../tools/zbstudio-old-win/src/editor/filetree.lua | 903 + .../zbstudio-old-win/src/editor/findreplace.lua | 1275 + .../tools/zbstudio-old-win/src/editor/gui.lua | 567 + .../tools/zbstudio-old-win/src/editor/ids.lua | 190 + .../tools/zbstudio-old-win/src/editor/inspect.lua | 243 + .../zbstudio-old-win/src/editor/iofilters.lua | 71 + .../tools/zbstudio-old-win/src/editor/keymap.lua | 136 + .../tools/zbstudio-old-win/src/editor/markers.lua | 247 + .../tools/zbstudio-old-win/src/editor/markup.lua | 214 + .../zbstudio-old-win/src/editor/menu_edit.lua | 390 + .../zbstudio-old-win/src/editor/menu_file.lua | 262 + .../zbstudio-old-win/src/editor/menu_help.lua | 118 + .../zbstudio-old-win/src/editor/menu_project.lua | 474 + .../zbstudio-old-win/src/editor/menu_search.lua | 420 + .../zbstudio-old-win/src/editor/menu_tools.lua | 111 + .../zbstudio-old-win/src/editor/menu_view.lua | 113 + .../tools/zbstudio-old-win/src/editor/outline.lua | 679 + .../tools/zbstudio-old-win/src/editor/output.lua | 498 + .../tools/zbstudio-old-win/src/editor/package.lua | 735 + .../tools/zbstudio-old-win/src/editor/print.lua | 195 + .../tools/zbstudio-old-win/src/editor/proto.lua | 68 + .../tools/zbstudio-old-win/src/editor/settings.lua | 593 + .../tools/zbstudio-old-win/src/editor/shellbox.lua | 574 + .../zbstudio-old-win/src/editor/singleinstance.lua | 98 + .../tools/zbstudio-old-win/src/editor/style.lua | 441 + .../tools/zbstudio-old-win/src/editor/toolbar.lua | 55 + .../tools/tools/zbstudio-old-win/src/main.lua | 774 + .../tools/tools/zbstudio-old-win/src/util.lua | 645 + .../tools/tools/zbstudio-old-win/src/version.lua | 1 + .../tools/tools/zbstudio-old-win/tools/cg.lua | 537 + .../tools/tools/zbstudio-old-win/tools/clcc.lua | 67 + .../tools/zbstudio-old-win/tools/cstringify.lua | 21 + .../tools/tools/zbstudio-old-win/tools/dx.lua | 157 + .../tools/zbstudio-old-win/tools/ffitoapi.lua | 313 + .../tools/tools/zbstudio-old-win/tools/glslc.lua | 470 + .../tools/zbstudio-old-win/tools/perforce_edit.lua | 14 + .../zbstudio-old-win/tools/perforce_revert.lua | 14 + .../tools/tools/zbstudio-old-win/zbstudio.exe | Bin 0 -> 51296 bytes .../tools/tools/zbstudio-old-win/zbstudio/app.lua | 53 + .../tools/zbstudio-old-win/zbstudio/config.lua | 38 + .../zbstudio/res/16/BOOKMARK-TOGGLE.png | Bin 0 -> 884 bytes .../zbstudio/res/16/DEBUG-BREAK.png | Bin 0 -> 374 bytes .../zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png | Bin 0 -> 702 bytes .../zbstudio/res/16/DEBUG-CALLSTACK.png | Bin 0 -> 500 bytes .../zbstudio/res/16/DEBUG-DETACH.png | Bin 0 -> 583 bytes .../zbstudio/res/16/DEBUG-RUN-TO.png | Bin 0 -> 329 bytes .../zbstudio/res/16/DEBUG-START.png | Bin 0 -> 259 bytes .../zbstudio/res/16/DEBUG-STEP-INTO.png | Bin 0 -> 335 bytes .../zbstudio/res/16/DEBUG-STEP-OUT.png | Bin 0 -> 356 bytes .../zbstudio/res/16/DEBUG-STEP-OVER.png | Bin 0 -> 362 bytes .../zbstudio/res/16/DEBUG-STOP.png | Bin 0 -> 594 bytes .../zbstudio/res/16/DEBUG-WATCH.png | Bin 0 -> 786 bytes .../zbstudio/res/16/DIR-SETUP-FILE.png | Bin 0 -> 778 bytes .../zbstudio-old-win/zbstudio/res/16/DIR-SETUP.png | Bin 0 -> 738 bytes .../zbstudio/res/16/FILE-KNOWN.png | Bin 0 -> 623 bytes .../zbstudio-old-win/zbstudio/res/16/FILE-NEW.png | Bin 0 -> 730 bytes .../zbstudio/res/16/FILE-NORMAL-START.png | Bin 0 -> 743 bytes .../zbstudio/res/16/FILE-NORMAL.png | Bin 0 -> 652 bytes .../zbstudio-old-win/zbstudio/res/16/FILE-OPEN.png | Bin 0 -> 602 bytes .../zbstudio/res/16/FILE-SAVE-ALL.png | Bin 0 -> 1322 bytes .../zbstudio-old-win/zbstudio/res/16/FILE-SAVE.png | Bin 0 -> 1346 bytes .../zbstudio/res/16/FIND-AND-REPLACE.png | Bin 0 -> 451 bytes .../zbstudio/res/16/FIND-IN-FILES.png | Bin 0 -> 671 bytes .../zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png | Bin 0 -> 402 bytes .../zbstudio/res/16/FIND-OPT-CONTEXT.png | Bin 0 -> 306 bytes .../zbstudio/res/16/FIND-OPT-DOWN.png | Bin 0 -> 340 bytes .../zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png | Bin 0 -> 445 bytes .../zbstudio/res/16/FIND-OPT-REGEX.png | Bin 0 -> 387 bytes .../zbstudio/res/16/FIND-OPT-SELECTION.png | Bin 0 -> 229 bytes .../zbstudio/res/16/FIND-OPT-SETDIR.png | Bin 0 -> 716 bytes .../zbstudio/res/16/FIND-OPT-SUBDIR.png | Bin 0 -> 742 bytes .../zbstudio/res/16/FIND-OPT-WORD.png | Bin 0 -> 398 bytes .../zbstudio/res/16/FIND-OPT-WRAP-AROUND.png | Bin 0 -> 415 bytes .../zbstudio/res/16/FIND-REPLACE-NEXT.png | Bin 0 -> 520 bytes .../zbstudio-old-win/zbstudio/res/16/FIND.png | Bin 0 -> 662 bytes .../zbstudio/res/16/FOLDER-MAPPED.png | Bin 0 -> 656 bytes .../zbstudio-old-win/zbstudio/res/16/FOLDER.png | Bin 0 -> 615 bytes .../tools/zbstudio-old-win/zbstudio/res/16/LICENSE | 28 + .../zbstudio-old-win/zbstudio/res/16/RUN-NOW.png | Bin 0 -> 292 bytes .../tools/zbstudio-old-win/zbstudio/res/16/RUN.png | Bin 0 -> 271 bytes .../zbstudio/res/16/VALUE-ACALL.png | Bin 0 -> 371 bytes .../zbstudio/res/16/VALUE-CALL.png | Bin 0 -> 717 bytes .../zbstudio/res/16/VALUE-GCALL.png | Bin 0 -> 374 bytes .../zbstudio/res/16/VALUE-LCALL.png | Bin 0 -> 433 bytes .../zbstudio/res/16/VALUE-LOCAL.png | Bin 0 -> 698 bytes .../zbstudio/res/16/VALUE-SCALL.png | Bin 0 -> 428 bytes .../zbstudio-old-win/zbstudio/res/16/VALUE-UP.png | Bin 0 -> 753 bytes .../zbstudio/res/24/BOOKMARK-TOGGLE.png | Bin 0 -> 1087 bytes .../zbstudio/res/24/DEBUG-BREAK.png | Bin 0 -> 473 bytes .../zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png | Bin 0 -> 1457 bytes .../zbstudio/res/24/DEBUG-CALLSTACK.png | Bin 0 -> 566 bytes .../zbstudio/res/24/DEBUG-DETACH.png | Bin 0 -> 755 bytes .../zbstudio/res/24/DEBUG-RUN-TO.png | Bin 0 -> 400 bytes .../zbstudio/res/24/DEBUG-START.png | Bin 0 -> 369 bytes .../zbstudio/res/24/DEBUG-STEP-INTO.png | Bin 0 -> 451 bytes .../zbstudio/res/24/DEBUG-STEP-OUT.png | Bin 0 -> 450 bytes .../zbstudio/res/24/DEBUG-STEP-OVER.png | Bin 0 -> 484 bytes .../zbstudio/res/24/DEBUG-STOP.png | Bin 0 -> 799 bytes .../zbstudio/res/24/DEBUG-WATCH.png | Bin 0 -> 1008 bytes .../zbstudio/res/24/DIR-SETUP-FILE.png | Bin 0 -> 1365 bytes .../zbstudio-old-win/zbstudio/res/24/DIR-SETUP.png | Bin 0 -> 1412 bytes .../zbstudio-old-win/zbstudio/res/24/FILE-NEW.png | Bin 0 -> 821 bytes .../zbstudio-old-win/zbstudio/res/24/FILE-OPEN.png | Bin 0 -> 780 bytes .../zbstudio/res/24/FILE-SAVE-ALL.png | Bin 0 -> 622 bytes .../zbstudio-old-win/zbstudio/res/24/FILE-SAVE.png | Bin 0 -> 1165 bytes .../zbstudio/res/24/FIND-AND-REPLACE.png | Bin 0 -> 495 bytes .../zbstudio/res/24/FIND-IN-FILES.png | Bin 0 -> 1173 bytes .../zbstudio-old-win/zbstudio/res/24/FIND.png | Bin 0 -> 775 bytes .../tools/zbstudio-old-win/zbstudio/res/24/LICENSE | 27 + .../zbstudio-old-win/zbstudio/res/24/RUN-NOW.png | Bin 0 -> 384 bytes .../tools/zbstudio-old-win/zbstudio/res/24/RUN.png | Bin 0 -> 358 bytes .../zbstudio-old-win/zbstudio/res/estrela.png | Bin 0 -> 6252 bytes .../zbstudio-old-win/zbstudio/res/zbstudio.ico | Bin 0 -> 32038 bytes .../zbstudio-old-win/zbstudio/res/zerobrane.png | Bin 0 -> 10255 bytes love2dToAPK/tools/tools/zbstudio-win/CHANGELOG.md | 2364 + love2dToAPK/tools/tools/zbstudio-win/LICENSE | 237 + love2dToAPK/tools/tools/zbstudio-win/README.md | 113 + .../tools/tools/zbstudio-win/api/cg/stdlib.lua | 205 + .../tools/tools/zbstudio-win/api/glsl/std.lua | 277 + .../tools/tools/zbstudio-win/api/lua/baselib.lua | 1238 + .../tools/tools/zbstudio-win/api/lua/love2d.lua | 6566 ++ .../tools/tools/zbstudio-win/api/lua/luajit2.lua | 52 + .../tools/tools/zbstudio-win/api/lua/wxwidgets.lua | 24 + .../tools/tools/zbstudio-win/api/opencl/std.lua | 278 + .../tools/tools/zbstudio-win/cfg/estrela.lua | 19 + .../tools/tools/zbstudio-win/cfg/i18n/cn.lua | 344 + .../tools/tools/zbstudio-win/cfg/i18n/de.lua | 345 + .../tools/tools/zbstudio-win/cfg/i18n/en.lua | 7 + .../tools/tools/zbstudio-win/cfg/i18n/eo.lua | 346 + .../tools/tools/zbstudio-win/cfg/i18n/es.lua | 346 + .../tools/tools/zbstudio-win/cfg/i18n/fr.lua | 345 + .../tools/tools/zbstudio-win/cfg/i18n/it.lua | 345 + .../tools/tools/zbstudio-win/cfg/i18n/pt-br.lua | 347 + .../tools/tools/zbstudio-win/cfg/i18n/ru.lua | 345 + .../tools/tools/zbstudio-win/cfg/scheme-picker.lua | 28 + .../tools/tools/zbstudio-win/cfg/tomorrow.lua | 311 + .../tools/tools/zbstudio-win/cfg/user-sample.lua | 170 + love2dToAPK/tools/tools/zbstudio-win/cfg/user.lua | 56 + .../tools/tools/zbstudio-win/cfg/xcode-keys.lua | 73 + .../tools/zbstudio-win/interpreters/love2d.lua | 61 + .../tools/zbstudio-win/interpreters/luabase.lua | 101 + .../tools/zbstudio-win/interpreters/luadeb.lua | 2 + .../tools/zbstudio-win/interpreters/luadeb52.lua | 2 + .../tools/zbstudio-win/interpreters/luadeb53.lua | 4 + .../tools/zbstudio-win/lualibs/copas/copas.lua | 636 + .../zbstudio-win/lualibs/coxpcall/coxpcall.lua | 68 + .../tools/zbstudio-win/lualibs/dist/config.lua | 112 + .../zbstudio-win/lualibs/dist/constraints.lua | 271 + .../tools/zbstudio-win/lualibs/dist/depends.lua | 770 + .../tools/tools/zbstudio-win/lualibs/dist/git.lua | 306 + .../tools/tools/zbstudio-win/lualibs/dist/init.lua | 349 + .../tools/zbstudio-win/lualibs/dist/logger.lua | 64 + .../tools/zbstudio-win/lualibs/dist/manifest.lua | 248 + .../tools/zbstudio-win/lualibs/dist/package.lua | 596 + .../tools/tools/zbstudio-win/lualibs/dist/sys.lua | 386 + .../tools/zbstudio-win/lualibs/dist/utils.lua | 151 + .../tools/tools/zbstudio-win/lualibs/git.lua | 5 + .../tools/zbstudio-win/lualibs/git/objects.lua | 121 + .../tools/tools/zbstudio-win/lualibs/git/pack.lua | 316 + .../tools/zbstudio-win/lualibs/git/protocol.lua | 188 + .../tools/tools/zbstudio-win/lualibs/git/repo.lua | 283 + .../tools/tools/zbstudio-win/lualibs/git/util.lua | 233 + .../tools/tools/zbstudio-win/lualibs/ltn12.lua | 298 + .../tools/zbstudio-win/lualibs/lua_lexer_loose.lua | 212 + .../zbstudio-win/lualibs/lua_parser_loose.lua | 337 + .../tools/tools/zbstudio-win/lualibs/luadist.lua | 746 + .../tools/zbstudio-win/lualibs/luainspect/ast.lua | 915 + .../zbstudio-win/lualibs/luainspect/compat_env.lua | 390 + .../tools/zbstudio-win/lualibs/luainspect/dump.lua | 90 + .../zbstudio-win/lualibs/luainspect/globals.lua | 222 + .../tools/zbstudio-win/lualibs/luainspect/init.lua | 1454 + .../zbstudio-win/lualibs/luainspect/signatures.lua | 433 + .../zbstudio-win/lualibs/luainspect/typecheck.lua | 40 + .../zbstudio-win/lualibs/luainspect/types.lua | 130 + .../zbstudio-win/lualibs/metalua/compiler.lua | 162 + .../lualibs/metalua/compiler/parser.lua | 42 + .../metalua/compiler/parser/annot/generator.lua | 48 + .../metalua/compiler/parser/annot/grammar.lua | 112 + .../lualibs/metalua/compiler/parser/common.lua | 27 + .../lualibs/metalua/compiler/parser/expr.lua | 213 + .../lualibs/metalua/compiler/parser/ext.lua | 96 + .../lualibs/metalua/compiler/parser/lexer.lua | 44 + .../lualibs/metalua/compiler/parser/meta.lua | 138 + .../lualibs/metalua/compiler/parser/misc.lua | 147 + .../lualibs/metalua/compiler/parser/stat.lua | 283 + .../lualibs/metalua/compiler/parser/table.lua | 77 + .../lualibs/metalua/grammar/generator.lua | 832 + .../zbstudio-win/lualibs/metalua/grammar/lexer.lua | 678 + .../tools/zbstudio-win/lualibs/metalua/pprint.lua | 295 + .../tools/tools/zbstudio-win/lualibs/mime.lua | 90 + .../zbstudio-win/lualibs/mobdebug/mobdebug.lua | 1609 + .../tools/tools/zbstudio-win/lualibs/sha2.lua | 239 + .../tools/tools/zbstudio-win/lualibs/socket.lua | 165 + .../tools/zbstudio-win/lualibs/socket/ftp.lua | 285 + .../tools/zbstudio-win/lualibs/socket/headers.lua | 104 + .../tools/zbstudio-win/lualibs/socket/http.lua | 354 + .../tools/zbstudio-win/lualibs/socket/smtp.lua | 256 + .../tools/tools/zbstudio-win/lualibs/socket/tp.lua | 126 + .../tools/zbstudio-win/lualibs/socket/url.lua | 307 + .../tools/tools/zbstudio-win/lualibs/ssl.lua | 93 + .../tools/tools/zbstudio-win/lualibs/ssl/https.lua | 138 + .../tools/tools/zbstudio-win/lualibs/testwell.lua | 315 + love2dToAPK/tools/tools/zbstudio-win/spec/lua.lua | 284 + love2dToAPK/tools/tools/zbstudio-win/spec/text.lua | 9 + love2dToAPK/tools/tools/zbstudio-win/src/defs.lua | 332 + .../tools/zbstudio-win/src/editor/autocomplete.lua | 652 + .../tools/zbstudio-win/src/editor/commandbar.lua | 359 + .../tools/zbstudio-win/src/editor/commands.lua | 1054 + .../tools/zbstudio-win/src/editor/debugger.lua | 1696 + .../tools/tools/zbstudio-win/src/editor/editor.lua | 1619 + .../tools/zbstudio-win/src/editor/filetree.lua | 903 + .../tools/zbstudio-win/src/editor/findreplace.lua | 1275 + .../tools/tools/zbstudio-win/src/editor/gui.lua | 567 + .../tools/tools/zbstudio-win/src/editor/ids.lua | 190 + .../tools/zbstudio-win/src/editor/inspect.lua | 243 + .../tools/zbstudio-win/src/editor/iofilters.lua | 71 + .../tools/tools/zbstudio-win/src/editor/keymap.lua | 136 + .../tools/zbstudio-win/src/editor/markers.lua | 247 + .../tools/tools/zbstudio-win/src/editor/markup.lua | 214 + .../tools/zbstudio-win/src/editor/menu_edit.lua | 390 + .../tools/zbstudio-win/src/editor/menu_file.lua | 262 + .../tools/zbstudio-win/src/editor/menu_help.lua | 118 + .../tools/zbstudio-win/src/editor/menu_project.lua | 474 + .../tools/zbstudio-win/src/editor/menu_search.lua | 420 + .../tools/zbstudio-win/src/editor/menu_tools.lua | 111 + .../tools/zbstudio-win/src/editor/menu_view.lua | 113 + .../tools/zbstudio-win/src/editor/outline.lua | 679 + .../tools/tools/zbstudio-win/src/editor/output.lua | 498 + .../tools/zbstudio-win/src/editor/package.lua | 735 + .../tools/tools/zbstudio-win/src/editor/print.lua | 195 + .../tools/tools/zbstudio-win/src/editor/proto.lua | 68 + .../tools/zbstudio-win/src/editor/settings.lua | 593 + .../tools/zbstudio-win/src/editor/shellbox.lua | 574 + .../zbstudio-win/src/editor/singleinstance.lua | 98 + .../tools/tools/zbstudio-win/src/editor/style.lua | 441 + .../tools/zbstudio-win/src/editor/toolbar.lua | 55 + love2dToAPK/tools/tools/zbstudio-win/src/main.lua | 774 + love2dToAPK/tools/tools/zbstudio-win/src/util.lua | 645 + .../tools/tools/zbstudio-win/src/version.lua | 1 + love2dToAPK/tools/tools/zbstudio-win/tools/cg.lua | 537 + .../tools/tools/zbstudio-win/tools/clcc.lua | 67 + .../tools/tools/zbstudio-win/tools/cstringify.lua | 21 + love2dToAPK/tools/tools/zbstudio-win/tools/dx.lua | 157 + .../tools/tools/zbstudio-win/tools/ffitoapi.lua | 313 + .../tools/tools/zbstudio-win/tools/glslc.lua | 470 + .../tools/zbstudio-win/tools/perforce_edit.lua | 14 + .../tools/zbstudio-win/tools/perforce_revert.lua | 14 + love2dToAPK/tools/tools/zbstudio-win/zbstudio.exe | Bin 0 -> 51296 bytes .../tools/tools/zbstudio-win/zbstudio/app.lua | 53 + .../tools/tools/zbstudio-win/zbstudio/config.lua | 38 + .../zbstudio/res/16/BOOKMARK-TOGGLE.png | Bin 0 -> 884 bytes .../zbstudio-win/zbstudio/res/16/DEBUG-BREAK.png | Bin 0 -> 374 bytes .../zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png | Bin 0 -> 702 bytes .../zbstudio/res/16/DEBUG-CALLSTACK.png | Bin 0 -> 500 bytes .../zbstudio-win/zbstudio/res/16/DEBUG-DETACH.png | Bin 0 -> 583 bytes .../zbstudio-win/zbstudio/res/16/DEBUG-RUN-TO.png | Bin 0 -> 329 bytes .../zbstudio-win/zbstudio/res/16/DEBUG-START.png | Bin 0 -> 259 bytes .../zbstudio/res/16/DEBUG-STEP-INTO.png | Bin 0 -> 335 bytes .../zbstudio/res/16/DEBUG-STEP-OUT.png | Bin 0 -> 356 bytes .../zbstudio/res/16/DEBUG-STEP-OVER.png | Bin 0 -> 362 bytes .../zbstudio-win/zbstudio/res/16/DEBUG-STOP.png | Bin 0 -> 594 bytes .../zbstudio-win/zbstudio/res/16/DEBUG-WATCH.png | Bin 0 -> 786 bytes .../zbstudio/res/16/DIR-SETUP-FILE.png | Bin 0 -> 778 bytes .../zbstudio-win/zbstudio/res/16/DIR-SETUP.png | Bin 0 -> 738 bytes .../zbstudio-win/zbstudio/res/16/FILE-KNOWN.png | Bin 0 -> 623 bytes .../zbstudio-win/zbstudio/res/16/FILE-NEW.png | Bin 0 -> 730 bytes .../zbstudio/res/16/FILE-NORMAL-START.png | Bin 0 -> 743 bytes .../zbstudio-win/zbstudio/res/16/FILE-NORMAL.png | Bin 0 -> 652 bytes .../zbstudio-win/zbstudio/res/16/FILE-OPEN.png | Bin 0 -> 602 bytes .../zbstudio-win/zbstudio/res/16/FILE-SAVE-ALL.png | Bin 0 -> 1322 bytes .../zbstudio-win/zbstudio/res/16/FILE-SAVE.png | Bin 0 -> 1346 bytes .../zbstudio/res/16/FIND-AND-REPLACE.png | Bin 0 -> 451 bytes .../zbstudio-win/zbstudio/res/16/FIND-IN-FILES.png | Bin 0 -> 671 bytes .../zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png | Bin 0 -> 402 bytes .../zbstudio/res/16/FIND-OPT-CONTEXT.png | Bin 0 -> 306 bytes .../zbstudio-win/zbstudio/res/16/FIND-OPT-DOWN.png | Bin 0 -> 340 bytes .../zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png | Bin 0 -> 445 bytes .../zbstudio/res/16/FIND-OPT-REGEX.png | Bin 0 -> 387 bytes .../zbstudio/res/16/FIND-OPT-SELECTION.png | Bin 0 -> 229 bytes .../zbstudio/res/16/FIND-OPT-SETDIR.png | Bin 0 -> 716 bytes .../zbstudio/res/16/FIND-OPT-SUBDIR.png | Bin 0 -> 742 bytes .../zbstudio-win/zbstudio/res/16/FIND-OPT-WORD.png | Bin 0 -> 398 bytes .../zbstudio/res/16/FIND-OPT-WRAP-AROUND.png | Bin 0 -> 415 bytes .../zbstudio/res/16/FIND-REPLACE-NEXT.png | Bin 0 -> 520 bytes .../tools/zbstudio-win/zbstudio/res/16/FIND.png | Bin 0 -> 662 bytes .../zbstudio-win/zbstudio/res/16/FOLDER-MAPPED.png | Bin 0 -> 656 bytes .../tools/zbstudio-win/zbstudio/res/16/FOLDER.png | Bin 0 -> 615 bytes .../tools/zbstudio-win/zbstudio/res/16/LICENSE | 28 + .../tools/zbstudio-win/zbstudio/res/16/RUN-NOW.png | Bin 0 -> 292 bytes .../tools/zbstudio-win/zbstudio/res/16/RUN.png | Bin 0 -> 271 bytes .../zbstudio-win/zbstudio/res/16/VALUE-ACALL.png | Bin 0 -> 371 bytes .../zbstudio-win/zbstudio/res/16/VALUE-CALL.png | Bin 0 -> 717 bytes .../zbstudio-win/zbstudio/res/16/VALUE-GCALL.png | Bin 0 -> 374 bytes .../zbstudio-win/zbstudio/res/16/VALUE-LCALL.png | Bin 0 -> 433 bytes .../zbstudio-win/zbstudio/res/16/VALUE-LOCAL.png | Bin 0 -> 698 bytes .../zbstudio-win/zbstudio/res/16/VALUE-SCALL.png | Bin 0 -> 428 bytes .../zbstudio-win/zbstudio/res/16/VALUE-UP.png | Bin 0 -> 753 bytes .../zbstudio/res/24/BOOKMARK-TOGGLE.png | Bin 0 -> 1087 bytes .../zbstudio-win/zbstudio/res/24/DEBUG-BREAK.png | Bin 0 -> 473 bytes .../zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png | Bin 0 -> 1457 bytes .../zbstudio/res/24/DEBUG-CALLSTACK.png | Bin 0 -> 566 bytes .../zbstudio-win/zbstudio/res/24/DEBUG-DETACH.png | Bin 0 -> 755 bytes .../zbstudio-win/zbstudio/res/24/DEBUG-RUN-TO.png | Bin 0 -> 400 bytes .../zbstudio-win/zbstudio/res/24/DEBUG-START.png | Bin 0 -> 369 bytes .../zbstudio/res/24/DEBUG-STEP-INTO.png | Bin 0 -> 451 bytes .../zbstudio/res/24/DEBUG-STEP-OUT.png | Bin 0 -> 450 bytes .../zbstudio/res/24/DEBUG-STEP-OVER.png | Bin 0 -> 484 bytes .../zbstudio-win/zbstudio/res/24/DEBUG-STOP.png | Bin 0 -> 799 bytes .../zbstudio-win/zbstudio/res/24/DEBUG-WATCH.png | Bin 0 -> 1008 bytes .../zbstudio/res/24/DIR-SETUP-FILE.png | Bin 0 -> 1365 bytes .../zbstudio-win/zbstudio/res/24/DIR-SETUP.png | Bin 0 -> 1412 bytes .../zbstudio-win/zbstudio/res/24/FILE-NEW.png | Bin 0 -> 821 bytes .../zbstudio-win/zbstudio/res/24/FILE-OPEN.png | Bin 0 -> 780 bytes .../zbstudio-win/zbstudio/res/24/FILE-SAVE-ALL.png | Bin 0 -> 622 bytes .../zbstudio-win/zbstudio/res/24/FILE-SAVE.png | Bin 0 -> 1165 bytes .../zbstudio/res/24/FIND-AND-REPLACE.png | Bin 0 -> 495 bytes .../zbstudio-win/zbstudio/res/24/FIND-IN-FILES.png | Bin 0 -> 1173 bytes .../tools/zbstudio-win/zbstudio/res/24/FIND.png | Bin 0 -> 775 bytes .../tools/zbstudio-win/zbstudio/res/24/LICENSE | 27 + .../tools/zbstudio-win/zbstudio/res/24/RUN-NOW.png | Bin 0 -> 384 bytes .../tools/zbstudio-win/zbstudio/res/24/RUN.png | Bin 0 -> 358 bytes .../tools/zbstudio-win/zbstudio/res/estrela.png | Bin 0 -> 6252 bytes .../tools/zbstudio-win/zbstudio/res/zbstudio.ico | Bin 0 -> 32038 bytes .../tools/zbstudio-win/zbstudio/res/zerobrane.png | Bin 0 -> 10255 bytes 1683 files changed, 459856 insertions(+) create mode 100644 love2dToAPK/tools/icon.png create mode 100644 love2dToAPK/tools/startAnt.bat create mode 100644 love2dToAPK/tools/tools/adb/AdbWinApi.dll create mode 100644 love2dToAPK/tools/tools/adb/AdbWinUsbApi.dll create mode 100644 love2dToAPK/tools/tools/adb/NOTICE.txt create mode 100644 love2dToAPK/tools/tools/adb/adb.exe create mode 100644 love2dToAPK/tools/tools/adb/api/annotations.zip create mode 100644 love2dToAPK/tools/tools/adb/api/api-versions.xml create mode 100644 love2dToAPK/tools/tools/adb/dmtracedump.exe create mode 100644 love2dToAPK/tools/tools/adb/etc1tool.exe create mode 100644 love2dToAPK/tools/tools/adb/fastboot.exe create mode 100644 love2dToAPK/tools/tools/adb/hprof-conv.exe create mode 100644 love2dToAPK/tools/tools/adb/lib64/libc++.so create mode 100644 love2dToAPK/tools/tools/adb/libwinpthread-1.dll create mode 100644 love2dToAPK/tools/tools/adb/mke2fs.exe create mode 100644 love2dToAPK/tools/tools/adb/source.properties create mode 100644 love2dToAPK/tools/tools/adb/sqlite3.exe create mode 100644 love2dToAPK/tools/tools/adb/systrace/NOTICE create mode 100644 love2dToAPK/tools/tools/adb/systrace/UPSTREAM_REVISION create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_binary_dependencies.json create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_error.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_devicetest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/LICENSE create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/README.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/smoke_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/rules/catapult-camelcase.js create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/tests/catapult-camelcase.js create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/commits.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/hardware.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/keychain_unlock.sh create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_binaries.json create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_util.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/package.json create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/README.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/run_tests create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/setup.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log_io_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/meta_class.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/multiprocessing_shim.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/parsed_trace_events.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/trace_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/PRESUBMIT.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/chrome_binaries.json create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_global_lock.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/dependency_util.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/py_utils_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/base_symbol.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/class_definition.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/function_definition.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/import_statement.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/reference.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/module.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/offset_token.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/snippet.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor_util/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor_util/move.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/shell_util.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/test_data/foo.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/xvfb.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/PRESUBMIT.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/archive_info.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/exceptions.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/local_path_info.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/manager.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/pylintrc create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/PRESUBMIT.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/README.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/chrome.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/file_system.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_list.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_signal.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_temp_file.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_test_case.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_devicetest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_devicetest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/forwarder.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/install_commands.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/logcat_monitor.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/logcat_monitor_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/md5sum.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/md5sum_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/perf/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/perf/cache_control.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/perf/perf_control.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/perf/perf_control_devicetest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/perf/surface_stats_collector.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/perf/thermal_throttle.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/ports.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/aapt.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/adb_compatibility_devicetest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/adb_wrapper.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/adb_wrapper_devicetest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/adb_wrapper_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/build_tools.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/dexdump.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/fastboot.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/gce_adb_wrapper.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/intent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/keyevent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/shared_prefs.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/shared_prefs_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/split_select.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/test/data/push_directory/push_directory_contents.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/test/data/push_file.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/sdk/version_codes.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/settings.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/adb_run_shell_cmd.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/cpufreq.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/device_monitor.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/device_monitor_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/device_recovery.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/device_status.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/flash_device.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/keyboard.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/provision_devices.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/screenshot.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/script_common.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/script_common_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/video_recorder.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/tools/wait_for_devices.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/valgrind_tools/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/valgrind_tools/base_tool.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/base_error.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/constants/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/constants/exit_codes.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/devil_dependencies.json create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/devil_env.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/devil_env_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/battor_device_mapping.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/cmd_helper.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/cmd_helper_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/file_utils.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/find_usb_devices.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/find_usb_devices_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/geometry.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/geometry_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/host_utils.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/lazy/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/lazy/weak_constant.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/lsusb.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/lsusb_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/markdown.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/markdown_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/mock_calls.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/mock_calls_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/parallelizer.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/parallelizer_test.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/reraiser_thread.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/reraiser_thread_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/reset_usb.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/run_tests_helper.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/signal_handler.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/test/data/test_serial_map.json create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/timeout_retry.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/timeout_retry_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/update_mapping.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/usb_hubs.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/watchdog_timer.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/utils/zip_utils.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/docs/adb_wrapper.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/docs/device_blacklist.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/docs/device_utils.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/docs/markdown.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/docs/persistent_device_list.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/devil/pylintrc create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/PRESUBMIT.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/README.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/README.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/Application.mk create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/file_utils.cc create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/file_utils.h create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/logging.h create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/main.cc create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/process_info.cc create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/process_info.h create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/process_memory_stats.cc create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/atrace_helper/jni/process_memory_stats.h create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/chrome_startup_tracing_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/chrome_startup_tracing_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/chrome_tracing_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/chrome_tracing_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/ddms_tracing_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/ddms_tracing_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/fake_agent_1.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/fake_agent_2.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/flags.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/main.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/perf_tracing_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/perf_tracing_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/profiler.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/profiler_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/run_tests create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/third_party/COPYING create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/third_party/README.chromium create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/third_party/perf_to_tracing.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/ui.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/profile_chrome/util.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/pylintrc create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/AUTHORS create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/LICENSE create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/README.md create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/decorators.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/monitor_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/output_generator.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/output_generator_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/prefix.html create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/run_systrace.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/suffix.html create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/systrace_runner.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/systrace_trace_viewer.html create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_data create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_data_raw create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_data_stripped create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_extracted_tgids create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_extracted_threads create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_fixed_tgids create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_missing_tgids create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/atrace_procfs_dump create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/battor_test_data.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/compressed_atrace_data.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/decompressed_atrace_data.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/test_data/profile-chrome_systrace_perf_chrome_data create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/trace_result.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/agents_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/android_process_data_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/atrace_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/atrace_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/atrace_from_file_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/atrace_from_file_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/battor_trace_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/battor_trace_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/ftrace_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/ftrace_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/walt_agent.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_agents/walt_agent_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/tracing_controller.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/update_systrace_trace_viewer.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/util.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/systrace/systrace/util_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/LICENSE.txt create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/README.chromium create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/linux-product_info.patch create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/rfc2217.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/serialcli.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/serialjava.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/serialposix.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/serialutil.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/serialwin32.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/sermsdos.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/tools/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/tools/list_ports.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/tools/list_ports_linux.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/tools/list_ports_osx.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/tools/list_ports_posix.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/tools/list_ports_windows.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/tools/miniterm.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/urlhandler/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/urlhandler/protocol_hwgrep.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/urlhandler/protocol_loop.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/urlhandler/protocol_rfc2217.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/urlhandler/protocol_socket.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/pyserial/serial/win32.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/zipfile/LICENSE create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/zipfile/README.chromium create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/third_party/zipfile/zipfile_2_7_13.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/tracing/tracing/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/tracing/tracing/trace_data/__init__.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/tracing/tracing/trace_data/trace_data.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/tracing/tracing/trace_data/trace_data_unittest.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/catapult/tracing/tracing_project.py create mode 100644 love2dToAPK/tools/tools/adb/systrace/systrace.py create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/NOTICE.txt create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/aapt.exe create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/aidl.exe create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/bcc_compat.exe create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/dexdump.exe create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/dx.bat create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/lib/dx.jar create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/libbcc.dll create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/libbcinfo.dll create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/CMakeLists.txt create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/LICENSE.TXT create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/altivec.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/ammintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/avx2intrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/avxintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/bmi2intrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/bmiintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/cpuid.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/emmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/f16cintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/float.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/fma4intrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/fmaintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/immintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/iso646.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/limits.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/lzcntintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/mm3dnow.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/mm_malloc.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/mmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/module.map create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/nmmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/pmmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/popcntintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/prfchwintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/rdseedintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/rtmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/smmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/stdalign.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/stdarg.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/stdbool.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/stddef.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/stdint.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/stdnoreturn.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/tgmath.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/tmmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/unwind.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/varargs.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/wmmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/x86intrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/xmmintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/clang-include/xopintrin.h create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_allocation.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_atomic.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_cl.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_core.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_debug.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_element.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_graphics.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_math.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_matrix.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_mesh.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_object.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_program.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_quaternion.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_sampler.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_time.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/include/rs_types.rsh create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/bc/armeabi-v7a/libclcore.bc create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/bc/mips/libclcore.bc create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/intermediates/armeabi-v7a/libc.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/intermediates/armeabi-v7a/libcompiler_rt.a create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/intermediates/armeabi-v7a/libm.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/intermediates/mips/libc.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/intermediates/mips/libcompiler_rt.a create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/intermediates/mips/libm.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/packaged/armeabi-v7a/libRSSupport.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/packaged/armeabi-v7a/librsjni.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/packaged/mips/libRSSupport.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/packaged/mips/librsjni.so create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/renderscript/lib/renderscript-v8.jar create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/source.properties create mode 100644 love2dToAPK/tools/tools/android-win/build-tools/19.1.0/zipalign.exe create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/AdbWinApi.dll create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/AdbWinUsbApi.dll create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/NOTICE.txt create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/adb.exe create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/api/api-versions.xml create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/dmtracedump.exe create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/etc1tool.exe create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/fastboot.exe create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/hprof-conv.exe create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/source.properties create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/sqlite3.exe create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/AUTHORS create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/LICENSE create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/NOTICE create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/UPSTREAM_REVISION create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/prefix.html create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/script.js create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/style.css create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/suffix.html create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/systrace-legacy.py create mode 100644 love2dToAPK/tools/tools/android-win/platform-tools/systrace/systrace.py create mode 100644 love2dToAPK/tools/tools/android-win/platforms/android-19/android.jar create mode 100644 love2dToAPK/tools/tools/android-win/platforms/android-19/build.prop create mode 100644 love2dToAPK/tools/tools/android-win/platforms/android-19/framework.aidl create mode 100644 love2dToAPK/tools/tools/android-win/platforms/android-19/sdk.properties create mode 100644 love2dToAPK/tools/tools/android-win/platforms/android-19/source.properties create mode 100644 love2dToAPK/tools/tools/android-win/platforms/android-19/uiautomator.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/NOTICE.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/android.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/ant/NOTICE create mode 100644 love2dToAPK/tools/tools/android-win/tools/ant/build.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/ant/uibuild.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/.classpath create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/.project create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/.settings/org.eclipse.jdt.core.prefs create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/AndroidManifest.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/Implementation.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/NOTICE create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/assets/intro_help.html create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/proguard-project.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/project.properties create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/drawable-hdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/drawable-ldpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/drawable-mdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/drawable-xhdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/layout-land/sensors.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/layout/main.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/layout/multitouch.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/layout/sensor_row.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/layout/sensors.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/values-v11/styles_v11.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/values/strings.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/res/values/styles.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/activities/BaseBindingActivity.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/activities/MainActivity.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/activities/MultiTouchActivity.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/activities/SensorActivity.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/handlers/MultiTouchChannel.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/handlers/SensorChannel.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Channel.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Connection.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/lib/ProtocolConstants.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Socket.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/service/ControllerService.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/utils/ApiHelper.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/utils/ApiHelper_11.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/apps/SdkController/src/com/android/tools/sdkcontroller/views/MultiTouchView.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/ddms.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/draw9patch.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/hierarchyviewer.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/jobb.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/android.el create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/annotations-12.0.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/annotations.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/ant-tasks.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/archquery.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/asm-5.0.3.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/asm-analysis-5.0.3.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/asm-tree-5.0.3.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/asset-studio.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/build.template create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/build_gradle.template create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/builder-model.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/cglib-nodep-3.1.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/chimpchat.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/common.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/commons-codec-1.4.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/commons-compress-1.8.1.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/commons-logging-1.1.1.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/ddmlib.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/ddms.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/ddmuilib.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/devices.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/draw9patch.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/dvlib.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/easymock-3.3.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/ecj-4.4.2.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/emma.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/emma_ant.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/emma_device.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/fat32lib.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/find_java.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/find_java32.exe create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/find_java64.exe create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/gson-2.2.4.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/guava-17.0.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/hamcrest-core-1.3.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/hierarchyviewer2.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/hierarchyviewer2lib.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/httpclient-4.1.1.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/httpcore-4.1.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/httpmime-4.1.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/jcommon-1.0.12.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/jfreechart-1.0.9.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/jfreechart-swt-1.0.9.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/jobb.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/jsilver-1.0.0.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/junit-4.12.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/kxml2-2.3.0.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/layoutlib-api.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/libemugl_test_shared_library.dll create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/lint-api.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/lint-checks.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/lint-tests.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/lint.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/lombok-ast-0.2.3.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/manifest-merger.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/monkeyrunner.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/ninepatch.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/objenesis-2.1.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/org-eclipse-core-commands-3.6.0.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/org-eclipse-equinox-common-3.6.0.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/org-eclipse-jface-3.6.2.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/osgi-4.0.0.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/pc-bios/bios.bin create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/pc-bios/vgabios-cirrus.bin create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/plugin.prop create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/proguard-project.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/rule-api.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/screenshot2.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/sdk-common.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/sdklib.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/sdkmanager.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/sdkstats.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/sdkuilib.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/swtmenubar.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/traceview.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/uiautomatorviewer.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/lib/uibuild.template create mode 100644 love2dToAPK/tools/tools/android-win/tools/lint.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/mksdcard.exe create mode 100644 love2dToAPK/tools/tools/android-win/tools/monitor.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/monkeyrunner.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/README create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/ant/task.properties create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/android.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/examples.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/examples/Applet.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/examples/Application.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/examples/Bean.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/examples/NativeCallBack.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/lib/annotations.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/lib/annotations.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/Keep.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepApplication.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepClassMemberNames.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepClassMembers.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepGettersSetters.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepImplementations.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepName.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepPublicClassMemberNames.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepPublicClassMembers.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepPublicGettersSetters.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepPublicImplementations.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepPublicProtectedClassMemberNames.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/annotations/src/proguard/annotation/KeepPublicProtectedClassMembers.java create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/android-8.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/applets.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/applications1.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/applications2.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/applications3.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/library.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/midlets.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/proguard.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/ant/servlets.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/applets.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/applications.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/dictionaries/compact.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/dictionaries/keywords.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/dictionaries/shakespeare.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/dictionaries/windows.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/library.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/midlets.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/proguard.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/proguardall.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/proguardgui.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/retrace.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/scala.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/examples/servlets.pro create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/lib/proguard.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/lib/proguardgui.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/lib/retrace.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/license.html create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/proguard-android-optimize.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/proguard-android.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/proguard/proguard-project.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/source.properties create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/annotations.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-de.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-en.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-es.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-hu.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-it.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-nb.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-pt.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/support/typos-tr.txt create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/root/res/layout/activity_simple.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/root/res/menu/main.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/root/res/values-w820dp/dimens.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/root/res/values/dimens.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/root/src/app_package/SimpleActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivity/template_blank_activity.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/res/layout/activity_fragment_container.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/res/layout/fragment_simple.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/res/menu/main.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/res/values-w820dp/dimens.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/res/values/dimens.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/src/app_package/SimpleActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/src/app_package/include_fragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/root/src/app_package/include_options_menu.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/BlankActivityWithFragment/template_blank_activity_fragment.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/root/res/layout/activity_simple.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/root/src/app_package/SimpleActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/EmptyActivity/template_blank_activity.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/res/layout/activity_fullscreen.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/res/values-v11/styles.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/res/values/attrs.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/res/values/colors.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/res/values/styles.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/src/app_package/FullscreenActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/src/app_package/util/SystemUiHider.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/src/app_package/util/SystemUiHiderBase.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/root/src/app_package/util/SystemUiHiderHoneycomb.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/FullscreenActivity/template_fullscreen_activity.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/root/res/layout/activity_login.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/root/res/values/dimens.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/root/src/app_package/LoginActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/root/src/app_package/PlusBaseActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/LoginActivity/template_login_activity.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/res/layout/activity_content_detail.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/res/layout/activity_content_list.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/res/layout/activity_content_twopane.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/res/layout/fragment_content_detail.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/res/values-large/refs.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/res/values-sw600dp/refs.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/src/app_package/ContentDetailActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/src/app_package/ContentDetailFragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/src/app_package/ContentListActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/src/app_package/ContentListFragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/root/src/app_package/dummy/DummyContent.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/MasterDetailFlow/template_master_detail.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-hdpi/drawer_shadow.9.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-hdpi/ic_drawer.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-mdpi/drawer_shadow.9.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-mdpi/ic_drawer.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-xhdpi/drawer_shadow.9.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-xhdpi/ic_drawer.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-xxhdpi/drawer_shadow.9.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/drawable-xxhdpi/ic_drawer.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/layout/activity_drawer.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/layout/fragment_navigation_drawer.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/layout/fragment_simple.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/menu/global.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/menu/main.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/values-w820dp/dimens.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/values/dimens.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/src/app_package/DrawerActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/src/app_package/NavigationDrawerFragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/src/app_package/include_fragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/root/src/app_package/include_options_menu.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/NavigationDrawerActivity/template_blank_activity_drawer.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/root/res/xml/pref_data_sync.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/root/res/xml/pref_general.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/root/res/xml/pref_headers.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/root/res/xml/pref_notification.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/root/src/app_package/SettingsActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/SettingsActivity/template_settings_activity.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/res/layout/activity_fragment_container.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/res/layout/activity_pager.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/res/layout/fragment_simple.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/res/menu/main.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/res/values-w820dp/dimens.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/res/values/dimens.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/src/app_package/DropdownActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/src/app_package/TabsAndPagerActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/src/app_package/include_fragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/root/src/app_package/include_options_menu.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/template_blank_activity_dropdown.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/template_blank_activity_pager.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/activities/TabbedActivity/template_blank_activity_tabs.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/gradle/utils/dependencies.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/gradle/wrapper/gradle/wrapper/gradle-wrapper.jar create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/gradle/wrapper/gradle/wrapper/gradle-wrapper.properties create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/gradle/wrapper/gradlew create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/gradle/wrapper/gradlew.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AidlFile/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AidlFile/root/src/app_package/interface.aidl.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AidlFile/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AidlFolder/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AidlFolder/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AidlFolder/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AndroidManifest/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AndroidManifest/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AndroidManifest/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AndroidManifest/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/res/drawable-nodpi/example_appwidget_preview.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/res/layout/appwidget.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/res/layout/appwidget_configure.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/res/values-v14/dimens.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/res/values/dimens.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/res/xml/appwidget_info.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/src/app_package/AppWidget.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/root/src/app_package/AppWidgetConfigureActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x1.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x1_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x1_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x1_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x2.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x2_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x2_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x2_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x3.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x3_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x3_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x3_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x4.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x4_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x4_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_1x4_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x1.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x1_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x1_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x1_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x2.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x2_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x2_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x2_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x3.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x3_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x3_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x3_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x4.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x4_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x4_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_2x4_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x1.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x1_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x1_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x1_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x2.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x2_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x2_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x2_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x3.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x3_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x3_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x3_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x4.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x4_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x4_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_3x4_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x1.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x1_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x1_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x1_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x2.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x2_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x2_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x2_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x3.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x3_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x3_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x3_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x4.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x4_h.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x4_v.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AppWidget/thumbs/template_widget_4x4_vh.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AssetsFolder/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AssetsFolder/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/AssetsFolder/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BlankFragment/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BlankFragment/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BlankFragment/root/res/layout/fragment_blank.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BlankFragment/root/res/values/strings.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BlankFragment/root/src/app_package/BlankFragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BlankFragment/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BlankFragment/template_blank_fragment.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BroadcastReceiver/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BroadcastReceiver/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BroadcastReceiver/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BroadcastReceiver/root/src/app_package/BroadcastReceiver.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/BroadcastReceiver/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ContentProvider/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ContentProvider/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ContentProvider/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ContentProvider/root/src/app_package/ContentProvider.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ContentProvider/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/CustomView/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/CustomView/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/CustomView/root/res/layout/sample.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/CustomView/root/res/values/attrs.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/CustomView/root/src/app_package/CustomView.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/CustomView/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/root/res/layout-v17/dream.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/root/res/xml/dream_prefs.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/root/res/xml/xml_dream.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/root/src/app_package/DreamService.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/root/src/app_package/SettingsActivity.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Daydream/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/IntentService/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/IntentService/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/IntentService/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/IntentService/root/src/app_package/IntentService.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/IntentService/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/JavaFolder/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/JavaFolder/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/JavaFolder/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/JniFolder/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/JniFolder/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/JniFolder/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/LayoutResourceFile/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/LayoutResourceFile/root/res/layout.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/LayoutResourceFile/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/res/layout/fragment_grid.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/res/layout/fragment_list.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/res/values-large/refs_lrg.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/res/values-sw600dp/refs_lrg.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/res/values/refs.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/res/values/refs_lrg.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/src/app_package/ListFragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/root/src/app_package/dummy/DummyContent.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ListFragment/templates_list_fragment.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-hdpi/ic_action_stat_reply.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-hdpi/ic_action_stat_share.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-mdpi/ic_action_stat_reply.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-mdpi/ic_action_stat_share.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-nodpi/example_picture_large.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-nodpi/example_picture_small.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-xhdpi/ic_action_stat_reply.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/drawable-xhdpi/ic_action_stat_share.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/root/src/app_package/NotificationHelper.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_list.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_list_actions.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_none.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_none_actions.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_picture.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_picture_actions.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_text.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Notification/template_notification_text_actions.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/PlusOneFragment/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/PlusOneFragment/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/PlusOneFragment/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/PlusOneFragment/root/res/layout/fragment_plus_one.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/PlusOneFragment/root/src/app_package/PlusOneFragment.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/PlusOneFragment/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/PlusOneFragment/templates_plusone_fragment.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ResFolder/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ResFolder/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ResFolder/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ResourcesFolder/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ResourcesFolder/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ResourcesFolder/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/RsFolder/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/RsFolder/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/RsFolder/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Service/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Service/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Service/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Service/root/src/app_package/Service.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/Service/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ValueResourceFile/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ValueResourceFile/root/res/values.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/other/ValueResourceFile/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/res/drawable-hdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/res/drawable-mdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/res/drawable-xhdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/res/values-v11/styles_hc.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/res/values-v14/styles_ics.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/res/values/styles.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/root/settings.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidApplication/template_new_project.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/AndroidManifest.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/res/drawable-hdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/res/drawable-mdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/res/drawable-xhdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/res/values-v11/styles_hc.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/res/values-v14/styles_ics.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/res/values/strings.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/res/values/styles.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/root/settings.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewAndroidLibrary/template_new_project.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewJavaLibrary/globals.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewJavaLibrary/recipe.xml.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewJavaLibrary/root/build.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewJavaLibrary/root/settings.gradle.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewJavaLibrary/root/src/library_package/Placeholder.java.ftl create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewJavaLibrary/template.xml create mode 100644 love2dToAPK/tools/tools/android-win/tools/templates/projects/NewJavaLibrary/template_new_project.png create mode 100644 love2dToAPK/tools/tools/android-win/tools/traceview.bat create mode 100644 love2dToAPK/tools/tools/android-win/tools/uiautomatorviewer.bat create mode 100644 love2dToAPK/tools/tools/ant/CONTRIBUTORS create mode 100644 love2dToAPK/tools/tools/ant/INSTALL create mode 100644 love2dToAPK/tools/tools/ant/KEYS create mode 100644 love2dToAPK/tools/tools/ant/LICENSE create mode 100644 love2dToAPK/tools/tools/ant/NOTICE create mode 100644 love2dToAPK/tools/tools/ant/README create mode 100644 love2dToAPK/tools/tools/ant/WHATSNEW create mode 100644 love2dToAPK/tools/tools/ant/contributors.xml create mode 100644 love2dToAPK/tools/tools/ant/etc/ant-bootstrap.jar create mode 100644 love2dToAPK/tools/tools/ant/etc/changelog.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/checkstyle/checkstyle-frames-sortby-check.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/checkstyle/checkstyle-frames.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/checkstyle/checkstyle-text.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/checkstyle/checkstyle-xdoc.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/coverage-frames.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/jdepend-frames.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/jdepend.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/junit-frames-xalan1.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/junit-frames.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/junit-noframes.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/log.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/maudit-frames.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/mmetrics-frames.xsl create mode 100644 love2dToAPK/tools/tools/ant/etc/tagdiff.xsl create mode 100644 love2dToAPK/tools/tools/ant/fetch.xml create mode 100644 love2dToAPK/tools/tools/ant/get-m2.xml create mode 100644 love2dToAPK/tools/tools/ant/lib/README create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-antlr.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-antlr.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-bcel.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-bcel.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-bsf.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-bsf.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-log4j.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-log4j.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-oro.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-oro.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-regexp.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-regexp.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-resolver.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-resolver.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-xalan2.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-apache-xalan2.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-commons-logging.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-commons-logging.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-commons-net.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-commons-net.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jai.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jai.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-javamail.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-javamail.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jdepend.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jdepend.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jmf.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jmf.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jsch.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-jsch.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-junit.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-junit.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-junit4.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-junit4.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-launcher.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-launcher.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-netrexx.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-netrexx.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-parent.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-swing.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-swing.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-testutil.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant-testutil.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/ant.jar create mode 100644 love2dToAPK/tools/tools/ant/lib/ant.pom create mode 100644 love2dToAPK/tools/tools/ant/lib/libraries.properties create mode 100644 love2dToAPK/tools/tools/ant/patch.xml create mode 100644 love2dToAPK/tools/tools/jdk-win/COPYRIGHT create mode 100644 love2dToAPK/tools/tools/jdk-win/LICENSE create mode 100644 love2dToAPK/tools/tools/jdk-win/README.html create mode 100644 love2dToAPK/tools/tools/jdk-win/THIRDPARTYLICENSEREADME-JAVAFX.txt create mode 100644 love2dToAPK/tools/tools/jdk-win/THIRDPARTYLICENSEREADME.txt create mode 100644 love2dToAPK/tools/tools/jdk-win/include/classfile_constants.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/jawt.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/jdwpTransport.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/jni.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/jvmti.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/jvmticmlr.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/win32/bridge/AccessBridgeCallbacks.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/win32/bridge/AccessBridgeCalls.c create mode 100644 love2dToAPK/tools/tools/jdk-win/include/win32/bridge/AccessBridgeCalls.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/win32/bridge/AccessBridgePackages.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/win32/jawt_md.h create mode 100644 love2dToAPK/tools/tools/jdk-win/include/win32/jni_md.h create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/COPYRIGHT create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/LICENSE create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/README.txt create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/THIRDPARTYLICENSEREADME-JAVAFX.txt create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/THIRDPARTYLICENSEREADME.txt create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/Welcome.html create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/accessibility.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/calendars.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/charsets.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/classlist create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/cmm/CIEXYZ.pf create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/cmm/GRAY.pf create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/cmm/LINEAR_RGB.pf create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/cmm/PYCC.pf create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/cmm/sRGB.pf create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/content-types.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/currency.data create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/deploy.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/access-bridge.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/cldrdata.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/dnsns.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/jaccess.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/jfxrt.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/localedata.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/meta-index create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/nashorn.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/sunec.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/sunjce_provider.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/sunmscapi.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/sunpkcs11.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/ext/zipfs.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/flavormap.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/fontconfig.bfc create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/fontconfig.properties.src create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/hijrah-config-umalqura.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/i386/jvm.cfg create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/javafx.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/javaws.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/jce.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/jfr.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/jfr/default.jfc create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/jfr/profile.jfc create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/jfxswt.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/jsse.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/jvm.hprof.txt create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/logging.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/management-agent.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/management/jmxremote.access create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/management/jmxremote.password.template create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/management/management.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/management/snmp.acl.template create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/meta-index create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/net.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/plugin.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/psfont.properties.ja create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/psfontj2d.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/resources.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/rt.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/US_export_policy.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/blacklist create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/blacklisted.certs create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/cacerts create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/java.policy create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/java.security create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/javaws.policy create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/local_policy.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/security/trusted.libraries create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/sound.properties create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/tzdb.dat create mode 100644 love2dToAPK/tools/tools/jdk-win/jre/lib/tzmappings create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/ant-javafx.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/ct.sym create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/dt.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/ir.idl create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/javafx-mx.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/jawt.lib create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/jconsole.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/jvm.lib create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/orb.idl create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/packager.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/sa-jdi.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/lib/tools.jar create mode 100644 love2dToAPK/tools/tools/jdk-win/release create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/.classpath create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/.project create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/AndroidManifest.xml create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/README.md create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/ant.properties create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/assets/game.love create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/build.properties create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/build.xml create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/default.properties create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/gen/R.java.d create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/gen/love/to/android/BuildConfig.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/gen/love/to/android/R.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/gen/love/to/android1219203756/BuildConfig.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/gen/love/to/android1219203756/R.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/gen/love/to/android1220074642/BuildConfig.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/gen/love/to/android1220074642/R.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi-v7a/libgnustl_shared.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi-v7a/liblove.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi-v7a/libmpg123.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi-v7a/libopenal.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi/libgnustl_shared.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi/liblove.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi/libmpg123.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/libs/armeabi/libopenal.so create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/original/AndroidManifest.xml create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/original/love/to/android/LtaActivity.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/project.properties create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/res/drawable-xxhdpi/ic_launcher.png create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/src/love/to/android/LtaActivity.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/src/org/libsdl/app/SDLActivity.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/src/org/love2d/android/DownloadActivity.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/src/org/love2d/android/DownloadService.java create mode 100644 love2dToAPK/tools/tools/love-android-sdl2/src/org/love2d/android/GameActivity.java create mode 100644 love2dToAPK/tools/tools/love-old-win/DevIL.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/OpenAL32.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/SDL2.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/changes.txt create mode 100644 love2dToAPK/tools/tools/love-old-win/game.ico create mode 100644 love2dToAPK/tools/tools/love-old-win/license.txt create mode 100644 love2dToAPK/tools/tools/love-old-win/love.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/love.exe create mode 100644 love2dToAPK/tools/tools/love-old-win/love.ico create mode 100644 love2dToAPK/tools/tools/love-old-win/lua51.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/mpg123.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/msvcp120.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/msvcr120.dll create mode 100644 love2dToAPK/tools/tools/love-old-win/readme.txt create mode 100644 love2dToAPK/tools/tools/love-win/OpenAL32.dll create mode 100644 love2dToAPK/tools/tools/love-win/SDL2.dll create mode 100644 love2dToAPK/tools/tools/love-win/changes.txt create mode 100644 love2dToAPK/tools/tools/love-win/game.ico create mode 100644 love2dToAPK/tools/tools/love-win/license.txt create mode 100644 love2dToAPK/tools/tools/love-win/love.dll create mode 100644 love2dToAPK/tools/tools/love-win/love.exe create mode 100644 love2dToAPK/tools/tools/love-win/love.ico create mode 100644 love2dToAPK/tools/tools/love-win/lua51.dll create mode 100644 love2dToAPK/tools/tools/love-win/mpg123.dll create mode 100644 love2dToAPK/tools/tools/love-win/msvcp120.dll create mode 100644 love2dToAPK/tools/tools/love-win/msvcr120.dll create mode 100644 love2dToAPK/tools/tools/love-win/readme.txt create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/ABOUT-NLS create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/AUTHORS create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/BUGS create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/COPYING create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/ChangeLog create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/INSTALL create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/NEWS create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/README create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/README-alpha create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/README.boot create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/THANKS create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/po/ChangeLog create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex10.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex11.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex12.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex13.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex14.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex15.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex16.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex21.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex27.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex28.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex7.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex8.c create mode 100644 love2dToAPK/tools/tools/sed-win/contrib/sed/4.2.1/sed-4.2.1/sed-4.2.1-src/testsuite/bug-regex9.c create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/CHANGELOG.md create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/LICENSE create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/README.md create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/api/cg/stdlib.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/api/glsl/std.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/api/lua/baselib.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/api/lua/love2d.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/api/lua/luajit2.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/api/lua/wxwidgets.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/api/opencl/std.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/estrela.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/cn.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/de.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/en.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/eo.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/es.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/fr.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/it.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/pt-br.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/i18n/ru.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/scheme-picker.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/tomorrow.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/user-sample.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/user.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/cfg/xcode-keys.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/interpreters/love2d.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/interpreters/luabase.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/interpreters/luadeb.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/interpreters/luadeb52.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/interpreters/luadeb53.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/copas/copas.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/coxpcall/coxpcall.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/config.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/constraints.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/depends.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/git.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/init.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/logger.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/manifest.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/package.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/sys.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/dist/utils.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/git.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/git/objects.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/git/pack.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/git/protocol.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/git/repo.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/git/util.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/ltn12.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/lua_lexer_loose.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/lua_parser_loose.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luadist.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/ast.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/compat_env.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/dump.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/globals.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/init.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/signatures.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/typecheck.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/luainspect/types.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/annot/generator.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/annot/grammar.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/common.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/expr.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/ext.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/lexer.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/meta.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/misc.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/stat.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/compiler/parser/table.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/grammar/generator.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/grammar/lexer.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/metalua/pprint.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/mime.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/mobdebug/mobdebug.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/sha2.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/socket.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/socket/ftp.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/socket/headers.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/socket/http.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/socket/smtp.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/socket/tp.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/socket/url.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/ssl.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/ssl/https.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/lualibs/testwell.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/spec/lua.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/spec/text.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/defs.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/autocomplete.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/commandbar.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/commands.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/debugger.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/editor.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/filetree.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/findreplace.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/gui.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/ids.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/inspect.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/iofilters.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/keymap.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/markers.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/markup.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/menu_edit.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/menu_file.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/menu_help.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/menu_project.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/menu_search.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/menu_tools.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/menu_view.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/outline.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/output.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/package.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/print.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/proto.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/settings.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/shellbox.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/singleinstance.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/style.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/editor/toolbar.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/main.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/util.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/src/version.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/cg.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/clcc.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/cstringify.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/dx.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/ffitoapi.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/glslc.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/perforce_edit.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/tools/perforce_revert.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio.exe create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/app.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/config.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/BOOKMARK-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-BREAK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-CALLSTACK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-DETACH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-RUN-TO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-START.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-STEP-INTO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-STEP-OUT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-STEP-OVER.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-STOP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DEBUG-WATCH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DIR-SETUP-FILE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/DIR-SETUP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FILE-KNOWN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FILE-NEW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FILE-NORMAL-START.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FILE-NORMAL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FILE-OPEN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FILE-SAVE-ALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FILE-SAVE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-AND-REPLACE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-IN-FILES.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-CONTEXT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-DOWN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-REGEX.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-SELECTION.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-SETDIR.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-SUBDIR.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-WORD.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-OPT-WRAP-AROUND.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND-REPLACE-NEXT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FIND.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FOLDER-MAPPED.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/FOLDER.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/LICENSE create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/RUN-NOW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/RUN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/VALUE-ACALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/VALUE-CALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/VALUE-GCALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/VALUE-LCALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/VALUE-LOCAL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/VALUE-SCALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/16/VALUE-UP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/BOOKMARK-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-BREAK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-CALLSTACK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-DETACH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-RUN-TO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-START.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-STEP-INTO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-STEP-OUT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-STEP-OVER.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-STOP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DEBUG-WATCH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DIR-SETUP-FILE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/DIR-SETUP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/FILE-NEW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/FILE-OPEN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/FILE-SAVE-ALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/FILE-SAVE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/FIND-AND-REPLACE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/FIND-IN-FILES.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/FIND.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/LICENSE create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/RUN-NOW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/24/RUN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/estrela.png create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/zbstudio.ico create mode 100644 love2dToAPK/tools/tools/zbstudio-old-win/zbstudio/res/zerobrane.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/CHANGELOG.md create mode 100644 love2dToAPK/tools/tools/zbstudio-win/LICENSE create mode 100644 love2dToAPK/tools/tools/zbstudio-win/README.md create mode 100644 love2dToAPK/tools/tools/zbstudio-win/api/cg/stdlib.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/api/glsl/std.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/api/lua/baselib.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/api/lua/love2d.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/api/lua/luajit2.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/api/lua/wxwidgets.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/api/opencl/std.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/estrela.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/cn.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/de.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/en.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/eo.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/es.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/fr.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/it.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/pt-br.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/i18n/ru.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/scheme-picker.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/tomorrow.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/user-sample.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/user.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/cfg/xcode-keys.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/interpreters/love2d.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/interpreters/luabase.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/interpreters/luadeb.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/interpreters/luadeb52.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/interpreters/luadeb53.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/copas/copas.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/coxpcall/coxpcall.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/config.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/constraints.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/depends.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/git.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/init.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/logger.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/manifest.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/package.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/sys.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/utils.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/git.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/git/objects.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/git/pack.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/git/protocol.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/git/repo.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/git/util.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/ltn12.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/lua_lexer_loose.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/lua_parser_loose.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luadist.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/ast.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/compat_env.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/dump.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/globals.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/init.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/signatures.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/typecheck.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/luainspect/types.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/annot/generator.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/annot/grammar.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/common.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/expr.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/ext.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/lexer.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/meta.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/misc.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/stat.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/compiler/parser/table.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/grammar/generator.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/grammar/lexer.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/metalua/pprint.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/mime.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/mobdebug/mobdebug.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/sha2.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/socket.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/socket/ftp.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/socket/headers.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/socket/http.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/socket/smtp.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/socket/tp.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/socket/url.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/ssl.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/ssl/https.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/lualibs/testwell.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/spec/lua.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/spec/text.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/defs.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/autocomplete.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/commandbar.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/commands.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/debugger.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/editor.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/filetree.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/findreplace.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/gui.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/ids.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/inspect.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/iofilters.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/keymap.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/markers.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/markup.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/menu_edit.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/menu_file.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/menu_help.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/menu_project.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/menu_search.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/menu_tools.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/menu_view.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/outline.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/output.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/package.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/print.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/proto.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/settings.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/shellbox.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/singleinstance.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/style.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/editor/toolbar.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/main.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/util.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/src/version.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/cg.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/clcc.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/cstringify.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/dx.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/ffitoapi.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/glslc.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/perforce_edit.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/tools/perforce_revert.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio.exe create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/app.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/config.lua create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/BOOKMARK-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-BREAK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-BREAKPOINT-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-CALLSTACK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-DETACH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-RUN-TO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-START.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-STEP-INTO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-STEP-OUT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-STEP-OVER.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-STOP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DEBUG-WATCH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DIR-SETUP-FILE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/DIR-SETUP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FILE-KNOWN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FILE-NEW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FILE-NORMAL-START.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FILE-NORMAL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FILE-OPEN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FILE-SAVE-ALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FILE-SAVE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-AND-REPLACE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-IN-FILES.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-CASE-SENSITIVE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-CONTEXT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-DOWN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-MULTI-RESULTS.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-REGEX.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-SELECTION.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-SETDIR.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-SUBDIR.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-WORD.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-OPT-WRAP-AROUND.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND-REPLACE-NEXT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FIND.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FOLDER-MAPPED.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/FOLDER.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/LICENSE create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/RUN-NOW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/RUN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/VALUE-ACALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/VALUE-CALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/VALUE-GCALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/VALUE-LCALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/VALUE-LOCAL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/VALUE-SCALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/16/VALUE-UP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/BOOKMARK-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-BREAK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-BREAKPOINT-TOGGLE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-CALLSTACK.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-DETACH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-RUN-TO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-START.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-STEP-INTO.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-STEP-OUT.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-STEP-OVER.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-STOP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DEBUG-WATCH.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DIR-SETUP-FILE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/DIR-SETUP.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/FILE-NEW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/FILE-OPEN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/FILE-SAVE-ALL.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/FILE-SAVE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/FIND-AND-REPLACE.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/FIND-IN-FILES.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/FIND.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/LICENSE create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/RUN-NOW.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/24/RUN.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/estrela.png create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/zbstudio.ico create mode 100644 love2dToAPK/tools/tools/zbstudio-win/zbstudio/res/zerobrane.png (limited to 'love2dToAPK/tools') diff --git a/love2dToAPK/tools/icon.png b/love2dToAPK/tools/icon.png new file mode 100644 index 0000000..e0567f6 Binary files /dev/null and b/love2dToAPK/tools/icon.png differ diff --git a/love2dToAPK/tools/startAnt.bat b/love2dToAPK/tools/startAnt.bat new file mode 100644 index 0000000..2613353 --- /dev/null +++ b/love2dToAPK/tools/startAnt.bat @@ -0,0 +1,12 @@ +@echo off + +setlocal +set ANT_HOME=%~dp0\tools\ant +set JAVA_HOME=%~dp0\tools\jdk-win +set ANDROID_HOME=%~dp0\tools\android-win +set PATH=%PATH%;%ANT_HOME%\bin + +cd tools\love-android-sdl2 + +call ant debug + diff --git a/love2dToAPK/tools/tools/adb/AdbWinApi.dll b/love2dToAPK/tools/tools/adb/AdbWinApi.dll new file mode 100644 index 0000000..7abe26c Binary files /dev/null and b/love2dToAPK/tools/tools/adb/AdbWinApi.dll differ diff --git a/love2dToAPK/tools/tools/adb/AdbWinUsbApi.dll b/love2dToAPK/tools/tools/adb/AdbWinUsbApi.dll new file mode 100644 index 0000000..e7a6de1 Binary files /dev/null and b/love2dToAPK/tools/tools/adb/AdbWinUsbApi.dll differ diff --git a/love2dToAPK/tools/tools/adb/NOTICE.txt b/love2dToAPK/tools/tools/adb/NOTICE.txt new file mode 100644 index 0000000..a574afb --- /dev/null +++ b/love2dToAPK/tools/tools/adb/NOTICE.txt @@ -0,0 +1,6260 @@ +Notices for files contained in the tools directory: +============================================================ +Notices for file(s): +/lib64/libtinyxml2.so +------------------------------------------------------------ +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +============================================================ +Notices for file(s): +/framework/antlr-runtime.jar +------------------------------------------------------------ +[The "BSD license"] +Copyright (c) 201 Terence Parr +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +============================================================ +Notices for file(s): +/lib/libcompiler_rt-extras.a +/lib64/libcompiler_rt-extras.a +/lib64/libcompiler_rt.so +------------------------------------------------------------ +============================================================================== +compiler_rt License +============================================================================== + +The compiler_rt library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + + +============================================================ +Notices for file(s): +/lib/liblog.a +/lib/liblog.so +/lib64/liblog.a +/lib64/liblog.so +------------------------------------------------------------ + + Copyright (c) 2005-2014, 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. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +============================================================ +Notices for file(s): +/bin/v8mkpeephole +/lib/libv8base.a +/lib64/libv8base.a +------------------------------------------------------------ +This license applies to all parts of V8 that are not externally +maintained libraries. The externally maintained libraries used by V8 +are: + + - PCRE test suite, located in + test/mjsunit/third_party/regexp-pcre/regexp-pcre.js. This is based on the + test suite from PCRE-7.3, which is copyrighted by the University + of Cambridge and Google, Inc. The copyright notice and license + are embedded in regexp-pcre.js. + + - Layout tests, located in test/mjsunit/third_party/object-keys. These are + based on layout tests from webkit.org which are copyrighted by + Apple Computer, Inc. and released under a 3-clause BSD license. + + - Strongtalk assembler, the basis of the files assembler-arm-inl.h, + assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, + assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h, + assembler-x64.cc, assembler-x64.h, assembler-mips-inl.h, + assembler-mips.cc, assembler-mips.h, assembler.cc and assembler.h. + This code is copyrighted by Sun Microsystems Inc. and released + under a 3-clause BSD license. + + - Valgrind client API header, located at third_party/valgrind/valgrind.h + This is release under the BSD license. + +These libraries have their own licenses; we recommend you read them, +as their terms may differ from the terms below. + +Further license information can be found in LICENSE files located in +sub-directories. + +Copyright 2014, the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +fdlibm + +Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +======================================================================== + +Strongtalk + +Copyright (c) 1994-2006 Sun Microsystems Inc. +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +- Redistribution in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of Sun Microsystems or the names of contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The original source code covered by the above license above has been +modified significantly by Google Inc. +Copyright 2006-2008 the V8 project authors. All rights reserved. + +======================================================================== + +valgrind + +---------------------------------------------------------------- + +Notice that the following BSD-style license applies to this one +file (valgrind.h) only. The rest of Valgrind is licensed under the +terms of the GNU General Public License, version 2, unless +otherwise indicated. See the COPYING file in the source +distribution for details. + +---------------------------------------------------------------- + +This file is part of Valgrind, a dynamic binary instrumentation +framework. + +Copyright (C) 2000-2007 Julian Seward. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +============================================================ +Notices for file(s): +/framework/org-netbeans-api-visual.jar +/framework/org-openide-util.jar +------------------------------------------------------------ +The GNU General Public License (GPL) Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. + +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away +your freedom to share and change it. By contrast, the GNU +General Public License is intended to guarantee your freedom +to share and change free software--to make sure the software +is free for all its users. This General Public License +applies to most of the Free Software Foundation's software +and to any other program whose authors commit to using it. +(Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can +apply it to your programs, too. When we speak of free +software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and +charge for this service if you wish), that you receive +source code or can get it if you want it, that you can +change the software or use pieces of it in new free +programs; and that you know you can do these things. To +protect your rights, we need to make restrictions that +forbid anyone to deny you these rights or to ask you to +surrender the rights. These restrictions translate to +certain responsibilities for you if you distribute copies of +the software, or if you modify it. + +For example, if you distribute copies of such a program, +whether gratis or for a fee, you must give the recipients +all the rights that you have. You must make sure that they, +too, receive or can get the source code. And you must show +them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the +software, and (2) offer you this license which gives you +legal permission to copy, distribute and/or modify the +software. + +Also, for each author's protection and ours, we want to make +certain that everyone understands that there is no warranty +for this free software. If the software is modified by +someone else and passed on, we want its recipients to know +that what they have is not the original, so that any +problems introduced by others will not reflect on the +original authors' reputations. + +Finally, any free program is threatened constantly by +software patents. We wish to avoid the danger that +redistributors of a free program will individually obtain +patent licenses, in effect making the program proprietary. +To prevent this, we have made it clear that any patent must +be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution +and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND +MODIFICATION + +0. This License applies to any program or other work which +contains a notice placed by the copyright holder saying it +may be distributed under the terms of this General Public +License. The "Program", below, refers to any such program or +work, and a "work based on the Program" means either the +Program or any derivative work under copyright law: that is +to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into +another language. (Hereinafter, translation is included +without limitation in the term "modification".) Each +licensee is addressed as "you". + +Activities other than copying, distribution and modification +are not covered by this License; they are outside its scope. +The act of running the Program is not restricted, and the +output from the Program is covered only if its contents +constitute a work based on the Program (independent of +having been made by running the Program). Whether that is +true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the +Program's source code as you receive it, in any medium, +provided that you conspicuously and appropriately publish on +each copy an appropriate copyright notice and disclaimer of +warranty; keep intact all the notices that refer to this +License and to the absence of any warranty; and give any +other recipients of the Program a copy of this License along +with the Program. + +You may charge a fee for the physical act of transferring a +copy, and you may at your option offer warranty protection +in exchange for a fee. + +2. You may modify your copy or copies of the Program or any +portion of it, thus forming a work based on the Program, and +copy and distribute such modifications or work under the +terms of Section 1 above, provided that you also meet all of +these conditions: + +a) You must cause the modified files to carry prominent +notices stating that you changed the files and the date of +any change. + +b) You must cause any work that you distribute or publish, +that in whole or in part contains or is derived from the +Program or any part thereof, to be licensed as a whole at no +charge to all third parties under the terms of this License. + +c) If the modified program normally reads commands +interactively when run, you must cause it, when started +running for such interactive use in the most ordinary way, +to print or display an announcement including an appropriate +copyright notice and a notice that there is no warranty (or +else, saying that you provide a warranty) and that users may +redistribute the program under these conditions, and telling +the user how to view a copy of this License. (Exception: if +the Program itself is interactive but does not normally +print such an announcement, your work based on the Program +is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the +Program, and can be reasonably considered independent and +separate works in themselves, then this License, and its +terms, do not apply to those sections when you distribute +them as separate works. But when you distribute the same +sections as part of a whole which is a work based on the +Program, the distribution of the whole must be on the terms +of this License, whose permissions for other licensees +extend to the entire whole, and thus to each and every part +regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights +or contest your rights to work written entirely by you; +rather, the intent is to exercise the right to control the +distribution of derivative or collective works based on the +Program. In addition, mere aggregation of another work not +based on the Program with the Program (or with a work based +on the Program) on a volume of a storage or distribution +medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based +on it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you +also do one of the following: + +a) Accompany it with the complete corresponding +machine-readable source code, which must be distributed +under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least +three years, to give any third party, for a charge no more +than your cost of physically performing source distribution, +a complete machine-readable copy of the corresponding source +code, to be distributed under the terms of Sections 1 and 2 +above on a medium customarily used for software interchange; +or, + +c) Accompany it with the information you received as to the +offer to distribute corresponding source code. (This +alternative is allowed only for noncommercial distribution +and only if you received the program in object code or +executable form with such an offer, in accord with +Subsection b above.) + +The source code for a work means the preferred form of the +work for making modifications to it. For an executable work, +complete source code means all the source code for all +modules it contains, plus any associated interface +definition files, plus the scripts used to control +compilation and installation of the executable. However, as +a special exception, the source code distributed need not +include anything that is normally distributed (in either +source or binary form) with the major components (compiler, +kernel, and so on) of the operating system on which the +executable runs, unless that component itself accompanies +the executable. If distribution of executable or object code +is made by offering access to copy from a designated place, +then offering equivalent access to copy the source code from +the same place counts as distribution of the source code, +even though third parties are not compelled to copy the +source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the +Program except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense or distribute +the Program is void, and will automatically terminate your +rights under this License. However, parties who have +received copies, or rights, from you under this License will +not have their licenses terminated so long as such parties +remain in full compliance. + +5. You are not required to accept this License, since you +have not signed it. However, nothing else grants you +permission to modify or distribute the Program or its +derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or +distributing the Program (or any work based on the Program), +you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or +modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based +on the Program), the recipient automatically receives a +license from the original licensor to copy, distribute or +modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. You are +not responsible for enforcing compliance by third parties to +this License. + +7. If, as a consequence of a court judgment or allegation of +patent infringement or for any other reason (not limited to +patent issues), conditions are imposed on you (whether by +court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as +to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a +consequence you may not distribute the Program at all. For +example, if a patent license would not permit royalty-free +redistribution of the Program by all those who receive +copies directly or indirectly through you, then the only way +you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or +unenforceable under any particular circumstance, the balance +of the section is intended to apply and the section as a +whole is intended to apply in other circumstances. It is not +the purpose of this section to induce you to infringe any +patents or other property right claims or to contest +validity of any such claims; this section has the sole +purpose of protecting the integrity of the free software +distribution system, which is implemented by public license +practices. Many people have made generous contributions to +the wide range of software distributed through that system +in reliance on consistent application of that system; it is +up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee +cannot impose that choice. + +This section is intended to make thoroughly clear what is +believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is +restricted in certain countries either by patents or by +copyrighted interfaces, the original copyright holder who +places the Program under this License may add an explicit +geographical distribution limitation excluding those +countries, so that distribution is permitted only in or +among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the +body of this License. + +9. The Free Software Foundation may publish revised and/or +new versions of the General Public License from time to +time. Such new versions will be similar in spirit to the +present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If +the Program specifies a version number of this License which +applies to it and "any later version", you have the option +of following the terms and conditions either of that version +or of any later version published by the Free Software +Foundation. If the Program does not specify a version number +of this License, you may choose any version ever published +by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into +other free programs whose distribution conditions are +different, write to the author to ask for permission. For +software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be +guided by the two goals of preserving the free status of all +derivatives of our free software and of promoting the +sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS +NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE +COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR +IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED +TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY +WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED +ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF +THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT +LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE +PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the +greatest possible use to the public, the best way to achieve +this is to make it free software which everyone can +redistribute and change under these terms. + +To do so, attach the following notices to the program. It is +safest to attach them to the start of each source file to +most effectively convey the exclusion of warranty; and each +file should have at least the "copyright" line and a pointer +to where the full notice is found. + +One line to give the program's name and a brief idea of what +it does. + +Copyright (C) +This program is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later +version. 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. You should have received a copy of the GNU +General Public License along with this program; if not, +write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and +paper mail. If the program is interactive, make it output a +short notice like this when it starts in an interactive +mode: + +Gnomovision version 69, Copyright (C) year name of author +Gnomovision comes with ABSOLUTELY NO WARRANTY; for details +type `show w'. This is free software, and you are welcome to +redistribute it under certain conditions; type `show c' for +details. The hypothetical commands `show w' and `show c' +should show the appropriate parts of the General Public +License. Of course, the commands you use may be called +something other than `show w' and `show c'; they could even +be mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a +programmer) or your school, if any, to sign a "copyright +disclaimer" for the program, if necessary. Here is a sample; +alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the program `Gnomovision' (which makes passes at compilers) +written by James Hacker. + +signature of Ty Coon, 1 April 1989 +Ty Coon, President of Vice +This General Public License does not permit incorporating +your program into proprietary programs. If your program is a +subroutine library, you may consider it more useful to +permit linking proprietary applications with the library. If +this is what you want to do, use the GNU Library General +Public License instead of this License. + +"CLASSPATH" EXCEPTION TO THE GPL VERSION 2 + +Certain source files distributed by Sun Microsystems, Inc. +are subject to the following clarification and special +exception to the GPL Version 2, but only where Sun has +expressly included in the particular source file's header +the words "Sun designates this particular file as subject +to the "Classpath" exception as provided by Sun in the +License file that accompanied this code." + + Linking this library statically or dynamically with other +modules is making a combined work based on this library. +Thus, the terms and conditions of the GNU General Public +License Version 2 cover the whole combination. + + As a special exception, the copyright holders of this +library give you permission to link this library with +independent modules to produce an executable, regardless of +the license terms of these independent modules, and to copy +and distribute the resulting executable under terms of your +choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license +of that module. An independent module is a module which is +not derived from or based on this library. If you modify +this library, you may extend this exception to your version +of the library, but you are not obligated to do so. If you +do not wish to do so, delete this exception statement from +your version. +============================================================ +Notices for file(s): +/lib/libopenjdkjvm.so +/lib/libopenjdkjvmd.so +/lib64/libopenjdkjvm.so +/lib64/libopenjdkjvmd.so +------------------------------------------------------------ +Copyright (C) 2014 The Android Open Source Project +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This file implements interfaces from the file jvm.h. This implementation +is licensed under the same terms as the file jvm.h. The +copyright and license information for the file jvm.h follows. + +Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This code is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 only, as +published by the Free Software Foundation. Oracle designates this +particular file as subject to the "Classpath" exception as provided +by Oracle in the LICENSE file that accompanied this code. + +This code 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 +version 2 for more details (a copy is included in the LICENSE file that +accompanied this code). + +You should have received a copy of the GNU General Public License version +2 along with this work; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. + +============================================================ +Notices for file(s): +/bin/mdnsd +/lib/libmdnssd.a +/lib64/libmdnssd.a +------------------------------------------------------------ +The majority of the source code in the mDNSResponder project is licensed +under the terms of the Apache License, Version 2.0, available from: + + +To accommodate license compatibility with the widest possible range +of client code licenses, the shared library code, which is linked +at runtime into the same address space as the client using it, is +licensed under the terms of the "Three-Clause BSD License". + +The Linux Name Service Switch code, contributed by National ICT +Australia Ltd (NICTA) is licensed under the terms of the NICTA Public +Software Licence (which is substantially similar to the "Three-Clause +BSD License", with some additional language pertaining to Australian law). + +============================================================ +Notices for file(s): +/bin/fsck.f2fs +/bin/make_f2fs +/lib/libf2fs_fmt_host.a +/lib64/libf2fs_fmt_host.a +/lib64/libf2fs_fmt_host_dyn.so +------------------------------------------------------------ +The tools for F2FS are covered by GNU Public License version 2. +Exceptionally, the following files are also covered by the GNU Lesser General +Public License Version 2.1 as the dual licenses. +- include/f2fs_fs.h +- lib/libf2fs.c +- lib/libf2fs_io.c +- mkfs/f2fs_format.c +- mkfs/f2fs_format_main.c +- mkfs/f2fs_format_utils.c +- mkfs/f2fs_format_utils.h + +================================================================================ +Copyright (c) 2012 Samsung Electronics Co., Ltd. + http://www.samsung.com/ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +================================================================================ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +================================================================================ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +============================================================ +Notices for file(s): +/bin/fc_sort +------------------------------------------------------------ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +============================================================ +Notices for file(s): +/bin/assemble_vintf +/framework/guavalib.jar +/framework/jarjar.jar +/framework/jsilver.jar +/lib64/libhidl-gen-hash.so +/lib64/libvintf.so +------------------------------------------------------------ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +============================================================ +Notices for file(s): +/lib64/libcap.so +------------------------------------------------------------ +Unless otherwise *explicitly* stated, the following text describes the +licensed conditions under which the contents of this libcap release +may be used and distributed: + +------------------------------------------------------------------------- +Redistribution and use in source and binary forms of libcap, with +or without modification, are permitted provided that the following +conditions are met: + +1. Redistributions of source code must retain any existing copyright + notice, and this entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce all prior and current + copyright notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +3. The name of any author may not be used to endorse or promote + products derived from this software without their specific prior + written permission. + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License (v2.0 - see below), in which case the +provisions of the GNU GPL are required INSTEAD OF the above +restrictions. (This clause is necessary due to a potential conflict +between the GNU GPL and the restrictions contained in a BSD-style +copyright.) + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +------------------------------------------------------------------------- + +------------------------- +Full text of gpl-2.0.txt: +------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + +============================================================ +Notices for file(s): +/lib/libunwind.so +/lib64/libunwind.so +------------------------------------------------------------ +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +============================================================ +Notices for file(s): +/lib/libopenjdkjvmti.so +/lib/libopenjdkjvmtid.so +/lib64/libopenjdkjvmti.so +/lib64/libopenjdkjvmtid.so +------------------------------------------------------------ +Copyright (C) 2016 The Android Open Source Project +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This file implements interfaces from the file jvmti.h. This implementation +is licensed under the same terms as the file jvmti.h. The +copyright and license information for the file jvmti.h follows. + +Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This code is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 only, as +published by the Free Software Foundation. Oracle designates this +particular file as subject to the "Classpath" exception as provided +by Oracle in the LICENSE file that accompanied this code. + +This code 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 +version 2 for more details (a copy is included in the LICENSE file that +accompanied this code). + +You should have received a copy of the GNU General Public License version +2 along with this work; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. + +============================================================ +Notices for file(s): +/framework/commons-compress-1.0.jar +------------------------------------------------------------ +Apache Commons Compress +Copyright 2002-2009 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +Original BZip2 classes contributed by Keiron Liddle +, Aftex Software to the Apache Ant project + +Original Tar classes from contributors of the Apache Ant project + +Original Zip classes from contributors of the Apache Ant project + +Original CPIO classes contributed by Markus Kuss and the jRPM project +(jrpm.sourceforge.net) + +============================================================ +Notices for file(s): +/bin/sgdisk +------------------------------------------------------------ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +============================================================ +Notices for file(s): +/bin/sqlite3 +/lib/libsqlite.so +/lib64/libsqlite.so +------------------------------------------------------------ +2001 September 15 + +The author disclaims copyright to this source code. In place of +a legal notice, here is a blessing: + + May you do good and not evil. + May you find forgiveness for yourself and forgive others. + May you share freely, never taking more than you give. + + +============================================================ +Notices for file(s): +/framework/conscrypt.jar +/lib/libconscrypt_openjdk_jni.so +/lib/libjavacrypto.so +/lib64/libconscrypt_openjdk_jni.so +/lib64/libjavacrypto.so +------------------------------------------------------------ +Copyright 2016 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 product contains a modified portion of `Netty`, a configurable network +stack in Java, which can be obtained at: + + * LICENSE: + * licenses/LICENSE.netty.txt (Apache License 2.0) + * HOMEPAGE: + * http://netty.io/ + +This product contains a modified portion of `Apache Harmony`, modular Java runtime, +which can be obtained at: + + * LICENSE: + * licenses/LICENSE.harmony.txt (Apache License 2.0) + * HOMEPAGE: + * https://harmony.apache.org/ + +============================================================ +Notices for file(s): +/lib64/libplatformprotos.so +------------------------------------------------------------ + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Android-specific code. == + ========================================================================= + +Android Code +Copyright 2005-2008 The Android Open Source Project + +This product includes software developed as part of +The Android Open Source Project (http://source.android.com). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Apache Commons code. == + ========================================================================= + +Apache Commons +Copyright 1999-2006 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Jakarta Commons Logging. == + ========================================================================= + +Jakarta Commons Logging (JCL) +Copyright 2005,2006 The Apache Software Foundation. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Nuance code. == + ========================================================================= + +These files are Copyright 2007 Nuance Communications, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Media Codecs code. == + ========================================================================= + +Media Codecs +These files are Copyright 1998 - 2009 PacketVideo, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the mDnsResponder code. == + ========================================================================= + +mDnsResponder TXTRecord +This file is Copyright 2004 Apple Computer, Inc. but released under +the Apache2 License. + + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the TagSoup code. == + ========================================================================= + +This file is part of TagSoup and is Copyright 2002-2008 by John Cowan. + +TagSoup is licensed under the Apache License, +Version 2.0. You may obtain a copy of this license at +http://www.apache.org/licenses/LICENSE-2.0 . You may also have +additional legal rights not granted by this license. + +TagSoup is distributed in the hope that it will be useful, but +unless required by applicable law or agreed to in writing, TagSoup +is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, either express or implied; not even the implied warranty +of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for Additional Codecs code. == + ========================================================================= + +Additional Codecs +These files are Copyright 2003-2010 VisualOn, but released under +the Apache2 License. + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Audio Effects code. == + ========================================================================= + +Audio Effects +These files are Copyright (C) 2004-2010 NXP Software and +Copyright (C) 2010 The Android Open Source Project, but released under +the Apache2 License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + + +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +Unicode Data Files include all data files under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +and http://www.unicode.org/cldr/data/ . Unicode Software includes any +source code published in the Unicode Standard or under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, and +http://www.unicode.org/cldr/data/. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA +FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY +ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF +THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, +DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed +under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation (the +"Data Files") or Unicode software and any associated documentation (the +"Software") to deal in the Data Files or Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, and/or sell copies of the Data Files or Software, +and to permit persons to whom the Data Files or Software are furnished to +do so, provided that (a) the above copyright notice(s) and this permission +notice appear with all copies of the Data Files or Software, (b) both the +above copyright notice(s) and this permission notice appear in associated +documentation, and (c) there is clear notice in each modified Data File +or in the Software as well as in the documentation associated with the +Data File(s) or Software that the data or software has been modified. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS +INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT +OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in these Data Files or Software without prior written +authorization of the copyright holder. + +============================================================ +Notices for file(s): +/bin/adb +/lib/libdiagnose_usb.a +/lib64/libadb.a +/lib64/libdiagnose_usb.a +------------------------------------------------------------ + + Copyright (c) 2006-2009, The Android Open Source Project + Copyright 2006, Brian Swetland + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +------------------------------------------------------------ +libwinpthread license: +------------------------------------------------------------ +Copyright (c) 2011 mingw-w64 project + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +/* + * Parts of this library are derived by: + * + * Posix Threads library for Microsoft Windows + * + * Use at own risk, there is no implied warranty to this code. + * It uses undocumented features of Microsoft Windows that can change + * at any time in the future. + * + * (C) 2010 Lockless Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Lockless Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +============================================================ +Notices for file(s): +/bin/llvm-rs-cc +------------------------------------------------------------ +========================= +NOTICE file for slang.git +========================= + + Copyright (c) 2005-2011, 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. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + + +=========================================== +NOTICE file for external/clang (clang.git). +Note: libclang*.a are statically linked. +=========================================== + +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2007-2011 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- + + + + +========================================= +NOTICE file for external/llvm (llvm.git). +Note: libLLVM*.a are statically linked. +========================================= + +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2011 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +Autoconf llvm/autoconf + llvm/projects/ModuleMaker/autoconf + llvm/projects/sample/autoconf +CellSPU backend llvm/lib/Target/CellSPU/README.txt +Google Test llvm/utils/unittest/googletest +OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} + +============================================================ +Notices for file(s): +/bin/aapt +/bin/aidl +/bin/dexdump +/bin/dx +/framework/dx.jar +/lib/libaapt.a +/lib/libandroidfw.a +/lib/libcutils.a +/lib/libcutils.so +/lib/libnativehelper.so +/lib/libutils.a +/lib64/libaapt.a +/lib64/libandroidfw.a +/lib64/libcutils.a +/lib64/libcutils.so +/lib64/libnativehelper.so +/lib64/libutils.a +------------------------------------------------------------ + + Copyright (c) 2005-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. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +============================================================ +Notices for file(s): +/lib/libjavacore.so +/lib/libopenjdk.so +/lib/libopenjdkd.so +/lib64/libjavacore.so +/lib64/libopenjdk.so +/lib64/libopenjdkd.so +------------------------------------------------------------ + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Android-specific code. == + ========================================================================= + +Android Code +Copyright 2005-2008 The Android Open Source Project + +This product includes software developed as part of +The Android Open Source Project (http://source.android.com). + + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Apache Harmony distribution. == + ========================================================================= + +Apache Harmony +Copyright 2006 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +Portions of Harmony were originally developed by +Intel Corporation and are licensed to the Apache Software +Foundation under the "Software Grant and Corporate Contribution +License Agreement", informally known as the "Intel Harmony CLA". + + + ========================================================================= + == NOTICE file for the ICU License. == + ========================================================================= + +Copyright (c) 1995-2014 International Business Machines Corporation and others + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +All trademarks and registered trademarks mentioned herein are the +property of their respective owners. + + + ========================================================================= + == NOTICE file for the KXML License. == + ========================================================================= + +Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + ========================================================================= + == NOTICE file for the W3C License. == + ========================================================================= + +Copyright (c) 2000 World Wide Web Consortium, (Massachusetts Institute +of Technology, Institut National de Recherche en Informatique et en +Automatique, Keio University). All Rights Reserved. This program is +distributed under the W3C's Software Intellectual Property License. +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 W3C License http://www.w3.org/Consortium/Legal/ for more details. + + ========================================================================= + == NOTICE file for the fdlibm License. == + ========================================================================= + +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +============================================================ +Notices for file(s): +/lib/libexpat-host.so +/lib/libexpat.a +/lib64/libexpat-host.so +/lib64/libexpat.a +------------------------------------------------------------ +Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper +Copyright (c) 2001-2016 Expat maintainers + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +============================================================ +Notices for file(s): +/framework/doclava.jar +------------------------------------------------------------ + + Copyright (C) 2010 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +====================================================================== + +jQuery 1.2.6 - New Wave Javascript + +Copyright (c) 2008 John Resig (jquery.com) +Dual licensed under the MIT (MIT-LICENSE.txt) +and GPL (GPL-LICENSE.txt) licenses. + +Copyright (c) 2009 John Resig, http://jquery.com/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +============================================================ +Notices for file(s): +/bin/minigzip +/lib/libz-host.so +/lib/libz.a +/lib64/libz-host.so +/lib64/libz.a +------------------------------------------------------------ + (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +============================================================ +Notices for file(s): +/bin/aprotoc +/framework/host-libprotobuf-java-full.jar +/framework/host-libprotobuf-java-lite.jar +/lib64/libprotobuf-cpp-full.so +/lib64/libprotobuf-cpp-lite.so +/lib64/libprotoc.so +------------------------------------------------------------ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +============================================================ +Notices for file(s): +/bin/memory_replay +/nativetest/memory_replay_tests/memory_replay_tests32 +/nativetest64/memory_replay_tests/memory_replay_tests64 +------------------------------------------------------------ + + Copyright (c) 2015, 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. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +============================================================ +Notices for file(s): +/bin/blk_alloc_to_base_fs +/bin/make_ext4fs +/bin/mkuserimg_mke2fs.sh +/lib/libext4_utils.a +/lib/libf2fs_dlutils_host.a +/lib/libf2fs_ioutils_host.a +/lib/libf2fs_utils_host.a +/lib64/libext4_utils.a +/lib64/libext4_utils.so +/lib64/libf2fs_dlutils_host.a +/lib64/libf2fs_ioutils_host.a +/lib64/libf2fs_utils_host.a +------------------------------------------------------------ + + Copyright (c) 2010, 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. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +============================================================ +Notices for file(s): +/framework/emmalib.jar +------------------------------------------------------------ +Common Public License - v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S +ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was +added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules +of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative +works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, +use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the +combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered +by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + + c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the +Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other +entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole +responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the +Program, it is Recipient's responsibility to acquire that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this +Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, +and implied warranties or conditions of merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost +profits; + + iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium +customarily used for software exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the +Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the +commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other +Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a +third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a +commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to +qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate +with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor +then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this +section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, +WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for +determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to +the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this +Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any +patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes +patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other +software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a +reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the +Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and +survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following +manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the +right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new +version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under +which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new +version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, +whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal +action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. + +============================================================ +Notices for file(s): +/lib/libgtest_host.a +/lib/libgtest_main_host.a +/lib64/libgtest_host.a +/lib64/libgtest_main_host.a +------------------------------------------------------------ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +============================================================ +Notices for file(s): +/lib/libc++.so +/lib/libc++_static.a +/lib64/libc++.so +/lib64/libc++_static.a +------------------------------------------------------------ +============================================================================== +libc++ License +============================================================================== + +The libc++ library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================ +Notices for file(s): +/lib64/libbz.so +------------------------------------------------------------ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +-------------------------------------------------------------------------- + +============================================================ +Notices for file(s): +/lib/libpcre2.a +/lib64/libpcre2.a +/lib64/libpcre2.so +------------------------------------------------------------ +PCRE LICENCE +------------ + +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Release 8 of PCRE is distributed under the terms of the "BSD" licence, as +specified below. The documentation for PCRE, supplied in the "doc" +directory, is distributed under the same terms as the software itself. + +The basic library functions are written in C and are freestanding. Also +included in the distribution is a set of C++ wrapper functions, and a +just-in-time compiler that can be used to optimize pattern matching. These +are both optional features that can be omitted when the library is built. + + +THE BASIC LIBRARY FUNCTIONS +--------------------------- + +Written by: Philip Hazel +Email local part: ph10 +Email domain: cam.ac.uk + +University of Cambridge Computing Service, +Cambridge, England. + +Copyright (c) 1997-2014 University of Cambridge +All rights reserved. + + +PCRE JUST-IN-TIME COMPILATION SUPPORT +------------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2010-2014 Zoltan Herczeg +All rights reserved. + + +STACK-LESS JUST-IN-TIME COMPILER +-------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2009-2014 Zoltan Herczeg +All rights reserved. + + +THE C++ WRAPPER FUNCTIONS +------------------------- + +Contributed by: Google Inc. + +Copyright (c) 2007-2012, Google Inc. +All rights reserved. + + +THE "BSD" LICENCE +----------------- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the name of Google + Inc. nor the names of their contributors may be used to endorse or + promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +End + +============================================================ +Notices for file(s): +/lib64/libtinyalsa.so +------------------------------------------------------------ +Copyright 2011, The Android Open Source Project + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Android Open Source Project nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + + +============================================================ +Notices for file(s): +/lib/liblz4.so +/lib64/liblz4.so +------------------------------------------------------------ +LZ4 Library +Copyright (c) 2011-2016, Yann Collet +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +============================================================ +Notices for file(s): +/usr/share/zoneinfo/tzdata +------------------------------------------------------------ +With a few exceptions, all files in the tz code and data (including +this one) are in the public domain. The exceptions are date.c, +newstrftime.3, and strftime.c, which contain material derived from BSD +and which use the BSD 3-clause license. + +============================================================ +Notices for file(s): +/framework/bouncycastle.jar +------------------------------------------------------------ +Copyright (c) 2000-2015 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +============================================================ +Notices for file(s): +/lib/libcrypto-host.so +/lib/libcrypto.a +/lib/libssl-host.so +/lib64/libcrypto-host.so +/lib64/libcrypto.a +/lib64/libssl-host.so +------------------------------------------------------------ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a dual license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. Actually both licenses are BSD-style + Open Source licenses. In case of any license issues related to OpenSSL + please contact openssl-core@openssl.org. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + +============================================================ +Notices for file(s): +/lib/libusb.a +/lib64/libusb.a +------------------------------------------------------------ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + + diff --git a/love2dToAPK/tools/tools/adb/adb.exe b/love2dToAPK/tools/tools/adb/adb.exe new file mode 100644 index 0000000..322185c Binary files /dev/null and b/love2dToAPK/tools/tools/adb/adb.exe differ diff --git a/love2dToAPK/tools/tools/adb/api/annotations.zip b/love2dToAPK/tools/tools/adb/api/annotations.zip new file mode 100644 index 0000000..32bb74c Binary files /dev/null and b/love2dToAPK/tools/tools/adb/api/annotations.zip differ diff --git a/love2dToAPK/tools/tools/adb/api/api-versions.xml b/love2dToAPK/tools/tools/adb/api/api-versions.xml new file mode 100644 index 0000000..fc6841e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/api/api-versions.xml @@ -0,0 +1,75120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/love2dToAPK/tools/tools/adb/dmtracedump.exe b/love2dToAPK/tools/tools/adb/dmtracedump.exe new file mode 100644 index 0000000..db5b507 Binary files /dev/null and b/love2dToAPK/tools/tools/adb/dmtracedump.exe differ diff --git a/love2dToAPK/tools/tools/adb/etc1tool.exe b/love2dToAPK/tools/tools/adb/etc1tool.exe new file mode 100644 index 0000000..86aabc6 Binary files /dev/null and b/love2dToAPK/tools/tools/adb/etc1tool.exe differ diff --git a/love2dToAPK/tools/tools/adb/fastboot.exe b/love2dToAPK/tools/tools/adb/fastboot.exe new file mode 100644 index 0000000..6e15f5a Binary files /dev/null and b/love2dToAPK/tools/tools/adb/fastboot.exe differ diff --git a/love2dToAPK/tools/tools/adb/hprof-conv.exe b/love2dToAPK/tools/tools/adb/hprof-conv.exe new file mode 100644 index 0000000..0c53d48 Binary files /dev/null and b/love2dToAPK/tools/tools/adb/hprof-conv.exe differ diff --git a/love2dToAPK/tools/tools/adb/lib64/libc++.so b/love2dToAPK/tools/tools/adb/lib64/libc++.so new file mode 100644 index 0000000..7489d9c Binary files /dev/null and b/love2dToAPK/tools/tools/adb/lib64/libc++.so differ diff --git a/love2dToAPK/tools/tools/adb/libwinpthread-1.dll b/love2dToAPK/tools/tools/adb/libwinpthread-1.dll new file mode 100644 index 0000000..3aa88d7 Binary files /dev/null and b/love2dToAPK/tools/tools/adb/libwinpthread-1.dll differ diff --git a/love2dToAPK/tools/tools/adb/mke2fs.exe b/love2dToAPK/tools/tools/adb/mke2fs.exe new file mode 100644 index 0000000..d4491e1 Binary files /dev/null and b/love2dToAPK/tools/tools/adb/mke2fs.exe differ diff --git a/love2dToAPK/tools/tools/adb/source.properties b/love2dToAPK/tools/tools/adb/source.properties new file mode 100644 index 0000000..7b0ac1b --- /dev/null +++ b/love2dToAPK/tools/tools/adb/source.properties @@ -0,0 +1,3 @@ +Pkg.UserSrc=false +#Pkg.Revision=26.0.0 +Pkg.Revision=27.0.0 diff --git a/love2dToAPK/tools/tools/adb/sqlite3.exe b/love2dToAPK/tools/tools/adb/sqlite3.exe new file mode 100644 index 0000000..ef34825 Binary files /dev/null and b/love2dToAPK/tools/tools/adb/sqlite3.exe differ diff --git a/love2dToAPK/tools/tools/adb/systrace/NOTICE b/love2dToAPK/tools/tools/adb/systrace/NOTICE new file mode 100644 index 0000000..624b6da --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/NOTICE @@ -0,0 +1,205 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/love2dToAPK/tools/tools/adb/systrace/UPSTREAM_REVISION b/love2dToAPK/tools/tools/adb/systrace/UPSTREAM_REVISION new file mode 100644 index 0000000..d19651e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/UPSTREAM_REVISION @@ -0,0 +1 @@ +6171fd4dd88d738437b803fbf5374be6bf9c5342 diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/__init__.py new file mode 100644 index 0000000..f18f330 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import os +import sys + +def _JoinPath(*path_parts): + return os.path.abspath(os.path.join(*path_parts)) + + +def _AddDirToPythonPath(*path_parts): + path = _JoinPath(*path_parts) + if os.path.isdir(path) and path not in sys.path: + # Some call sites that use Telemetry assume that sys.path[0] is the + # directory containing the script, so we add these extra paths to right + # after sys.path[0]. + sys.path.insert(1, path) + +_CATAPULT_DIR = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + os.path.pardir, os.path.pardir, os.path.pardir) + +_AddDirToPythonPath(_CATAPULT_DIR, 'common', 'battor') +_AddDirToPythonPath(_CATAPULT_DIR, 'common', 'py_utils') +_AddDirToPythonPath(_CATAPULT_DIR, 'dependency_manager') +_AddDirToPythonPath(_CATAPULT_DIR, 'devil') +_AddDirToPythonPath(_CATAPULT_DIR, 'third_party', 'pyserial') diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_binary_dependencies.json b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_binary_dependencies.json new file mode 100644 index 0000000..58c203e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_binary_dependencies.json @@ -0,0 +1,114 @@ +{ + "config_type": "BaseConfig", + "dependencies": { + "avrdude_binary": { + "cloud_storage_base_folder": "binary_dependencies/battor", + "cloud_storage_bucket": "chromium-telemetry", + "file_info": { + "darwin_x86_64": { + "cloud_storage_hash": "6de6324c279ea75c79c68cab4c2ddcc68da1b286", + "download_path": "../bin/darwin/x86_64/avrdude", + "local_paths": [ + "../bin/override/avrdude" + ] + }, + "linux2_x86_64": { + "cloud_storage_hash": "db29526605f6f95a75ab33f4060b8c330152de69", + "download_path": "../bin/linux2/x86_64/avrdude", + "local_paths": [ + "../bin/override/avrdude" + ] + }, + "win32_AMD64": { + "cloud_storage_hash": "517aa73b093e254007076cf5ac7afb94151df2ed", + "download_path": "../bin/win/x86_64/avrdude.exe", + "local_paths": [ + "../bin/override/avrdude.exe" + ] + }, + "win32_x86": { + "cloud_storage_hash": "517aa73b093e254007076cf5ac7afb94151df2ed", + "download_path": "../bin/win/x86_64/avrdude.exe", + "local_paths": [ + "../bin/override/avrdude.exe" + ] + }, + "win_AMD64": { + "cloud_storage_hash": "517aa73b093e254007076cf5ac7afb94151df2ed", + "download_path": "../bin/win/x86_64/avrdude.exe", + "local_paths": [ + "../bin/override/avrdude.exe" + ] + } + } + }, + "avrdude_config": { + "cloud_storage_base_folder": "binary_dependencies/battor", + "cloud_storage_bucket": "chromium-telemetry", + "file_info": { + "default": { + "cloud_storage_hash": "ccdfa12743429b8b92b61a20163d6311ab55a4fa", + "download_path": "../bin/battor/avrdude.conf", + "local_paths": [ + "../bin/override/avrdude.conf" + ] + } + } + }, + "battor_agent_binary": { + "cloud_storage_base_folder": "binary_dependencies/battor", + "cloud_storage_bucket": "chromium-telemetry", + "file_info": { + "darwin_x86_64": { + "cloud_storage_hash": "276b3507a1c617c01734d85a2133ed200f2a477b", + "download_path": "../bin/darwin/x86_64/battor_agent", + "local_paths": [ + "../bin/override/battor_agent" + ] + }, + "linux2_x86_64": { + "cloud_storage_hash": "582cfe85971ca84aa75cf078bafb737d0cbdfb31", + "download_path": "../bin/linux2/x86_64/battor_agent", + "local_paths": [ + "../bin/override/battor_agent" + ] + }, + "win32_AMD64": { + "cloud_storage_hash": "609c5f79a03b347ddbfd6e544d229a56851c0f66", + "download_path": "../bin/win/AMD64/battor_agent.exe", + "local_paths": [ + "../bin/override/battor_agent.exe" + ] + }, + "win32_x86": { + "cloud_storage_hash": "609c5f79a03b347ddbfd6e544d229a56851c0f66", + "download_path": "../bin/win/x86_64/battor_agent.exe", + "local_paths": [ + "../bin/override/battor_agent.exe" + ] + }, + "win_AMD64": { + "cloud_storage_hash": "609c5f79a03b347ddbfd6e544d229a56851c0f66", + "download_path": "../bin/win/AMD64/battor_agent.exe", + "local_paths": [ + "../bin/override/battor_agent.exe" + ] + } + } + }, + "battor_firmware": { + "cloud_storage_base_folder": "binary_dependencies/battor", + "cloud_storage_bucket": "chromium-telemetry", + "file_info": { + "default": { + "cloud_storage_hash": "da987f879c341bf2f928dc0f65cc6477c2d32bbc", + "download_path": "../bin/battor/battor_firmware.hex", + "local_paths": [ + "../bin/override/battor_firmware.hex" + ], + "version_in_cs": "3c3ce4d" + } + } + } + } +} diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_error.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_error.py new file mode 100644 index 0000000..3ea6efc --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_error.py @@ -0,0 +1,8 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from devil import base_error + +class BattOrError(base_error.BaseError): + pass diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper.py new file mode 100644 index 0000000..6947f83 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper.py @@ -0,0 +1,420 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import atexit +import datetime +import os +import logging +import platform +import random +import subprocess +import sys +import tempfile +import time + +from battor import battor_error +import py_utils +from py_utils import cloud_storage +import dependency_manager +from devil.utils import battor_device_mapping +from devil.utils import find_usb_devices + +import serial +from serial.tools import list_ports + + +DEFAULT_SHELL_CLOSE_TIMEOUT_S = 60 + + +def IsBattOrConnected(test_platform, android_device=None, + android_device_map=None, android_device_file=None): + """Returns True if BattOr is detected.""" + if test_platform == 'android': + if not android_device: + raise ValueError('Must pass android device serial when determining ' + 'support on android platform') + + if not android_device_map: + device_tree = find_usb_devices.GetBusNumberToDeviceTreeMap() + if device_tree: + logging.warning('Device tree:') + for _, node in sorted(device_tree.iteritems()): + node.Display() + else: + logging.warning('Empty device tree.') + if len(battor_device_mapping.GetBattOrList(device_tree)) == 1: + return True + if android_device_file: + android_device_map = battor_device_mapping.ReadSerialMapFile( + android_device_file) + else: + try: + android_device_map = battor_device_mapping.GenerateSerialMap() + logging.warning('Android device map: %s', android_device_map) + except battor_error.BattOrError: + logging.exception('Error generating serial map') + return False + + # If neither if statement above is triggered, it means that an + # android_device_map was passed in and will be used. + return str(android_device) in android_device_map + + elif test_platform == 'win': + for (_1, desc, _2) in serial.tools.list_ports.comports(): + if 'USB Serial Port' in desc: + return True + logging.info('No usb serial port discovered. Available ones are: %s' % + list(serial.tools.list_ports.comports())) + return False + + elif test_platform == 'mac': + for (_1, desc, _2) in serial.tools.list_ports.comports(): + if 'BattOr' in desc: + return True + return False + + elif test_platform == 'linux': + device_tree = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=True) + return bool(battor_device_mapping.GetBattOrList(device_tree)) + + return False + + +class BattOrWrapper(object): + """A class for communicating with a BattOr in python.""" + _EXIT_CMD = 'Exit' + _GET_FIRMWARE_GIT_HASH_CMD = 'GetFirmwareGitHash' + _START_TRACING_CMD = 'StartTracing' + _STOP_TRACING_CMD = 'StopTracing' + _SUPPORTS_CLOCKSYNC_CMD = 'SupportsExplicitClockSync' + _RECORD_CLOCKSYNC_CMD = 'RecordClockSyncMarker' + _SUPPORTED_PLATFORMS = ['android', 'chromeos', 'linux', 'mac', 'win'] + + _BATTOR_PARTNO = 'x192a3u' + _BATTOR_PROGRAMMER = 'avr109' + _BATTOR_BAUDRATE = '115200' + + def __init__(self, target_platform, android_device=None, battor_path=None, + battor_map_file=None, battor_map=None, serial_log_bucket=None, + autoflash=True): + """Constructor. + + Args: + target_platform: Platform BattOr is attached to. + android_device: Serial number of Android device. + battor_path: Path to BattOr device. + battor_map_file: File giving map of [device serial: BattOr path] + battor_map: Map of [device serial: BattOr path] + serial_log_bucket: The cloud storage bucket to which BattOr agent serial + logs are uploaded on failure. + + Attributes: + _battor_path: Path to BattOr. Typically similar to /tty/USB0. + _battor_agent_binary: Path to the BattOr agent binary used to communicate + with the BattOr. + _tracing: A bool saying if tracing has been started. + _battor_shell: A subprocess running the battor_agent_binary + _trace_results_path: Path to BattOr trace results file. + _serial_log_bucket: Cloud storage bucket to which BattOr agent serial logs + are uploaded on failure. + _serial_log_file: Temp file for the BattOr agent serial log. + """ + self._battor_path = self._GetBattOrPath(target_platform, android_device, + battor_path, battor_map_file, battor_map) + config = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + 'battor_binary_dependencies.json') + + self._dm = dependency_manager.DependencyManager( + [dependency_manager.BaseConfig(config)]) + self._battor_agent_binary = self._dm.FetchPath( + 'battor_agent_binary', '%s_%s' % (sys.platform, platform.machine())) + + self._autoflash = autoflash + self._serial_log_bucket = serial_log_bucket + self._tracing = False + self._battor_shell = None + self._trace_results_path = None + self._start_tracing_time = None + self._stop_tracing_time = None + self._trace_results = None + self._serial_log_file = None + self._target_platform = target_platform + self._git_hash = None + + atexit.register(self.KillBattOrShell) + + def _FlashBattOr(self): + assert self._battor_shell, ( + 'Must start shell before attempting to flash BattOr') + + try: + device_git_hash = self.GetFirmwareGitHash() + battor_firmware, cs_git_hash = self._dm.FetchPathWithVersion( + 'battor_firmware', 'default') + if cs_git_hash != device_git_hash: + logging.info( + 'Flashing BattOr with old firmware version <%s> with new ' + 'version <%s>.', device_git_hash, cs_git_hash) + avrdude_config = self._dm.FetchPath('avrdude_config', 'default') + self.StopShell() + return self.FlashFirmware(battor_firmware, avrdude_config) + return False + except ValueError: + logging.exception('Git hash returned from BattOr was not as expected: %s' + % self._git_hash) + + finally: + if not self._battor_shell: + # TODO(charliea): Once we understand why BattOrs are crashing, remove + # this log. + # http://crbug.com/699581 + logging.info('_FlashBattOr serial log:') + self._UploadSerialLogToCloudStorage() + self._serial_log_file = None + + self.StartShell() + + def KillBattOrShell(self): + if self._battor_shell: + logging.critical('BattOr shell was not properly closed. Killing now.') + self._battor_shell.kill() + + def GetShellReturnCode(self): + """Gets the return code of the BattOr agent shell.""" + rc = self._battor_shell.poll() + return rc + + def StartShell(self): + """Start BattOr binary shell.""" + assert not self._battor_shell, 'Attempting to start running BattOr shell.' + + battor_cmd = [self._battor_agent_binary] + if self._serial_log_bucket: + # Create and immediately close a temp file in order to get a filename + # for the serial log. + self._serial_log_file = tempfile.NamedTemporaryFile(delete=False) + self._serial_log_file.close() + battor_cmd.append('--battor-serial-log=%s' % self._serial_log_file.name) + if self._battor_path: + battor_cmd.append('--battor-path=%s' % self._battor_path) + self._battor_shell = self._StartShellImpl(battor_cmd) + assert self.GetShellReturnCode() is None, 'Shell failed to start.' + + def StopShell(self, timeout=None): + """Stop BattOr binary shell.""" + assert self._battor_shell, 'Attempting to stop a non-running BattOr shell.' + assert not self._tracing, 'Attempting to stop a BattOr shell while tracing.' + timeout = timeout if timeout else DEFAULT_SHELL_CLOSE_TIMEOUT_S + + self._SendBattOrCommand(self._EXIT_CMD, check_return=False) + try: + py_utils.WaitFor(lambda: self.GetShellReturnCode() != None, timeout) + except py_utils.TimeoutException: + self.KillBattOrShell() + finally: + self._battor_shell = None + + def StartTracing(self): + """Start tracing on the BattOr.""" + assert self._battor_shell, 'Must start shell before tracing' + assert not self._tracing, 'Tracing already started.' + self._FlashBattOr() + self._SendBattOrCommand(self._START_TRACING_CMD) + self._tracing = True + self._start_tracing_time = int(time.time()) + + def StopTracing(self): + """Stop tracing on the BattOr.""" + assert self._tracing, 'Must run StartTracing before StopTracing' + # Create temp file to reserve location for saving results. + temp_file = tempfile.NamedTemporaryFile(delete=False) + self._trace_results_path = temp_file.name + temp_file.close() + self._SendBattOrCommand( + '%s %s' % (self._STOP_TRACING_CMD, self._trace_results_path), + check_return=False) + self._tracing = False + self._stop_tracing_time = int(time.time()) + + def CollectTraceData(self, timeout=None): + """Collect trace data from battor. + Args: + timeout: timeout for waiting on the BattOr process to terminate in + seconds. + Returns: Trace data in form of a list. + """ + # The BattOr shell terminates after returning the results. + if timeout is None: + timeout = self._stop_tracing_time - self._start_tracing_time + py_utils.WaitFor(lambda: self.GetShellReturnCode() != None, timeout) + + # TODO(charliea): Once we understand why BattOrs are crashing, only do + # this on failure. + # http://crbug.com/699581 + logging.info('CollectTraceData serial log:') + self._UploadSerialLogToCloudStorage() + + with open(self._trace_results_path) as results: + self._trace_results = results.read() + self._battor_shell = None + self._serial_log_file = None + return self._trace_results + + def SupportsExplicitClockSync(self): + """Returns if BattOr supports Clock Sync events.""" + return bool(int(self._SendBattOrCommand(self._SUPPORTS_CLOCKSYNC_CMD, + check_return=False))) + + def RecordClockSyncMarker(self, sync_id): + """Record clock sync event on BattOr.""" + if not isinstance(sync_id, basestring): + raise TypeError('sync_id must be a string.') + self._SendBattOrCommand('%s %s' % (self._RECORD_CLOCKSYNC_CMD, sync_id)) + + def _GetBattOrPath(self, target_platform, android_device=None, + battor_path=None, battor_map_file=None, battor_map=None): + """Determines most likely path to the correct BattOr.""" + if target_platform not in self._SUPPORTED_PLATFORMS: + raise battor_error.BattOrError( + '%s is an unsupported platform.' % target_platform) + if target_platform in ['win']: + # Right now, the BattOr agent binary isn't able to automatically detect + # the BattOr port on Windows. To get around this, we know that the BattOr + # shows up with a name of 'USB Serial Port', so use the COM port that + # corresponds to a device with that name. + for (port, desc, _) in serial.tools.list_ports.comports(): + if 'USB Serial Port' in desc: + return port + raise battor_error.BattOrError( + 'Could not find BattOr attached to machine.') + if target_platform in ['mac']: + for (port, desc, _) in serial.tools.list_ports.comports(): + if 'BattOr' in desc: + return port + + if target_platform in ['android', 'linux']: + device_tree = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=True) + if battor_path: + if not isinstance(battor_path, basestring): + raise battor_error.BattOrError( + 'An invalid BattOr path was specified.') + return battor_path + + if target_platform == 'android': + if not android_device: + raise battor_error.BattOrError( + 'Must specify device for Android platform.') + if not battor_map_file and not battor_map: + # No map was passed, so must create one. + battor_map = battor_device_mapping.GenerateSerialMap() + + return battor_device_mapping.GetBattOrPathFromPhoneSerial( + str(android_device), serial_map_file=battor_map_file, + serial_map=battor_map) + + # Not Android and no explicitly passed BattOr. + battors = battor_device_mapping.GetBattOrList(device_tree) + if len(battors) != 1: + raise battor_error.BattOrError( + 'For non-Android platforms, exactly one BattOr must be ' + 'attached unless address is explicitly given.') + return '/dev/%s' % battors.pop() + + raise NotImplementedError( + 'BattOr Wrapper not implemented for given platform') + + def _SendBattOrCommandImpl(self, cmd): + """Sends command to the BattOr.""" + self._battor_shell.stdin.write('%s\n' % cmd) + self._battor_shell.stdin.flush() + return self._battor_shell.stdout.readline() + + def _SendBattOrCommand(self, cmd, check_return=True): + status = self._SendBattOrCommandImpl(cmd) + + if check_return and not 'Done.' in status: + self.KillBattOrShell() + self._UploadSerialLogToCloudStorage() + self._serial_log_file = None + raise battor_error.BattOrError( + 'BattOr did not complete command \'%s\' correctly.\n' + 'Outputted: %s' % (cmd, status)) + return status + + def _StartShellImpl(self, battor_cmd): + return subprocess.Popen( + battor_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, shell=False) + + def _UploadSerialLogToCloudStorage(self): + """Uploads the BattOr serial log to cloud storage.""" + if not self._serial_log_file or not cloud_storage.IsNetworkIOEnabled(): + return + + remote_path = ('battor-serial-log-%s-%d.txt' % ( + datetime.datetime.now().strftime('%Y-%m-%d_%H-%M.txt'), + random.randint(1, 100000))) + + try: + cloud_url = cloud_storage.Insert( + self._serial_log_bucket, remote_path, self._serial_log_file.name) + sys.stderr.write('View BattOr serial log at %s\n' % cloud_url) + except cloud_storage.PermissionError as e: + logging.error('Cannot upload BattOr serial log file to cloud storage due ' + 'to permission error: %s' % e.message) + + def GetFirmwareGitHash(self): + """Gets the git hash for the BattOr firmware. + + Returns: Git hash for firmware currently on the BattOr. + Also sets self._git_hash to this value. + + Raises: ValueException if the git hash is not in hex. + """ + assert self._battor_shell, ('Must start shell before getting firmware git ' + 'hash') + self._git_hash = self._SendBattOrCommand(self._GET_FIRMWARE_GIT_HASH_CMD, + check_return=False).strip() + # We expect the git hash to be a valid 6 character hexstring. This will + # throw a ValueError exception otherwise. + int(self._git_hash, 16) + return self._git_hash + + def FlashFirmware(self, hex_path, avrdude_config_path): + """Flashes the BattOr using an avrdude config at config_path with the new + firmware at hex_path. + """ + assert not self._battor_shell, 'Cannot flash BattOr with open shell' + + avrdude_binary = self._dm.FetchPath( + 'avrdude_binary', '%s_%s' % (sys.platform, platform.machine())) + # Sanitize hex file path for windows. It contains :/ which avrdude + # is not capable of handling. + _, hex_path = os.path.splitdrive(hex_path) + avr_cmd = [ + avrdude_binary, + '-e', # Specify to erase data on chip. + '-p', self._BATTOR_PARTNO, # Specify AVR device. + # Specify which microcontroller programmer to use. + '-c', self._BATTOR_PROGRAMMER, + '-b', self._BATTOR_BAUDRATE, # Specify the baud rate to communicate at. + '-P', self._battor_path, # Serial path to the battor. + # Command to execute with hex file and path to hex file. + '-U', 'flash:w:%s' % hex_path, + '-C', avrdude_config_path, # AVRdude config file path. + '2>&1' # All output goes to stderr for some reason. + ] + try: + subprocess.check_output(avr_cmd) + except subprocess.CalledProcessError as e: + raise BattOrFlashError('BattOr flash failed with return code %s.' + % e.returncode) + + self._git_hash = None + return True + + +class BattOrFlashError(Exception): + pass diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_devicetest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_devicetest.py new file mode 100644 index 0000000..4ca59a7 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_devicetest.py @@ -0,0 +1,106 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import platform +import os +import sys +import time +import unittest + +if __name__ == '__main__': + sys.path.append( + os.path.join(os.path.dirname(__file__), '..')) + +from battor import battor_wrapper +from devil.utils import battor_device_mapping +from devil.utils import find_usb_devices +from py_utils import cloud_storage + + +_SUPPORTED_CQ_PLATFORMS = ['win', 'linux', 'mac'] + +class BattOrWrapperDeviceTest(unittest.TestCase): + def setUp(self): + test_platform = platform.system() + self._battor_list = None + if 'Win' in test_platform: + self._platform = 'win' + elif 'Linux' in test_platform: + self._platform = 'linux' + device_tree = find_usb_devices.GetBusNumberToDeviceTreeMap() + self._battor_list = battor_device_mapping.GetBattOrList(device_tree) + elif 'Darwin' in test_platform: + self._platform = 'mac' + + if not battor_wrapper.IsBattOrConnected(self._platform): + self._battor_list = [] + + def testFullRun(self): + # If battor_list is an empty list, a BattOr was expected but not found. + if self._battor_list is not None and not self._battor_list: + logging.critical('No BattOrs attached. Cannot run tests.') + return + + if self._platform not in _SUPPORTED_CQ_PLATFORMS: + logging.critical('Platform %s is not supported on CQ.' % self._platform) + return + + + battor_path = (None if not self._battor_list + else '/dev/%s' % self._battor_list[0]) + battor = battor_wrapper.BattOrWrapper( + self._platform, battor_path=battor_path, + serial_log_bucket=cloud_storage.TELEMETRY_OUTPUT) + try: + battor.StartShell() + self.assertTrue(isinstance(battor.GetFirmwareGitHash(), basestring)) + # We expect the git hash to be a valid 6 character hexstring. This will + # throw a ValueError exception otherwise. + int(battor.GetFirmwareGitHash(), 16) + self.assertTrue(len(battor.GetFirmwareGitHash()) == 7) + battor.StopShell() + + battor.StartShell() + battor.StartTracing() + # TODO(rnephew): This sleep is required for now because crbug.com/602266 + # causes the BattOr to crash when the trace time is too short. Once that + # bug is fixed, we should remove this delay. + time.sleep(1) + battor.RecordClockSyncMarker('abc') + # Sleep here because clock sync marker will be flaky if not. + time.sleep(1) + battor.StopTracing() + + # Below is a work around for crbug.com/603309. On this short of a trace, 5 + # seconds is enough to ensure that the trace will finish flushing to the + # file. The process is then killed so that BattOrWrapper knows that the + # process has been closed after tracing stops. + if self._platform == 'win': + time.sleep(5) + battor._battor_shell.kill() + results = battor.CollectTraceData().splitlines() + except: + if battor._battor_shell is not None: + battor._battor_shell.kill() + battor._battor_shell = None + raise + + self.assertTrue('# BattOr' in results[0]) + self.assertTrue('# voltage_range' in results[1]) + self.assertTrue('# current_range' in results[2]) + self.assertTrue('# sample_rate' in results[3]) + # First line with results. Should be 3 'words'. + self.assertTrue(len(results[4].split()) == 3) + clock_sync_found = False + for entry in results: + if '' in entry: + clock_sync_found = True + break + self.assertTrue(clock_sync_found, 'BattOr Data:%s\n' % repr(results)) + + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_unittest.py new file mode 100644 index 0000000..3e48a33 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/battor/battor/battor_wrapper_unittest.py @@ -0,0 +1,365 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import dependency_manager +import logging +import mock +import subprocess +import unittest + +from battor import battor_error +from battor import battor_wrapper +from devil.utils import battor_device_mapping +from devil.utils import find_usb_devices + +import serial +from serial.tools import list_ports + + +class DependencyManagerMock(object): + def __init__(self, _): + self._fetch_return = 'path' + self._version_return = 'cbaa843' + + def FetchPath(self, _, *unused): + del unused + return self._fetch_return + + def FetchPathWithVersion(self, _, *unused): + del unused + return self._fetch_return, self._version_return + +class PopenMock(object): + def __init__(self, *unused): + pass + + def poll(self): + pass + + def kill(self): + pass + + +class IsBattOrConnectedTest(unittest.TestCase): + def setUp(self): + # Windows monkey patches. + self._serial_tools_return = [] + self._comports = serial.tools.list_ports.comports + serial.tools.list_ports.comports = lambda: self._serial_tools_return + + # Linux/Android monkey patches. + self._generate_serial_map_return = {} + self._generate_serial_map = battor_device_mapping.GenerateSerialMap + battor_device_mapping.GenerateSerialMap = ( + lambda: self._generate_serial_map_return) + + self._read_serial_map_file_return = {} + self._read_serial_map_file = battor_device_mapping.ReadSerialMapFile + battor_device_mapping.ReadSerialMapFile = ( + lambda f: self._read_serial_map_file_return) + + self._get_bus_number_to_device_tree_map = ( + find_usb_devices.GetBusNumberToDeviceTreeMap) + find_usb_devices.GetBusNumberToDeviceTreeMap = lambda fast=None: {} + + self._get_battor_list_return = [] + self._get_battor_list = battor_device_mapping.GetBattOrList + battor_device_mapping.GetBattOrList = lambda x: self._get_battor_list_return + + def tearDown(self): + serial.tools.list_ports.comports = self._comports + battor_device_mapping.GenerateSerialMap = self._generate_serial_map + battor_device_mapping.ReadSerialMapFile = self._read_serial_map_file + find_usb_devices.GetBusNumberToDeviceTreeMap = ( + self._get_bus_number_to_device_tree_map) + battor_device_mapping.GetBattOrList = self._get_battor_list + + def forceException(self): + raise NotImplementedError + + def testAndroidWithBattOr(self): + self._generate_serial_map_return = {'abc': '123'} + self.assertTrue(battor_wrapper.IsBattOrConnected('android', 'abc')) + + def testAndroidWithoutMatchingBattOr(self): + self._generate_serial_map_return = {'notabc': 'not123'} + self.assertFalse(battor_wrapper.IsBattOrConnected('android', 'abc')) + + def testAndroidNoDevicePassed(self): + with self.assertRaises(ValueError): + battor_wrapper.IsBattOrConnected('android') + + def testAndroidWithMapAndFile(self): + device_map = {'abc': '123'} + battor_device_mapping.ReadSerialMapFile = self.forceException + self.assertTrue( + battor_wrapper.IsBattOrConnected('android', android_device='abc', + android_device_map=device_map, + android_device_file='file')) + + def testAndroidWithMap(self): + self.assertTrue( + battor_wrapper.IsBattOrConnected('android', android_device='abc', + android_device_map={'abc', '123'})) + + def testAndroidWithFile(self): + self._read_serial_map_file_return = {'abc': '123'} + self.assertTrue( + battor_wrapper.IsBattOrConnected('android', android_device='abc', + android_device_file='file')) + + def testLinuxWithBattOr(self): + self._get_battor_list_return = ['battor'] + self.assertTrue(battor_wrapper.IsBattOrConnected('linux')) + + def testLinuxWithoutBattOr(self): + self._get_battor_list_return = [] + self.assertFalse(battor_wrapper.IsBattOrConnected('linux')) + + def testMacWithBattOr(self): + self._serial_tools_return = [('/dev/tty.usbserial-MAA', 'BattOr v3.3', '')] + self.assertTrue(battor_wrapper.IsBattOrConnected('mac')) + + def testMacWithoutBattOr(self): + self._serial_tools_return = [('/dev/tty.usbserial-MAA', 'not_one', '')] + self.assertFalse(battor_wrapper.IsBattOrConnected('mac')) + + def testWinWithBattOr(self): + self._serial_tools_return = [('COM4', 'USB Serial Port', '')] + self.assertTrue(battor_wrapper.IsBattOrConnected('win')) + + def testWinWithoutBattOr(self): + self._get_battor_list_return = [] + self.assertFalse(battor_wrapper.IsBattOrConnected('win')) + + +class BattOrWrapperTest(unittest.TestCase): + def setUp(self): + self._battor = None + self._is_battor = True + self._battor_list = ['battor1'] + self._should_pass = True + self._fake_map = {'battor1': 'device1'} + self._fake_return_code = None + self._fake_battor_return = 'Done.\n' + + self._get_battor_path_from_phone_serial = ( + battor_device_mapping.GetBattOrPathFromPhoneSerial) + self._get_bus_number_to_device_tree_map = ( + find_usb_devices.GetBusNumberToDeviceTreeMap) + self._dependency_manager = dependency_manager.DependencyManager + self._get_battor_list = battor_device_mapping.GetBattOrList + self._is_battor = battor_device_mapping.IsBattOr + self._generate_serial_map = battor_device_mapping.GenerateSerialMap + self._serial_tools = serial.tools.list_ports.comports + + battor_device_mapping.GetBattOrPathFromPhoneSerial = ( + lambda x, serial_map_file=None, serial_map=None: x + '_battor') + find_usb_devices.GetBusNumberToDeviceTreeMap = lambda fast=False: True + dependency_manager.DependencyManager = DependencyManagerMock + battor_device_mapping.GetBattOrList = lambda x: self._battor_list + battor_device_mapping.IsBattOr = lambda x, y: self._is_battor + battor_device_mapping.GenerateSerialMap = lambda: self._fake_map + serial.tools.list_ports.comports = lambda: [('COM4', 'USB Serial Port', '')] + + self._subprocess_check_output_code = 0 + def subprocess_check_output_mock(*unused): + if self._subprocess_check_output_code != 0: + raise subprocess.CalledProcessError(None, None) + return 0 + self._subprocess_check_output = subprocess.check_output + subprocess.check_output = subprocess_check_output_mock + + def tearDown(self): + battor_device_mapping.GetBattOrPathFromPhoneSerial = ( + self._get_battor_path_from_phone_serial) + find_usb_devices.GetBusNumberToDeviceTreeMap = ( + self._get_bus_number_to_device_tree_map) + dependency_manager.DependencyManager = self._dependency_manager + battor_device_mapping.GetBattOrList = self._get_battor_list + battor_device_mapping.IsBattOr = self._is_battor + battor_device_mapping.GenerateSerialMap = self._generate_serial_map + serial.tools.list_ports.comports = self._serial_tools + subprocess.check_output = self._subprocess_check_output + + def _DefaultBattOrReplacements(self): + battor_wrapper.DEFAULT_SHELL_CLOSE_TIMEOUT_S = .1 + self._battor._StartShellImpl = lambda *unused: PopenMock() + self._battor.GetShellReturnCode = lambda *unused: self._fake_return_code + self._battor._SendBattOrCommandImpl = lambda x: self._fake_battor_return + self._battor._StopTracingImpl = lambda *unused: (self._fake_battor_return, + None) + + def testBadPlatform(self): + with self.assertRaises(battor_error.BattOrError): + self._battor = battor_wrapper.BattOrWrapper('unknown') + + def testInitAndroidWithBattOr(self): + self._battor = battor_wrapper.BattOrWrapper('android', android_device='abc') + self.assertEquals(self._battor._battor_path, 'abc_battor') + + def testInitAndroidWithoutBattOr(self): + self._battor_list = [] + self._fake_map = {} + battor_device_mapping.GetBattOrPathFromPhoneSerial = ( + self._get_battor_path_from_phone_serial) + with self.assertRaises(battor_error.BattOrError): + self._battor = battor_wrapper.BattOrWrapper('android', + android_device='abc') + + def testInitBattOrPathIsBattOr(self): + battor_path = 'battor/path/here' + self._battor = battor_wrapper.BattOrWrapper( + 'android', android_device='abc', battor_path=battor_path) + self.assertEquals(self._battor._battor_path, battor_path) + + def testInitNonAndroidWithBattOr(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self.assertEquals(self._battor._battor_path, 'COM4') + + def testInitNonAndroidWithMultipleBattOr(self): + self._battor_list.append('battor2') + with self.assertRaises(battor_error.BattOrError): + self._battor = battor_wrapper.BattOrWrapper('linux') + + def testInitNonAndroidWithoutBattOr(self): + self._battor_list = [] + serial.tools.list_ports.comports = lambda: [('COM4', 'None', '')] + with self.assertRaises(battor_error.BattOrError): + self._battor = battor_wrapper.BattOrWrapper('win') + + def testStartShellPass(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self.assertIsNotNone(self._battor._battor_shell) + + def testStartShellDoubleStart(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + with self.assertRaises(AssertionError): + self._battor.StartShell() + + def testStartShellFail(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.GetShellReturnCode = lambda *unused: 1 + with self.assertRaises(AssertionError): + self._battor.StartShell() + + def testStartTracingPass(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._battor.StartTracing() + self.assertTrue(self._battor._tracing) + + def testStartTracingDoubleStart(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._battor.StartTracing() + with self.assertRaises(AssertionError): + self._battor.StartTracing() + + def testStartTracingCommandFails(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor._SendBattOrCommandImpl = lambda *unused: 'Fail.\n' + self._battor.StartShell() + with self.assertRaises(battor_error.BattOrError): + self._battor.StartTracing() + + def testStopTracingPass(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._battor.StartTracing() + self._battor.GetShellReturnCode = lambda *unused: 0 + self._battor.StopTracing() + self.assertFalse(self._battor._tracing) + + def testStopTracingNotRunning(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + with self.assertRaises(AssertionError): + self._battor.StopTracing() + + def testFlashFirmwarePass(self): + self._battor = battor_wrapper.BattOrWrapper('linux') + self._DefaultBattOrReplacements() + self.assertTrue(self._battor.FlashFirmware('hex_path', 'config_path')) + + def testFlashFirmwareFail(self): + self._battor = battor_wrapper.BattOrWrapper('linux') + self._DefaultBattOrReplacements() + self._subprocess_check_output_code = 1 + with self.assertRaises(battor_wrapper.BattOrFlashError): + self._battor.FlashFirmware('hex_path', 'config_path') + + def testFlashFirmwareShellRunning(self): + self._battor = battor_wrapper.BattOrWrapper('linux') + self._DefaultBattOrReplacements() + self._battor.StartShell() + with self.assertRaises(AssertionError): + self._battor.FlashFirmware('hex_path', 'config_path') + + def testGetFirmwareGitHashNotRunning(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + with self.assertRaises(AssertionError): + self._battor.GetFirmwareGitHash() + + def testGetFirmwareGitHashPass(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._battor.GetFirmwareGitHash = lambda: 'cbaa843' + self.assertTrue(isinstance(self._battor.GetFirmwareGitHash(), basestring)) + + def testStopShellPass(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._fake_return_code = 0 + self._battor.StopShell() + self.assertIsNone(self._battor._battor_shell) + + @mock.patch('time.sleep', mock.Mock) + def testStopShellTimeOutAndKill(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._battor.StopShell() + self.assertIsNone(self._battor._battor_shell) + + def testStopShellNotStarted(self): + self._battor = battor_wrapper.BattOrWrapper('win') + self._DefaultBattOrReplacements() + with self.assertRaises(AssertionError): + self._battor.StopShell() + + @mock.patch('time.sleep', mock.Mock) + def testFlashBattOrSameGitHash(self): + self._battor = battor_wrapper.BattOrWrapper('linux') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._battor.GetFirmwareGitHash = lambda: 'cbaa843' + dependency_manager.DependencyManager._version_return = 'cbaa843' + self.assertFalse(self._battor._FlashBattOr()) + + @mock.patch('time.sleep', mock.Mock) + def testFlashBattOrDifferentGitHash(self): + self._battor = battor_wrapper.BattOrWrapper('linux') + self._DefaultBattOrReplacements() + self._battor.StartShell() + self._battor.GetFirmwareGitHash = lambda: 'bazz732' + dependency_manager.DependencyManager._version_return = 'cbaa843' + self.assertTrue(self._battor._FlashBattOr()) + + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/LICENSE b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/LICENSE new file mode 100644 index 0000000..f943447 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/LICENSE @@ -0,0 +1,20 @@ +ESLint +Copyright jQuery Foundation and other contributors, https://jquery.org/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/README.md b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/README.md new file mode 100644 index 0000000..8ba5b63 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/README.md @@ -0,0 +1,5 @@ +This directory contains the Catapult eslint config, custom Catapult eslint rules, +and tests for those rules. + +Some of our custom rules are modified versions of those included with eslint, as +suggested in https://goo.gl/uAxFHq. diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/__init__.py new file mode 100644 index 0000000..082178a --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/__init__.py @@ -0,0 +1,68 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import subprocess +import sys + + +_CATAPULT_PATH = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + os.path.pardir, os.path.pardir, os.path.pardir) + + +def _AddToPathIfNeeded(path): + if path not in sys.path: + sys.path.insert(0, path) + + +def _UpdateSysPathIfNeeded(): + _AddToPathIfNeeded(os.path.join(_CATAPULT_PATH, 'common', 'node_runner')) + _AddToPathIfNeeded(os.path.join(_CATAPULT_PATH, 'common', 'py_utils')) + + +_UpdateSysPathIfNeeded() + + +import py_utils +from node_runner import node_util + + +BASE_ESLINT_CMD = [ + node_util.GetNodePath(), + os.path.join(node_util.GetNodeModulesPath(), 'eslint', 'bin', 'eslint.js'), + '--color' +] + + +DEFAULT_ESLINT_RULES_DIR = os.path.join( + py_utils.GetCatapultDir(), 'common', 'eslint', 'rules') + + +def _CreateEslintCommand(rulesdir, extra_args): + eslint_cmd = BASE_ESLINT_CMD + [ + '--rulesdir', rulesdir, '--ext', '.js,.html' + ] + if extra_args: + eslint_cmd.extend(extra_args.strip().split(' ')) + return eslint_cmd + + +def RunEslint(paths, rules_dir=DEFAULT_ESLINT_RULES_DIR, extra_args=None): + """Runs eslint on a list of paths. + + Args: + paths: A list of paths to run eslint on. + rules_dir: A directory of custom eslint rules. + extra_args: A string to append to the end of the eslint command. + """ + if type(paths) is not list or len(paths) == 0: + raise ValueError('Must specify a non-empty list of paths to lint.') + + try: + eslint_cmd = _CreateEslintCommand(rules_dir, extra_args) + return True, subprocess.check_output(eslint_cmd + paths, + stderr=subprocess.STDOUT).rstrip() + except subprocess.CalledProcessError as e: + return False, e.output.rstrip() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/smoke_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/smoke_test.py new file mode 100644 index 0000000..9a0f442 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/eslint/smoke_test.py @@ -0,0 +1,36 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import eslint +import os +import tempfile +import unittest + + +_TEMP_FILE_CONTENTS = ''' + + +''' + + +class SmokeTest(unittest.TestCase): + def testEslintFindsError(self): + try: + tmp_file = tempfile.NamedTemporaryFile( + delete=False, dir=os.path.dirname(__file__), suffix=".html") + tmp_file.write(_TEMP_FILE_CONTENTS) + tmp_file.close() + + success, output = eslint.RunEslint([tmp_file.name]) + self.assertFalse(success) + self.assertTrue('is not in camel case' in output) + finally: + os.remove(tmp_file.name) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/rules/catapult-camelcase.js b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/rules/catapult-camelcase.js new file mode 100644 index 0000000..bf31052 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/rules/catapult-camelcase.js @@ -0,0 +1,154 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +/* eslint-disable */ + +/** + * @fileoverview Rule to flag non-camelcased identifiers + * @author Nicholas C. Zakas + */ + +'use strict'; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "enforce Catapult camelcase naming convention", + category: "Stylistic Issues", + recommended: false + }, + + schema: [ + { + type: "object", + properties: { + properties: { + enum: ["always", "never"] + } + }, + additionalProperties: false + } + ] + }, + + create(context) { + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + // contains reported nodes to avoid reporting twice on destructuring with shorthand notation + var reported = []; + + /** + * Checks if a string contains an underscore and isn't all upper-case + * @param {string} name The string to check. + * @returns {boolean} if the string is underscored + * @private + */ + function isUnderscored(name) { + + // if there's an underscore, it might be A_VARANT, which is okay + return name.indexOf("_") > -1 && name !== name.toUpperCase(); + } + + /** + * Reports an AST node as a rule violation. + * @param {ASTNode} node The node to report. + * @returns {void} + * @private + */ + function report(node) { + if (reported.indexOf(node) < 0) { + reported.push(node); + context.report(node, "Identifier '{{name}}' is not in camel case.", { name: node.name }); + } + } + + var options = context.options[0] || {}; + let properties = options.properties || ""; + + if (properties !== "always" && properties !== "never") { + properties = "always"; + } + + return { + + Identifier(node) { + + /* + * Leading and trailing underscores are commonly used to flag + * private/protected identifiers, strip them. + * + * NOTE: This has four Catapult-specific style exceptions: + * + * - The prefix opt_ + * - The prefix g_ + * - The suffix _smallerIsBetter + * - The suffix _biggerIsBetter + */ + var name = node.name.replace(/(?:^opt_)|^(?:^g_)|^_+|_+$|(?:_smallerIsBetter)$|(?:_biggerIsBetter)$/g, ""), + effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; + + // MemberExpressions get special rules + if (node.parent.type === "MemberExpression") { + + // "never" check properties + if (properties === "never") { + return; + } + + // Always report underscored object names + if (node.parent.object.type === "Identifier" && + node.parent.object.name === node.name && + isUnderscored(name)) { + report(node); + + // Report AssignmentExpressions only if they are the left side of the assignment + } else if (effectiveParent.type === "AssignmentExpression" && + isUnderscored(name) && + (effectiveParent.right.type !== "MemberExpression" || + effectiveParent.left.type === "MemberExpression" && + effectiveParent.left.property.name === node.name)) { + report(node); + } + + // Properties have their own rules + } else if (node.parent.type === "Property") { + + // "never" check properties + if (properties === "never") { + return; + } + + if (node.parent.parent && node.parent.parent.type === "ObjectPattern" && + node.parent.key === node && node.parent.value !== node) { + return; + } + + if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { + report(node); + } + + // Check if it's an import specifier + } else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) { + + // Report only if the local imported identifier is underscored + if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) { + report(node); + } + + // Report anything that is underscored that isn't a CallExpression + } else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { + report(node); + } + } + + }; + + } +}; diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/tests/catapult-camelcase.js b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/tests/catapult-camelcase.js new file mode 100644 index 0000000..f0bdb37 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/eslint/tests/catapult-camelcase.js @@ -0,0 +1,324 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +/* eslint-disable */ + +/** + * @fileoverview Tests for camelcase rule. + * @author Nicholas C. Zakas + */ + +'use strict'; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../rules/catapult-camelcase"), + RuleTester = require("../../node_runner/node_runner/node_modules/eslint/lib/testers/rule-tester"); + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +var ruleTester = new RuleTester(); + +ruleTester.run("camelcase", rule, { + valid: [ + "firstName = \"Nicholas\"", + "FIRST_NAME = \"Nicholas\"", + "__myPrivateVariable = \"Patrick\"", + "myPrivateVariable_ = \"Patrick\"", + "function doSomething(){}", + "do_something()", + "foo.do_something()", + "var foo = bar.baz_boom;", + "var foo = bar.baz_boom.something;", + "foo.boom_pow.qux = bar.baz_boom.something;", + "if (bar.baz_boom) {}", + "var obj = { key: foo.bar_baz };", + "var arr = [foo.bar_baz];", + "[foo.bar_baz]", + "var arr = [foo.bar_baz.qux];", + "[foo.bar_baz.nesting]", + "if (foo.bar_baz === boom.bam_pow) { [foo.baz_boom] }", + // These tests are for Catapult-specific exceptions. + "opt_firstName = \"Nicholas\"", + "g_firstName = \"Nicholas\"", + "sizeInBytes_smallerIsBetter = \"Nicholas\"", + "sizeInBytes_biggerIsBetter = \"Nicholas\"", + { + code: "var o = {key: 1}", + options: [{properties: "always"}] + }, + { + code: "var o = {bar_baz: 1}", + options: [{properties: "never"}] + }, + { + code: "obj.a_b = 2;", + options: [{properties: "never"}] + }, + { + code: "var obj = {\n a_a: 1 \n};\n obj.a_b = 2;", + options: [{properties: "never"}] + }, + { + code: "obj.foo_bar = function(){};", + options: [{properties: "never"}] + }, + { + code: "var { category_id: category } = query;", + parserOptions: { ecmaVersion: 6 } + }, + { + code: "var { category_id: category } = query;", + parserOptions: { ecmaVersion: 6 }, + options: [{properties: "never"}] + }, + { + code: "import { camelCased } from \"external module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" } + }, + { + code: "import { no_camelcased as camelCased } from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" } + }, + { + code: "import { no_camelcased as camelCased, anoterCamelCased } from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" } + } + ], + invalid: [ + { + code: "first_name = \"Nicholas\"", + errors: [ + { + message: "Identifier 'first_name' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "__private_first_name = \"Patrick\"", + errors: [ + { + message: "Identifier '__private_first_name' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "function foo_bar(){}", + errors: [ + { + message: "Identifier 'foo_bar' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "obj.foo_bar = function(){};", + errors: [ + { + message: "Identifier 'foo_bar' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "bar_baz.foo = function(){};", + errors: [ + { + message: "Identifier 'bar_baz' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "[foo_bar.baz]", + errors: [ + { + message: "Identifier 'foo_bar' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "if (foo.bar_baz === boom.bam_pow) { [foo_bar.baz] }", + errors: [ + { + message: "Identifier 'foo_bar' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "foo.bar_baz = boom.bam_pow", + errors: [ + { + message: "Identifier 'bar_baz' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "var foo = { bar_baz: boom.bam_pow }", + errors: [ + { + message: "Identifier 'bar_baz' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "foo.qux.boom_pow = { bar: boom.bam_pow }", + errors: [ + { + message: "Identifier 'boom_pow' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "var o = {bar_baz: 1}", + options: [{properties: "always"}], + errors: [ + { + message: "Identifier 'bar_baz' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "obj.a_b = 2;", + options: [{properties: "always"}], + errors: [ + { + message: "Identifier 'a_b' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "obj.a_b = 2;", + options: [{properties: "always"}], + errors: [ + { + message: "Identifier 'a_b' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "var { category_id: category_id } = query;", + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + message: "Identifier 'category_id' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "var { category_id } = query;", + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + message: "Identifier 'category_id' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import no_camelcased from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camelcased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import * as no_camelcased from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camelcased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import { no_camelcased } from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camelcased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import { no_camelcased as no_camel_cased } from \"external module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camel_cased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import { camelCased as no_camel_cased } from \"external module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camel_cased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import { camelCased, no_camelcased } from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camelcased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import { no_camelcased as camelCased, another_no_camelcased } from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'another_no_camelcased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import camelCased, { no_camelcased } from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camelcased' is not in camel case.", + type: "Identifier" + } + ] + }, + { + code: "import no_camelcased, { another_no_camelcased as camelCased } from \"external-module\";", + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "Identifier 'no_camelcased' is not in camel case.", + type: "Identifier" + } + ] + } + ] +}); diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/commits.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/commits.py new file mode 100644 index 0000000..3938c40 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/commits.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Print statistics about the rate of commits to a repository.""" + +import datetime +import itertools +import json +import math +import urllib +import urllib2 + + +_BASE_URL = 'https://chromium.googlesource.com/' +# Can be up to 10,000. +_REVISION_COUNT = 1000 + +_REPOSITORIES = [ + 'chromium/src', + 'angle/angle', + 'skia', + 'v8/v8', +] + + +def Pairwise(iterable): + """s -> (s0,s1), (s1,s2), (s2, s3), ...""" + a, b = itertools.tee(iterable) + next(b, None) + return itertools.izip(a, b) + + +def Percentile(data, percentile): + """Find a percentile of a list of values. + + Parameters: + data: A sorted list of values. + percentile: The percentile to look up, from 0.0 to 1.0. + + Returns: + The percentile. + + Raises: + ValueError: If data is empty. + """ + if not data: + raise ValueError() + + k = (len(data) - 1) * percentile + f = math.floor(k) + c = math.ceil(k) + + if f == c: + return data[int(k)] + return data[int(f)] * (c - k) + data[int(c)] * (k - f) + + +def CommitTimes(repository, revision_count): + parameters = urllib.urlencode((('n', revision_count), ('format', 'JSON'))) + url = '%s/%s/+log?%s' % (_BASE_URL, urllib.quote(repository), parameters) + data = json.loads(''.join(urllib2.urlopen(url).read().splitlines()[1:])) + + commit_times = [] + for revision in data['log']: + commit_time_string = revision['committer']['time'] + commit_time = datetime.datetime.strptime( + commit_time_string, '%a %b %d %H:%M:%S %Y') + commit_times.append(commit_time) + + return commit_times + + +def main(): + for repository in _REPOSITORIES: + commit_times = CommitTimes(repository, _REVISION_COUNT) + + commit_durations = [] + for time1, time2 in Pairwise(commit_times): + commit_durations.append((time1 - time2).total_seconds()) + commit_durations.sort() + + print 'REPOSITORY:', repository + print 'Start Date:', min(commit_times) + print ' End Date:', max(commit_times) + print ' Duration:', max(commit_times) - min(commit_times) + print ' n:', len(commit_times) + + for p in (0.00, 0.05, 0.25, 0.50, 0.75, 0.95, 1.00): + percentile = Percentile(commit_durations, p) + print '%3d%% commit duration:' % (p * 100), '%6ds' % percentile + mean = math.fsum(commit_durations) / len(commit_durations) + print ' Min commit duration:', '%6ds' % min(commit_durations) + print 'Mean commit duration:', '%6ds' % mean + print ' Max commit duration:', '%6ds' % max(commit_durations) + print + + +if __name__ == '__main__': + main() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/hardware.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/hardware.py new file mode 100644 index 0000000..5e49c5c --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/hardware.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Query build slave hardware info, and print it to stdout as csv.""" + +import csv +import json +import logging +import sys +import urllib2 + + +_MASTERS = [ + 'chromium.perf', + 'chromium.perf.fyi', + 'client.catapult', + 'tryserver.chromium.perf', + 'tryserver.client.catapult', +] + + +_KEYS = [ + 'master', 'builder', 'hostname', + + 'os family', 'os version', 'bitness (userland)', + + 'product name', 'architecture', 'processor count', 'processor type', + 'memory total', + + 'facter version', 'git version', 'puppet version', 'python version', + 'ruby version', + + 'android device 1', 'android device 2', 'android device 3', + 'android device 4', 'android device 5', 'android device 6', + 'android device 7', 'android device 8', +] +_EXCLUDED_KEYS = frozenset([ + 'architecture (userland)', + 'b directory', + 'last puppet run', + 'uptime', + 'windows version', +]) + + +def main(): + writer = csv.DictWriter(sys.stdout, _KEYS) + writer.writeheader() + + for master_name in _MASTERS: + master_data = json.load(urllib2.urlopen( + 'http://build.chromium.org/p/%s/json/slaves' % master_name)) + + slaves = sorted(master_data.iteritems(), + key=lambda x: (x[1]['builders'].keys(), x[0])) + for slave_name, slave_data in slaves: + for builder_name in slave_data['builders']: + row = { + 'master': master_name, + 'builder': builder_name, + 'hostname': slave_name, + } + + host_data = slave_data['host'] + if host_data: + host_data = host_data.splitlines() + if len(host_data) > 1: + for line in host_data: + if not line: + continue + key, value = line.split(': ') + if key in _EXCLUDED_KEYS: + continue + row[key] = value + + # Munge keys. + row = {key.replace('_', ' '): value for key, value in row.iteritems()} + if 'osfamily' in row: + row['os family'] = row.pop('osfamily') + if 'product name' not in row and slave_name.startswith('slave'): + row['product name'] = 'Google Compute Engine' + + try: + writer.writerow(row) + except ValueError: + logging.error(row) + raise + + +if __name__ == '__main__': + main() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/keychain_unlock.sh b/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/keychain_unlock.sh new file mode 100644 index 0000000..e550f8d --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/lab/keychain_unlock.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Script to SSH into a list of bots and set up their keychains for Telemetry. +# https://www.chromium.org/developers/telemetry/telemetry-mac-keychain-setup + +for hostname in "$@" +do + ssh -t "$hostname" 'security unlock-keychain login.keychain +security delete-generic-password -s "Chrome Safe Storage" login.keychain +security add-generic-password -a Chrome -w "+NTclOvR4wLMgRlLIL9bHQ==" \ + -s "Chrome Safe Storage" -A login.keychain' +done diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/__init__.py new file mode 100644 index 0000000..ce33e05 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_binaries.json b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_binaries.json new file mode 100644 index 0000000..4245249 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_binaries.json @@ -0,0 +1,53 @@ +{ + "config_type": "BaseConfig", + "dependencies": { + "node": { + "cloud_storage_base_folder": "binary_dependencies", + "cloud_storage_bucket": "chromium-telemetry", + "file_info": { + "linux_x86_64": { + "cloud_storage_hash": "5750e968975e7f5ab8cb694f5e92a34a890e129d", + "download_path": "bin/node/node-linux64.zip", + "path_within_archive": "node-v6.7.0-linux-x64/bin/node", + "version_in_cs": "6.7.0" + }, + "mac_x86_64": { + "cloud_storage_hash": "1af7c221e530165af8a6ab8ff7ccb1f2dd54036d", + "download_path": "bin/node/node-mac64.zip", + "path_within_archive": "node-v6.7.0-darwin-x64/bin/node", + "version_in_cs": "6.7.0" + }, + "win_AMD64": { + "cloud_storage_hash": "23f21bfb2edf874a8b6bdb6c1acb408bc7edeced", + "download_path": "bin/node/node-win64.zip", + "path_within_archive": "node-v6.7.0-win-x64/node.exe", + "version_in_cs": "6.7.0" + } + } + }, + "npm": { + "cloud_storage_base_folder": "binary_dependencies", + "cloud_storage_bucket": "chromium-telemetry", + "file_info": { + "linux_x86_64": { + "cloud_storage_hash": "5750e968975e7f5ab8cb694f5e92a34a890e129d", + "download_path": "bin/node/node-linux64.zip", + "path_within_archive": "node-v6.7.0-linux-x64/lib/node_modules/npm/bin/npm-cli.js", + "version_in_cs": "6.7.0" + }, + "mac_x86_64": { + "cloud_storage_hash": "1af7c221e530165af8a6ab8ff7ccb1f2dd54036d", + "download_path": "bin/node/node-mac64.zip", + "path_within_archive": "node-v6.7.0-darwin-x64/lib/node_modules/npm/bin/npm-cli.js", + "version_in_cs": "6.7.0" + }, + "win_AMD64": { + "cloud_storage_hash": "23f21bfb2edf874a8b6bdb6c1acb408bc7edeced", + "download_path": "bin/node/node-win64.zip", + "path_within_archive": "node-v6.7.0-win-x64\\node_modules\\npm\\bin\\npm-cli.js", + "version_in_cs": "6.7.0" + } + } + } + } +} diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_util.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_util.py new file mode 100644 index 0000000..05d0084 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/node_util.py @@ -0,0 +1,60 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import subprocess +import sys + +import py_utils +from py_utils import binary_manager +from py_utils import dependency_util + + +def _NodeBinariesConfigPath(): + return os.path.realpath(os.path.join( + os.path.dirname(os.path.abspath(__file__)), 'node_binaries.json')) + + +class _NodeManager(object): + def __init__(self): + self.bm = binary_manager.BinaryManager( + [_NodeBinariesConfigPath()]) + self.os_name = dependency_util.GetOSNameForCurrentDesktopPlatform() + self.arch_name = dependency_util.GetArchForCurrentDesktopPlatform( + self.os_name) + self.node_path = self.bm.FetchPath('node', self.os_name, self.arch_name) + self.npm_path = self.bm.FetchPath('npm', self.os_name, self.arch_name) + + self.node_initialized = False + + def InitNode(self): + if self.node_initialized: + return # So we only init once per run + self.node_initialized = True + old_dir = os.path.abspath(os.curdir) + os.chdir(os.path.join(os.path.abspath( + py_utils.GetCatapultDir()), 'common', 'node_runner', 'node_runner')) + subprocess.call([self.node_path, self.npm_path, 'install']) + os.chdir(old_dir) + + +_NODE_MANAGER = _NodeManager() + + +def InitNode(): + _NODE_MANAGER.InitNode() + + +def GetNodePath(): + return _NODE_MANAGER.node_path + + +def GetNodeModulesPath(): + _NODE_MANAGER.InitNode() + path = os.path.abspath(os.path.join(os.path.dirname(__file__), + 'node_modules')) + if sys.platform.startswith('win'): + # Escape path on Windows because it's very long and must be passed to NTFS. + path = u'\\\\?\\' + path + return path diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/package.json b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/package.json new file mode 100644 index 0000000..27d0325 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/node_runner/node_runner/package.json @@ -0,0 +1,22 @@ +{ + "name": "catapult_base", + "version": "1.0.0", + "description": "Catapult project base", + "repository": { + "type": "git", + "url": "https://github.com/catapult-project/catapult/tree/master/catapult_base" + }, + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "The Chromium Authors", + "license": "BSD-2-Clause", + "gypfile": false, + "private": true, + "dependencies": { + "eslint": "^3.14.1", + "eslint-config-google": "^0.6.0", + "eslint-plugin-html": "^2.0.0" + } +} diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/README.txt b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/README.txt new file mode 100644 index 0000000..2f0d33d --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/README.txt @@ -0,0 +1,7 @@ +py_trace_event allows low-overhead instrumentation of a multi-threaded, +multi-process application in order to study its global performance +characteristics. It uses the trace event format used in Chromium/Chrome's +about:tracing system. + +Trace files generated by py_trace_event can be viewed and manipulated by +trace_event_viewer. diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/__init__.py new file mode 100644 index 0000000..b8b6630 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/__init__.py @@ -0,0 +1,9 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import os +import sys + +SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) +PY_UTILS = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', 'py_utils')) +sys.path.append(PY_UTILS) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/run_tests b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/run_tests new file mode 100644 index 0000000..7f9673d --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/run_tests @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import logging +import optparse +import os +import platform +import re +import sys +import types +import traceback +import unittest + + +def discover(dir, filters): + if hasattr(unittest.TestLoader, 'discover'): + return unittest.TestLoader().discover(dir, '*') + + # poor mans unittest.discover + loader = unittest.TestLoader() + subsuites = [] + + for (dirpath, dirnames, filenames) in os.walk(dir): + for filename in [x for x in filenames if re.match('.*_test\.py$', x)]: + if filename.startswith('.') or filename.startswith('_'): + continue + fqn = dirpath.replace( + '/', '.') + '.' + re.match('(.+)\.py$', filename).group(1) + + # load the test + try: + module = __import__(fqn,fromlist=[True]) + except: + print "While importing [%s]\n" % fqn + traceback.print_exc() + continue + + def test_is_selected(name): + for f in filters: + if re.search(f,name): + return True + return False + + if hasattr(module, 'suite'): + base_suite = module.suite() + else: + base_suite = loader.loadTestsFromModule(module) + new_suite = unittest.TestSuite() + for t in base_suite: + if isinstance(t, unittest.TestSuite): + for i in t: + if test_is_selected(i.id()): + new_suite.addTest(i) + elif isinstance(t, unittest.TestCase): + if test_is_selected(t.id()): + new_suite.addTest(t) + else: + raise Exception("Wtf, expected TestSuite or TestCase, got %s" % t) + + if new_suite.countTestCases(): + subsuites.append(new_suite) + + return unittest.TestSuite(subsuites) + + +def main(): + parser = optparse.OptionParser() + parser.add_option( + '-v', '--verbose', action='count', default=0, + help='Increase verbosity level (repeat as needed)') + parser.add_option('--debug', dest='debug', action='store_true', default=False, + help='Break into pdb when an assertion fails') + parser.add_option('--incremental', dest='incremental', action='store_true', + default=False, help='Run tests one at a time.') + parser.add_option('--stop', dest='stop_on_error', action='store_true', + default=False, help='Stop running tests on error.') + (options, args) = parser.parse_args() + + if options.verbose >= 2: + logging.basicConfig(level=logging.DEBUG) + elif options.verbose: + logging.basicConfig(level=logging.INFO) + else: + logging.basicConfig(level=logging.WARNING) + + # install hook on set_trace if --debug + if options.debug: + import exceptions + class DebuggingAssertionError(exceptions.AssertionError): + def __init__(self, *args): + exceptions.AssertionError.__init__(self, *args) + print "Assertion failed, entering PDB..." + import pdb + if hasattr(sys, '_getframe'): + pdb.Pdb().set_trace(sys._getframe().f_back.f_back) + else: + pdb.set_trace() + unittest.TestCase.failureException = DebuggingAssertionError + + def hook(*args): + import traceback, pdb + traceback.print_exception(*args) + pdb.pm() + sys.excepthook = hook + + import browser + browser.debug_mode = True + + else: + def hook(exc, value, tb): + import traceback + if not str(value).startswith("_noprint"): + traceback.print_exception(exc, value, tb) + import src.message_loop + if src.message_loop.is_main_loop_running(): + if not str(value).startswith("_noprint"): + print "Untrapped exception! Exiting message loop with exception." + src.message_loop.quit_main_loop(quit_with_exception=True) + + sys.excepthook = hook + + # make sure cwd is the base directory! + os.chdir(os.path.dirname(__file__)) + + if len(args) > 0: + suites = discover('trace_event_impl', args) + else: + suites = discover('trace_event_impl', ['.*']) + + r = unittest.TextTestRunner() + if not options.incremental: + res = r.run(suites) + if res.wasSuccessful(): + return 0 + return 255 + else: + ok = True + for s in suites: + if isinstance(s, unittest.TestSuite): + for t in s: + print '--------------------------------------------------------------' + print 'Running %s' % str(t) + res = r.run(t) + if not res.wasSuccessful(): + ok = False + if options.stop_on_error: + break + if ok == False and options.stop_on_error: + break + else: + res = r.run(s) + if not res.wasSuccessful(): + ok = False + if options.stop_on_error: + break + if ok: + return 0 + return 255 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/setup.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/setup.py new file mode 100644 index 0000000..0b0070a --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/setup.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# Copyright 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +from distutils.core import setup +setup( + name='py_trace_event', + packages=['trace_event_impl'], + version='0.1.0', + description='Performance tracing for python', + author='Nat Duca' +) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event.py new file mode 100644 index 0000000..1abbfa7 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event.py @@ -0,0 +1,266 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +from py_trace_event import trace_time + + +r"""Instrumentation-based profiling for Python. + +trace_event allows you to hand-instrument your code with areas of interest. +When enabled, trace_event logs the start and stop times of these events to a +logfile. These resulting logfiles can be viewed with either Chrome's +about:tracing UI or with the standalone trace_event_viewer available at + http://www.github.com/natduca/trace_event_viewer/ + +To use trace event, call trace_event_enable and start instrumenting your code: + from trace_event import * + + if "--trace" in sys.argv: + trace_enable("myfile.trace") + + @traced + def foo(): + ... + + class MyFoo(object): + @traced + def bar(self): + ... + +trace_event records trace events to an in-memory buffer. If your application is +long running and you want to see the results of a trace before it exits, you can +call trace_flush to write any in-memory events to disk. + +To help intregrating trace_event into existing codebases that dont want to add +trace_event as a dependancy, trace_event is split into an import shim +(trace_event.py) and an implementaiton (trace_event_impl/*). You can copy the +shim, trace_event.py, directly into your including codebase. If the +trace_event_impl is not found, the shim will simply noop. + +trace_event is safe with regard to Python threads. Simply trace as you normally +would and each thread's timing will show up in the trace file. + +Multiple processes can safely output into a single trace_event logfile. If you +fork after enabling tracing, the child process will continue outputting to the +logfile. Use of the multiprocessing module will work as well. In both cases, +however, note that disabling tracing in the parent process will not stop tracing +in the child processes. +""" + +try: + import trace_event_impl +except ImportError: + trace_event_impl = None + + +def trace_can_enable(): + """ + Returns True if a trace_event_impl was found. If false, + trace_enable will fail. Regular tracing methods, including + trace_begin and trace_end, will simply be no-ops. + """ + return trace_event_impl != None + +if trace_event_impl: + import time + + + def trace_is_enabled(): + return trace_event_impl.trace_is_enabled() + + def trace_enable(logfile): + return trace_event_impl.trace_enable(logfile) + + def trace_disable(): + return trace_event_impl.trace_disable() + + def trace_flush(): + trace_event_impl.trace_flush() + + def trace_begin(name, **kwargs): + args_to_log = {key: repr(value) for key, value in kwargs.iteritems()} + trace_event_impl.add_trace_event("B", trace_time.Now(), "python", name, + args_to_log) + + def trace_end(name): + trace_event_impl.add_trace_event("E", trace_time.Now(), "python", name) + + def trace(name, **kwargs): + return trace_event_impl.trace(name, **kwargs) + + TracedMetaClass = trace_event_impl.TracedMetaClass + + def traced(fn): + return trace_event_impl.traced(fn) + + def clock_sync(sync_id, issue_ts=None): + ''' + Add a clock sync event to the trace log. + + Args: + sync_id: ID of clock sync event. + issue_ts: Time at which clock sync was issued, in microseconds. + ''' + time_stamp = trace_time.Now() + args_to_log = {'sync_id': sync_id} + if issue_ts: # Issuer if issue_ts is set, else reciever. + assert issue_ts <= time_stamp + args_to_log['issue_ts'] = issue_ts + trace_event_impl.add_trace_event( + "c", time_stamp, "python", "clock_sync", args_to_log) + + def is_tracing_controllable(): + return trace_event_impl.is_tracing_controllable() + +else: + import contextlib + + def trace_enable(): + raise TraceException( + "Cannot enable trace_event. No trace_event_impl module found.") + + def trace_disable(): + pass + + def trace_is_enabled(): + return False + + def trace_flush(): + pass + + def trace_begin(name, **kwargs): + del name # unused. + del kwargs # unused. + pass + + def trace_end(name): + del name # unused. + pass + + @contextlib.contextmanager + def trace(name, **kwargs): + del name # unused + del kwargs # unused + yield + + def traced(fn): + return fn + + def clock_sync(sync_id, issue_ts=None): + del sync_id # unused. + pass + + def is_tracing_controllable(): + return False + +trace_enable.__doc__ = """Enables tracing. + + Once enabled, the enabled bit propagates to forked processes and + multiprocessing subprocesses. Regular child processes, e.g. those created via + os.system/popen, or subprocess.Popen instances, will not get traced. You can, + however, enable tracing on those subprocess manually. + + Trace files are multiprocess safe, so you can have multiple processes + outputting to the same tracelog at once. + + log_file can be one of three things: + + None: a logfile is opened based on sys[argv], namely + "./" + sys.argv[0] + ".json" + + string: a logfile of the given name is opened. + + file-like object: the fileno() is is used. The underlying file descriptor + must support fcntl.lockf() operations. + """ + +trace_disable.__doc__ = """Disables tracing, if enabled. + + Will not disable tracing on any existing child proceses that were forked + from this process. You must disable them yourself. + """ + +trace_flush.__doc__ = """Flushes any currently-recorded trace data to disk. + + trace_event records traces into an in-memory buffer for efficiency. Flushing + is only done at process exit or when this method is called. + """ + +trace_is_enabled.__doc__ = """Returns whether tracing is enabled. + """ + +trace_begin.__doc__ = """Records the beginning of an event of the given name. + + The building block for performance tracing. A typical example is: + from trace_event import * + def something_heavy(): + trace_begin("something_heavy") + + trace_begin("read") + try: + lines = open().readlines() + finally: + trace_end("read") + + trace_begin("parse") + try: + parse(lines) + finally: + trace_end("parse") + + trace_end("something_heavy") + + Note that a trace_end call must be issued for every trace_begin call. When + tracing around blocks that might throw exceptions, you should use the trace + function, or a try-finally pattern to ensure that the trace_end method is + called. + + See the documentation for the @traced decorator for a simpler way to + instrument functions and methods. + """ + +trace_end.__doc__ = """Records the end of an event of the given name. + + See the documentation for trace_begin for more information. + + Make sure to issue a trace_end for every trace_begin issued. Failure to pair + these calls will lead to bizarrely tall looking traces in the + trace_event_viewer UI. + """ + +trace.__doc__ = """Traces a block of code using a with statement. + + Example usage: + from trace_event import * + def something_heavy(lines): + with trace("parse_lines", lines=lines): + parse(lines) + + If tracing an entire function call, prefer the @traced decorator. + """ + +traced.__doc__ = """ + Traces the provided function, using the function name for the actual generated + event. + + Prefer this decorator over the explicit trace_begin and trace_end functions + whenever you are tracing the start and stop of a function. It automatically + issues trace_begin/end events, even when the wrapped function throws. + + You can also pass the function's argument names to traced, and the argument + values will be added to the trace. Example usage: + from trace_event import * + @traced("url") + def send_request(url): + urllib2.urlopen(url).read() + """ + +clock_sync.__doc__ = """ + Issues a clock sync marker event. + + Clock sync markers are used to synchronize the clock domains of different + traces so that they can be used together. It takes a sync_id, and if it is + the issuer of a clock sync event it will also require an issue_ts. The + issue_ts is a timestamp from when the clocksync was first issued. This is used + to calculate the time difference between clock domains. + """ diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/__init__.py new file mode 100644 index 0000000..d250e03 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/__init__.py @@ -0,0 +1,7 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +from log import * +from decorators import * +from meta_class import * +import multiprocessing_shim diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators.py new file mode 100644 index 0000000..dc753f1 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators.py @@ -0,0 +1,87 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import contextlib +import inspect +import time +import functools + +import log +from py_trace_event import trace_time + + +@contextlib.contextmanager +def trace(name, **kwargs): + category = "python" + start = trace_time.Now() + args_to_log = {key: repr(value) for key, value in kwargs.iteritems()} + log.add_trace_event("B", start, category, name, args_to_log) + try: + yield + finally: + end = trace_time.Now() + log.add_trace_event("E", end, category, name) + +def traced(*args): + def get_wrapper(func): + if inspect.isgeneratorfunction(func): + raise Exception("Can not trace generators.") + + category = "python" + + arg_spec = inspect.getargspec(func) + is_method = arg_spec.args and arg_spec.args[0] == "self" + + def arg_spec_tuple(name): + arg_index = arg_spec.args.index(name) + defaults_length = len(arg_spec.defaults) if arg_spec.defaults else 0 + default_index = arg_index + defaults_length - len(arg_spec.args) + if default_index >= 0: + default = arg_spec.defaults[default_index] + else: + default = None + return (name, arg_index, default) + + args_to_log = map(arg_spec_tuple, arg_names) + + @functools.wraps(func) + def traced_function(*args, **kwargs): + # Everything outside traced_function is done at decoration-time. + # Everything inside traced_function is done at run-time and must be fast. + if not log._enabled: # This check must be at run-time. + return func(*args, **kwargs) + + def get_arg_value(name, index, default): + if name in kwargs: + return kwargs[name] + elif index < len(args): + return args[index] + else: + return default + + if is_method: + name = "%s.%s" % (args[0].__class__.__name__, func.__name__) + else: + name = "%s.%s" % (func.__module__, func.__name__) + + # Be sure to repr before calling func. Argument values may change. + arg_values = { + name: repr(get_arg_value(name, index, default)) + for name, index, default in args_to_log} + + start = trace_time.Now() + log.add_trace_event("B", start, category, name, arg_values) + try: + return func(*args, **kwargs) + finally: + end = trace_time.Now() + log.add_trace_event("E", end, category, name) + return traced_function + + no_decorator_arguments = len(args) == 1 and callable(args[0]) + if no_decorator_arguments: + arg_names = () + return get_wrapper(args[0]) + else: + arg_names = args + return get_wrapper diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators_test.py new file mode 100644 index 0000000..5bb13ad --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/decorators_test.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import decorators +import logging +import unittest + +from trace_test import TraceTest +#from .trace_test import TraceTest + +def generator(): + yield 1 + yield 2 + +class DecoratorTests(unittest.TestCase): + def test_tracing_object_fails(self): + self.assertRaises(Exception, lambda: decorators.trace(1)) + self.assertRaises(Exception, lambda: decorators.trace("")) + self.assertRaises(Exception, lambda: decorators.trace([])) + + def test_tracing_generators_fail(self): + self.assertRaises(Exception, lambda: decorators.trace(generator)) + +class ClassToTest(object): + @decorators.traced + def method1(self): + return 1 + + @decorators.traced + def method2(self): + return 1 + +@decorators.traced +def traced_func(): + return 1 + +class DecoratorTests(TraceTest): + def _get_decorated_method_name(self, f): + res = self.go(f) + events = res.findEventsOnThread(res.findThreadIds()[0]) + + # Sanity checks. + self.assertEquals(2, len(events)) + self.assertEquals(events[0]["name"], events[1]["name"]) + return events[1]["name"] + + + def test_func_names_work(self): + self.assertEquals('__main__.traced_func', + self._get_decorated_method_name(traced_func)) + + def test_method_names_work(self): + ctt = ClassToTest() + self.assertEquals('ClassToTest.method1', + self._get_decorated_method_name(ctt.method1)) + self.assertEquals('ClassToTest.method2', + self._get_decorated_method_name(ctt.method2)) + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log.py new file mode 100644 index 0000000..95d012f --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log.py @@ -0,0 +1,179 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import atexit +import json +import os +import sys +import time +import threading + +from py_trace_event import trace_time + +from py_utils import lock + + +_lock = threading.Lock() + +_enabled = False +_log_file = None + +_cur_events = [] # events that have yet to be buffered + +_tls = threading.local() # tls used to detect forking/etc +_atexit_regsitered_for_pid = None + +_control_allowed = True + + +class TraceException(Exception): + pass + +def _note(msg, *args): + pass +# print "%i: %s" % (os.getpid(), msg) + + +def _locked(fn): + def locked_fn(*args,**kwargs): + _lock.acquire() + try: + ret = fn(*args,**kwargs) + finally: + _lock.release() + return ret + return locked_fn + +def _disallow_tracing_control(): + global _control_allowed + _control_allowed = False + +def trace_enable(log_file=None): + _trace_enable(log_file) + +@_locked +def _trace_enable(log_file=None): + global _enabled + if _enabled: + raise TraceException("Already enabled") + if not _control_allowed: + raise TraceException("Tracing control not allowed in child processes.") + _enabled = True + global _log_file + if log_file == None: + if sys.argv[0] == '': + n = 'trace_event' + else: + n = sys.argv[0] + log_file = open("%s.json" % n, "ab", False) + _note("trace_event: tracelog name is %s.json" % n) + elif isinstance(log_file, basestring): + _note("trace_event: tracelog name is %s" % log_file) + log_file = open("%s" % log_file, "ab", False) + elif not hasattr(log_file, 'fileno'): + raise TraceException( + "Log file must be None, a string, or file-like object with a fileno()") + + _log_file = log_file + with lock.FileLock(_log_file, lock.LOCK_EX): + _log_file.seek(0, os.SEEK_END) + + lastpos = _log_file.tell() + creator = lastpos == 0 + if creator: + _note("trace_event: Opened new tracelog, lastpos=%i", lastpos) + _log_file.write('[') + + tid = threading.current_thread().ident + if not tid: + tid = os.getpid() + x = {"ph": "M", "category": "process_argv", + "pid": os.getpid(), "tid": threading.current_thread().ident, + "ts": trace_time.Now(), + "name": "process_argv", "args": {"argv": sys.argv}} + _log_file.write("%s\n" % json.dumps(x)) + else: + _note("trace_event: Opened existing tracelog") + _log_file.flush() + +@_locked +def trace_flush(): + if _enabled: + _flush() + +@_locked +def trace_disable(): + global _enabled + if not _control_allowed: + raise TraceException("Tracing control not allowed in child processes.") + if not _enabled: + return + _enabled = False + _flush(close=True) + +def _flush(close=False): + global _log_file + with lock.FileLock(_log_file, lock.LOCK_EX): + _log_file.seek(0, os.SEEK_END) + if len(_cur_events): + _log_file.write(",\n") + _log_file.write(",\n".join([json.dumps(e) for e in _cur_events])) + del _cur_events[:] + + if close: + # We might not be the only process writing to this logfile. So, + # we will simply close the file rather than writign the trailing ] that + # it technically requires. The trace viewer understands that this may + # happen and will insert a trailing ] during loading. + pass + _log_file.flush() + + if close: + _note("trace_event: Closed") + _log_file.close() + _log_file = None + else: + _note("trace_event: Flushed") + +@_locked +def trace_is_enabled(): + return _enabled + +@_locked +def add_trace_event(ph, ts, category, name, args=None): + global _enabled + if not _enabled: + return + if not hasattr(_tls, 'pid') or _tls.pid != os.getpid(): + _tls.pid = os.getpid() + global _atexit_regsitered_for_pid + if _tls.pid != _atexit_regsitered_for_pid: + _atexit_regsitered_for_pid = _tls.pid + atexit.register(_trace_disable_atexit) + _tls.pid = os.getpid() + del _cur_events[:] # we forked, clear the event buffer! + tid = threading.current_thread().ident + if not tid: + tid = os.getpid() + _tls.tid = tid + + _cur_events.append({"ph": ph, + "category": category, + "pid": _tls.pid, + "tid": _tls.tid, + "ts": ts, + "name": name, + "args": args or {}}); + +def trace_begin(name, args=None): + add_trace_event("B", trace_time.Now(), "python", name, args) + +def trace_end(name, args=None): + add_trace_event("E", trace_time.Now(), "python", name, args) + +def _trace_disable_atexit(): + trace_disable() + +def is_tracing_controllable(): + global _control_allowed + return _control_allowed diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log_io_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log_io_test.py new file mode 100644 index 0000000..99a0621 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/log_io_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import logging +import os +import sys +import tempfile +import unittest + +from log import * +from parsed_trace_events import * + + +class LogIOTest(unittest.TestCase): + def test_enable_with_file(self): + file = tempfile.NamedTemporaryFile() + trace_enable(open(file.name, 'w+')) + trace_disable() + e = ParsedTraceEvents(trace_filename = file.name) + file.close() + self.assertTrue(len(e) > 0) + + def test_enable_with_filename(self): + file = tempfile.NamedTemporaryFile() + trace_enable(file.name) + trace_disable() + e = ParsedTraceEvents(trace_filename = file.name) + file.close() + self.assertTrue(len(e) > 0) + + def test_enable_with_implicit_filename(self): + expected_filename = "%s.json" % sys.argv[0] + def do_work(): + file = tempfile.NamedTemporaryFile() + trace_enable() + trace_disable() + e = ParsedTraceEvents(trace_filename = expected_filename) + file.close() + self.assertTrue(len(e) > 0) + try: + do_work() + finally: + if os.path.exists(expected_filename): + os.unlink(expected_filename) + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/meta_class.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/meta_class.py new file mode 100644 index 0000000..4ede79b --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/meta_class.py @@ -0,0 +1,16 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import types + +from py_trace_event.trace_event_impl import decorators + + +class TracedMetaClass(type): + def __new__(cls, name, bases, attrs): + for attr_name, attr_value in attrs.iteritems(): + if isinstance(attr_value, types.FunctionType): + attrs[attr_name] = decorators.traced(attr_value) + + return super(TracedMetaClass, cls).__new__(cls, name, bases, attrs) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/multiprocessing_shim.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/multiprocessing_shim.py new file mode 100644 index 0000000..9796bdf --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/multiprocessing_shim.py @@ -0,0 +1,92 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import multiprocessing +import log +import time + + +_RealProcess = multiprocessing.Process +__all__ = [] + + +class ProcessSubclass(_RealProcess): + def __init__(self, shim, *args, **kwards): + _RealProcess.__init__(self, *args, **kwards) + self._shim = shim + + def run(self,*args,**kwargs): + log._disallow_tracing_control() + try: + r = _RealProcess.run(self, *args, **kwargs) + finally: + if log.trace_is_enabled(): + log.trace_flush() # todo, reduce need for this... + return r + +class ProcessShim(): + def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): + self._proc = ProcessSubclass(self, group, target, name, args, kwargs) + # hint to testing code that the shimming worked + self._shimmed_by_trace_event = True + + def run(self): + self._proc.run() + + def start(self): + self._proc.start() + + def terminate(self): + if log.trace_is_enabled(): + # give the flush a chance to finish --> TODO: find some other way. + time.sleep(0.25) + self._proc.terminate() + + def join(self, timeout=None): + self._proc.join( timeout) + + def is_alive(self): + return self._proc.is_alive() + + @property + def name(self): + return self._proc.name + + @name.setter + def name(self, name): + self._proc.name = name + + @property + def daemon(self): + return self._proc.daemon + + @daemon.setter + def daemon(self, daemonic): + self._proc.daemon = daemonic + + @property + def authkey(self): + return self._proc._authkey + + @authkey.setter + def authkey(self, authkey): + self._proc.authkey = AuthenticationString(authkey) + + @property + def exitcode(self): + return self._proc.exitcode + + @property + def ident(self): + return self._proc.ident + + @property + def pid(self): + return self._proc.pid + + def __repr__(self): + return self._proc.__repr__() + +# Monkeypatch in our process replacement. +if multiprocessing.Process != ProcessShim: + multiprocessing.Process = ProcessShim diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/parsed_trace_events.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/parsed_trace_events.py new file mode 100644 index 0000000..fdc7514 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/parsed_trace_events.py @@ -0,0 +1,98 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import math +import json + + +class ParsedTraceEvents(object): + def __init__(self, events = None, trace_filename = None): + """ + Utility class for filtering and manipulating trace data. + + events -- An iterable object containing trace events + trace_filename -- A file object that contains a complete trace. + + """ + if trace_filename and events: + raise Exception("Provide either a trace file or event list") + if not trace_filename and events == None: + raise Exception("Provide either a trace file or event list") + + if trace_filename: + f = open(trace_filename, 'r') + t = f.read() + f.close() + + # If the event data begins with a [, then we know it should end with a ]. + # The reason we check for this is because some tracing implementations + # cannot guarantee that a ']' gets written to the trace file. So, we are + # forgiving and if this is obviously the case, we fix it up before + # throwing the string at JSON.parse. + if t[0] == '[': + n = len(t); + if t[n - 1] != ']' and t[n - 1] != '\n': + t = t + ']' + elif t[n - 2] != ']' and t[n - 1] == '\n': + t = t + ']' + elif t[n - 3] != ']' and t[n - 2] == '\r' and t[n - 1] == '\n': + t = t + ']' + + try: + events = json.loads(t) + except ValueError: + raise Exception("Corrupt trace, did not parse. Value: %s" % t) + + if 'traceEvents' in events: + events = events['traceEvents'] + + if not hasattr(events, '__iter__'): + raise Exception, 'events must be iteraable.' + self.events = events + self.pids = None + self.tids = None + + def __len__(self): + return len(self.events) + + def __getitem__(self, i): + return self.events[i] + + def __setitem__(self, i, v): + self.events[i] = v + + def __repr__(self): + return "[%s]" % ",\n ".join([repr(e) for e in self.events]) + + def findProcessIds(self): + if self.pids: + return self.pids + pids = set() + for e in self.events: + if "pid" in e and e["pid"]: + pids.add(e["pid"]) + self.pids = list(pids) + return self.pids + + def findThreadIds(self): + if self.tids: + return self.tids + tids = set() + for e in self.events: + if "tid" in e and e["tid"]: + tids.add(e["tid"]) + self.tids = list(tids) + return self.tids + + def findEventsOnProcess(self, pid): + return ParsedTraceEvents([e for e in self.events if e["pid"] == pid]) + + def findEventsOnThread(self, tid): + return ParsedTraceEvents( + [e for e in self.events if e["ph"] != "M" and e["tid"] == tid]) + + def findByPhase(self, ph): + return ParsedTraceEvents([e for e in self.events if e["ph"] == ph]) + + def findByName(self, n): + return ParsedTraceEvents([e for e in self.events if e["name"] == n]) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/trace_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/trace_test.py new file mode 100644 index 0000000..7047e0e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_impl/trace_test.py @@ -0,0 +1,48 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import tempfile +import unittest + +#from .log import * +#from .parsed_trace_events import * + +from log import * +from parsed_trace_events import * + +class TraceTest(unittest.TestCase): + def __init__(self, *args): + """ + Infrastructure for running tests of the tracing system. + + Does not actually run any tests. Look at subclasses for those. + """ + unittest.TestCase.__init__(self, *args) + self._file = None + + def go(self, cb): + """ + Enables tracing, runs the provided callback, and if successful, returns a + TraceEvents object with the results. + """ + self._file = tempfile.NamedTemporaryFile() + trace_enable(open(self._file.name, 'a+')) + + try: + cb() + finally: + trace_disable() + e = ParsedTraceEvents(trace_filename = self._file.name) + self._file.close() + self._file = None + return e + + @property + def trace_filename(self): + return self._file.name + + def tearDown(self): + if trace_is_enabled(): + trace_disable() + if self._file: + self._file.close() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_unittest.py new file mode 100644 index 0000000..f88ef95 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_event_unittest.py @@ -0,0 +1,423 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import contextlib +import json +import logging +import math +import multiprocessing +import os +import tempfile +import time +import unittest + +from py_trace_event import trace_event +from py_trace_event import trace_time +from py_trace_event.trace_event_impl import log + + +class TraceEventTests(unittest.TestCase): + + def setUp(self): + tf = tempfile.NamedTemporaryFile(delete=False) + self._log_path = tf.name + tf.close() + + def tearDown(self): + if os.path.exists(self._log_path): + os.remove(self._log_path) + + @contextlib.contextmanager + def _test_trace(self, disable=True): + try: + trace_event.trace_enable(self._log_path) + yield + finally: + if disable: + trace_event.trace_disable() + + def testNoImpl(self): + orig_impl = trace_event.trace_event_impl + try: + trace_event.trace_event_impl = None + self.assertFalse(trace_event.trace_can_enable()) + finally: + trace_event.trace_event_impl = orig_impl + + def testImpl(self): + self.assertTrue(trace_event.trace_can_enable()) + + def testIsEnabledFalse(self): + self.assertFalse(trace_event.trace_is_enabled()) + + def testIsEnabledTrue(self): + with self._test_trace(): + self.assertTrue(trace_event.trace_is_enabled()) + + def testEnable(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 1) + self.assertTrue(trace_event.trace_is_enabled()) + log_output = log_output.pop() + self.assertEquals(log_output['category'], 'process_argv') + self.assertEquals(log_output['name'], 'process_argv') + self.assertTrue(log_output['args']['argv']) + self.assertEquals(log_output['ph'], 'M') + + def testDoubleEnable(self): + try: + with self._test_trace(): + with self._test_trace(): + pass + except log.TraceException: + return + assert False + + def testDisable(self): + with self._test_trace(disable=False): + with open(self._log_path, 'r') as f: + self.assertTrue(trace_event.trace_is_enabled()) + trace_event.trace_disable() + self.assertEquals(len(json.loads(f.read() + ']')), 1) + self.assertFalse(trace_event.trace_is_enabled()) + + def testDoubleDisable(self): + with self._test_trace(): + pass + trace_event.trace_disable() + + def testFlushChanges(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + trace_event.clock_sync('1') + self.assertEquals(len(json.loads(f.read() + ']')), 1) + f.seek(0) + trace_event.trace_flush() + self.assertEquals(len(json.loads(f.read() + ']')), 2) + + def testFlushNoChanges(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + self.assertEquals(len(json.loads(f.read() + ']')),1) + f.seek(0) + trace_event.trace_flush() + self.assertEquals(len(json.loads(f.read() + ']')), 1) + + def testDoubleFlush(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + trace_event.clock_sync('1') + self.assertEquals(len(json.loads(f.read() + ']')), 1) + f.seek(0) + trace_event.trace_flush() + trace_event.trace_flush() + self.assertEquals(len(json.loads(f.read() + ']')), 2) + + def testTraceBegin(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + trace_event.trace_begin('test_event', this='that') + trace_event.trace_flush() + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 2) + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'process_argv') + self.assertEquals(current_entry['name'], 'process_argv') + self.assertTrue( current_entry['args']['argv']) + self.assertEquals( current_entry['ph'], 'M') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], 'test_event') + self.assertEquals(current_entry['args']['this'], '\'that\'') + self.assertEquals(current_entry['ph'], 'B') + + def testTraceEnd(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + trace_event.trace_end('test_event') + trace_event.trace_flush() + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 2) + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'process_argv') + self.assertEquals(current_entry['name'], 'process_argv') + self.assertTrue(current_entry['args']['argv']) + self.assertEquals(current_entry['ph'], 'M') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], 'test_event') + self.assertEquals(current_entry['args'], {}) + self.assertEquals(current_entry['ph'], 'E') + + def testTrace(self): + with self._test_trace(): + with trace_event.trace('test_event', this='that'): + pass + trace_event.trace_flush() + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 3) + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'process_argv') + self.assertEquals(current_entry['name'], 'process_argv') + self.assertTrue(current_entry['args']['argv']) + self.assertEquals(current_entry['ph'], 'M') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], 'test_event') + self.assertEquals(current_entry['args']['this'], '\'that\'') + self.assertEquals(current_entry['ph'], 'B') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], 'test_event') + self.assertEquals(current_entry['args'], {}) + self.assertEquals(current_entry['ph'], 'E') + + def testTracedDecorator(self): + @trace_event.traced("this") + def test_decorator(this="that"): + pass + + with self._test_trace(): + test_decorator() + trace_event.trace_flush() + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 3) + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'process_argv') + self.assertEquals(current_entry['name'], 'process_argv') + self.assertTrue(current_entry['args']['argv']) + self.assertEquals(current_entry['ph'], 'M') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], '__main__.test_decorator') + self.assertEquals(current_entry['args']['this'], '\'that\'') + self.assertEquals(current_entry['ph'], 'B') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], '__main__.test_decorator') + self.assertEquals(current_entry['args'], {}) + self.assertEquals(current_entry['ph'], 'E') + + def testClockSyncWithTs(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + trace_event.clock_sync('id', issue_ts=trace_time.Now()) + trace_event.trace_flush() + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 2) + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'process_argv') + self.assertEquals(current_entry['name'], 'process_argv') + self.assertTrue(current_entry['args']['argv']) + self.assertEquals(current_entry['ph'], 'M') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], 'clock_sync') + self.assertTrue(current_entry['args']['issue_ts']) + self.assertEquals(current_entry['ph'], 'c') + + def testClockSyncWithoutTs(self): + with self._test_trace(): + with open(self._log_path, 'r') as f: + trace_event.clock_sync('id') + trace_event.trace_flush() + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 2) + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'process_argv') + self.assertEquals(current_entry['name'], 'process_argv') + self.assertTrue(current_entry['args']['argv']) + self.assertEquals(current_entry['ph'], 'M') + current_entry = log_output.pop(0) + self.assertEquals(current_entry['category'], 'python') + self.assertEquals(current_entry['name'], 'clock_sync') + self.assertFalse(current_entry['args'].get('issue_ts')) + self.assertEquals(current_entry['ph'], 'c') + + def testTime(self): + actual_diff = [] + def func1(): + trace_begin("func1") + start = time.time() + time.sleep(0.25) + end = time.time() + actual_diff.append(end-start) # Pass via array because of Python scoping + trace_end("func1") + + with self._test_trace(): + start_ts = time.time() + trace_event.trace_begin('test') + end_ts = time.time() + trace_event.trace_end('test') + trace_event.trace_flush() + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 3) + meta_data = log_output[0] + open_data = log_output[1] + close_data = log_output[2] + self.assertEquals(meta_data['category'], 'process_argv') + self.assertEquals(meta_data['name'], 'process_argv') + self.assertTrue(meta_data['args']['argv']) + self.assertEquals(meta_data['ph'], 'M') + self.assertEquals(open_data['category'], 'python') + self.assertEquals(open_data['name'], 'test') + self.assertEquals(open_data['ph'], 'B') + self.assertEquals(close_data['category'], 'python') + self.assertEquals(close_data['name'], 'test') + self.assertEquals(close_data['ph'], 'E') + event_time_diff = close_data['ts'] - open_data['ts'] + recorded_time_diff = (end_ts - start_ts) * 1000000 + self.assertLess(math.fabs(event_time_diff - recorded_time_diff), 1000) + + def testNestedCalls(self): + with self._test_trace(): + trace_event.trace_begin('one') + trace_event.trace_begin('two') + trace_event.trace_end('two') + trace_event.trace_end('one') + trace_event.trace_flush() + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 5) + meta_data = log_output[0] + one_open = log_output[1] + two_open = log_output[2] + two_close = log_output[3] + one_close = log_output[4] + self.assertEquals(meta_data['category'], 'process_argv') + self.assertEquals(meta_data['name'], 'process_argv') + self.assertTrue(meta_data['args']['argv']) + self.assertEquals(meta_data['ph'], 'M') + + self.assertEquals(one_open['category'], 'python') + self.assertEquals(one_open['name'], 'one') + self.assertEquals(one_open['ph'], 'B') + self.assertEquals(one_close['category'], 'python') + self.assertEquals(one_close['name'], 'one') + self.assertEquals(one_close['ph'], 'E') + + self.assertEquals(two_open['category'], 'python') + self.assertEquals(two_open['name'], 'two') + self.assertEquals(two_open['ph'], 'B') + self.assertEquals(two_close['category'], 'python') + self.assertEquals(two_close['name'], 'two') + self.assertEquals(two_close['ph'], 'E') + + self.assertLessEqual(one_open['ts'], two_open['ts']) + self.assertGreaterEqual(one_close['ts'], two_close['ts']) + + def testInterleavedCalls(self): + with self._test_trace(): + trace_event.trace_begin('one') + trace_event.trace_begin('two') + trace_event.trace_end('one') + trace_event.trace_end('two') + trace_event.trace_flush() + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 5) + meta_data = log_output[0] + one_open = log_output[1] + two_open = log_output[2] + two_close = log_output[4] + one_close = log_output[3] + self.assertEquals(meta_data['category'], 'process_argv') + self.assertEquals(meta_data['name'], 'process_argv') + self.assertTrue(meta_data['args']['argv']) + self.assertEquals(meta_data['ph'], 'M') + + self.assertEquals(one_open['category'], 'python') + self.assertEquals(one_open['name'], 'one') + self.assertEquals(one_open['ph'], 'B') + self.assertEquals(one_close['category'], 'python') + self.assertEquals(one_close['name'], 'one') + self.assertEquals(one_close['ph'], 'E') + + self.assertEquals(two_open['category'], 'python') + self.assertEquals(two_open['name'], 'two') + self.assertEquals(two_open['ph'], 'B') + self.assertEquals(two_close['category'], 'python') + self.assertEquals(two_close['name'], 'two') + self.assertEquals(two_close['ph'], 'E') + + self.assertLessEqual(one_open['ts'], two_open['ts']) + self.assertLessEqual(one_close['ts'], two_close['ts']) + + def testMultiprocess(self): + def child_function(): + with trace_event.trace('child_event'): + pass + + with self._test_trace(): + trace_event.trace_begin('parent_event') + trace_event.trace_flush() + p = multiprocessing.Process(target=child_function) + p.start() + self.assertTrue(hasattr(p, "_shimmed_by_trace_event")) + p.join() + trace_event.trace_end('parent_event') + trace_event.trace_flush() + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 5) + meta_data = log_output[0] + parent_open = log_output[1] + child_open = log_output[2] + child_close = log_output[3] + parent_close = log_output[4] + self.assertEquals(meta_data['category'], 'process_argv') + self.assertEquals(meta_data['name'], 'process_argv') + self.assertTrue(meta_data['args']['argv']) + self.assertEquals(meta_data['ph'], 'M') + + self.assertEquals(parent_open['category'], 'python') + self.assertEquals(parent_open['name'], 'parent_event') + self.assertEquals(parent_open['ph'], 'B') + + self.assertEquals(child_open['category'], 'python') + self.assertEquals(child_open['name'], 'child_event') + self.assertEquals(child_open['ph'], 'B') + + self.assertEquals(child_close['category'], 'python') + self.assertEquals(child_close['name'], 'child_event') + self.assertEquals(child_close['ph'], 'E') + + self.assertEquals(parent_close['category'], 'python') + self.assertEquals(parent_close['name'], 'parent_event') + self.assertEquals(parent_close['ph'], 'E') + + def testMultiprocessExceptionInChild(self): + def bad_child(): + trace_event.trace_disable() + + with self._test_trace(): + p = multiprocessing.Pool(1) + trace_event.trace_begin('parent') + self.assertRaises(Exception, lambda: p.apply(bad_child, ())) + p.close() + p.terminate() + p.join() + trace_event.trace_end('parent') + trace_event.trace_flush() + with open(self._log_path, 'r') as f: + log_output = json.loads(f.read() + ']') + self.assertEquals(len(log_output), 3) + meta_data = log_output[0] + parent_open = log_output[1] + parent_close = log_output[2] + self.assertEquals(parent_open['category'], 'python') + self.assertEquals(parent_open['name'], 'parent') + self.assertEquals(parent_open['ph'], 'B') + self.assertEquals(parent_close['category'], 'python') + self.assertEquals(parent_close['name'], 'parent') + self.assertEquals(parent_close['ph'], 'E') + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time.py new file mode 100644 index 0000000..c5e3fe1 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time.py @@ -0,0 +1,234 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import ctypes +import ctypes.util +import logging +import os +import platform +import sys +import time +import threading + + +GET_TICK_COUNT_LAST_NOW = 0 +# If GET_TICK_COUNTER_LAST_NOW is less than the current time, the clock has +# rolled over, and this needs to be accounted for. +GET_TICK_COUNT_WRAPAROUNDS = 0 +# The current detected platform +_CLOCK = None +_NOW_FUNCTION = None +# Mapping of supported platforms and what is returned by sys.platform. +_PLATFORMS = { + 'mac': 'darwin', + 'linux': 'linux', + 'windows': 'win32', + 'cygwin': 'cygwin', + 'freebsd': 'freebsd', + 'sunos': 'sunos5', + 'bsd': 'bsd' +} +# Mapping of what to pass get_clocktime based on platform. +_CLOCK_MONOTONIC = { + 'linux': 1, + 'freebsd': 4, + 'bsd': 3, + 'sunos5': 4 +} + +_LINUX_CLOCK = 'LINUX_CLOCK_MONOTONIC' +_MAC_CLOCK = 'MAC_MACH_ABSOLUTE_TIME' +_WIN_HIRES = 'WIN_QPC' +_WIN_LORES = 'WIN_ROLLOVER_PROTECTED_TIME_GET_TIME' + +def InitializeMacNowFunction(plat): + """Sets a monotonic clock for the Mac platform. + + Args: + plat: Platform that is being run on. Unused in GetMacNowFunction. Passed + for consistency between initilaizers. + """ + del plat # Unused + global _CLOCK # pylint: disable=global-statement + global _NOW_FUNCTION # pylint: disable=global-statement + _CLOCK = _MAC_CLOCK + libc = ctypes.CDLL('/usr/lib/libc.dylib', use_errno=True) + class MachTimebaseInfoData(ctypes.Structure): + """System timebase info. Defined in .""" + _fields_ = (('numer', ctypes.c_uint32), + ('denom', ctypes.c_uint32)) + + mach_absolute_time = libc.mach_absolute_time + mach_absolute_time.restype = ctypes.c_uint64 + + timebase = MachTimebaseInfoData() + libc.mach_timebase_info(ctypes.byref(timebase)) + ticks_per_second = timebase.numer / timebase.denom * 1.0e9 + + def MacNowFunctionImpl(): + return mach_absolute_time() / ticks_per_second + _NOW_FUNCTION = MacNowFunctionImpl + + +def GetClockGetTimeClockNumber(plat): + for key in _CLOCK_MONOTONIC: + if plat.startswith(key): + return _CLOCK_MONOTONIC[key] + raise LookupError('Platform not in clock dicitonary') + +def InitializeLinuxNowFunction(plat): + """Sets a monotonic clock for linux platforms. + + Args: + plat: Platform that is being run on. + """ + global _CLOCK # pylint: disable=global-statement + global _NOW_FUNCTION # pylint: disable=global-statement + _CLOCK = _LINUX_CLOCK + clock_monotonic = GetClockGetTimeClockNumber(plat) + try: + # Attempt to find clock_gettime in the C library. + clock_gettime = ctypes.CDLL(ctypes.util.find_library('c'), + use_errno=True).clock_gettime + except AttributeError: + # If not able to find int in the C library, look in rt library. + clock_gettime = ctypes.CDLL(ctypes.util.find_library('rt'), + use_errno=True).clock_gettime + + class Timespec(ctypes.Structure): + """Time specification, as described in clock_gettime(3).""" + _fields_ = (('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long)) + + def LinuxNowFunctionImpl(): + ts = Timespec() + if clock_gettime(clock_monotonic, ctypes.pointer(ts)): + errno = ctypes.get_errno() + raise OSError(errno, os.strerror(errno)) + return ts.tv_sec + ts.tv_nsec / 1.0e9 + + _NOW_FUNCTION = LinuxNowFunctionImpl + + +def IsQPCUsable(): + """Determines if system can query the performance counter. + The performance counter is a high resolution timer on windows systems. + Some chipsets have unreliable performance counters, so this checks that one + of those chipsets is not present. + + Returns: + True if QPC is useable, false otherwise. + """ + + # Sample output: 'Intel64 Family 6 Model 23 Stepping 6, GenuineIntel' + info = platform.processor() + if 'AuthenticAMD' in info and 'Family 15' in info: + return False + if not hasattr(ctypes, 'windll'): + return False + try: # If anything goes wrong during this, assume QPC isn't available. + frequency = ctypes.c_int64() + ctypes.windll.Kernel32.QueryPerformanceFrequency( + ctypes.byref(frequency)) + if float(frequency.value) <= 0: + return False + except Exception: # pylint: disable=broad-except + logging.exception('Error when determining if QPC is usable.') + return False + return True + + +def InitializeWinNowFunction(plat): + """Sets a monotonic clock for windows platforms. + + Args: + plat: Platform that is being run on. + """ + global _CLOCK # pylint: disable=global-statement + global _NOW_FUNCTION # pylint: disable=global-statement + + if IsQPCUsable(): + _CLOCK = _WIN_HIRES + qpc_return = ctypes.c_int64() + qpc_frequency = ctypes.c_int64() + ctypes.windll.Kernel32.QueryPerformanceFrequency( + ctypes.byref(qpc_frequency)) + qpc_frequency = float(qpc_frequency.value) + qpc = ctypes.windll.Kernel32.QueryPerformanceCounter + + def WinNowFunctionImpl(): + qpc(ctypes.byref(qpc_return)) + return qpc_return.value / qpc_frequency + + else: + _CLOCK = _WIN_LORES + kernel32 = (ctypes.cdll.kernel32 + if plat.startswith(_PLATFORMS['cygwin']) + else ctypes.windll.kernel32) + get_tick_count_64 = getattr(kernel32, 'GetTickCount64', None) + + # Windows Vista or newer + if get_tick_count_64: + get_tick_count_64.restype = ctypes.c_ulonglong + + def WinNowFunctionImpl(): + return get_tick_count_64() / 1000.0 + + else: # Pre Vista. + get_tick_count = kernel32.GetTickCount + get_tick_count.restype = ctypes.c_uint32 + get_tick_count_lock = threading.Lock() + + def WinNowFunctionImpl(): + global GET_TICK_COUNT_LAST_NOW # pylint: disable=global-statement + global GET_TICK_COUNT_WRAPAROUNDS # pylint: disable=global-statement + with get_tick_count_lock: + current_sample = get_tick_count() + if current_sample < GET_TICK_COUNT_LAST_NOW: + GET_TICK_COUNT_WRAPAROUNDS += 1 + GET_TICK_COUNT_LAST_NOW = current_sample + final_ms = GET_TICK_COUNT_WRAPAROUNDS << 32 + final_ms += GET_TICK_COUNT_LAST_NOW + return final_ms / 1000.0 + + _NOW_FUNCTION = WinNowFunctionImpl + + +def InitializeNowFunction(plat): + """Sets a monotonic clock for the current platform. + + Args: + plat: Platform that is being run on. + """ + if plat.startswith(_PLATFORMS['mac']): + InitializeMacNowFunction(plat) + + elif (plat.startswith(_PLATFORMS['linux']) + or plat.startswith(_PLATFORMS['freebsd']) + or plat.startswith(_PLATFORMS['bsd']) + or plat.startswith(_PLATFORMS['sunos'])): + InitializeLinuxNowFunction(plat) + + elif (plat.startswith(_PLATFORMS['windows']) + or plat.startswith(_PLATFORMS['cygwin'])): + InitializeWinNowFunction(plat) + + else: + raise RuntimeError('%s is not a supported platform.' % plat) + + global _NOW_FUNCTION + global _CLOCK + assert _NOW_FUNCTION, 'Now function not properly set during initialization.' + assert _CLOCK, 'Clock not properly set during initialization.' + + +def Now(): + return _NOW_FUNCTION() * 1e6 # convert from seconds to microseconds + + +def GetClock(): + return _CLOCK + + +InitializeNowFunction(sys.platform) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time_unittest.py new file mode 100644 index 0000000..ab54bd6 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_trace_event/py_trace_event/trace_time_unittest.py @@ -0,0 +1,123 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import contextlib +import logging +import platform +import sys +import unittest + +from py_trace_event import trace_time + + +class TimerTest(unittest.TestCase): + # Helper methods. + @contextlib.contextmanager + def ReplacePlatformProcessorCall(self, f): + try: + old_proc = platform.processor + platform.processor = f + yield + finally: + platform.processor = old_proc + + @contextlib.contextmanager + def ReplaceQPCCheck(self, f): + try: + old_qpc = trace_time.IsQPCUsable + trace_time.IsQPCUsable = f + yield + finally: + trace_time.IsQPCUsable = old_qpc + + # Platform detection tests. + def testInitializeNowFunction_platformNotSupported(self): + with self.assertRaises(RuntimeError): + trace_time.InitializeNowFunction('invalid_platform') + + def testInitializeNowFunction_windows(self): + if not (sys.platform.startswith(trace_time._PLATFORMS['windows']) + or sys.platform.startswith(trace_time._PLATFORMS['cygwin'])): + return True + trace_time.InitializeNowFunction(sys.platform) + self.assertTrue(trace_time.GetClock() == trace_time._WIN_HIRES + or trace_time.GetClock() == trace_time._WIN_LORES) + + def testInitializeNowFunction_linux(self): + if not sys.platform.startswith(trace_time._PLATFORMS['linux']): + return True + trace_time.InitializeNowFunction(sys.platform) + self.assertEqual(trace_time.GetClock(), trace_time._LINUX_CLOCK) + + def testInitializeNowFunction_mac(self): + if not sys.platform.startswith(trace_time._PLATFORMS['mac']): + return True + trace_time.InitializeNowFunction(sys.platform) + self.assertEqual(trace_time.GetClock(), trace_time._MAC_CLOCK) + + # Windows Tests + def testIsQPCUsable_buggyAthlonProcReturnsFalse(self): + if not (sys.platform.startswith(trace_time._PLATFORMS['windows']) + or sys.platform.startswith(trace_time._PLATFORMS['cygwin'])): + return True + + def BuggyAthlonProc(): + return 'AMD64 Family 15 Model 23 Stepping 6, AuthenticAMD' + + with self.ReplacePlatformProcessorCall(BuggyAthlonProc): + self.assertFalse(trace_time.IsQPCUsable()) + + def testIsQPCUsable_returnsTrueOnWindows(self): + if not (sys.platform.startswith(trace_time._PLATFORMS['windows']) + or sys.platform.startswith(trace_time._PLATFORMS['cygwin'])): + return True + + def Proc(): + return 'Intel64 Family 15 Model 23 Stepping 6, GenuineIntel' + + with self.ReplacePlatformProcessorCall(Proc): + self.assertTrue(trace_time.IsQPCUsable()) + + def testGetWinNowFunction_QPC(self): + if not (sys.platform.startswith(trace_time._PLATFORMS['windows']) + or sys.platform.startswith(trace_time._PLATFORMS['cygwin'])): + return True + # Test requires QPC to be available on platform. + if not trace_time.IsQPCUsable(): + return True + self.assertGreater(trace_time.monotonic(), 0) + + # Works even if QPC would work. + def testGetWinNowFunction_GetTickCount(self): + if not (sys.platform.startswith(trace_time._PLATFORMS['windows']) + or sys.platform.startswith(trace_time._PLATFORMS['cygwin'])): + return True + with self.ReplaceQPCCheck(lambda: False): + self.assertGreater(trace_time.monotonic(), 0) + + # Linux tests. + def testGetClockGetTimeClockNumber_linux(self): + self.assertEquals(trace_time.GetClockGetTimeClockNumber('linux'), 1) + + def testGetClockGetTimeClockNumber_freebsd(self): + self.assertEquals(trace_time.GetClockGetTimeClockNumber('freebsd'), 4) + + def testGetClockGetTimeClockNumber_bsd(self): + self.assertEquals(trace_time.GetClockGetTimeClockNumber('bsd'), 3) + + def testGetClockGetTimeClockNumber_sunos(self): + self.assertEquals(trace_time.GetClockGetTimeClockNumber('sunos5'), 4) + + # Smoke Test. + def testMonotonic(self): + time_one = trace_time.Now() + for _ in xrange(1000): + time_two = trace_time.Now() + self.assertLessEqual(time_one, time_two) + time_one = time_two + + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/PRESUBMIT.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/PRESUBMIT.py new file mode 100644 index 0000000..c1d92fe --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/PRESUBMIT.py @@ -0,0 +1,31 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +def CheckChangeOnUpload(input_api, output_api): + return _CommonChecks(input_api, output_api) + + +def CheckChangeOnCommit(input_api, output_api): + return _CommonChecks(input_api, output_api) + + +def _CommonChecks(input_api, output_api): + results = [] + results += input_api.RunTests(input_api.canned_checks.GetPylint( + input_api, output_api, extra_paths_list=_GetPathsToPrepend(input_api), + pylintrc='../../pylintrc')) + return results + + +def _GetPathsToPrepend(input_api): + project_dir = input_api.PresubmitLocalPath() + catapult_dir = input_api.os_path.join(project_dir, '..', '..') + return [ + project_dir, + input_api.os_path.join(catapult_dir, 'dependency_manager'), + input_api.os_path.join(catapult_dir, 'devil'), + input_api.os_path.join(catapult_dir, 'third_party', 'mock'), + input_api.os_path.join(catapult_dir, 'third_party', 'pyfakefs'), + ] diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/__init__.py new file mode 100644 index 0000000..3f26311 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/__init__.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python + +# Copyright (c) 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import functools +import inspect +import os +import sys +import time + + +def GetCatapultDir(): + return os.path.normpath( + os.path.join(os.path.dirname(__file__), '..', '..', '..')) + + +def IsRunningOnCrosDevice(): + """Returns True if we're on a ChromeOS device.""" + lsb_release = '/etc/lsb-release' + if sys.platform.startswith('linux') and os.path.exists(lsb_release): + with open(lsb_release, 'r') as f: + res = f.read() + if res.count('CHROMEOS_RELEASE_NAME'): + return True + return False + + +def _ExecutableExtensions(): + # pathext is, e.g. '.com;.exe;.bat;.cmd' + exts = os.getenv('PATHEXT').split(';') #e.g. ['.com','.exe','.bat','.cmd'] + return [x[1:].upper() for x in exts] #e.g. ['COM','EXE','BAT','CMD'] + + +def IsExecutable(path): + if os.path.isfile(path): + if hasattr(os, 'name') and os.name == 'nt': + return path.split('.')[-1].upper() in _ExecutableExtensions() + else: + return os.access(path, os.X_OK) + else: + return False + + +def _AddDirToPythonPath(*path_parts): + path = os.path.abspath(os.path.join(*path_parts)) + if os.path.isdir(path) and path not in sys.path: + # Some callsite that use telemetry assumes that sys.path[0] is the directory + # containing the script, so we add these extra paths to right after it. + sys.path.insert(1, path) + +_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'devil')) +_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'dependency_manager')) +_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'third_party', 'mock')) +# mox3 is needed for pyfakefs usage, but not for pylint. +_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'third_party', 'mox3')) +_AddDirToPythonPath( + os.path.join(GetCatapultDir(), 'third_party', 'pyfakefs')) + +from devil.utils import timeout_retry +from devil.utils import reraiser_thread + + +# Decorator that adds timeout functionality to a function. +def Timeout(default_timeout): + return lambda func: TimeoutDeco(func, default_timeout) + +# Note: Even though the "timeout" keyword argument is the only +# keyword argument that will need to be given to the decorated function, +# we still have to use the **kwargs syntax, because we have to use +# the *args syntax here before (since the decorator decorates functions +# with different numbers of positional arguments) and Python doesn't allow +# a single named keyword argument after *args. +# (e.g., 'def foo(*args, bar=42):' is a syntax error) + +def TimeoutDeco(func, default_timeout): + @functools.wraps(func) + def RunWithTimeout(*args, **kwargs): + if 'timeout' in kwargs: + timeout = kwargs['timeout'] + else: + timeout = default_timeout + try: + return timeout_retry.Run(func, timeout, 0, args=args) + except reraiser_thread.TimeoutError: + print '%s timed out.' % func.__name__ + return False + return RunWithTimeout + + +MIN_POLL_INTERVAL_IN_SECONDS = 0.1 +MAX_POLL_INTERVAL_IN_SECONDS = 5 +OUTPUT_INTERVAL_IN_SECONDS = 300 + +def WaitFor(condition, timeout): + """Waits for up to |timeout| secs for the function |condition| to return True. + + Polling frequency is (elapsed_time / 10), with a min of .1s and max of 5s. + + Returns: + Result of |condition| function (if present). + """ + def GetConditionString(): + if condition.__name__ == '': + try: + return inspect.getsource(condition).strip() + except IOError: + pass + return condition.__name__ + + # Do an initial check to see if its true. + res = condition() + if res: + return res + start_time = time.time() + last_output_time = start_time + elapsed_time = time.time() - start_time + while elapsed_time < timeout: + res = condition() + if res: + return res + now = time.time() + elapsed_time = now - start_time + last_output_elapsed_time = now - last_output_time + if last_output_elapsed_time > OUTPUT_INTERVAL_IN_SECONDS: + last_output_time = time.time() + poll_interval = min(max(elapsed_time / 10., MIN_POLL_INTERVAL_IN_SECONDS), + MAX_POLL_INTERVAL_IN_SECONDS) + time.sleep(poll_interval) + raise TimeoutException('Timed out while waiting %ds for %s.' % + (timeout, GetConditionString())) + +class TimeoutException(Exception): + """The operation failed to complete because of a timeout. + + It is possible that waiting for a longer period of time would result in a + successful operation. + """ + pass diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager.py new file mode 100644 index 0000000..8af08cf --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager.py @@ -0,0 +1,61 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging + +import dependency_manager + + +class BinaryManager(object): + """ This class is effectively a subclass of dependency_manager, but uses a + different number of arguments for FetchPath and LocalPath. + """ + + def __init__(self, config_files): + if not config_files or type(config_files) != list: + raise ValueError( + 'Must supply a list of config files to the BinaryManager') + configs = [dependency_manager.BaseConfig(config) for config in config_files] + self._dependency_manager = dependency_manager.DependencyManager(configs) + + def FetchPathWithVersion(self, binary_name, os_name, arch, os_version=None): + """ Return a path to the executable for , or None if not found. + + Will attempt to download from cloud storage if needed. + """ + return self._WrapDependencyManagerFunction( + self._dependency_manager.FetchPathWithVersion, binary_name, os_name, + arch, os_version) + + def FetchPath(self, binary_name, os_name, arch, os_version=None): + """ Return a path to the executable for , or None if not found. + + Will attempt to download from cloud storage if needed. + """ + return self._WrapDependencyManagerFunction( + self._dependency_manager.FetchPath, binary_name, os_name, arch, + os_version) + + def LocalPath(self, binary_name, os_name, arch, os_version=None): + """ Return a local path to the given binary name, or None if not found. + + Will not download from cloud_storage. + """ + return self._WrapDependencyManagerFunction( + self._dependency_manager.LocalPath, binary_name, os_name, arch, + os_version) + + def _WrapDependencyManagerFunction( + self, function, binary_name, os_name, arch, os_version): + platform = '%s_%s' % (os_name, arch) + if os_version: + try: + versioned_platform = '%s_%s_%s' % (os_name, os_version, arch) + return function(binary_name, versioned_platform) + except dependency_manager.NoPathFoundError: + logging.warning( + 'Cannot find path for %s on platform %s. Falling back to %s.', + binary_name, versioned_platform, platform) + return function(binary_name, platform) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager_unittest.py new file mode 100644 index 0000000..ccf21ad --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/binary_manager_unittest.py @@ -0,0 +1,214 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import os + +from pyfakefs import fake_filesystem_unittest +from dependency_manager import exceptions + +from py_utils import binary_manager + +class BinaryManagerTest(fake_filesystem_unittest.TestCase): + # TODO(aiolos): disable cloud storage use during this test. + + def setUp(self): + self.setUpPyfakefs() + # pylint: disable=bad-continuation + self.expected_dependencies = { + 'dep_1': { + 'cloud_storage_base_folder': 'dependencies/fake_config', + 'cloud_storage_bucket': 'chrome-tel', + 'file_info': { + 'linux_x86_64': { + 'cloud_storage_hash': '661ce936b3276f7ec3d687ab62be05b96d796f21', + 'download_path': 'bin/linux/x86_64/dep_1' + }, + 'mac_x86_64': { + 'cloud_storage_hash': 'c7b1bfc6399dc683058e88dac1ef0f877edea74b', + 'download_path': 'bin/mac/x86_64/dep_1' + }, + 'win_AMD64': { + 'cloud_storage_hash': 'ac4fee89a51662b9d920bce443c19b9b2929b198', + 'download_path': 'bin/win/AMD64/dep_1.exe' + }, + 'win_x86': { + 'cloud_storage_hash': 'e246e183553ea26967d7b323ea269e3357b9c837', + 'download_path': 'bin/win/x86/dep_1.exe' + } + } + }, + 'dep_2': { + 'cloud_storage_base_folder': 'dependencies/fake_config', + 'cloud_storage_bucket': 'chrome-tel', + 'file_info': { + 'linux_x86_64': { + 'cloud_storage_hash': '13a57efae9a680ac0f160b3567e02e81f4ac493c', + 'download_path': 'bin/linux/x86_64/dep_2', + 'local_paths': [ + '../../example/location/linux/dep_2', + '../../example/location2/linux/dep_2' + ] + }, + 'mac_x86_64': { + 'cloud_storage_hash': 'd10c0ddaa8586b20449e951216bee852fa0f8850', + 'download_path': 'bin/mac/x86_64/dep_2', + 'local_paths': [ + '../../example/location/mac/dep_2', + '../../example/location2/mac/dep_2' + ] + }, + 'win_AMD64': { + 'cloud_storage_hash': 'fd5b417f78c7f7d9192a98967058709ded1d399d', + 'download_path': 'bin/win/AMD64/dep_2.exe', + 'local_paths': [ + '../../example/location/win64/dep_2', + '../../example/location2/win64/dep_2' + ] + }, + 'win_x86': { + 'cloud_storage_hash': 'cf5c8fe920378ce30d057e76591d57f63fd31c1a', + 'download_path': 'bin/win/x86/dep_2.exe', + 'local_paths': [ + '../../example/location/win32/dep_2', + '../../example/location2/win32/dep_2' + ] + }, + 'android_k_x64': { + 'cloud_storage_hash': '09177be2fed00b44df0e777932828425440b23b3', + 'download_path': 'bin/android/x64/k/dep_2.apk', + 'local_paths': [ + '../../example/location/android_x64/k/dep_2', + '../../example/location2/android_x64/k/dep_2' + ] + }, + 'android_l_x64': { + 'cloud_storage_hash': '09177be2fed00b44df0e777932828425440b23b3', + 'download_path': 'bin/android/x64/l/dep_2.apk', + 'local_paths': [ + '../../example/location/android_x64/l/dep_2', + '../../example/location2/android_x64/l/dep_2' + ] + }, + 'android_k_x86': { + 'cloud_storage_hash': 'bcf02af039713a48b69b89bd7f0f9c81ed8183a4', + 'download_path': 'bin/android/x86/k/dep_2.apk', + 'local_paths': [ + '../../example/location/android_x86/k/dep_2', + '../../example/location2/android_x86/k/dep_2' + ] + }, + 'android_l_x86': { + 'cloud_storage_hash': '12a74cec071017ba11655b5740b8a58e2f52a219', + 'download_path': 'bin/android/x86/l/dep_2.apk', + 'local_paths': [ + '../../example/location/android_x86/l/dep_2', + '../../example/location2/android_x86/l/dep_2' + ] + } + } + }, + 'dep_3': { + 'file_info': { + 'linux_x86_64': { + 'local_paths': [ + '../../example/location/linux/dep_3', + '../../example/location2/linux/dep_3' + ] + }, + 'mac_x86_64': { + 'local_paths': [ + '../../example/location/mac/dep_3', + '../../example/location2/mac/dep_3' + ] + }, + 'win_AMD64': { + 'local_paths': [ + '../../example/location/win64/dep_3', + '../../example/location2/win64/dep_3' + ] + }, + 'win_x86': { + 'local_paths': [ + '../../example/location/win32/dep_3', + '../../example/location2/win32/dep_3' + ] + } + } + } + } + # pylint: enable=bad-continuation + fake_config = { + 'config_type': 'BaseConfig', + 'dependencies': self.expected_dependencies + } + + self.base_config = os.path.join(os.path.dirname(__file__), + 'example_config.json') + self.fs.CreateFile(self.base_config, contents=json.dumps(fake_config)) + linux_file = os.path.join( + os.path.dirname(self.base_config), + os.path.join('..', '..', 'example', 'location2', 'linux', 'dep_2')) + android_file = os.path.join( + os.path.dirname(self.base_config), + '..', '..', 'example', 'location', 'android_x86', 'l', 'dep_2') + self.expected_dep2_linux_file = os.path.abspath(linux_file) + self.expected_dep2_android_file = os.path.abspath(android_file) + self.fs.CreateFile(self.expected_dep2_linux_file) + self.fs.CreateFile(self.expected_dep2_android_file) + + def tearDown(self): + self.tearDownPyfakefs() + + def testInitializationNoConfig(self): + with self.assertRaises(ValueError): + binary_manager.BinaryManager(None) + + def testInitializationMissingConfig(self): + with self.assertRaises(ValueError): + binary_manager.BinaryManager(os.path.join('missing', 'path')) + + def testInitializationWithConfig(self): + with self.assertRaises(ValueError): + manager = binary_manager.BinaryManager(self.base_config) + manager = binary_manager.BinaryManager([self.base_config]) + self.assertItemsEqual(self.expected_dependencies, + manager._dependency_manager._lookup_dict) + + def testSuccessfulFetchPathNoOsVersion(self): + manager = binary_manager.BinaryManager([self.base_config]) + found_path = manager.FetchPath('dep_2', 'linux', 'x86_64') + self.assertEqual(self.expected_dep2_linux_file, found_path) + + def testSuccessfulFetchPathOsVersion(self): + manager = binary_manager.BinaryManager([self.base_config]) + found_path = manager.FetchPath('dep_2', 'android', 'x86', 'l') + self.assertEqual(self.expected_dep2_android_file, found_path) + + def testSuccessfulFetchPathFallbackToNoOsVersion(self): + manager = binary_manager.BinaryManager([self.base_config]) + found_path = manager.FetchPath('dep_2', 'linux', 'x86_64', 'fake_version') + self.assertEqual(self.expected_dep2_linux_file, found_path) + + def testFailedFetchPathMissingDep(self): + manager = binary_manager.BinaryManager([self.base_config]) + with self.assertRaises(exceptions.NoPathFoundError): + manager.FetchPath('missing_dep', 'linux', 'x86_64') + with self.assertRaises(exceptions.NoPathFoundError): + manager.FetchPath('missing_dep', 'android', 'x86', 'l') + with self.assertRaises(exceptions.NoPathFoundError): + manager.FetchPath('dep_1', 'linux', 'bad_arch') + with self.assertRaises(exceptions.NoPathFoundError): + manager.FetchPath('dep_1', 'bad_os', 'x86') + + def testSuccessfulLocalPathNoOsVersion(self): + manager = binary_manager.BinaryManager([self.base_config]) + found_path = manager.LocalPath('dep_2', 'linux', 'x86_64') + self.assertEqual(self.expected_dep2_linux_file, found_path) + + def testSuccessfulLocalPathOsVersion(self): + manager = binary_manager.BinaryManager([self.base_config]) + found_path = manager.LocalPath('dep_2', 'android', 'x86', 'l') + self.assertEqual(self.expected_dep2_android_file, found_path) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/chrome_binaries.json b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/chrome_binaries.json new file mode 100644 index 0000000..bb0b2e1 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/chrome_binaries.json @@ -0,0 +1,86 @@ +{ + "config_type": "BaseConfig", + "dependencies": { + "chrome_canary": { + "cloud_storage_base_folder": "binary_dependencies", + "cloud_storage_bucket": "chrome-telemetry", + "file_info": { + "mac_x86_64": { + "cloud_storage_hash": "ab33866d00fb0c9d6543c20a21da5f047ba6a7b6", + "download_path": "bin/reference_builds/chrome-mac64.zip", + "path_within_archive": "chrome-mac/Google Chrome.app/Contents/MacOS/Google Chrome", + "version_in_cs": "58.0.3004.0" + }, + "win_AMD64": { + "cloud_storage_hash": "2348f9bcf421fa4739493a12b4c8e3210a528d84", + "download_path": "bin\\reference_build\\chrome-win64-pgo.zip", + "path_within_archive": "chrome-win64-pgo\\chrome.exe", + "version_in_cs": "58.0.3004.0" + }, + "win_x86": { + "cloud_storage_hash": "421c59cfbc02bee9b74f68869af3a930b5988e71", + "download_path": "bin\\reference_build\\chrome-win32-pgo.zip", + "path_within_archive": "chrome-win32-pgo\\chrome.exe", + "version_in_cs": "58.0.3004.0" + } + } + }, + "chrome_dev": { + "cloud_storage_base_folder": "binary_dependencies", + "cloud_storage_bucket": "chrome-telemetry", + "file_info": { + "linux_x86_64": { + "cloud_storage_hash": "d61c3c5a81dc5e0a896589ab3d72a253e4b9cc90", + "download_path": "bin/reference_build/chrome-linux64.zip", + "path_within_archive": "chrome-precise64/chrome", + "version_in_cs": "58.0.3000.4" + } + } + }, + "chrome_stable": { + "cloud_storage_base_folder": "binary_dependencies", + "cloud_storage_bucket": "chrome-telemetry", + "file_info": { + "android_k_armeabi-v7a": { + "cloud_storage_hash": "2f0629a395974793c3a25e6c2dc971487742bd49", + "download_path": "bin/reference_build/android_k_armeabi-v7a/ChromeStable.apk", + "version_in_cs": "56.0.2924.87" + }, + "android_l_arm64-v8a": { + "cloud_storage_hash": "03306b04e49ed3b0c4c29da84a128d76659624f2", + "download_path": "bin/reference_build/android_l_arm64-v8a/ChromeStable.apk", + "version_in_cs": "56.0.2924.87" + }, + "android_l_armeabi-v7a": { + "cloud_storage_hash": "2f0629a395974793c3a25e6c2dc971487742bd49", + "download_path": "bin/reference_build/android_l_armeabi-v7a/ChromeStable.apk", + "version_in_cs": "56.0.2924.87" + }, + "linux_x86_64": { + "cloud_storage_hash": "07dd594d89c8350978ed368b55204d7ee3641001", + "download_path": "bin/reference_build/chrome-linux64.zip", + "path_within_archive": "chrome-precise64/chrome", + "version_in_cs": "56.0.2924.87" + }, + "mac_x86_64": { + "cloud_storage_hash": "e2e1ac31913ab6976084375540e17bbaa2401820", + "download_path": "bin/reference_builds/chrome-mac64.zip", + "path_within_archive": "chrome-mac/Google Chrome.app/Contents/MacOS/Google Chrome", + "version_in_cs": "56.0.2924.87" + }, + "win_AMD64": { + "cloud_storage_hash": "d6624303bceff81503db78c4ad17d1ebd1af7b68", + "download_path": "bin\\reference_build\\chrome-win64-pgo.zip", + "path_within_archive": "chrome-win64-pgo\\chrome.exe", + "version_in_cs": "56.0.2924.87" + }, + "win_x86": { + "cloud_storage_hash": "2b89d4571eeac4d80d4a1fac7c92db3f7e0bd565", + "download_path": "bin\\reference_build\\chrome-win32-pgo.zip", + "path_within_archive": "chrome-win32-pgo\\chrome.exe", + "version_in_cs": "56.0.2924.87" + } + } + } + } +} \ No newline at end of file diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage.py new file mode 100644 index 0000000..7bc9a19 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage.py @@ -0,0 +1,461 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Wrappers for gsutil, for basic interaction with Google Cloud Storage.""" + +import collections +import contextlib +import hashlib +import logging +import os +import shutil +import stat +import subprocess +import re +import sys +import tempfile + +import py_utils +from py_utils import lock + +# Do a no-op import here so that cloud_storage_global_lock dep is picked up +# by https://cs.chromium.org/chromium/src/build/android/test_runner.pydeps. +# TODO(nedn, jbudorick): figure out a way to get rid of this ugly hack. +from py_utils import cloud_storage_global_lock # pylint: disable=unused-import + +logger = logging.getLogger(__name__) # pylint: disable=invalid-name + + +PUBLIC_BUCKET = 'chromium-telemetry' +PARTNER_BUCKET = 'chrome-partner-telemetry' +INTERNAL_BUCKET = 'chrome-telemetry' +TELEMETRY_OUTPUT = 'chrome-telemetry-output' + +# Uses ordered dict to make sure that bucket's key-value items are ordered from +# the most open to the most restrictive. +BUCKET_ALIASES = collections.OrderedDict(( + ('public', PUBLIC_BUCKET), + ('partner', PARTNER_BUCKET), + ('internal', INTERNAL_BUCKET), + ('output', TELEMETRY_OUTPUT), +)) + +BUCKET_ALIAS_NAMES = BUCKET_ALIASES.keys() + + +_GSUTIL_PATH = os.path.join(py_utils.GetCatapultDir(), 'third_party', 'gsutil', + 'gsutil') + +# TODO(tbarzic): A workaround for http://crbug.com/386416 and +# http://crbug.com/359293. See |_RunCommand|. +_CROS_GSUTIL_HOME_WAR = '/home/chromeos-test/' + + +# If Environment variables has DISABLE_CLOUD_STORAGE_IO set to '1', any method +# calls that invoke cloud storage network io will throw exceptions. +DISABLE_CLOUD_STORAGE_IO = 'DISABLE_CLOUD_STORAGE_IO' + +# The maximum number of seconds to wait to acquire the pseudo lock for a cloud +# storage file before raising an exception. +LOCK_ACQUISITION_TIMEOUT = 10 + + +class CloudStorageError(Exception): + + @staticmethod + def _GetConfigInstructions(): + command = _GSUTIL_PATH + if py_utils.IsRunningOnCrosDevice(): + command = 'HOME=%s %s' % (_CROS_GSUTIL_HOME_WAR, _GSUTIL_PATH) + return ('To configure your credentials:\n' + ' 1. Run "%s config" and follow its instructions.\n' + ' 2. If you have a @google.com account, use that account.\n' + ' 3. For the project-id, just enter 0.' % command) + + +class PermissionError(CloudStorageError): + + def __init__(self): + super(PermissionError, self).__init__( + 'Attempted to access a file from Cloud Storage but you don\'t ' + 'have permission. ' + self._GetConfigInstructions()) + + +class CredentialsError(CloudStorageError): + + def __init__(self): + super(CredentialsError, self).__init__( + 'Attempted to access a file from Cloud Storage but you have no ' + 'configured credentials. ' + self._GetConfigInstructions()) + + +class CloudStorageIODisabled(CloudStorageError): + pass + + +class NotFoundError(CloudStorageError): + pass + + +class ServerError(CloudStorageError): + pass + + +# TODO(tonyg/dtu): Can this be replaced with distutils.spawn.find_executable()? +def _FindExecutableInPath(relative_executable_path, *extra_search_paths): + search_paths = list(extra_search_paths) + os.environ['PATH'].split(os.pathsep) + for search_path in search_paths: + executable_path = os.path.join(search_path, relative_executable_path) + if py_utils.IsExecutable(executable_path): + return executable_path + return None + + +def _EnsureExecutable(gsutil): + """chmod +x if gsutil is not executable.""" + st = os.stat(gsutil) + if not st.st_mode & stat.S_IEXEC: + os.chmod(gsutil, st.st_mode | stat.S_IEXEC) + + +def _RunCommand(args): + # On cros device, as telemetry is running as root, home will be set to /root/, + # which is not writable. gsutil will attempt to create a download tracker dir + # in home dir and fail. To avoid this, override HOME dir to something writable + # when running on cros device. + # + # TODO(tbarzic): Figure out a better way to handle gsutil on cros. + # http://crbug.com/386416, http://crbug.com/359293. + gsutil_env = None + if py_utils.IsRunningOnCrosDevice(): + gsutil_env = os.environ.copy() + gsutil_env['HOME'] = _CROS_GSUTIL_HOME_WAR + + if os.name == 'nt': + # If Windows, prepend python. Python scripts aren't directly executable. + args = [sys.executable, _GSUTIL_PATH] + args + else: + # Don't do it on POSIX, in case someone is using a shell script to redirect. + args = [_GSUTIL_PATH] + args + _EnsureExecutable(_GSUTIL_PATH) + + if args[0] not in ('help', 'hash', 'version') and not IsNetworkIOEnabled(): + raise CloudStorageIODisabled( + "Environment variable DISABLE_CLOUD_STORAGE_IO is set to 1. " + 'Command %s is not allowed to run' % args) + + gsutil = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, env=gsutil_env) + stdout, stderr = gsutil.communicate() + + if gsutil.returncode: + raise GetErrorObjectForCloudStorageStderr(stderr) + + return stdout + + +def GetErrorObjectForCloudStorageStderr(stderr): + if (stderr.startswith(( + 'You are attempting to access protected data with no configured', + 'Failure: No handler was ready to authenticate.')) or + re.match('.*401.*does not have .* access to .*', stderr)): + return CredentialsError() + if ('status=403' in stderr or 'status 403' in stderr or + '403 Forbidden' in stderr or + re.match('.*403.*does not have .* access to .*', stderr)): + return PermissionError() + if (stderr.startswith('InvalidUriError') or 'No such object' in stderr or + 'No URLs matched' in stderr or 'One or more URLs matched no' in stderr): + return NotFoundError(stderr) + if '500 Internal Server Error' in stderr: + return ServerError(stderr) + return CloudStorageError(stderr) + + +def IsNetworkIOEnabled(): + """Returns true if cloud storage is enabled.""" + disable_cloud_storage_env_val = os.getenv(DISABLE_CLOUD_STORAGE_IO) + + if disable_cloud_storage_env_val and disable_cloud_storage_env_val != '1': + logger.error( + 'Unsupported value of environment variable ' + 'DISABLE_CLOUD_STORAGE_IO. Expected None or \'1\' but got %s.', + disable_cloud_storage_env_val) + + return disable_cloud_storage_env_val != '1' + + +def List(bucket): + query = 'gs://%s/' % bucket + stdout = _RunCommand(['ls', query]) + return [url[len(query):] for url in stdout.splitlines()] + + +def Exists(bucket, remote_path): + try: + _RunCommand(['ls', 'gs://%s/%s' % (bucket, remote_path)]) + return True + except NotFoundError: + return False + + +def Move(bucket1, bucket2, remote_path): + url1 = 'gs://%s/%s' % (bucket1, remote_path) + url2 = 'gs://%s/%s' % (bucket2, remote_path) + logger.info('Moving %s to %s', url1, url2) + _RunCommand(['mv', url1, url2]) + + +def Copy(bucket_from, bucket_to, remote_path_from, remote_path_to): + """Copy a file from one location in CloudStorage to another. + + Args: + bucket_from: The cloud storage bucket where the file is currently located. + bucket_to: The cloud storage bucket it is being copied to. + remote_path_from: The file path where the file is located in bucket_from. + remote_path_to: The file path it is being copied to in bucket_to. + + It should: cause no changes locally or to the starting file, and will + overwrite any existing files in the destination location. + """ + url1 = 'gs://%s/%s' % (bucket_from, remote_path_from) + url2 = 'gs://%s/%s' % (bucket_to, remote_path_to) + logger.info('Copying %s to %s', url1, url2) + _RunCommand(['cp', url1, url2]) + + +def Delete(bucket, remote_path): + url = 'gs://%s/%s' % (bucket, remote_path) + logger.info('Deleting %s', url) + _RunCommand(['rm', url]) + + +def Get(bucket, remote_path, local_path): + with _FileLock(local_path): + _GetLocked(bucket, remote_path, local_path) + + +_CLOUD_STORAGE_GLOBAL_LOCK = os.path.join( + os.path.dirname(os.path.abspath(__file__)), 'cloud_storage_global_lock.py') + + +@contextlib.contextmanager +def _FileLock(base_path): + pseudo_lock_path = '%s.pseudo_lock' % base_path + _CreateDirectoryIfNecessary(os.path.dirname(pseudo_lock_path)) + + # Make sure that we guard the creation, acquisition, release, and removal of + # the pseudo lock all with the same guard (_CLOUD_STORAGE_GLOBAL_LOCK). + # Otherwise, we can get nasty interleavings that result in multiple processes + # thinking they have an exclusive lock, like: + # + # (Process 1) Create and acquire the pseudo lock + # (Process 1) Release the pseudo lock + # (Process 1) Release the file lock + # (Process 2) Open and acquire the existing pseudo lock + # (Process 1) Delete the (existing) pseudo lock + # (Process 3) Create and acquire a new pseudo lock + # + # Using the same guard for creation and removal of the pseudo lock guarantees + # that all processes are referring to the same lock. + pseudo_lock_fd = None + pseudo_lock_fd_return = [] + py_utils.WaitFor(lambda: _AttemptPseudoLockAcquisition(pseudo_lock_path, + pseudo_lock_fd_return), + LOCK_ACQUISITION_TIMEOUT) + pseudo_lock_fd = pseudo_lock_fd_return[0] + + try: + yield + finally: + py_utils.WaitFor(lambda: _AttemptPseudoLockRelease(pseudo_lock_fd), + LOCK_ACQUISITION_TIMEOUT) + +def _AttemptPseudoLockAcquisition(pseudo_lock_path, pseudo_lock_fd_return): + """Try to acquire the lock and return a boolean indicating whether the attempt + was successful. If the attempt was successful, pseudo_lock_fd_return, which + should be an empty array, will be modified to contain a single entry: the file + descriptor of the (now acquired) lock file. + + This whole operation is guarded with the global cloud storage lock, which + prevents race conditions that might otherwise cause multiple processes to + believe they hold the same pseudo lock (see _FileLock for more details). + """ + pseudo_lock_fd = None + try: + with open(_CLOUD_STORAGE_GLOBAL_LOCK) as global_file: + with lock.FileLock(global_file, lock.LOCK_EX | lock.LOCK_NB): + # Attempt to acquire the lock in a non-blocking manner. If we block, + # then we'll cause deadlock because another process will be unable to + # acquire the cloud storage global lock in order to release the pseudo + # lock. + pseudo_lock_fd = open(pseudo_lock_path, 'w') + lock.AcquireFileLock(pseudo_lock_fd, lock.LOCK_EX | lock.LOCK_NB) + pseudo_lock_fd_return.append(pseudo_lock_fd) + return True + except (lock.LockException, IOError): + # We failed to acquire either the global cloud storage lock or the pseudo + # lock. + if pseudo_lock_fd: + pseudo_lock_fd.close() + return False + + +def _AttemptPseudoLockRelease(pseudo_lock_fd): + """Try to release the pseudo lock and return a boolean indicating whether + the release was succesful. + + This whole operation is guarded with the global cloud storage lock, which + prevents race conditions that might otherwise cause multiple processes to + believe they hold the same pseudo lock (see _FileLock for more details). + """ + pseudo_lock_path = pseudo_lock_fd.name + try: + with open(_CLOUD_STORAGE_GLOBAL_LOCK) as global_file: + with lock.FileLock(global_file, lock.LOCK_EX | lock.LOCK_NB): + lock.ReleaseFileLock(pseudo_lock_fd) + pseudo_lock_fd.close() + try: + os.remove(pseudo_lock_path) + except OSError: + # We don't care if the pseudo lock gets removed elsewhere before + # we have a chance to do so. + pass + return True + except (lock.LockException, IOError): + # We failed to acquire the global cloud storage lock and are thus unable to + # release the pseudo lock. + return False + + +def _CreateDirectoryIfNecessary(directory): + if not os.path.exists(directory): + os.makedirs(directory) + + +def _GetLocked(bucket, remote_path, local_path): + url = 'gs://%s/%s' % (bucket, remote_path) + logger.info('Downloading %s to %s', url, local_path) + _CreateDirectoryIfNecessary(os.path.dirname(local_path)) + with tempfile.NamedTemporaryFile( + dir=os.path.dirname(local_path), + delete=False) as partial_download_path: + try: + # Windows won't download to an open file. + partial_download_path.close() + try: + _RunCommand(['cp', url, partial_download_path.name]) + except ServerError: + logger.info('Cloud Storage server error, retrying download') + _RunCommand(['cp', url, partial_download_path.name]) + shutil.move(partial_download_path.name, local_path) + finally: + if os.path.exists(partial_download_path.name): + os.remove(partial_download_path.name) + + +def Insert(bucket, remote_path, local_path, publicly_readable=False): + """ Upload file in |local_path| to cloud storage. + Args: + bucket: the google cloud storage bucket name. + remote_path: the remote file path in |bucket|. + local_path: path of the local file to be uploaded. + publicly_readable: whether the uploaded file has publicly readable + permission. + + Returns: + The url where the file is uploaded to. + """ + url = 'gs://%s/%s' % (bucket, remote_path) + command_and_args = ['cp'] + extra_info = '' + if publicly_readable: + command_and_args += ['-a', 'public-read'] + extra_info = ' (publicly readable)' + command_and_args += [local_path, url] + logger.info('Uploading %s to %s%s', local_path, url, extra_info) + _RunCommand(command_and_args) + return 'https://console.developers.google.com/m/cloudstorage/b/%s/o/%s' % ( + bucket, remote_path) + + +def GetIfHashChanged(cs_path, download_path, bucket, file_hash): + """Downloads |download_path| to |file_path| if |file_path| doesn't exist or + it's hash doesn't match |file_hash|. + + Returns: + True if the binary was changed. + Raises: + CredentialsError if the user has no configured credentials. + PermissionError if the user does not have permission to access the bucket. + NotFoundError if the file is not in the given bucket in cloud_storage. + """ + with _FileLock(download_path): + if (os.path.exists(download_path) and + CalculateHash(download_path) == file_hash): + return False + _GetLocked(bucket, cs_path, download_path) + return True + + +def GetIfChanged(file_path, bucket): + """Gets the file at file_path if it has a hash file that doesn't match or + if there is no local copy of file_path, but there is a hash file for it. + + Returns: + True if the binary was changed. + Raises: + CredentialsError if the user has no configured credentials. + PermissionError if the user does not have permission to access the bucket. + NotFoundError if the file is not in the given bucket in cloud_storage. + """ + with _FileLock(file_path): + hash_path = file_path + '.sha1' + if not os.path.exists(hash_path): + logger.warning('Hash file not found: %s', hash_path) + return False + + expected_hash = ReadHash(hash_path) + if os.path.exists(file_path) and CalculateHash(file_path) == expected_hash: + return False + _GetLocked(bucket, expected_hash, file_path) + return True + + +def GetFilesInDirectoryIfChanged(directory, bucket): + """ Scan the directory for .sha1 files, and download them from the given + bucket in cloud storage if the local and remote hash don't match or + there is no local copy. + """ + if not os.path.isdir(directory): + raise ValueError( + '%s does not exist. Must provide a valid directory path.' % directory) + # Don't allow the root directory to be a serving_dir. + if directory == os.path.abspath(os.sep): + raise ValueError('Trying to serve root directory from HTTP server.') + for dirpath, _, filenames in os.walk(directory): + for filename in filenames: + path_name, extension = os.path.splitext( + os.path.join(dirpath, filename)) + if extension != '.sha1': + continue + GetIfChanged(path_name, bucket) + + +def CalculateHash(file_path): + """Calculates and returns the hash of the file at file_path.""" + sha1 = hashlib.sha1() + with open(file_path, 'rb') as f: + while True: + # Read in 1mb chunks, so it doesn't all have to be loaded into memory. + chunk = f.read(1024 * 1024) + if not chunk: + break + sha1.update(chunk) + return sha1.hexdigest() + + +def ReadHash(hash_path): + with open(hash_path, 'rb') as f: + return f.read(1024).rstrip() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_global_lock.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_global_lock.py new file mode 100644 index 0000000..5718e10 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_global_lock.py @@ -0,0 +1,5 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is used by cloud_storage._FileLock implementation, don't delete it! diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_unittest.py new file mode 100644 index 0000000..a513b26 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/cloud_storage_unittest.py @@ -0,0 +1,284 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import shutil +import sys +import tempfile +import unittest + +import mock +from pyfakefs import fake_filesystem_unittest + +import py_utils +from py_utils import cloud_storage +from py_utils import lock + +_CLOUD_STORAGE_GLOBAL_LOCK_PATH = os.path.join( + os.path.dirname(__file__), 'cloud_storage_global_lock.py') + +def _FakeReadHash(_): + return 'hashthis!' + + +def _FakeCalulateHashMatchesRead(_): + return 'hashthis!' + + +def _FakeCalulateHashNewHash(_): + return 'omgnewhash' + + +class CloudStorageFakeFsUnitTest(fake_filesystem_unittest.TestCase): + + def setUp(self): + self.original_environ = os.environ.copy() + os.environ['DISABLE_CLOUD_STORAGE_IO'] = '' + self.setUpPyfakefs() + self.fs.CreateFile( + os.path.join(py_utils.GetCatapultDir(), + 'third_party', 'gsutil', 'gsutil')) + + def CreateFiles(self, file_paths): + for f in file_paths: + self.fs.CreateFile(f) + + def tearDown(self): + self.tearDownPyfakefs() + os.environ = self.original_environ + + def _FakeRunCommand(self, cmd): + pass + + def _FakeGet(self, bucket, remote_path, local_path): + pass + + def _AssertRunCommandRaisesError(self, communicate_strs, error): + with mock.patch('py_utils.cloud_storage.subprocess.Popen') as popen: + p_mock = mock.Mock() + popen.return_value = p_mock + p_mock.returncode = 1 + for stderr in communicate_strs: + p_mock.communicate.return_value = ('', stderr) + self.assertRaises(error, cloud_storage._RunCommand, []) + + def testRunCommandCredentialsError(self): + strs = ['You are attempting to access protected data with no configured', + 'Failure: No handler was ready to authenticate.'] + self._AssertRunCommandRaisesError(strs, cloud_storage.CredentialsError) + + def testRunCommandPermissionError(self): + strs = ['status=403', 'status 403', '403 Forbidden'] + self._AssertRunCommandRaisesError(strs, cloud_storage.PermissionError) + + def testRunCommandNotFoundError(self): + strs = ['InvalidUriError', 'No such object', 'No URLs matched', + 'One or more URLs matched no', 'InvalidUriError'] + self._AssertRunCommandRaisesError(strs, cloud_storage.NotFoundError) + + def testRunCommandServerError(self): + strs = ['500 Internal Server Error'] + self._AssertRunCommandRaisesError(strs, cloud_storage.ServerError) + + def testRunCommandGenericError(self): + strs = ['Random string'] + self._AssertRunCommandRaisesError(strs, cloud_storage.CloudStorageError) + + def testInsertCreatesValidCloudUrl(self): + orig_run_command = cloud_storage._RunCommand + try: + cloud_storage._RunCommand = self._FakeRunCommand + remote_path = 'test-remote-path.html' + local_path = 'test-local-path.html' + cloud_url = cloud_storage.Insert(cloud_storage.PUBLIC_BUCKET, + remote_path, local_path) + self.assertEqual('https://console.developers.google.com/m/cloudstorage' + '/b/chromium-telemetry/o/test-remote-path.html', + cloud_url) + finally: + cloud_storage._RunCommand = orig_run_command + + @mock.patch('py_utils.cloud_storage.subprocess') + def testExistsReturnsFalse(self, subprocess_mock): + p_mock = mock.Mock() + subprocess_mock.Popen.return_value = p_mock + p_mock.communicate.return_value = ( + '', + 'CommandException: One or more URLs matched no objects.\n') + p_mock.returncode_result = 1 + self.assertFalse(cloud_storage.Exists('fake bucket', + 'fake remote path')) + + @mock.patch('py_utils.cloud_storage.CalculateHash') + @mock.patch('py_utils.cloud_storage._GetLocked') + @mock.patch('py_utils.cloud_storage._FileLock') + @mock.patch('py_utils.cloud_storage.os.path') + def testGetIfHashChanged(self, path_mock, unused_lock_mock, get_mock, + calc_hash_mock): + path_mock.exists.side_effect = [False, True, True] + calc_hash_mock.return_value = 'hash' + + # The file at |local_path| doesn't exist. We should download file from cs. + ret = cloud_storage.GetIfHashChanged( + 'remote_path', 'local_path', 'cs_bucket', 'hash') + self.assertTrue(ret) + get_mock.assert_called_once_with('cs_bucket', 'remote_path', 'local_path') + get_mock.reset_mock() + self.assertFalse(calc_hash_mock.call_args) + calc_hash_mock.reset_mock() + + # A local file exists at |local_path| but has the wrong hash. + # We should download file from cs. + ret = cloud_storage.GetIfHashChanged( + 'remote_path', 'local_path', 'cs_bucket', 'new_hash') + self.assertTrue(ret) + get_mock.assert_called_once_with('cs_bucket', 'remote_path', 'local_path') + get_mock.reset_mock() + calc_hash_mock.assert_called_once_with('local_path') + calc_hash_mock.reset_mock() + + # Downloaded file exists locally and has the right hash. Don't download. + ret = cloud_storage.GetIfHashChanged( + 'remote_path', 'local_path', 'cs_bucket', 'hash') + self.assertFalse(get_mock.call_args) + self.assertFalse(ret) + calc_hash_mock.reset_mock() + get_mock.reset_mock() + + @mock.patch('py_utils.cloud_storage._FileLock') + def testGetIfChanged(self, unused_lock_mock): + orig_get = cloud_storage._GetLocked + orig_read_hash = cloud_storage.ReadHash + orig_calculate_hash = cloud_storage.CalculateHash + cloud_storage.ReadHash = _FakeReadHash + cloud_storage.CalculateHash = _FakeCalulateHashMatchesRead + file_path = 'test-file-path.wpr' + hash_path = file_path + '.sha1' + try: + cloud_storage._GetLocked = self._FakeGet + # hash_path doesn't exist. + self.assertFalse(cloud_storage.GetIfChanged(file_path, + cloud_storage.PUBLIC_BUCKET)) + # hash_path exists, but file_path doesn't. + self.CreateFiles([hash_path]) + self.assertTrue(cloud_storage.GetIfChanged(file_path, + cloud_storage.PUBLIC_BUCKET)) + # hash_path and file_path exist, and have same hash. + self.CreateFiles([file_path]) + self.assertFalse(cloud_storage.GetIfChanged(file_path, + cloud_storage.PUBLIC_BUCKET)) + # hash_path and file_path exist, and have different hashes. + cloud_storage.CalculateHash = _FakeCalulateHashNewHash + self.assertTrue(cloud_storage.GetIfChanged(file_path, + cloud_storage.PUBLIC_BUCKET)) + finally: + cloud_storage._GetLocked = orig_get + cloud_storage.CalculateHash = orig_calculate_hash + cloud_storage.ReadHash = orig_read_hash + + @unittest.skipIf(sys.platform.startswith('win'), + 'https://github.com/catapult-project/catapult/issues/1861') + def testGetFilesInDirectoryIfChanged(self): + self.CreateFiles([ + 'real_dir_path/dir1/1file1.sha1', + 'real_dir_path/dir1/1file2.txt', + 'real_dir_path/dir1/1file3.sha1', + 'real_dir_path/dir2/2file.txt', + 'real_dir_path/dir3/3file1.sha1']) + + def IncrementFilesUpdated(*_): + IncrementFilesUpdated.files_updated += 1 + IncrementFilesUpdated.files_updated = 0 + orig_get_if_changed = cloud_storage.GetIfChanged + cloud_storage.GetIfChanged = IncrementFilesUpdated + try: + self.assertRaises(ValueError, cloud_storage.GetFilesInDirectoryIfChanged, + os.path.abspath(os.sep), cloud_storage.PUBLIC_BUCKET) + self.assertEqual(0, IncrementFilesUpdated.files_updated) + self.assertRaises(ValueError, cloud_storage.GetFilesInDirectoryIfChanged, + 'fake_dir_path', cloud_storage.PUBLIC_BUCKET) + self.assertEqual(0, IncrementFilesUpdated.files_updated) + cloud_storage.GetFilesInDirectoryIfChanged('real_dir_path', + cloud_storage.PUBLIC_BUCKET) + self.assertEqual(3, IncrementFilesUpdated.files_updated) + finally: + cloud_storage.GetIfChanged = orig_get_if_changed + + def testCopy(self): + orig_run_command = cloud_storage._RunCommand + + def AssertCorrectRunCommandArgs(args): + self.assertEqual(expected_args, args) + cloud_storage._RunCommand = AssertCorrectRunCommandArgs + expected_args = ['cp', 'gs://bucket1/remote_path1', + 'gs://bucket2/remote_path2'] + try: + cloud_storage.Copy('bucket1', 'bucket2', 'remote_path1', 'remote_path2') + finally: + cloud_storage._RunCommand = orig_run_command + + + @mock.patch('py_utils.cloud_storage._FileLock') + def testDisableCloudStorageIo(self, unused_lock_mock): + os.environ['DISABLE_CLOUD_STORAGE_IO'] = '1' + dir_path = 'real_dir_path' + self.fs.CreateDirectory(dir_path) + file_path = os.path.join(dir_path, 'file1') + file_path_sha = file_path + '.sha1' + self.CreateFiles([file_path, file_path_sha]) + with open(file_path_sha, 'w') as f: + f.write('hash1234') + with self.assertRaises(cloud_storage.CloudStorageIODisabled): + cloud_storage.Copy('bucket1', 'bucket2', 'remote_path1', 'remote_path2') + with self.assertRaises(cloud_storage.CloudStorageIODisabled): + cloud_storage.Get('bucket', 'foo', file_path) + with self.assertRaises(cloud_storage.CloudStorageIODisabled): + cloud_storage.GetIfChanged(file_path, 'foo') + with self.assertRaises(cloud_storage.CloudStorageIODisabled): + cloud_storage.GetIfHashChanged('bar', file_path, 'bucket', 'hash1234') + with self.assertRaises(cloud_storage.CloudStorageIODisabled): + cloud_storage.Insert('bucket', 'foo', file_path) + with self.assertRaises(cloud_storage.CloudStorageIODisabled): + cloud_storage.GetFilesInDirectoryIfChanged(dir_path, 'bucket') + + +class CloudStorageRealFsUnitTest(unittest.TestCase): + + def setUp(self): + self.original_environ = os.environ.copy() + os.environ['DISABLE_CLOUD_STORAGE_IO'] = '' + + def tearDown(self): + os.environ = self.original_environ + + @mock.patch('py_utils.cloud_storage.LOCK_ACQUISITION_TIMEOUT', .005) + def testGetPseudoLockUnavailableCausesTimeout(self): + with tempfile.NamedTemporaryFile(suffix='.pseudo_lock') as pseudo_lock_fd: + with lock.FileLock(pseudo_lock_fd, lock.LOCK_EX | lock.LOCK_NB): + with self.assertRaises(py_utils.TimeoutException): + file_path = pseudo_lock_fd.name.replace('.pseudo_lock', '') + cloud_storage.GetIfChanged(file_path, cloud_storage.PUBLIC_BUCKET) + + @mock.patch('py_utils.cloud_storage.LOCK_ACQUISITION_TIMEOUT', .005) + def testGetGlobalLockUnavailableCausesTimeout(self): + with open(_CLOUD_STORAGE_GLOBAL_LOCK_PATH) as global_lock_fd: + with lock.FileLock(global_lock_fd, lock.LOCK_EX | lock.LOCK_NB): + tmp_dir = tempfile.mkdtemp() + try: + file_path = os.path.join(tmp_dir, 'foo') + with self.assertRaises(py_utils.TimeoutException): + cloud_storage.GetIfChanged(file_path, cloud_storage.PUBLIC_BUCKET) + finally: + shutil.rmtree(tmp_dir) + + +class CloudStorageErrorHandlingTest(unittest.TestCase): + def runTest(self): + self.assertIsInstance(cloud_storage.GetErrorObjectForCloudStorageStderr( + 'ServiceException: 401 Anonymous users does not have ' + 'storage.objects.get access to object chrome-partner-telemetry'), + cloud_storage.CredentialsError) + self.assertIsInstance(cloud_storage.GetErrorObjectForCloudStorageStderr( + '403 Caller does not have storage.objects.list access to bucket ' + 'chrome-telemetry'), cloud_storage.PermissionError) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext.py new file mode 100644 index 0000000..922d27d --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext.py @@ -0,0 +1,33 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +class _OptionalContextManager(object): + + def __init__(self, manager, condition): + self._manager = manager + self._condition = condition + + def __enter__(self): + if self._condition: + return self._manager.__enter__() + return None + + def __exit__(self, exc_type, exc_val, exc_tb): + if self._condition: + return self._manager.__exit__(exc_type, exc_val, exc_tb) + return None + + +def Optional(manager, condition): + """Wraps the provided context manager and runs it if condition is True. + + Args: + manager: A context manager to conditionally run. + condition: If true, runs the given context manager. + Returns: + A context manager that conditionally executes the given manager. + """ + return _OptionalContextManager(manager, condition) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext_unittest.py new file mode 100644 index 0000000..b83e7e5 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/contextlib_ext_unittest.py @@ -0,0 +1,34 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +from py_utils import contextlib_ext + + +class OptionalUnittest(unittest.TestCase): + + class SampleContextMgr(object): + + def __init__(self): + self.entered = False + self.exited = False + + def __enter__(self): + self.entered = True + + def __exit__(self, exc_type, exc_val, exc_tb): + self.exited = True + + def testConditionTrue(self): + c = self.SampleContextMgr() + with contextlib_ext.Optional(c, True): + self.assertTrue(c.entered) + self.assertTrue(c.exited) + + def testConditionFalse(self): + c = self.SampleContextMgr() + with contextlib_ext.Optional(c, False): + self.assertFalse(c.entered) + self.assertFalse(c.exited) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/dependency_util.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/dependency_util.py new file mode 100644 index 0000000..d3cfe89 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/dependency_util.py @@ -0,0 +1,49 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import platform +import sys + +import py_utils + +def GetOSAndArchForCurrentDesktopPlatform(): + os_name = GetOSNameForCurrentDesktopPlatform() + return os_name, GetArchForCurrentDesktopPlatform(os_name) + + +def GetOSNameForCurrentDesktopPlatform(): + if py_utils.IsRunningOnCrosDevice(): + return 'chromeos' + if sys.platform.startswith('linux'): + return 'linux' + if sys.platform == 'darwin': + return 'mac' + if sys.platform == 'win32': + return 'win' + return sys.platform + + +def GetArchForCurrentDesktopPlatform(os_name): + if os_name == 'chromeos': + # Current tests outside of telemetry don't run on chromeos, and + # platform.machine is not the way telemetry gets the arch name on chromeos. + raise NotImplementedError() + return platform.machine() + + +def GetChromeApkOsVersion(version_name): + version = version_name[0] + assert version.isupper(), ( + 'First character of versions name %s was not an uppercase letter.') + if version < 'L': + return 'k' + elif version > 'M': + return 'n' + return 'l' + + +def ChromeBinariesConfigPath(): + return os.path.realpath(os.path.join( + os.path.dirname(os.path.abspath(__file__)), 'chrome_binaries.json')) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock.py new file mode 100644 index 0000000..aa9a095 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock.py @@ -0,0 +1,117 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import contextlib +import os + +LOCK_EX = None # Exclusive lock +LOCK_SH = None # Shared lock +LOCK_NB = None # Non-blocking (LockException is raised if resource is locked) + + +class LockException(Exception): + pass + + +if os.name == 'nt': + import win32con # pylint: disable=import-error + import win32file # pylint: disable=import-error + import pywintypes # pylint: disable=import-error + LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK + LOCK_SH = 0 # the default + LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY + _OVERLAPPED = pywintypes.OVERLAPPED() +elif os.name == 'posix': + import fcntl # pylint: disable=import-error + LOCK_EX = fcntl.LOCK_EX + LOCK_SH = fcntl.LOCK_SH + LOCK_NB = fcntl.LOCK_NB + + +@contextlib.contextmanager +def FileLock(target_file, flags): + """ Lock the target file. Similar to AcquireFileLock but allow user to write: + with FileLock(f, LOCK_EX): + ...do stuff on file f without worrying about race condition + Args: see AcquireFileLock's documentation. + """ + AcquireFileLock(target_file, flags) + try: + yield + finally: + ReleaseFileLock(target_file) + + +def AcquireFileLock(target_file, flags): + """ Lock the target file. Note that if |target_file| is closed, the lock is + automatically released. + Args: + target_file: file handle of the file to acquire lock. + flags: can be any of the type LOCK_EX, LOCK_SH, LOCK_NB, or a bitwise + OR combination of flags. + """ + assert flags in ( + LOCK_EX, LOCK_SH, LOCK_NB, LOCK_EX | LOCK_NB, LOCK_SH | LOCK_NB) + if os.name == 'nt': + _LockImplWin(target_file, flags) + elif os.name == 'posix': + _LockImplPosix(target_file, flags) + else: + raise NotImplementedError('%s is not supported' % os.name) + + +def ReleaseFileLock(target_file): + """ Unlock the target file. + Args: + target_file: file handle of the file to release the lock. + """ + if os.name == 'nt': + _UnlockImplWin(target_file) + elif os.name == 'posix': + _UnlockImplPosix(target_file) + else: + raise NotImplementedError('%s is not supported' % os.name) + +# These implementations are based on +# http://code.activestate.com/recipes/65203/ + +def _LockImplWin(target_file, flags): + hfile = win32file._get_osfhandle(target_file.fileno()) + try: + win32file.LockFileEx(hfile, flags, 0, -0x10000, _OVERLAPPED) + except pywintypes.error, exc_value: + if exc_value[0] == 33: + raise LockException('Error trying acquiring lock of %s: %s' % + (target_file.name, exc_value[2])) + else: + raise + + +def _UnlockImplWin(target_file): + hfile = win32file._get_osfhandle(target_file.fileno()) + try: + win32file.UnlockFileEx(hfile, 0, -0x10000, _OVERLAPPED) + except pywintypes.error, exc_value: + if exc_value[0] == 158: + # error: (158, 'UnlockFileEx', 'The segment is already unlocked.') + # To match the 'posix' implementation, silently ignore this error + pass + else: + # Q: Are there exceptions/codes we should be dealing with here? + raise + + +def _LockImplPosix(target_file, flags): + try: + fcntl.flock(target_file.fileno(), flags) + except IOError, exc_value: + if exc_value[0] == 11 or exc_value[0] == 35: + raise LockException('Error trying acquiring lock of %s: %s' % + (target_file.name, exc_value[1])) + else: + raise + + +def _UnlockImplPosix(target_file): + fcntl.flock(target_file.fileno(), fcntl.LOCK_UN) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock_unittest.py new file mode 100644 index 0000000..a260621 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/lock_unittest.py @@ -0,0 +1,165 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import multiprocessing +import os +import time +import unittest +import tempfile + + +from py_utils import lock + + +def _AppendTextToFile(file_name): + with open(file_name, 'a') as f: + lock.AcquireFileLock(f, lock.LOCK_EX) + # Sleep 100 ms to increase the chance of another process trying to acquire + # the lock of file as the same time. + time.sleep(0.1) + f.write('Start') + for _ in range(10000): + f.write('*') + f.write('End') + + +def _ReadFileWithSharedLockBlockingThenWrite(read_file, write_file): + with open(read_file, 'r') as f: + lock.AcquireFileLock(f, lock.LOCK_SH) + content = f.read() + with open(write_file, 'a') as f2: + lock.AcquireFileLock(f2, lock.LOCK_EX) + f2.write(content) + + +def _ReadFileWithExclusiveLockNonBlocking(target_file, status_file): + with open(target_file, 'r') as f: + try: + lock.AcquireFileLock(f, lock.LOCK_EX | lock.LOCK_NB) + with open(status_file, 'w') as f2: + f2.write('LockException was not raised') + except lock.LockException: + with open(status_file, 'w') as f2: + f2.write('LockException raised') + + +class FileLockTest(unittest.TestCase): + def setUp(self): + tf = tempfile.NamedTemporaryFile(delete=False) + tf.close() + self.temp_file_path = tf.name + + def tearDown(self): + os.remove(self.temp_file_path) + + def testExclusiveLock(self): + processess = [] + for _ in range(10): + p = multiprocessing.Process( + target=_AppendTextToFile, args=(self.temp_file_path,)) + p.start() + processess.append(p) + for p in processess: + p.join() + + # If the file lock works as expected, there should be 10 atomic writes of + # 'Start***...***End' to the file in some order, which lead to the final + # file content as below. + expected_file_content = ''.join((['Start'] + ['*']*10000 + ['End']) * 10) + with open(self.temp_file_path, 'r') as f: + # Use assertTrue instead of assertEquals since the strings are big, hence + # assertEquals's assertion failure will contain huge strings. + self.assertTrue(expected_file_content == f.read()) + + def testSharedLock(self): + tf = tempfile.NamedTemporaryFile(delete=False) + tf.close() + temp_write_file = tf.name + try: + with open(self.temp_file_path, 'w') as f: + f.write('0123456789') + with open(self.temp_file_path, 'r') as f: + # First, acquire a shared lock on temp_file_path + lock.AcquireFileLock(f, lock.LOCK_SH) + + processess = [] + # Create 10 processes that also try to acquire shared lock from + # temp_file_path then append temp_file_path's content to temp_write_file + for _ in range(10): + p = multiprocessing.Process( + target=_ReadFileWithSharedLockBlockingThenWrite, + args=(self.temp_file_path, temp_write_file)) + p.start() + processess.append(p) + for p in processess: + p.join() + + # temp_write_file should contains 10 copy of temp_file_path's content. + with open(temp_write_file, 'r') as f: + self.assertEquals('0123456789'*10, f.read()) + finally: + os.remove(temp_write_file) + + def testNonBlockingLockAcquiring(self): + tf = tempfile.NamedTemporaryFile(delete=False) + tf.close() + temp_status_file = tf.name + try: + with open(self.temp_file_path, 'w') as f: + lock.AcquireFileLock(f, lock.LOCK_EX) + p = multiprocessing.Process( + target=_ReadFileWithExclusiveLockNonBlocking, + args=(self.temp_file_path, temp_status_file)) + p.start() + p.join() + with open(temp_status_file, 'r') as f: + self.assertEquals('LockException raised', f.read()) + finally: + os.remove(temp_status_file) + + def testUnlockBeforeClosingFile(self): + tf = tempfile.NamedTemporaryFile(delete=False) + tf.close() + temp_status_file = tf.name + try: + with open(self.temp_file_path, 'r') as f: + lock.AcquireFileLock(f, lock.LOCK_SH) + lock.ReleaseFileLock(f) + p = multiprocessing.Process( + target=_ReadFileWithExclusiveLockNonBlocking, + args=(self.temp_file_path, temp_status_file)) + p.start() + p.join() + with open(temp_status_file, 'r') as f: + self.assertEquals('LockException was not raised', f.read()) + finally: + os.remove(temp_status_file) + + def testContextualLock(self): + tf = tempfile.NamedTemporaryFile(delete=False) + tf.close() + temp_status_file = tf.name + try: + with open(self.temp_file_path, 'r') as f: + with lock.FileLock(f, lock.LOCK_EX): + # Within this block, accessing self.temp_file_path from another + # process should raise exception. + p = multiprocessing.Process( + target=_ReadFileWithExclusiveLockNonBlocking, + args=(self.temp_file_path, temp_status_file)) + p.start() + p.join() + with open(temp_status_file, 'r') as f: + self.assertEquals('LockException raised', f.read()) + + # Accessing self.temp_file_path here should not raise exception. + p = multiprocessing.Process( + target=_ReadFileWithExclusiveLockNonBlocking, + args=(self.temp_file_path, temp_status_file)) + p.start() + p.join() + with open(temp_status_file, 'r') as f: + self.assertEquals('LockException was not raised', f.read()) + finally: + os.remove(temp_status_file) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/py_utils_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/py_utils_unittest.py new file mode 100644 index 0000000..e614a45 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/py_utils_unittest.py @@ -0,0 +1,55 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import os +import sys +import unittest + +import py_utils + + +class PathTest(unittest.TestCase): + + def testIsExecutable(self): + self.assertFalse(py_utils.IsExecutable('nonexistent_file')) + # We use actual files on disk instead of pyfakefs because the executable is + # set different on win that posix platforms and pyfakefs doesn't support + # win platform well. + self.assertFalse(py_utils.IsExecutable(_GetFileInTestDir('foo.txt'))) + self.assertTrue(py_utils.IsExecutable(sys.executable)) + + +def _GetFileInTestDir(file_name): + return os.path.join(os.path.dirname(__file__), 'test_data', file_name) + + +class WaitForTest(unittest.TestCase): + + def testWaitForTrue(self): + def ReturnTrue(): + return True + self.assertTrue(py_utils.WaitFor(ReturnTrue, .1)) + + def testWaitForFalse(self): + def ReturnFalse(): + return False + + with self.assertRaises(py_utils.TimeoutException): + py_utils.WaitFor(ReturnFalse, .1) + + def testWaitForEventuallyTrue(self): + # Use list to pass to inner function in order to allow modifying the + # variable from the outer scope. + c = [0] + def ReturnCounterBasedValue(): + c[0] += 1 + return c[0] > 2 + + self.assertTrue(py_utils.WaitFor(ReturnCounterBasedValue, .5)) + + def testWaitForTrueLambda(self): + self.assertTrue(py_utils.WaitFor(lambda: True, .1)) + + def testWaitForFalseLambda(self): + with self.assertRaises(py_utils.TimeoutException): + py_utils.WaitFor(lambda: False, .1) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/__init__.py new file mode 100644 index 0000000..e3fbb5f --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Style-preserving Python code transforms. + +This module provides components for modifying and querying Python code. They can +be used to build custom refactorings and linters. +""" + +import functools +import multiprocessing + +# pylint: disable=wildcard-import +from py_utils.refactor.annotated_symbol import * +from py_utils.refactor.module import Module + + +def _TransformFile(transform, file_path): + module = Module(file_path) + result = transform(module) + module.Write() + return result + + +def Transform(transform, file_paths): + transform = functools.partial(_TransformFile, transform) + return multiprocessing.Pool().map(transform, file_paths) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/__init__.py new file mode 100644 index 0000000..610bc15 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/__init__.py @@ -0,0 +1,71 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# pylint: disable=wildcard-import +from py_utils.refactor.annotated_symbol.class_definition import * +from py_utils.refactor.annotated_symbol.function_definition import * +from py_utils.refactor.annotated_symbol.import_statement import * +from py_utils.refactor.annotated_symbol.reference import * +from py_utils.refactor import snippet + + +__all__ = [ + 'Annotate', + + 'Class', + 'Function', + 'Import', + 'Reference', +] + + +# Specific symbol types with extra methods for manipulating them. +# Python's full grammar is here: +# https://docs.python.org/2/reference/grammar.html + +# Annotated Symbols have an Annotate classmethod that takes a symbol type and +# list of children, and returns an instance of that annotated Symbol. + +ANNOTATED_SYMBOLS = ( + AsName, + Class, + DottedName, + ImportFrom, + ImportName, + Function, +) + + +# Unfortunately, some logical groupings are not represented by a node in the +# parse tree. To work around this, some annotated Symbols have an Annotate +# classmethod that takes and returns a list of Snippets instead. + +ANNOTATED_GROUPINGS = ( + Reference, +) + + +def Annotate(f): + """Return the syntax tree of the given file.""" + return _AnnotateNode(snippet.Snippetize(f)) + + +def _AnnotateNode(node): + if not isinstance(node, snippet.Symbol): + return node + + children = map(_AnnotateNode, node.children) + + for symbol_type in ANNOTATED_GROUPINGS: + annotated_grouping = symbol_type.Annotate(children) + if annotated_grouping: + children = annotated_grouping + break + + for symbol_type in ANNOTATED_SYMBOLS: + annotated_symbol = symbol_type.Annotate(node.type, children) + if annotated_symbol: + return annotated_symbol + + return snippet.Symbol(node.type, children) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/base_symbol.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/base_symbol.py new file mode 100644 index 0000000..2e28e89 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/base_symbol.py @@ -0,0 +1,36 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from py_utils.refactor import snippet + + +class AnnotatedSymbol(snippet.Symbol): + def __init__(self, symbol_type, children): + super(AnnotatedSymbol, self).__init__(symbol_type, children) + self._modified = False + + @property + def modified(self): + if self._modified: + return True + return super(AnnotatedSymbol, self).modified + + def __setattr__(self, name, value): + if (hasattr(self.__class__, name) and + isinstance(getattr(self.__class__, name), property)): + self._modified = True + return super(AnnotatedSymbol, self).__setattr__(name, value) + + def Cut(self, child): + for i in xrange(len(self._children)): + if self._children[i] == child: + self._modified = True + del self._children[i] + break + else: + raise ValueError('%s is not in %s.' % (child, self)) + + def Paste(self, child): + self._modified = True + self._children.append(child) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/class_definition.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/class_definition.py new file mode 100644 index 0000000..814958f --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/class_definition.py @@ -0,0 +1,51 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import symbol + +from py_utils.refactor.annotated_symbol import base_symbol + + +__all__ = [ + 'Class', +] + + +class Class(base_symbol.AnnotatedSymbol): + # pylint: disable=abstract-class-not-used + + @classmethod + def Annotate(cls, symbol_type, children): + if symbol_type != symbol.stmt: + return None + + compound_statement = children[0] + if compound_statement.type != symbol.compound_stmt: + return None + + statement = compound_statement.children[0] + if statement.type == symbol.classdef: + return cls(statement.type, statement.children) + elif (statement.type == symbol.decorated and + statement.children[-1].type == symbol.classdef): + return cls(statement.type, statement.children) + else: + return None + + @property + def suite(self): + # TODO: Complete. + raise NotImplementedError() + + def FindChild(self, snippet_type, **kwargs): + return self.suite.FindChild(snippet_type, **kwargs) + + def FindChildren(self, snippet_type): + return self.suite.FindChildren(snippet_type) + + def Cut(self, child): + self.suite.Cut(child) + + def Paste(self, child): + self.suite.Paste(child) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/function_definition.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/function_definition.py new file mode 100644 index 0000000..50a1672 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/function_definition.py @@ -0,0 +1,51 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import symbol + +from py_utils.refactor.annotated_symbol import base_symbol + + +__all__ = [ + 'Function', +] + + +class Function(base_symbol.AnnotatedSymbol): + # pylint: disable=abstract-class-not-used + + @classmethod + def Annotate(cls, symbol_type, children): + if symbol_type != symbol.stmt: + return None + + compound_statement = children[0] + if compound_statement.type != symbol.compound_stmt: + return None + + statement = compound_statement.children[0] + if statement.type == symbol.funcdef: + return cls(statement.type, statement.children) + elif (statement.type == symbol.decorated and + statement.children[-1].type == symbol.funcdef): + return cls(statement.type, statement.children) + else: + return None + + @property + def suite(self): + # TODO: Complete. + raise NotImplementedError() + + def FindChild(self, snippet_type, **kwargs): + return self.suite.FindChild(snippet_type, **kwargs) + + def FindChildren(self, snippet_type): + return self.suite.FindChildren(snippet_type) + + def Cut(self, child): + self.suite.Cut(child) + + def Paste(self, child): + self.suite.Paste(child) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/import_statement.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/import_statement.py new file mode 100644 index 0000000..5c38c10 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/import_statement.py @@ -0,0 +1,322 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import itertools +import keyword +import symbol +import token + +from py_utils.refactor.annotated_symbol import base_symbol +from py_utils.refactor import snippet + + +__all__ = [ + 'AsName', + 'DottedName', + 'Import', + 'ImportFrom', + 'ImportName', +] + + +class DottedName(base_symbol.AnnotatedSymbol): + @classmethod + def Annotate(cls, symbol_type, children): + if symbol_type != symbol.dotted_name: + return None + return cls(symbol_type, children) + + @property + def value(self): + return ''.join(token_snippet.value for token_snippet in self._children) + + @value.setter + def value(self, value): + value_parts = value.split('.') + for value_part in value_parts: + if keyword.iskeyword(value_part): + raise ValueError('%s is a reserved keyword.' % value_part) + + # If we have too many children, cut the list down to size. + self._children = self._children[:len(value_parts)*2-1] + + # Update child nodes. + for child, value_part in itertools.izip_longest( + self._children[::2], value_parts): + if child: + # Modify existing children. This helps preserve comments and spaces. + child.value = value_part + else: + # Add children as needed. + self._children.append(snippet.TokenSnippet.Create(token.DOT, '.')) + self._children.append( + snippet.TokenSnippet.Create(token.NAME, value_part)) + + +class AsName(base_symbol.AnnotatedSymbol): + @classmethod + def Annotate(cls, symbol_type, children): + if (symbol_type != symbol.dotted_as_name and + symbol_type != symbol.import_as_name): + return None + return cls(symbol_type, children) + + @property + def name(self): + return self.children[0].value + + @name.setter + def name(self, value): + self.children[0].value = value + + @property + def alias(self): + if len(self.children) < 3: + return None + return self.children[2].value + + @alias.setter + def alias(self, value): + if keyword.iskeyword(value): + raise ValueError('%s is a reserved keyword.' % value) + + if value: + if len(self.children) < 3: + # If we currently have no alias, add one. + self.children.append( + snippet.TokenSnippet.Create(token.NAME, 'as', (0, 1))) + self.children.append( + snippet.TokenSnippet.Create(token.NAME, value, (0, 1))) + else: + # We already have an alias. Just update the value. + self.children[2].value = value + else: + # Removing the alias. Strip the "as foo". + self.children = [self.children[0]] + + +class Import(base_symbol.AnnotatedSymbol): + """An import statement. + + Example: + import a.b.c as d + from a.b import c as d + + In these examples, + path == 'a.b.c' + alias == 'd' + root == 'a.b' (only for "from" imports) + module == 'c' (only for "from" imports) + name (read-only) == the name used by references to the module, which is the + alias if there is one, the full module path in "full" imports, and the + module name in "from" imports. + """ + @property + def has_from(self): + """Returns True iff the import statment is of the form "from x import y".""" + raise NotImplementedError() + + @property + def values(self): + raise NotImplementedError() + + @property + def paths(self): + raise NotImplementedError() + + @property + def aliases(self): + raise NotImplementedError() + + @property + def path(self): + """The full dotted path of the module.""" + raise NotImplementedError() + + @path.setter + def path(self, value): + raise NotImplementedError() + + @property + def alias(self): + """The alias, if the module is renamed with "as". None otherwise.""" + raise NotImplementedError() + + @alias.setter + def alias(self, value): + raise NotImplementedError() + + @property + def name(self): + """The name used to reference this import's module.""" + raise NotImplementedError() + + +class ImportName(Import): + @classmethod + def Annotate(cls, symbol_type, children): + if symbol_type != symbol.import_stmt: + return None + if children[0].type != symbol.import_name: + return None + assert len(children) == 1 + return cls(symbol_type, children[0].children) + + @property + def has_from(self): + return False + + @property + def values(self): + dotted_as_names = self.children[1] + return tuple((dotted_as_name.name, dotted_as_name.alias) + for dotted_as_name in dotted_as_names.children[::2]) + + @property + def paths(self): + return tuple(path for path, _ in self.values) + + @property + def aliases(self): + return tuple(alias for _, alias in self.values) + + @property + def _dotted_as_name(self): + dotted_as_names = self.children[1] + if len(dotted_as_names.children) != 1: + raise NotImplementedError( + 'This method only works if the statement has one import.') + return dotted_as_names.children[0] + + @property + def path(self): + return self._dotted_as_name.name + + @path.setter + def path(self, value): # pylint: disable=arguments-differ + self._dotted_as_name.name = value + + @property + def alias(self): + return self._dotted_as_name.alias + + @alias.setter + def alias(self, value): # pylint: disable=arguments-differ + self._dotted_as_name.alias = value + + @property + def name(self): + if self.alias: + return self.alias + else: + return self.path + + +class ImportFrom(Import): + @classmethod + def Annotate(cls, symbol_type, children): + if symbol_type != symbol.import_stmt: + return None + if children[0].type != symbol.import_from: + return None + assert len(children) == 1 + return cls(symbol_type, children[0].children) + + @property + def has_from(self): + return True + + @property + def values(self): + try: + import_as_names = self.FindChild(symbol.import_as_names) + except ValueError: + return (('*', None),) + + return tuple((import_as_name.name, import_as_name.alias) + for import_as_name in import_as_names.children[::2]) + + @property + def paths(self): + module = self.module + return tuple('.'.join((module, name)) for name, _ in self.values) + + @property + def aliases(self): + return tuple(alias for _, alias in self.values) + + @property + def root(self): + return self.FindChild(symbol.dotted_name).value + + @root.setter + def root(self, value): + self.FindChild(symbol.dotted_name).value = value + + @property + def _import_as_name(self): + try: + import_as_names = self.FindChild(symbol.import_as_names) + except ValueError: + return None + + if len(import_as_names.children) != 1: + raise NotImplementedError( + 'This method only works if the statement has one import.') + + return import_as_names.children[0] + + @property + def module(self): + import_as_name = self._import_as_name + if import_as_name: + return import_as_name.name + else: + return '*' + + @module.setter + def module(self, value): + if keyword.iskeyword(value): + raise ValueError('%s is a reserved keyword.' % value) + + import_as_name = self._import_as_name + if value == '*': + # TODO: Implement this. + raise NotImplementedError() + else: + if import_as_name: + import_as_name.name = value + else: + # TODO: Implement this. + raise NotImplementedError() + + @property + def path(self): + return '.'.join((self.root, self.module)) + + @path.setter + def path(self, value): # pylint: disable=arguments-differ + self.root, _, self.module = value.rpartition('.') + + @property + def alias(self): + import_as_name = self._import_as_name + if import_as_name: + return import_as_name.alias + else: + return None + + @alias.setter + def alias(self, value): # pylint: disable=arguments-differ + import_as_name = self._import_as_name + if not import_as_name: + raise NotImplementedError('Cannot change alias for "import *".') + import_as_name.alias = value + + @property + def name(self): + if self.alias: + return self.alias + else: + return self.module diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/reference.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/reference.py new file mode 100644 index 0000000..757c57f --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/annotated_symbol/reference.py @@ -0,0 +1,75 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import itertools +import symbol +import token + +from py_utils.refactor.annotated_symbol import base_symbol +from py_utils.refactor import snippet + + +__all__ = [ + 'Reference', +] + + +class Reference(base_symbol.AnnotatedSymbol): + @classmethod + def Annotate(cls, nodes): + if not nodes: + return None + if nodes[0].type != symbol.atom: + return None + if not nodes[0].children or nodes[0].children[0].type != token.NAME: + return None + + for i in xrange(1, len(nodes)): + if not nodes: + break + if nodes[i].type != symbol.trailer: + break + if len(nodes[i].children) != 2: + break + if (nodes[i].children[0].type != token.DOT or + nodes[i].children[1].type != token.NAME): + break + else: + i = len(nodes) + + return [cls(nodes[:i])] + nodes[i:] + + def __init__(self, children): + super(Reference, self).__init__(-1, children) + + @property + def type_name(self): + return 'attribute_reference' + + @property + def value(self): + return ''.join(token_snippet.value + for child in self.children + for token_snippet in child.children) + + @value.setter + def value(self, value): + value_parts = value.split('.') + + # If we have too many children, cut the list down to size. + self._children = self._children[:len(value_parts)] + + # Update child nodes. + for child, value_part in itertools.izip_longest( + self._children, value_parts): + if child: + # Modify existing children. This helps preserve comments and spaces. + child.children[-1].value = value_part + else: + # Add children as needed. + token_snippets = [ + snippet.TokenSnippet.Create(token.DOT, '.'), + snippet.TokenSnippet.Create(token.NAME, value_part), + ] + self._children.append(snippet.Symbol(symbol.trailer, token_snippets)) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/module.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/module.py new file mode 100644 index 0000000..d6eae00 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/module.py @@ -0,0 +1,39 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from py_utils.refactor import annotated_symbol + + +class Module(object): + + def __init__(self, file_path): + self._file_path = file_path + + with open(self._file_path, 'r') as f: + self._snippet = annotated_symbol.Annotate(f) + + @property + def file_path(self): + return self._file_path + + @property + def modified(self): + return self._snippet.modified + + def FindAll(self, snippet_type): + return self._snippet.FindAll(snippet_type) + + def FindChildren(self, snippet_type): + return self._snippet.FindChildren(snippet_type) + + def Write(self): + """Write modifications to the file.""" + if not self.modified: + return + + # Stringify before opening the file for writing. + # If we fail, we won't truncate the file. + string = str(self._snippet) + with open(self._file_path, 'w') as f: + f.write(string) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/offset_token.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/offset_token.py new file mode 100644 index 0000000..5fa953e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/offset_token.py @@ -0,0 +1,115 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import collections +import itertools +import token +import tokenize + + +def _Pairwise(iterable): + """s -> (None, s0), (s0, s1), (s1, s2), (s2, s3), ...""" + a, b = itertools.tee(iterable) + a = itertools.chain((None,), a) + return itertools.izip(a, b) + + +class OffsetToken(object): + """A Python token with a relative position. + + A token is represented by a type defined in Python's token module, a string + representing the content, and an offset. Using relative positions makes it + easy to insert and remove tokens. + """ + + def __init__(self, token_type, string, offset): + self._type = token_type + self._string = string + self._offset = offset + + @property + def type(self): + return self._type + + @property + def type_name(self): + return token.tok_name[self._type] + + @property + def string(self): + return self._string + + @string.setter + def string(self, value): + self._string = value + + @property + def offset(self): + return self._offset + + def __str__(self): + return str((self.type_name, self.string, self.offset)) + + +def Tokenize(f): + """Read tokens from a file-like object. + + Args: + f: Any object that has a readline method. + + Returns: + A collections.deque containing OffsetTokens. Deques are cheaper and easier + to manipulate sequentially than lists. + """ + f.seek(0) + tokenize_tokens = tokenize.generate_tokens(f.readline) + + offset_tokens = collections.deque() + for prev_token, next_token in _Pairwise(tokenize_tokens): + token_type, string, (srow, scol), _, _ = next_token + if not prev_token: + offset_tokens.append(OffsetToken(token_type, string, (0, 0))) + else: + erow, ecol = prev_token[3] + if erow == srow: + offset_tokens.append(OffsetToken(token_type, string, (0, scol - ecol))) + else: + offset_tokens.append(OffsetToken( + token_type, string, (srow - erow, scol))) + + return offset_tokens + + +def Untokenize(offset_tokens): + """Return the string representation of an iterable of OffsetTokens.""" + # Make a copy. Don't modify the original. + offset_tokens = collections.deque(offset_tokens) + + # Strip leading NL tokens. + while offset_tokens[0].type == tokenize.NL: + offset_tokens.popleft() + + # Strip leading vertical whitespace. + first_token = offset_tokens.popleft() + # Take care not to modify the existing token. Create a new one in its place. + first_token = OffsetToken(first_token.type, first_token.string, + (0, first_token.offset[1])) + offset_tokens.appendleft(first_token) + + # Convert OffsetTokens to tokenize tokens. + tokenize_tokens = [] + row = 1 + col = 0 + for t in offset_tokens: + offset_row, offset_col = t.offset + if offset_row == 0: + col += offset_col + else: + row += offset_row + col = offset_col + tokenize_tokens.append((t.type, t.string, (row, col), (row, col), None)) + + # tokenize can't handle whitespace before line continuations. + # So add a space. + return tokenize.untokenize(tokenize_tokens).replace('\\\n', ' \\\n') diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/snippet.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/snippet.py new file mode 100644 index 0000000..b98561a --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor/snippet.py @@ -0,0 +1,244 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import parser +import symbol +import sys +import token +import tokenize + +from py_utils.refactor import offset_token + + +class Snippet(object): + """A node in the Python parse tree. + + The Python grammar is defined at: + https://docs.python.org/2/reference/grammar.html + + There are two types of Snippets: + TokenSnippets are leaf nodes containing actual text. + Symbols are internal nodes representing higher-level groupings, and are + defined by the left-hand sides of the BNFs in the above link. + """ + @property + def type(self): + raise NotImplementedError() + + @property + def type_name(self): + raise NotImplementedError() + + @property + def children(self): + """Return a list of this node's children.""" + raise NotImplementedError() + + @property + def tokens(self): + """Return a tuple of the tokens this Snippet contains.""" + raise NotImplementedError() + + def PrintTree(self, indent=0, stream=sys.stdout): + """Spew a pretty-printed parse tree. Mostly useful for debugging.""" + raise NotImplementedError() + + def __str__(self): + return offset_token.Untokenize(self.tokens) + + def FindAll(self, snippet_type): + if isinstance(snippet_type, int): + if self.type == snippet_type: + yield self + else: + if isinstance(self, snippet_type): + yield self + + for child in self.children: + for snippet in child.FindAll(snippet_type): + yield snippet + + def FindChild(self, snippet_type, **kwargs): + for child in self.children: + if isinstance(snippet_type, int): + if child.type != snippet_type: + continue + else: + if not isinstance(child, snippet_type): + continue + + for attribute, value in kwargs: + if getattr(child, attribute) != value: + break + else: + return child + raise ValueError('%s is not in %s. Children are: %s' % + (snippet_type, self, self.children)) + + def FindChildren(self, snippet_type): + if isinstance(snippet_type, int): + for child in self.children: + if child.type == snippet_type: + yield child + else: + for child in self.children: + if isinstance(child, snippet_type): + yield child + + +class TokenSnippet(Snippet): + """A Snippet containing a list of tokens. + + A list of tokens may start with any number of comments and non-terminating + newlines, but must end with a syntactically meaningful token. + """ + + def __init__(self, token_type, tokens): + # For operators and delimiters, the TokenSnippet's type may be more specific + # than the type of the constituent token. E.g. the TokenSnippet type is + # token.DOT, but the token type is token.OP. This is because the parser + # has more context than the tokenizer. + self._type = token_type + self._tokens = tokens + self._modified = False + + @classmethod + def Create(cls, token_type, string, offset=(0, 0)): + return cls(token_type, + [offset_token.OffsetToken(token_type, string, offset)]) + + @property + def type(self): + return self._type + + @property + def type_name(self): + return token.tok_name[self.type] + + @property + def value(self): + return self._tokens[-1].string + + @value.setter + def value(self, value): + self._tokens[-1].string = value + self._modified = True + + @property + def children(self): + return [] + + @property + def tokens(self): + return tuple(self._tokens) + + @property + def modified(self): + return self._modified + + def PrintTree(self, indent=0, stream=sys.stdout): + stream.write(' ' * indent) + if not self.tokens: + print >> stream, self.type_name + return + + print >> stream, '%-4s' % self.type_name, repr(self.tokens[0].string) + for tok in self.tokens[1:]: + stream.write(' ' * indent) + print >> stream, ' ' * max(len(self.type_name), 4), repr(tok.string) + + +class Symbol(Snippet): + """A Snippet containing sub-Snippets. + + The possible types and type_names are defined in Python's symbol module.""" + + def __init__(self, symbol_type, children): + self._type = symbol_type + self._children = children + + @property + def type(self): + return self._type + + @property + def type_name(self): + return symbol.sym_name[self.type] + + @property + def children(self): + return self._children + + @children.setter + def children(self, value): # pylint: disable=arguments-differ + self._children = value + + @property + def tokens(self): + tokens = [] + for child in self.children: + tokens += child.tokens + return tuple(tokens) + + @property + def modified(self): + return any(child.modified for child in self.children) + + def PrintTree(self, indent=0, stream=sys.stdout): + stream.write(' ' * indent) + + # If there's only one child, collapse it onto the same line. + node = self + while len(node.children) == 1 and len(node.children[0].children) == 1: + print >> stream, node.type_name, + node = node.children[0] + + print >> stream, node.type_name + for child in node.children: + child.PrintTree(indent + 2, stream) + + +def Snippetize(f): + """Return the syntax tree of the given file.""" + f.seek(0) + syntax_tree = parser.st2list(parser.suite(f.read())) + tokens = offset_token.Tokenize(f) + + snippet = _SnippetizeNode(syntax_tree, tokens) + assert not tokens + return snippet + + +def _SnippetizeNode(node, tokens): + # The parser module gives a syntax tree that discards comments, + # non-terminating newlines, and whitespace information. Use the tokens given + # by the tokenize module to annotate the syntax tree with the information + # needed to exactly reproduce the original source code. + node_type = node[0] + + if node_type >= token.NT_OFFSET: + # Symbol. + children = tuple(_SnippetizeNode(child, tokens) for child in node[1:]) + return Symbol(node_type, children) + else: + # Token. + grabbed_tokens = [] + while tokens and ( + tokens[0].type == tokenize.COMMENT or tokens[0].type == tokenize.NL): + grabbed_tokens.append(tokens.popleft()) + + # parser has 2 NEWLINEs right before the end. + # tokenize has 0 or 1 depending on if the file has one. + # Create extra nodes without consuming tokens to account for this. + if node_type == token.NEWLINE: + for tok in tokens: + if tok.type == token.ENDMARKER: + return TokenSnippet(node_type, grabbed_tokens) + if tok.type != token.DEDENT: + break + + assert tokens[0].type == token.OP or node_type == tokens[0].type + + grabbed_tokens.append(tokens.popleft()) + return TokenSnippet(node_type, grabbed_tokens) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor_util/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor_util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor_util/move.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor_util/move.py new file mode 100644 index 0000000..d68f93b --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/refactor_util/move.py @@ -0,0 +1,116 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import functools +import os +import sys + +from py_utils import refactor + + +def Run(sources, target, files_to_update): + """Move modules and update imports. + + Args: + sources: List of source module or package paths. + target: Destination module or package path. + files_to_update: Modules whose imports we should check for changes. + """ + # TODO(dtu): Support moving classes and functions. + moves = tuple(_Move(source, target) for source in sources) + + # Update imports and references. + refactor.Transform(functools.partial(_Update, moves), files_to_update) + + # Move files. + for move in moves: + os.rename(move.source_path, move.target_path) + + +def _Update(moves, module): + for import_statement in module.FindAll(refactor.Import): + for move in moves: + try: + if move.UpdateImportAndReferences(module, import_statement): + break + except NotImplementedError as e: + print >> sys.stderr, 'Error updating %s: %s' % (module.file_path, e) + + +class _Move(object): + + def __init__(self, source, target): + self._source_path = os.path.realpath(source) + self._target_path = os.path.realpath(target) + + if os.path.isdir(self._target_path): + self._target_path = os.path.join( + self._target_path, os.path.basename(self._source_path)) + + @property + def source_path(self): + return self._source_path + + @property + def target_path(self): + return self._target_path + + @property + def source_module_path(self): + return _ModulePath(self._source_path) + + @property + def target_module_path(self): + return _ModulePath(self._target_path) + + def UpdateImportAndReferences(self, module, import_statement): + """Update an import statement in a module and all its references.. + + Args: + module: The refactor.Module to update. + import_statement: The refactor.Import to update. + + Returns: + True if the import statement was updated, or False if the import statement + needed no updating. + """ + statement_path_parts = import_statement.path.split('.') + source_path_parts = self.source_module_path.split('.') + if source_path_parts != statement_path_parts[:len(source_path_parts)]: + return False + + # Update import statement. + old_name_parts = import_statement.name.split('.') + new_name_parts = ([self.target_module_path] + + statement_path_parts[len(source_path_parts):]) + import_statement.path = '.'.join(new_name_parts) + new_name = import_statement.name + + # Update references. + for reference in module.FindAll(refactor.Reference): + reference_parts = reference.value.split('.') + if old_name_parts != reference_parts[:len(old_name_parts)]: + continue + + new_reference_parts = [new_name] + reference_parts[len(old_name_parts):] + reference.value = '.'.join(new_reference_parts) + + return True + + +def _BaseDir(module_path): + if not os.path.isdir(module_path): + module_path = os.path.dirname(module_path) + + while '__init__.py' in os.listdir(module_path): + module_path = os.path.dirname(module_path) + + return module_path + + +def _ModulePath(module_path): + if os.path.split(module_path)[1] == '__init__.py': + module_path = os.path.dirname(module_path) + rel_path = os.path.relpath(module_path, _BaseDir(module_path)) + return os.path.splitext(rel_path)[0].replace(os.sep, '.') diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/shell_util.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/shell_util.py new file mode 100644 index 0000000..2a529c8 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/shell_util.py @@ -0,0 +1,40 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Shell scripting helpers (created for Telemetry dependency roll scripts). + +import os as _os +import shutil as _shutil +import subprocess as _subprocess +import tempfile as _tempfile +from contextlib import contextmanager as _contextmanager + +@_contextmanager +def ScopedChangeDir(new_path): + old_path = _os.getcwd() + _os.chdir(new_path) + print '> cd', _os.getcwd() + try: + yield + finally: + _os.chdir(old_path) + print '> cd', old_path + +@_contextmanager +def ScopedTempDir(): + temp_dir = _tempfile.mkdtemp() + try: + with ScopedChangeDir(temp_dir): + yield + finally: + _shutil.rmtree(temp_dir) + +def CallProgram(path_parts, *args, **kwargs): + '''Call an executable os.path.join(*path_parts) with the arguments specified + by *args. Any keyword arguments are passed as environment variables.''' + args = [_os.path.join(*path_parts)] + list(args) + env = dict(_os.environ) + env.update(kwargs) + print '>', ' '.join(args) + _subprocess.check_call(args, env=env) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext.py new file mode 100644 index 0000000..b095530 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext.py @@ -0,0 +1,25 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +import contextlib +import shutil +import tempfile + + +@contextlib.contextmanager +def NamedTemporaryDirectory(suffix='', prefix='tmp', dir=None): + """A context manager that manages a temporary directory. + + This is a context manager version of tempfile.mkdtemp. The arguments to this + function are the same as the arguments for that one. + """ + # This uses |dir| as a parameter name for consistency with mkdtemp. + # pylint: disable=redefined-builtin + + d = tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=dir) + try: + yield d + finally: + shutil.rmtree(d) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext_unittest.py new file mode 100644 index 0000000..6844623 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/tempfile_ext_unittest.py @@ -0,0 +1,39 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os + +from py_utils import tempfile_ext +from pyfakefs import fake_filesystem_unittest + + +class NamedTemporaryDirectoryTest(fake_filesystem_unittest.TestCase): + + def setUp(self): + self.setUpPyfakefs() + + def tearDown(self): + self.tearDownPyfakefs() + + def testBasic(self): + with tempfile_ext.NamedTemporaryDirectory() as d: + self.assertTrue(os.path.exists(d)) + self.assertTrue(os.path.isdir(d)) + self.assertFalse(os.path.exists(d)) + + def testSuffix(self): + test_suffix = 'foo' + with tempfile_ext.NamedTemporaryDirectory(suffix=test_suffix) as d: + self.assertTrue(os.path.basename(d).endswith(test_suffix)) + + def testPrefix(self): + test_prefix = 'bar' + with tempfile_ext.NamedTemporaryDirectory(prefix=test_prefix) as d: + self.assertTrue(os.path.basename(d).startswith(test_prefix)) + + def testDir(self): + test_dir = '/baz' + self.fs.CreateDirectory(test_dir) + with tempfile_ext.NamedTemporaryDirectory(dir=test_dir) as d: + self.assertEquals(test_dir, os.path.dirname(d)) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/test_data/foo.txt b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/test_data/foo.txt new file mode 100644 index 0000000..a9cac3e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/test_data/foo.txt @@ -0,0 +1 @@ +This file is not executable. diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/xvfb.py b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/xvfb.py new file mode 100644 index 0000000..c09f3e3 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/common/py_utils/py_utils/xvfb.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import os +import logging +import subprocess +import platform +import time + + +def ShouldStartXvfb(): + return platform.system() == 'Linux' + + +def StartXvfb(): + display = ':99' + xvfb_command = ['Xvfb', display, '-screen', '0', '1024x769x24', '-ac'] + xvfb_process = subprocess.Popen( + xvfb_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + time.sleep(0.2) + returncode = xvfb_process.poll() + if returncode is None: + os.environ['DISPLAY'] = display + else: + logging.error('Xvfb did not start, returncode: %s, stdout:\n%s', + returncode, xvfb_process.stdout.read()) + xvfb_process = None + return xvfb_process diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/PRESUBMIT.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/PRESUBMIT.py new file mode 100644 index 0000000..a34480c --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/PRESUBMIT.py @@ -0,0 +1,32 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +def CheckChangeOnUpload(input_api, output_api): + return _CommonChecks(input_api, output_api) + + +def CheckChangeOnCommit(input_api, output_api): + return _CommonChecks(input_api, output_api) + + +def _CommonChecks(input_api, output_api): + results = [] + results += input_api.RunTests(input_api.canned_checks.GetPylint( + input_api, output_api, extra_paths_list=_GetPathsToPrepend(input_api), + pylintrc='pylintrc')) + return results + + +def _GetPathsToPrepend(input_api): + project_dir = input_api.PresubmitLocalPath() + catapult_dir = input_api.os_path.join(project_dir, '..') + return [ + project_dir, + + input_api.os_path.join(catapult_dir, 'common', 'py_utils'), + + input_api.os_path.join(catapult_dir, 'third_party', 'mock'), + input_api.os_path.join(catapult_dir, 'third_party', 'pyfakefs'), + ] diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/__init__.py new file mode 100644 index 0000000..68efbdb --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/__init__.py @@ -0,0 +1,43 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import sys + + +CATAPULT_PATH = os.path.dirname(os.path.dirname(os.path.dirname( + os.path.abspath(__file__)))) +CATAPULT_THIRD_PARTY_PATH = os.path.join(CATAPULT_PATH, 'third_party') +DEPENDENCY_MANAGER_PATH = os.path.join(CATAPULT_PATH, 'dependency_manager') + + +def _AddDirToPythonPath(*path_parts): + path = os.path.abspath(os.path.join(*path_parts)) + if os.path.isdir(path) and path not in sys.path: + sys.path.append(path) + + +_AddDirToPythonPath(CATAPULT_PATH, 'common', 'py_utils') +_AddDirToPythonPath(CATAPULT_THIRD_PARTY_PATH, 'mock') +_AddDirToPythonPath(CATAPULT_THIRD_PARTY_PATH, 'pyfakefs') +_AddDirToPythonPath(CATAPULT_THIRD_PARTY_PATH, 'zipfile') +_AddDirToPythonPath(DEPENDENCY_MANAGER_PATH) + + +# pylint: disable=unused-import +from .archive_info import ArchiveInfo +from .base_config import BaseConfig +from .cloud_storage_info import CloudStorageInfo +from .dependency_info import DependencyInfo +from .exceptions import CloudStorageError +from .exceptions import CloudStorageUploadConflictError +from .exceptions import EmptyConfigError +from .exceptions import FileNotFoundError +from .exceptions import NoPathFoundError +from .exceptions import ReadWriteError +from .exceptions import UnsupportedConfigFormatError +from .local_path_info import LocalPathInfo +from .manager import DependencyManager +# pylint: enable=unused-import + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/archive_info.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/archive_info.py new file mode 100644 index 0000000..ff13f90 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/archive_info.py @@ -0,0 +1,80 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import glob +import os +import shutil + +from dependency_manager import exceptions +from dependency_manager import dependency_manager_util + + +class ArchiveInfo(object): + + def __init__(self, archive_file, unzip_path, path_within_archive, + stale_unzip_path_glob=None): + """ Container for the information needed to unzip a downloaded archive. + + Args: + archive_path: Path to the archive file. + unzip_path: Path to unzip the archive into. Assumes that this path + is unique for the archive. + path_within_archive: Specify if and how to handle zip archives + downloaded from cloud_storage. Expected values: + None: Do not unzip the file downloaded from cloud_storage. + '.': Unzip the file downloaded from cloud_storage. The + unzipped file/folder is the expected dependency. + file_path: Unzip the file downloaded from cloud_storage. + |file_path| is the path to the expected dependency, + relative to the unzipped archive path. + stale_unzip_path_glob: Optional argument specifying a glob matching + string which matches directories that should be removed before this + archive is extracted (if it is extracted at all). + """ + self._archive_file = archive_file + self._unzip_path = unzip_path + self._path_within_archive = path_within_archive + self._dependency_path = os.path.join( + self._unzip_path, self._path_within_archive) + self._stale_unzip_path_glob = stale_unzip_path_glob + if not self._has_minimum_data: + raise ValueError( + 'Not enough information specified to initialize an archive info.' + ' %s' % self) + + def GetUnzippedPath(self): + if self.ShouldUnzipArchive(): + # Remove stale unzip results + if self._stale_unzip_path_glob: + for path in glob.glob(self._stale_unzip_path_glob): + shutil.rmtree(path) + # TODO(aiolos): Replace UnzipFile with zipfile.extractall once python + # version 2.7.4 or later can safely be assumed. + dependency_manager_util.UnzipArchive( + self._archive_file, self._unzip_path) + if self.ShouldUnzipArchive(): + raise exceptions.ArchiveError( + "Expected path '%s' was not extracted from archive '%s'." % + (self._dependency_path, self._archive_file)) + return self._dependency_path + + def ShouldUnzipArchive(self): + if not self._has_minimum_data: + raise exceptions.ArchiveError( + 'Missing needed info to unzip archive. Known data: %s', + self.data_string) + return not os.path.exists(self._dependency_path) + + @property + def _has_minimum_data(self): + return all([self._archive_file, self._unzip_path, + self._dependency_path]) + + def __repr__(self): + return ( + 'ArchiveInfo(archive_file=%s, unzip_path=%s, path_within_archive=%s, ' + 'dependency_path =%s)' % ( + self._archive_file, self._unzip_path, self._path_within_archive, + self._dependency_path)) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config.py new file mode 100644 index 0000000..c735688 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config.py @@ -0,0 +1,388 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import logging +import os + +from py_utils import cloud_storage +from dependency_manager import archive_info +from dependency_manager import cloud_storage_info +from dependency_manager import dependency_info +from dependency_manager import exceptions +from dependency_manager import local_path_info +from dependency_manager import uploader + + +class BaseConfig(object): + """A basic config class for use with the DependencyManager. + + Initiated with a json file in the following format: + + { "config_type": "BaseConfig", + "dependencies": { + "dep_name1": { + "cloud_storage_base_folder": "base_folder1", + "cloud_storage_bucket": "bucket1", + "file_info": { + "platform1": { + "cloud_storage_hash": "hash_for_platform1", + "download_path": "download_path111", + "version_in_cs": "1.11.1.11." + "local_paths": ["local_path1110", "local_path1111"] + }, + "platform2": { + "cloud_storage_hash": "hash_for_platform2", + "download_path": "download_path2", + "local_paths": ["local_path20", "local_path21"] + }, + ... + } + }, + "dependency_name_2": { + ... + }, + ... + } + } + + Required fields: "dependencies" and "config_type". + Note that config_type must be "BaseConfig" + + Assumptions: + "cloud_storage_base_folder" is a top level folder in the given + "cloud_storage_bucket" where all of the dependency files are stored + at "dependency_name"_"cloud_storage_hash". + + "download_path" and all paths in "local_paths" are relative to the + config file's location. + + All or none of the following cloud storage related fields must be + included in each platform dictionary: + "cloud_storage_hash", "download_path", "cs_remote_path" + + "version_in_cs" is an optional cloud storage field, but is dependent + on the above cloud storage related fields. + + + Also note that platform names are often of the form os_architechture. + Ex: "win_AMD64" + + More information on the fields can be found in dependencies_info.py + """ + def __init__(self, file_path, writable=False): + """ Initialize a BaseConfig for the DependencyManager. + + Args: + writable: False: This config will be used to lookup information. + True: This config will be used to update information. + + file_path: Path to a file containing a json dictionary in the expected + json format for this config class. Base format expected: + + { "config_type": config_type, + "dependencies": dependencies_dict } + + config_type: must match the return value of GetConfigType. + dependencies: A dictionary with the information needed to + create dependency_info instances for the given + dependencies. + + See dependency_info.py for more information. + """ + self._config_path = file_path + self._writable = writable + self._pending_uploads = [] + if not self._config_path: + raise ValueError('Must supply config file path.') + if not os.path.exists(self._config_path): + if not writable: + raise exceptions.EmptyConfigError(file_path) + self._config_data = {} + self._WriteConfigToFile(self._config_path, dependencies=self._config_data) + else: + with open(file_path, 'r') as f: + config_data = json.load(f) + if not config_data: + raise exceptions.EmptyConfigError(file_path) + config_type = config_data.pop('config_type', None) + if config_type != self.GetConfigType(): + raise ValueError( + 'Supplied config_type (%s) is not the expected type (%s) in file ' + '%s' % (config_type, self.GetConfigType(), file_path)) + self._config_data = config_data.get('dependencies', {}) + + def IterDependencyInfo(self): + """ Yields a DependencyInfo for each dependency/platform pair. + + Raises: + ReadWriteError: If called when the config is writable. + ValueError: If any of the dependencies contain partial information for + downloading from cloud_storage. (See dependency_info.py) + """ + if self._writable: + raise exceptions.ReadWriteError( + 'Trying to read dependency info from a writable config. File for ' + 'config: %s' % self._config_path) + base_path = os.path.dirname(self._config_path) + for dependency in self._config_data: + dependency_dict = self._config_data.get(dependency) + platforms_dict = dependency_dict.get('file_info', {}) + for platform in platforms_dict: + platform_info = platforms_dict.get(platform) + + local_info = None + local_paths = platform_info.get('local_paths', []) + if local_paths: + paths = [] + for path in local_paths: + path = self._FormatPath(path) + paths.append(os.path.abspath(os.path.join(base_path, path))) + local_info = local_path_info.LocalPathInfo(paths) + + cs_info = None + cs_bucket = dependency_dict.get('cloud_storage_bucket') + cs_base_folder = dependency_dict.get('cloud_storage_base_folder', '') + download_path = platform_info.get('download_path') + if download_path: + download_path = self._FormatPath(download_path) + download_path = os.path.abspath( + os.path.join(base_path, download_path)) + + cs_hash = platform_info.get('cloud_storage_hash') + if not cs_hash: + raise exceptions.ConfigError( + 'Dependency %s has cloud storage info on platform %s, but is ' + 'missing a cloud storage hash.', dependency, platform) + cs_remote_path = self._CloudStorageRemotePath( + dependency, cs_hash, cs_base_folder) + version_in_cs = platform_info.get('version_in_cs') + + zip_info = None + path_within_archive = platform_info.get('path_within_archive') + if path_within_archive: + unzip_path = os.path.abspath( + os.path.join(os.path.dirname(download_path), + '%s_%s_%s' % (dependency, platform, cs_hash))) + stale_unzip_path_glob = os.path.abspath( + os.path.join(os.path.dirname(download_path), + '%s_%s_%s' % (dependency, platform, + '[0-9a-f]' * 40))) + zip_info = archive_info.ArchiveInfo( + download_path, unzip_path, path_within_archive, + stale_unzip_path_glob) + + cs_info = cloud_storage_info.CloudStorageInfo( + cs_bucket, cs_hash, download_path, cs_remote_path, + version_in_cs=version_in_cs, archive_info=zip_info) + + dep_info = dependency_info.DependencyInfo( + dependency, platform, self._config_path, + local_path_info=local_info, cloud_storage_info=cs_info) + yield dep_info + + @classmethod + def GetConfigType(cls): + return 'BaseConfig' + + @property + def config_path(self): + return self._config_path + + def AddCloudStorageDependencyUpdateJob( + self, dependency, platform, dependency_path, version=None, + execute_job=True): + """Update the file downloaded from cloud storage for a dependency/platform. + + Upload a new file to cloud storage for the given dependency and platform + pair and update the cloud storage hash and the version for the given pair. + + Example usage: + The following should update the default platform for 'dep_name': + UpdateCloudStorageDependency('dep_name', 'default', 'path/to/file') + + The following should update both the mac and win platforms for 'dep_name', + or neither if either update fails: + UpdateCloudStorageDependency( + 'dep_name', 'mac_x86_64', 'path/to/mac/file', execute_job=False) + UpdateCloudStorageDependency( + 'dep_name', 'win_AMD64', 'path/to/win/file', execute_job=False) + ExecuteUpdateJobs() + + Args: + dependency: The dependency to update. + platform: The platform to update the dependency info for. + dependency_path: Path to the new dependency to be used. + version: Version of the updated dependency, for checking future updates + against. + execute_job: True if the config should be written to disk and the file + should be uploaded to cloud storage after the update. False if + multiple updates should be performed atomically. Must call + ExecuteUpdateJobs after all non-executed jobs are added to complete + the update. + + Raises: + ReadWriteError: If the config was not initialized as writable, or if + |execute_job| is True but the config has update jobs still pending + execution. + ValueError: If no information exists in the config for |dependency| on + |platform|. + """ + self._ValidateIsConfigUpdatable( + execute_job=execute_job, dependency=dependency, platform=platform) + cs_hash = cloud_storage.CalculateHash(dependency_path) + if version: + self._SetPlatformData(dependency, platform, 'version_in_cs', version) + self._SetPlatformData(dependency, platform, 'cloud_storage_hash', cs_hash) + + cs_base_folder = self._GetPlatformData( + dependency, platform, 'cloud_storage_base_folder') + cs_bucket = self._GetPlatformData( + dependency, platform, 'cloud_storage_bucket') + cs_remote_path = self._CloudStorageRemotePath( + dependency, cs_hash, cs_base_folder) + self._pending_uploads.append(uploader.CloudStorageUploader( + cs_bucket, cs_remote_path, dependency_path)) + if execute_job: + self.ExecuteUpdateJobs() + + def ExecuteUpdateJobs(self, force=False): + """Write all config changes to the config_path specified in __init__. + + Upload all files pending upload and then write the updated config to + file. Attempt to remove all uploaded files on failure. + + Args: + force: True if files should be uploaded to cloud storage even if a + file already exists in the upload location. + + Returns: + True: if the config was dirty and the upload succeeded. + False: if the config was not dirty. + + Raises: + CloudStorageUploadConflictError: If |force| is False and the potential + upload location of a file already exists. + CloudStorageError: If copying an existing file to the backup location + or uploading a new file fails. + """ + self._ValidateIsConfigUpdatable() + if not self._IsDirty(): + logging.info('ExecuteUpdateJobs called on clean config') + return False + if not self._pending_uploads: + logging.debug('No files needing upload.') + else: + try: + for item_pending_upload in self._pending_uploads: + item_pending_upload.Upload(force) + self._WriteConfigToFile(self._config_path, self._config_data) + self._pending_uploads = [] + except: + # Attempt to rollback the update in any instance of failure, even user + # interrupt via Ctrl+C; but don't consume the exception. + logging.error('Update failed, attempting to roll it back.') + for upload_item in reversed(self._pending_uploads): + upload_item.Rollback() + raise + return True + + def GetVersion(self, dependency, platform): + """Return the Version information for the given dependency.""" + return self._GetPlatformData( + dependency, platform, data_type='version_in_cs') + + def _IsDirty(self): + with open(self._config_path, 'r') as fstream: + curr_config_data = json.load(fstream) + curr_config_data = curr_config_data.get('dependencies', {}) + return self._config_data != curr_config_data + + def _SetPlatformData(self, dependency, platform, data_type, data): + self._ValidateIsConfigWritable() + dependency_dict = self._config_data.get(dependency, {}) + platform_dict = dependency_dict.get('file_info', {}).get(platform) + if not platform_dict: + raise ValueError('No platform data for platform %s on dependency %s' % + (platform, dependency)) + if (data_type == 'cloud_storage_bucket' or + data_type == 'cloud_storage_base_folder'): + self._config_data[dependency][data_type] = data + else: + self._config_data[dependency]['file_info'][platform][data_type] = data + + def _GetPlatformData(self, dependency, platform, data_type=None): + dependency_dict = self._config_data.get(dependency, {}) + if not dependency_dict: + raise ValueError('Dependency %s is not in config.' % dependency) + platform_dict = dependency_dict.get('file_info', {}).get(platform) + if not platform_dict: + raise ValueError('No platform data for platform %s on dependency %s' % + (platform, dependency)) + if data_type: + if (data_type == 'cloud_storage_bucket' or + data_type == 'cloud_storage_base_folder'): + return dependency_dict.get(data_type) + return platform_dict.get(data_type) + return platform_dict + + def _ValidateIsConfigUpdatable( + self, execute_job=False, dependency=None, platform=None): + self._ValidateIsConfigWritable() + if self._IsDirty() and execute_job: + raise exceptions.ReadWriteError( + 'A change has already been made to this config. Either call without' + 'using the execute_job option or first call ExecuteUpdateJobs().') + if dependency and not self._config_data.get(dependency): + raise ValueError('Cannot update information because dependency %s does ' + 'not exist.' % dependency) + if platform and not self._GetPlatformData(dependency, platform): + raise ValueError('No dependency info is available for the given ' + 'dependency: %s' % dependency) + + def _ValidateIsConfigWritable(self): + if not self._writable: + raise exceptions.ReadWriteError( + 'Trying to update the information from a read-only config. ' + 'File for config: %s' % self._config_path) + + @staticmethod + def _CloudStorageRemotePath(dependency, cs_hash, cs_base_folder): + cs_remote_file = '%s_%s' % (dependency, cs_hash) + cs_remote_path = cs_remote_file if not cs_base_folder else ( + '%s/%s' % (cs_base_folder, cs_remote_file)) + return cs_remote_path + + @classmethod + def _FormatPath(cls, file_path): + """ Format |file_path| for the current file system. + + We may be downloading files for another platform, so paths must be + downloadable on the current system. + """ + if not file_path: + return file_path + if os.path.sep != '\\': + return file_path.replace('\\', os.path.sep) + elif os.path.sep != '/': + return file_path.replace('/', os.path.sep) + return file_path + + @classmethod + def _WriteConfigToFile(cls, file_path, dependencies=None): + json_dict = cls._GetJsonDict(dependencies) + file_dir = os.path.dirname(file_path) + if not os.path.exists(file_dir): + os.makedirs(file_dir) + with open(file_path, 'w') as outfile: + json.dump( + json_dict, outfile, indent=2, sort_keys=True, separators=(',', ': ')) + return json_dict + + @classmethod + def _GetJsonDict(cls, dependencies=None): + dependencies = dependencies or {} + json_dict = {'config_type': cls.GetConfigType(), + 'dependencies': dependencies} + return json_dict diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config_unittest.py new file mode 100644 index 0000000..0dc775b --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/base_config_unittest.py @@ -0,0 +1,1525 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# pylint: disable=unused-argument + +import os +import unittest + +from py_utils import cloud_storage +import mock +from pyfakefs import fake_filesystem_unittest +from pyfakefs import fake_filesystem +from pyfakefs import fake_filesystem_glob + +import dependency_manager +from dependency_manager import uploader + + +class BaseConfigCreationAndUpdateUnittests(fake_filesystem_unittest.TestCase): + def setUp(self): + self.addTypeEqualityFunc(uploader.CloudStorageUploader, + uploader.CloudStorageUploader.__eq__) + self.setUpPyfakefs() + self.dependencies = { + 'dep1': {'cloud_storage_bucket': 'bucket1', + 'cloud_storage_base_folder': 'dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1'}, + 'plat2': { + 'cloud_storage_hash': 'hash12', + 'download_path': '../../relative/dep1/path2'}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1'}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + + self.expected_file_lines = [ + # pylint: disable=bad-continuation + '{', '"config_type": "BaseConfig",', '"dependencies": {', + '"dep1": {', '"cloud_storage_base_folder": "dependencies_folder",', + '"cloud_storage_bucket": "bucket1",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "hash11",', + '"download_path": "../../relative/dep1/path1"', '},', + '"plat2": {', '"cloud_storage_hash": "hash12",', + '"download_path": "../../relative/dep1/path2"', '}', '}', '},', + '"dep2": {', '"cloud_storage_bucket": "bucket2",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "hash21",', + '"download_path": "../../relative/dep2/path1"', '},', + '"plat2": {', '"cloud_storage_hash": "hash22",', + '"download_path": "../../relative/dep2/path2"', '}', '}', '}', + '}', '}'] + + self.file_path = os.path.abspath(os.path.join( + 'path', 'to', 'config', 'file')) + + self.new_dep_path = 'path/to/new/dep' + self.fs.CreateFile(self.new_dep_path) + self.new_dep_hash = 'A23B56B7F23E798601F' + self.new_dependencies = { + 'dep1': {'cloud_storage_bucket': 'bucket1', + 'cloud_storage_base_folder': 'dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1'}, + 'plat2': { + 'cloud_storage_hash': self.new_dep_hash, + 'download_path': '../../relative/dep1/path2'}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1'}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + self.new_bucket = 'bucket1' + self.new_remote_path = 'dependencies_folder/dep1_%s' % self.new_dep_hash + self.new_pending_upload = uploader.CloudStorageUploader( + self.new_bucket, self.new_remote_path, self.new_dep_path) + self.expected_new_backup_path = '.'.join([self.new_remote_path, 'old']) + self.new_expected_file_lines = [ + # pylint: disable=bad-continuation + '{', '"config_type": "BaseConfig",', '"dependencies": {', + '"dep1": {', '"cloud_storage_base_folder": "dependencies_folder",', + '"cloud_storage_bucket": "bucket1",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "hash11",', + '"download_path": "../../relative/dep1/path1"', '},', + '"plat2": {', '"cloud_storage_hash": "%s",' % self.new_dep_hash, + '"download_path": "../../relative/dep1/path2"', '}', '}', '},', + '"dep2": {', '"cloud_storage_bucket": "bucket2",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "hash21",', + '"download_path": "../../relative/dep2/path1"', '},', + '"plat2": {', '"cloud_storage_hash": "hash22",', + '"download_path": "../../relative/dep2/path2"', '}', '}', '}', + '}', '}'] + + self.final_dep_path = 'path/to/final/dep' + self.fs.CreateFile(self.final_dep_path) + self.final_dep_hash = 'B34662F23B56B7F98601F' + self.final_bucket = 'bucket2' + self.final_remote_path = 'dep1_%s' % self.final_dep_hash + self.final_pending_upload = uploader.CloudStorageUploader( + self.final_bucket, self.final_remote_path, self.final_dep_path) + self.expected_final_backup_path = '.'.join([self.final_remote_path, + 'old']) + self.final_dependencies = { + 'dep1': {'cloud_storage_bucket': 'bucket1', + 'cloud_storage_base_folder': 'dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1'}, + 'plat2': { + 'cloud_storage_hash': self.new_dep_hash, + 'download_path': '../../relative/dep1/path2'}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': self.final_dep_hash, + 'download_path': '../../relative/dep2/path1'}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + self.final_expected_file_lines = [ + # pylint: disable=bad-continuation + '{', '"config_type": "BaseConfig",', '"dependencies": {', + '"dep1": {', '"cloud_storage_base_folder": "dependencies_folder",', + '"cloud_storage_bucket": "bucket1",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "hash11",', + '"download_path": "../../relative/dep1/path1"', '},', + '"plat2": {', '"cloud_storage_hash": "%s",' % self.new_dep_hash, + '"download_path": "../../relative/dep1/path2"', '}', '}', '},', + '"dep2": {', '"cloud_storage_bucket": "bucket2",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "%s",' % self.final_dep_hash, + '"download_path": "../../relative/dep2/path1"', '},', + '"plat2": {', '"cloud_storage_hash": "hash22",', + '"download_path": "../../relative/dep2/path2"', '}', '}', '}', + '}', '}'] + + + def tearDown(self): + self.tearDownPyfakefs() + + # Init is not meant to be overridden, so we should be mocking the + # base_config's json module, even in subclasses. + def testCreateEmptyConfig(self): + expected_file_lines = ['{', + '"config_type": "BaseConfig",', + '"dependencies": {}', + '}'] + config = dependency_manager.BaseConfig(self.file_path, writable=True) + + file_module = fake_filesystem.FakeFileOpen(self.fs) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual({}, config._config_data) + self.assertEqual(self.file_path, config._config_path) + + def testCreateEmptyConfigError(self): + self.assertRaises(dependency_manager.EmptyConfigError, + dependency_manager.BaseConfig, self.file_path) + + def testCloudStorageRemotePath(self): + dependency = 'dep_name' + cs_hash = self.new_dep_hash + cs_base_folder = 'dependency_remote_folder' + expected_remote_path = '%s/%s_%s' % (cs_base_folder, dependency, cs_hash) + remote_path = dependency_manager.BaseConfig._CloudStorageRemotePath( + dependency, cs_hash, cs_base_folder) + self.assertEqual(expected_remote_path, remote_path) + + cs_base_folder = 'dependency_remote_folder' + expected_remote_path = '%s_%s' % (dependency, cs_hash) + remote_path = dependency_manager.BaseConfig._CloudStorageRemotePath( + dependency, cs_hash, cs_base_folder) + + def testGetEmptyJsonDict(self): + expected_json_dict = {'config_type': 'BaseConfig', + 'dependencies': {}} + json_dict = dependency_manager.BaseConfig._GetJsonDict() + self.assertEqual(expected_json_dict, json_dict) + + def testGetNonEmptyJsonDict(self): + expected_json_dict = {"config_type": "BaseConfig", + "dependencies": self.dependencies} + json_dict = dependency_manager.BaseConfig._GetJsonDict(self.dependencies) + self.assertEqual(expected_json_dict, json_dict) + + def testWriteEmptyConfigToFile(self): + expected_file_lines = ['{', '"config_type": "BaseConfig",', + '"dependencies": {}', '}'] + self.assertFalse(os.path.exists(self.file_path)) + dependency_manager.BaseConfig._WriteConfigToFile(self.file_path) + self.assertTrue(os.path.exists(self.file_path)) + file_module = fake_filesystem.FakeFileOpen(self.fs) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + + def testWriteNonEmptyConfigToFile(self): + self.assertFalse(os.path.exists(self.file_path)) + dependency_manager.BaseConfig._WriteConfigToFile(self.file_path, + self.dependencies) + self.assertTrue(os.path.exists(self.file_path)) + expected_file_lines = list(self.expected_file_lines) + file_module = fake_filesystem.FakeFileOpen(self.fs) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsNoOp(self, uploader_cs_mock): + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + + self.assertFalse(config.ExecuteUpdateJobs()) + self.assertFalse(config._IsDirty()) + self.assertFalse(config._pending_uploads) + self.assertEqual(self.dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnInsertNoCSCollision( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = False + uploader_cs_mock.Insert.side_effect = cloud_storage.CloudStorageError + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path)] + expected_copy_calls = [] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnInsertCSCollisionForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = True + uploader_cs_mock.Insert.side_effect = cloud_storage.CloudStorageError + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path)] + expected_copy_calls = [mock.call(self.new_bucket, self.new_bucket, + self.new_remote_path, + self.expected_new_backup_path), + mock.call(self.new_bucket, self.new_bucket, + self.expected_new_backup_path, + self.new_remote_path)] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs, force=True) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnInsertCSCollisionNoForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = True + uploader_cs_mock.Insert.side_effect = cloud_storage.CloudStorageError + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [] + expected_copy_calls = [] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnCopy( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = True + uploader_cs_mock.Copy.side_effect = cloud_storage.CloudStorageError + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [] + expected_copy_calls = [mock.call(self.new_bucket, self.new_bucket, + self.new_remote_path, + self.expected_new_backup_path)] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs, force=True) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnSecondInsertNoCSCollision( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = False + uploader_cs_mock.Insert.side_effect = [ + True, cloud_storage.CloudStorageError] + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path), + mock.call(self.final_bucket, + self.final_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path), + mock.call(self.final_bucket, + self.final_remote_path, + self.final_dep_path)] + expected_copy_calls = [] + expected_delete_calls = [mock.call(self.new_bucket, self.new_remote_path)] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnSecondInsertCSCollisionForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = True + uploader_cs_mock.Insert.side_effect = [ + True, cloud_storage.CloudStorageError] + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path), + mock.call(self.final_bucket, + self.final_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path), + mock.call(self.final_bucket, + self.final_remote_path, + self.final_dep_path)] + expected_copy_calls = [mock.call(self.new_bucket, self.new_bucket, + self.new_remote_path, + self.expected_new_backup_path), + mock.call(self.final_bucket, self.final_bucket, + self.final_remote_path, + self.expected_final_backup_path), + mock.call(self.final_bucket, self.final_bucket, + self.expected_final_backup_path, + self.final_remote_path), + mock.call(self.new_bucket, self.new_bucket, + self.expected_new_backup_path, + self.new_remote_path)] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs, force=True) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnSecondInsertFirstCSCollisionForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.side_effect = [True, False, True] + uploader_cs_mock.Insert.side_effect = [ + True, cloud_storage.CloudStorageError] + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path), + mock.call(self.final_bucket, + self.final_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path), + mock.call(self.final_bucket, + self.final_remote_path, + self.final_dep_path)] + expected_copy_calls = [mock.call(self.new_bucket, self.new_bucket, + self.new_remote_path, + self.expected_new_backup_path), + mock.call(self.new_bucket, self.new_bucket, + self.expected_new_backup_path, + self.new_remote_path)] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs, force=True) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnFirstCSCollisionNoForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.side_effect = [True, False, True] + uploader_cs_mock.Insert.side_effect = [ + True, cloud_storage.CloudStorageError] + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [] + expected_copy_calls = [] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnSecondCopyCSCollision( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = True + uploader_cs_mock.Insert.return_value = True + uploader_cs_mock.Copy.side_effect = [ + True, cloud_storage.CloudStorageError, True] + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path), + mock.call(self.final_bucket, + self.final_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path)] + expected_copy_calls = [mock.call(self.new_bucket, self.new_bucket, + self.new_remote_path, + self.expected_new_backup_path), + mock.call(self.final_bucket, self.final_bucket, + self.final_remote_path, + self.expected_final_backup_path), + mock.call(self.new_bucket, self.new_bucket, + self.expected_new_backup_path, + self.new_remote_path)] + expected_delete_calls = [] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs, force=True) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnSecondCopyNoCSCollisionForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.side_effect = [False, True, False] + uploader_cs_mock.Copy.side_effect = cloud_storage.CloudStorageError + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path), + mock.call(self.final_bucket, + self.final_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path)] + expected_copy_calls = [mock.call(self.final_bucket, self.final_bucket, + self.final_remote_path, + self.expected_final_backup_path)] + expected_delete_calls = [mock.call(self.new_bucket, self.new_remote_path)] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs, force=True) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsFailureOnSecondCopyNoCSCollisionNoForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.side_effect = [False, True, False] + uploader_cs_mock.Copy.side_effect = cloud_storage.CloudStorageError + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path), + mock.call(self.final_bucket, + self.final_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path)] + expected_copy_calls = [] + expected_delete_calls = [mock.call(self.new_bucket, self.new_remote_path)] + + self.assertRaises(cloud_storage.CloudStorageError, + config.ExecuteUpdateJobs) + self.assertTrue(config._is_dirty) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsSuccessOnePendingDepNoCloudStorageCollision( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = False + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._pending_uploads = [self.new_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._IsDirty()) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path)] + expected_copy_calls = [] + expected_delete_calls = [] + + self.assertTrue(config.ExecuteUpdateJobs()) + self.assertFalse(config._IsDirty()) + self.assertFalse(config._pending_uploads) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.new_expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertFalse(config._pending_uploads) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + self.assertEqual(expected_delete_calls, + uploader_cs_mock.Delete.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsSuccessOnePendingDepCloudStorageCollision( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = True + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._pending_uploads = [self.new_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._IsDirty()) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path)] + expected_copy_calls = [mock.call(self.new_bucket, self.new_bucket, + self.new_remote_path, + self.expected_new_backup_path)] + + self.assertTrue(config.ExecuteUpdateJobs(force=True)) + self.assertFalse(config._IsDirty()) + self.assertFalse(config._pending_uploads) + self.assertEqual(self.new_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.new_expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertFalse(config._pending_uploads) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsErrorOnePendingDepCloudStorageCollisionNoForce( + self, uploader_cs_mock): + uploader_cs_mock.Exists.return_value = True + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.new_dependencies.copy() + config._is_dirty = True + config._pending_uploads = [self.new_pending_upload] + self.assertEqual(self.new_dependencies, config._config_data) + self.assertTrue(config._is_dirty) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path)] + expected_insert_calls = [] + expected_copy_calls = [] + + self.assertRaises(dependency_manager.CloudStorageUploadConflictError, + config.ExecuteUpdateJobs) + self.assertTrue(config._is_dirty) + self.assertTrue(config._pending_uploads) + self.assertEqual(self.new_dependencies, config._config_data) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testExecuteUpdateJobsSuccessMultiplePendingDepsOneCloudStorageCollision( + self, uploader_cs_mock): + uploader_cs_mock.Exists.side_effect = [False, True] + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + config._config_data = self.final_dependencies.copy() + config._pending_uploads = [self.new_pending_upload, + self.final_pending_upload] + self.assertEqual(self.final_dependencies, config._config_data) + self.assertTrue(config._IsDirty()) + self.assertEqual(2, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(self.final_pending_upload, config._pending_uploads[1]) + + expected_exists_calls = [mock.call(self.new_bucket, self.new_remote_path), + mock.call(self.final_bucket, + self.final_remote_path)] + expected_insert_calls = [mock.call(self.new_bucket, self.new_remote_path, + self.new_dep_path), + mock.call(self.final_bucket, + self.final_remote_path, + self.final_dep_path)] + expected_copy_calls = [mock.call(self.final_bucket, self.final_bucket, + self.final_remote_path, + self.expected_final_backup_path)] + + self.assertTrue(config.ExecuteUpdateJobs(force=True)) + self.assertFalse(config._IsDirty()) + self.assertFalse(config._pending_uploads) + self.assertEqual(self.final_dependencies, config._config_data) + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.final_expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + self.assertFalse(config._pending_uploads) + self.assertEqual(expected_insert_calls, + uploader_cs_mock.Insert.call_args_list) + self.assertEqual(expected_exists_calls, + uploader_cs_mock.Exists.call_args_list) + self.assertEqual(expected_copy_calls, + uploader_cs_mock.Copy.call_args_list) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testUpdateCloudStorageDependenciesReadOnlyConfig( + self, uploader_cs_mock): + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path) + with self.assertRaises(dependency_manager.ReadWriteError): + config.AddCloudStorageDependencyUpdateJob( + 'dep', 'plat', 'path') + with self.assertRaises(dependency_manager.ReadWriteError): + config.AddCloudStorageDependencyUpdateJob( + 'dep', 'plat', 'path', version='1.2.3') + with self.assertRaises(dependency_manager.ReadWriteError): + config.AddCloudStorageDependencyUpdateJob( + 'dep', 'plat', 'path', execute_job=False) + with self.assertRaises(dependency_manager.ReadWriteError): + config.AddCloudStorageDependencyUpdateJob( + 'dep', 'plat', 'path', version='1.2.3', execute_job=False) + + @mock.patch('dependency_manager.uploader.cloud_storage') + def testUpdateCloudStorageDependenciesMissingDependency( + self, uploader_cs_mock): + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob, + 'dep', 'plat', 'path') + self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob, + 'dep', 'plat', 'path', version='1.2.3') + self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob, + 'dep', 'plat', 'path', execute_job=False) + self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob, + 'dep', 'plat', 'path', version='1.2.3', execute_job=False) + + @mock.patch('dependency_manager.uploader.cloud_storage') + @mock.patch('dependency_manager.base_config.cloud_storage') + def testUpdateCloudStorageDependenciesWrite( + self, base_config_cs_mock, uploader_cs_mock): + expected_dependencies = self.dependencies + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertFalse(config._IsDirty()) + self.assertEqual(expected_dependencies, config._config_data) + + base_config_cs_mock.CalculateHash.return_value = self.new_dep_hash + uploader_cs_mock.Exists.return_value = False + expected_dependencies = self.new_dependencies + config.AddCloudStorageDependencyUpdateJob( + 'dep1', 'plat2', self.new_dep_path, execute_job=True) + self.assertFalse(config._IsDirty()) + self.assertFalse(config._pending_uploads) + self.assertEqual(expected_dependencies, config._config_data) + # check that file contents has been updated + file_module = fake_filesystem.FakeFileOpen(self.fs) + expected_file_lines = list(self.new_expected_file_lines) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + + expected_dependencies = self.final_dependencies + base_config_cs_mock.CalculateHash.return_value = self.final_dep_hash + config.AddCloudStorageDependencyUpdateJob( + 'dep2', 'plat1', self.final_dep_path, execute_job=True) + self.assertFalse(config._IsDirty()) + self.assertFalse(config._pending_uploads) + self.assertEqual(expected_dependencies, config._config_data) + # check that file contents has been updated + expected_file_lines = list(self.final_expected_file_lines) + file_module = fake_filesystem.FakeFileOpen(self.fs) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + + @mock.patch('dependency_manager.uploader.cloud_storage') + @mock.patch('dependency_manager.base_config.cloud_storage') + def testUpdateCloudStorageDependenciesNoWrite( + self, base_config_cs_mock, uploader_cs_mock): + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + config = dependency_manager.BaseConfig(self.file_path, writable=True) + + self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob, + 'dep', 'plat', 'path') + self.assertRaises(ValueError, config.AddCloudStorageDependencyUpdateJob, + 'dep', 'plat', 'path', version='1.2.3') + + expected_dependencies = self.dependencies + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertFalse(config._IsDirty()) + self.assertFalse(config._pending_uploads) + self.assertEqual(expected_dependencies, config._config_data) + + base_config_cs_mock.CalculateHash.return_value = self.new_dep_hash + uploader_cs_mock.Exists.return_value = False + expected_dependencies = self.new_dependencies + config.AddCloudStorageDependencyUpdateJob( + 'dep1', 'plat2', self.new_dep_path, execute_job=False) + self.assertTrue(config._IsDirty()) + self.assertEqual(1, len(config._pending_uploads)) + self.assertEqual(self.new_pending_upload, config._pending_uploads[0]) + self.assertEqual(expected_dependencies, config._config_data) + # check that file contents have not been updated. + expected_file_lines = list(self.expected_file_lines) + file_module = fake_filesystem.FakeFileOpen(self.fs) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + + expected_dependencies = self.final_dependencies + base_config_cs_mock.CalculateHash.return_value = self.final_dep_hash + config.AddCloudStorageDependencyUpdateJob( + 'dep2', 'plat1', self.final_dep_path, execute_job=False) + self.assertTrue(config._IsDirty()) + self.assertEqual(expected_dependencies, config._config_data) + # check that file contents have not been updated. + expected_file_lines = list(self.expected_file_lines) + file_module = fake_filesystem.FakeFileOpen(self.fs) + for line in file_module(self.file_path): + self.assertEqual(expected_file_lines.pop(0), line.strip()) + self.fs.CloseOpenFile(file_module(self.file_path)) + + +class BaseConfigDataManipulationUnittests(fake_filesystem_unittest.TestCase): + def setUp(self): + self.addTypeEqualityFunc(uploader.CloudStorageUploader, + uploader.CloudStorageUploader.__eq__) + self.setUpPyfakefs() + + self.cs_bucket = 'bucket1' + self.cs_base_folder = 'dependencies_folder' + self.cs_hash = 'hash12' + self.download_path = '../../relative/dep1/path2' + self.local_paths = ['../../../relative/local/path21', + '../../../relative/local/path22'] + self.platform_dict = {'cloud_storage_hash': self.cs_hash, + 'download_path': self.download_path, + 'local_paths': self.local_paths} + self.dependencies = { + 'dep1': { + 'cloud_storage_bucket': self.cs_bucket, + 'cloud_storage_base_folder': self.cs_base_folder, + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1', + 'local_paths': ['../../../relative/local/path11', + '../../../relative/local/path12']}, + 'plat2': self.platform_dict + } + }, + 'dep2': { + 'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1', + 'local_paths': ['../../../relative/local/path31', + '../../../relative/local/path32']}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + + self.file_path = os.path.abspath(os.path.join( + 'path', 'to', 'config', 'file')) + + + self.expected_file_lines = [ + # pylint: disable=bad-continuation + '{', '"config_type": "BaseConfig",', '"dependencies": {', + '"dep1": {', '"cloud_storage_base_folder": "dependencies_folder",', + '"cloud_storage_bucket": "bucket1",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "hash11",', + '"download_path": "../../relative/dep1/path1",', + '"local_paths": [', '"../../../relative/local/path11",', + '"../../../relative/local/path12"', ']', '},', + '"plat2": {', '"cloud_storage_hash": "hash12",', + '"download_path": "../../relative/dep1/path2",', + '"local_paths": [', '"../../../relative/local/path21",', + '"../../../relative/local/path22"', ']', + '}', '}', '},', + '"dep2": {', '"cloud_storage_bucket": "bucket2",', '"file_info": {', + '"plat1": {', '"cloud_storage_hash": "hash21",', + '"download_path": "../../relative/dep2/path1",', + '"local_paths": [', '"../../../relative/local/path31",', + '"../../../relative/local/path32"', ']', '},', + '"plat2": {', '"cloud_storage_hash": "hash22",', + '"download_path": "../../relative/dep2/path2"', '}', '}', '}', + '}', '}'] + self.fs.CreateFile(self.file_path, + contents='\n'.join(self.expected_file_lines)) + + + def testSetPlatformDataFailureNotWritable(self): + config = dependency_manager.BaseConfig(self.file_path) + self.assertRaises( + dependency_manager.ReadWriteError, config._SetPlatformData, + 'dep1', 'plat1', 'cloud_storage_bucket', 'new_bucket') + self.assertEqual(self.dependencies, config._config_data) + + def testSetPlatformDataFailure(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertRaises(ValueError, config._SetPlatformData, 'missing_dep', + 'plat2', 'cloud_storage_bucket', 'new_bucket') + self.assertEqual(self.dependencies, config._config_data) + self.assertRaises(ValueError, config._SetPlatformData, 'dep1', + 'missing_plat', 'cloud_storage_bucket', 'new_bucket') + self.assertEqual(self.dependencies, config._config_data) + + + def testSetPlatformDataCloudStorageBucketSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + updated_cs_dependencies = { + 'dep1': {'cloud_storage_bucket': 'new_bucket', + 'cloud_storage_base_folder': 'dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1', + 'local_paths': ['../../../relative/local/path11', + '../../../relative/local/path12']}, + 'plat2': { + 'cloud_storage_hash': 'hash12', + 'download_path': '../../relative/dep1/path2', + 'local_paths': ['../../../relative/local/path21', + '../../../relative/local/path22']}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1', + 'local_paths': ['../../../relative/local/path31', + '../../../relative/local/path32']}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + config._SetPlatformData('dep1', 'plat2', 'cloud_storage_bucket', + 'new_bucket') + self.assertEqual(updated_cs_dependencies, config._config_data) + + def testSetPlatformDataCloudStorageBaseFolderSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + updated_cs_dependencies = { + 'dep1': {'cloud_storage_bucket': 'bucket1', + 'cloud_storage_base_folder': 'new_dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1', + 'local_paths': ['../../../relative/local/path11', + '../../../relative/local/path12']}, + 'plat2': { + 'cloud_storage_hash': 'hash12', + 'download_path': '../../relative/dep1/path2', + 'local_paths': ['../../../relative/local/path21', + '../../../relative/local/path22']}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1', + 'local_paths': ['../../../relative/local/path31', + '../../../relative/local/path32']}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + config._SetPlatformData('dep1', 'plat2', 'cloud_storage_base_folder', + 'new_dependencies_folder') + self.assertEqual(updated_cs_dependencies, config._config_data) + + def testSetPlatformDataHashSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + updated_cs_dependencies = { + 'dep1': {'cloud_storage_bucket': 'bucket1', + 'cloud_storage_base_folder': 'dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1', + 'local_paths': ['../../../relative/local/path11', + '../../../relative/local/path12']}, + 'plat2': { + 'cloud_storage_hash': 'new_hash', + 'download_path': '../../relative/dep1/path2', + 'local_paths': ['../../../relative/local/path21', + '../../../relative/local/path22']}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1', + 'local_paths': ['../../../relative/local/path31', + '../../../relative/local/path32']}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + config._SetPlatformData('dep1', 'plat2', 'cloud_storage_hash', + 'new_hash') + self.assertEqual(updated_cs_dependencies, config._config_data) + + def testSetPlatformDataDownloadPathSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + updated_cs_dependencies = { + 'dep1': {'cloud_storage_bucket': 'bucket1', + 'cloud_storage_base_folder': 'dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1', + 'local_paths': ['../../../relative/local/path11', + '../../../relative/local/path12']}, + 'plat2': { + 'cloud_storage_hash': 'hash12', + 'download_path': '../../new/dep1/path2', + 'local_paths': ['../../../relative/local/path21', + '../../../relative/local/path22']}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1', + 'local_paths': ['../../../relative/local/path31', + '../../../relative/local/path32']}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + config._SetPlatformData('dep1', 'plat2', 'download_path', + '../../new/dep1/path2') + self.assertEqual(updated_cs_dependencies, config._config_data) + + def testSetPlatformDataLocalPathSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + updated_cs_dependencies = { + 'dep1': {'cloud_storage_bucket': 'bucket1', + 'cloud_storage_base_folder': 'dependencies_folder', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash11', + 'download_path': '../../relative/dep1/path1', + 'local_paths': ['../../../relative/local/path11', + '../../../relative/local/path12']}, + 'plat2': { + 'cloud_storage_hash': 'hash12', + 'download_path': '../../relative/dep1/path2', + 'local_paths': ['../../new/relative/local/path21', + '../../new/relative/local/path22']}}}, + 'dep2': {'cloud_storage_bucket': 'bucket2', + 'file_info': { + 'plat1': { + 'cloud_storage_hash': 'hash21', + 'download_path': '../../relative/dep2/path1', + 'local_paths': ['../../../relative/local/path31', + '../../../relative/local/path32']}, + 'plat2': { + 'cloud_storage_hash': 'hash22', + 'download_path': '../../relative/dep2/path2'}}}} + config._SetPlatformData('dep1', 'plat2', 'local_paths', + ['../../new/relative/local/path21', + '../../new/relative/local/path22']) + self.assertEqual(updated_cs_dependencies, config._config_data) + + def testGetPlatformDataFailure(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertRaises(ValueError, config._GetPlatformData, 'missing_dep', + 'plat2', 'cloud_storage_bucket') + self.assertEqual(self.dependencies, config._config_data) + self.assertRaises(ValueError, config._GetPlatformData, 'dep1', + 'missing_plat', 'cloud_storage_bucket') + self.assertEqual(self.dependencies, config._config_data) + + def testGetPlatformDataDictSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertEqual(self.platform_dict, + config._GetPlatformData('dep1', 'plat2')) + self.assertEqual(self.dependencies, config._config_data) + + def testGetPlatformDataCloudStorageBucketSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertEqual(self.cs_bucket, config._GetPlatformData( + 'dep1', 'plat2', 'cloud_storage_bucket')) + self.assertEqual(self.dependencies, config._config_data) + + def testGetPlatformDataCloudStorageBaseFolderSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertEqual(self.cs_base_folder, config._GetPlatformData( + 'dep1', 'plat2', 'cloud_storage_base_folder')) + self.assertEqual(self.dependencies, config._config_data) + + def testGetPlatformDataHashSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertEqual(self.cs_hash, config._GetPlatformData( + 'dep1', 'plat2', 'cloud_storage_hash')) + self.assertEqual(self.dependencies, config._config_data) + + def testGetPlatformDataDownloadPathSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertEqual(self.download_path, config._GetPlatformData( + 'dep1', 'plat2', 'download_path')) + self.assertEqual(self.dependencies, config._config_data) + + def testGetPlatformDataLocalPathSuccess(self): + config = dependency_manager.BaseConfig(self.file_path, writable=True) + self.assertEqual(self.local_paths, config._GetPlatformData( + 'dep1', 'plat2', 'local_paths')) + self.assertEqual(self.dependencies, config._config_data) + +class BaseConfigTest(unittest.TestCase): + """ Subclassable unittests for BaseConfig. + For subclasses: override setUp, GetConfigDataFromDict, + and EndToEndExpectedConfigData as needed. + + setUp must set the following properties: + self.config_type: String returnedd from GetConfigType in config subclass. + self.config_class: the class for the config subclass. + self.config_module: importable module for the config subclass. + self.empty_dict: expected dictionary for an empty config, as it would be + stored in a json file. + self.one_dep_dict: example dictionary for a config with one dependency, + as it would be stored in a json file. + """ + def setUp(self): + self.config_type = 'BaseConfig' + self.config_class = dependency_manager.BaseConfig + self.config_module = 'dependency_manager.base_config' + + self.empty_dict = {'config_type': self.config_type, + 'dependencies': {}} + + dependency_dict = { + 'dep': { + 'cloud_storage_base_folder': 'cs_base_folder1', + 'cloud_storage_bucket': 'bucket1', + 'file_info': { + 'plat1_arch1': { + 'cloud_storage_hash': 'hash111', + 'download_path': 'download_path111', + 'cs_remote_path': 'cs_path111', + 'version_in_cs': 'version_111', + 'local_paths': ['local_path1110', 'local_path1111'] + }, + 'plat1_arch2': { + 'cloud_storage_hash': 'hash112', + 'download_path': 'download_path112', + 'cs_remote_path': 'cs_path112', + 'local_paths': ['local_path1120', 'local_path1121'] + }, + 'win_arch1': { + 'cloud_storage_hash': 'hash1w1', + 'download_path': 'download\\path\\1w1', + 'cs_remote_path': 'cs_path1w1', + 'local_paths': ['local\\path\\1w10', 'local\\path\\1w11'] + }, + 'all_the_variables': { + 'cloud_storage_hash': 'hash111', + 'download_path': 'download_path111', + 'cs_remote_path': 'cs_path111', + 'version_in_cs': 'version_111', + 'path_within_archive': 'path/within/archive', + 'local_paths': ['local_path1110', 'local_path1111'] + } + } + } + } + self.one_dep_dict = {'config_type': self.config_type, + 'dependencies': dependency_dict} + + def GetConfigDataFromDict(self, config_dict): + return config_dict.get('dependencies', {}) + + @mock.patch('os.path') + @mock.patch('__builtin__.open') + def testInitBaseProperties(self, open_mock, path_mock): + # Init is not meant to be overridden, so we should be mocking the + # base_config's json module, even in subclasses. + json_module = 'dependency_manager.base_config.json' + with mock.patch(json_module) as json_mock: + json_mock.load.return_value = self.empty_dict.copy() + config = self.config_class('file_path') + self.assertEqual('file_path', config._config_path) + self.assertEqual(self.config_type, config.GetConfigType()) + self.assertEqual(self.GetConfigDataFromDict(self.empty_dict), + config._config_data) + + + @mock.patch('dependency_manager.dependency_info.DependencyInfo') + @mock.patch('os.path') + @mock.patch('__builtin__.open') + def testInitWithDependencies(self, open_mock, path_mock, dep_info_mock): + # Init is not meant to be overridden, so we should be mocking the + # base_config's json module, even in subclasses. + json_module = 'dependency_manager.base_config.json' + with mock.patch(json_module) as json_mock: + json_mock.load.return_value = self.one_dep_dict + config = self.config_class('file_path') + self.assertEqual('file_path', config._config_path) + self.assertEqual(self.config_type, config.GetConfigType()) + self.assertEqual(self.GetConfigDataFromDict(self.one_dep_dict), + config._config_data) + + def testFormatPath(self): + self.assertEqual(None, self.config_class._FormatPath(None)) + self.assertEqual('', self.config_class._FormatPath('')) + self.assertEqual('some_string', + self.config_class._FormatPath('some_string')) + + expected_path = os.path.join('some', 'file', 'path') + self.assertEqual(expected_path, + self.config_class._FormatPath('some/file/path')) + self.assertEqual(expected_path, + self.config_class._FormatPath('some\\file\\path')) + + @mock.patch('dependency_manager.base_config.json') + @mock.patch('dependency_manager.dependency_info.DependencyInfo') + @mock.patch('os.path.exists') + @mock.patch('__builtin__.open') + def testIterDependenciesError( + self, open_mock, exists_mock, dep_info_mock, json_mock): + # Init is not meant to be overridden, so we should be mocking the + # base_config's json module, even in subclasses. + json_mock.load.return_value = self.one_dep_dict + config = self.config_class('file_path', writable=True) + self.assertEqual(self.GetConfigDataFromDict(self.one_dep_dict), + config._config_data) + self.assertTrue(config._writable) + with self.assertRaises(dependency_manager.ReadWriteError): + for _ in config.IterDependencyInfo(): + pass + + @mock.patch('dependency_manager.base_config.json') + @mock.patch('dependency_manager.dependency_info.DependencyInfo') + @mock.patch('os.path.exists') + @mock.patch('__builtin__.open') + def testIterDependencies( + self, open_mock, exists_mock, dep_info_mock, json_mock): + json_mock.load.return_value = self.one_dep_dict + config = self.config_class('file_path') + self.assertEqual(self.GetConfigDataFromDict(self.one_dep_dict), + config._config_data) + expected_dep_info = ['dep_info0', 'dep_info1', 'dep_info2'] + dep_info_mock.side_effect = expected_dep_info + expected_calls = [ + mock.call('dep', 'plat1_arch1', 'file_path', cs_bucket='bucket1', + cs_hash='hash111', download_path='download_path111', + cs_remote_path='cs_path111', + local_paths=['local_path1110', 'local_path1111']), + mock.call('dep', 'plat1_arch1', 'file_path', cs_bucket='bucket1', + cs_hash='hash112', download_path='download_path112', + cs_remote_path='cs_path112', + local_paths=['local_path1120', 'local_path1121']), + mock.call('dep', 'win_arch1', 'file_path', cs_bucket='bucket1', + cs_hash='hash1w1', + download_path=os.path.join('download', 'path', '1w1'), + cs_remote_path='cs_path1w1', + local_paths=[os.path.join('download', 'path', '1w10'), + os.path.join('download', 'path', '1w11')])] + deps_seen = [] + for dep_info in config.IterDependencyInfo(): + deps_seen.append(dep_info) + dep_info_mock.assert_call_args(expected_calls) + self.assertItemsEqual(expected_dep_info, deps_seen) + + @mock.patch('dependency_manager.base_config.json') + @mock.patch('os.path.exists') + @mock.patch('__builtin__.open') + def testIterDependenciesStaleGlob(self, open_mock, exists_mock, json_mock): + json_mock.load.return_value = self.one_dep_dict + config = self.config_class('file_path') + + abspath = os.path.abspath + should_match = set(map(abspath, [ + 'dep_all_the_variables_0123456789abcdef0123456789abcdef01234567', + 'dep_all_the_variables_123456789abcdef0123456789abcdef012345678'])) + # Not testing case changes, because Windows is case-insensitive. + should_not_match = set(map(abspath, [ + # A configuration that doesn't unzip shouldn't clear any stale unzips. + 'dep_plat1_arch1_0123456789abcdef0123456789abcdef01234567', + # "Hash" component less than 40 characters (not a valid SHA1 hash). + 'dep_all_the_variables_0123456789abcdef0123456789abcdef0123456', + # "Hash" component greater than 40 characters (not a valid SHA1 hash). + 'dep_all_the_variables_0123456789abcdef0123456789abcdef012345678', + # "Hash" component not comprised of hex (not a valid SHA1 hash). + 'dep_all_the_variables_0123456789gggggg0123456789gggggg01234567'])) + + # Create a fake filesystem just for glob to use + fake_fs = fake_filesystem.FakeFilesystem() + fake_glob = fake_filesystem_glob.FakeGlobModule(fake_fs) + for stale_dir in set.union(should_match, should_not_match): + fake_fs.CreateDirectory(stale_dir) + fake_fs.CreateFile(os.path.join(stale_dir, 'some_file')) + + for dep_info in config.IterDependencyInfo(): + if dep_info.platform == 'all_the_variables': + cs_info = dep_info.cloud_storage_info + actual_glob = cs_info._archive_info._stale_unzip_path_glob + actual_matches = set(fake_glob.glob(actual_glob)) + self.assertItemsEqual(should_match, actual_matches) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info.py new file mode 100644 index 0000000..376c311 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info.py @@ -0,0 +1,110 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import errno +import os +import stat + +from py_utils import cloud_storage + +from dependency_manager import exceptions + +class CloudStorageInfo(object): + def __init__(self, cs_bucket, cs_hash, download_path, cs_remote_path, + version_in_cs=None, archive_info=None): + """ Container for the information needed to download a dependency from + cloud storage. + + Args: + cs_bucket: The cloud storage bucket the dependency is located in. + cs_hash: The hash of the file stored in cloud storage. + download_path: Where the file should be downloaded to. + cs_remote_path: Where the file is stored in the cloud storage bucket. + version_in_cs: The version of the file stored in cloud storage. + archive_info: An instance of ArchiveInfo if this dependency is an + archive. Else None. + """ + self._download_path = download_path + self._cs_remote_path = cs_remote_path + self._cs_bucket = cs_bucket + self._cs_hash = cs_hash + self._version_in_cs = version_in_cs + self._archive_info = archive_info + if not self._has_minimum_data: + raise ValueError( + 'Not enough information specified to initialize a cloud storage info.' + ' %s' % self) + + def DependencyExistsInCloudStorage(self): + return cloud_storage.Exists(self._cs_bucket, self._cs_remote_path) + + def GetRemotePath(self): + """Gets the path to a downloaded version of the dependency. + + May not download the file if it has already been downloaded. + Will unzip the downloaded file if a non-empty archive_info was passed in at + init. + + Returns: A path to an executable that was stored in cloud_storage, or None + if not found. + + Raises: + CredentialsError: If cloud_storage credentials aren't configured. + PermissionError: If cloud_storage credentials are configured, but not + with an account that has permission to download the needed file. + NotFoundError: If the needed file does not exist where expected in + cloud_storage or the downloaded zip file. + ServerError: If an internal server error is hit while downloading the + needed file. + CloudStorageError: If another error occured while downloading the remote + path. + FileNotFoundError: If the download was otherwise unsuccessful. + """ + if not self._has_minimum_data: + return None + + download_dir = os.path.dirname(self._download_path) + if not os.path.exists(download_dir): + try: + os.makedirs(download_dir) + except OSError as e: + # The logic above is racy, and os.makedirs will raise an OSError if + # the directory exists. + if e.errno != errno.EEXIST: + raise + + dependency_path = self._download_path + cloud_storage.GetIfHashChanged( + self._cs_remote_path, self._download_path, self._cs_bucket, + self._cs_hash) + if not os.path.exists(dependency_path): + raise exceptions.FileNotFoundError(dependency_path) + + if self.has_archive_info: + dependency_path = self._archive_info.GetUnzippedPath() + else: + mode = os.stat(dependency_path).st_mode + os.chmod(dependency_path, mode | stat.S_IXUSR) + return os.path.abspath(dependency_path) + + @property + def version_in_cs(self): + return self._version_in_cs + + @property + def _has_minimum_data(self): + return all([self._cs_bucket, self._cs_remote_path, self._download_path, + self._cs_hash]) + + + @property + def has_archive_info(self): + return bool(self._archive_info) + + def __repr__(self): + return ( + 'CloudStorageInfo(download_path=%s, cs_remote_path=%s, cs_bucket=%s, ' + 'cs_hash=%s, version_in_cs=%s, archive_info=%s)' % ( + self._download_path, self._cs_remote_path, self._cs_bucket, + self._cs_hash, self._version_in_cs, self._archive_info)) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info_unittest.py new file mode 100644 index 0000000..699cd50 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/cloud_storage_info_unittest.py @@ -0,0 +1,233 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import stat +import unittest + +import mock +from pyfakefs import fake_filesystem_unittest +from py_utils import cloud_storage + +from dependency_manager import archive_info +from dependency_manager import cloud_storage_info +from dependency_manager import exceptions + +class CloudStorageInfoTest(unittest.TestCase): + def testInitCloudStorageInfoErrors(self): + # Must specify cloud storage information atomically. + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + None, None, None, None) + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + 'cs_bucket', None, None, None) + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + None, 'cs_hash', None, None) + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + None, None, 'download_path', None) + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + None, None, None, 'cs_remote_path') + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + None, 'cs_hash', 'download_path', 'cs_remote_path') + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + 'cs_bucket', None, 'download_path', 'cs_remote_path') + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + 'cs_bucket', 'cs_hash', None, 'cs_remote_path') + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + 'cs_bucket', 'cs_hash', 'download_path', None) + + def testInitWithVersion(self): + self.assertRaises( + ValueError, cloud_storage_info.CloudStorageInfo, None, None, None, + 'cs_remote_path', version_in_cs='version_in_cs') + self.assertRaises( + ValueError, cloud_storage_info.CloudStorageInfo, None, 'cs_hash', + 'download_path', 'cs_remote_path', version_in_cs='version_in_cs') + + cs_info = cloud_storage_info.CloudStorageInfo( + 'cs_bucket', 'cs_hash', 'download_path', 'cs_remote_path', + version_in_cs='version_in_cs') + self.assertEqual('cs_hash', cs_info._cs_hash) + self.assertEqual('cs_bucket', cs_info._cs_bucket) + self.assertEqual('cs_remote_path', cs_info._cs_remote_path) + self.assertEqual('download_path', cs_info._download_path) + self.assertEqual('version_in_cs', cs_info._version_in_cs) + + def testInitWithArchiveInfoErrors(self): + zip_info = archive_info.ArchiveInfo( + 'download_path', 'unzip_location', 'path_within_archive') + self.assertRaises( + ValueError, cloud_storage_info.CloudStorageInfo, None, None, None, None, + archive_info=zip_info) + self.assertRaises( + ValueError, cloud_storage_info.CloudStorageInfo, None, None, None, + 'cs_remote_path', archive_info=zip_info) + self.assertRaises( + ValueError, cloud_storage_info.CloudStorageInfo, 'cs_bucket', 'cs_hash', + None, 'cs_remote_path', archive_info=zip_info) + self.assertRaises(ValueError, cloud_storage_info.CloudStorageInfo, + 'cs_bucket', 'cs_hash', + 'cs_remote_path', None, version_in_cs='version', + archive_info=zip_info) + + + def testInitWithArchiveInfo(self): + zip_info = archive_info.ArchiveInfo( + 'download_path', 'unzip_location', 'path_within_archive') + cs_info = cloud_storage_info.CloudStorageInfo( + 'cs_bucket', 'cs_hash', 'download_path', 'cs_remote_path', + archive_info=zip_info) + self.assertEqual('cs_hash', cs_info._cs_hash) + self.assertEqual('cs_bucket', cs_info._cs_bucket) + self.assertEqual('cs_remote_path', cs_info._cs_remote_path) + self.assertEqual('download_path', cs_info._download_path) + self.assertEqual(zip_info, cs_info._archive_info) + self.assertFalse(cs_info._version_in_cs) + + def testInitWithVersionAndArchiveInfo(self): + zip_info = archive_info.ArchiveInfo( + 'download_path', 'unzip_location', 'path_within_archive') + cs_info = cloud_storage_info.CloudStorageInfo( + 'cs_bucket', 'cs_hash', 'download_path', + 'cs_remote_path', version_in_cs='version_in_cs', + archive_info=zip_info) + self.assertEqual('cs_hash', cs_info._cs_hash) + self.assertEqual('cs_bucket', cs_info._cs_bucket) + self.assertEqual('cs_remote_path', cs_info._cs_remote_path) + self.assertEqual('download_path', cs_info._download_path) + self.assertEqual(zip_info, cs_info._archive_info) + self.assertEqual('version_in_cs', cs_info._version_in_cs) + + def testInitMinimumCloudStorageInfo(self): + cs_info = cloud_storage_info.CloudStorageInfo( + 'cs_bucket', + 'cs_hash', 'download_path', + 'cs_remote_path') + self.assertEqual('cs_hash', cs_info._cs_hash) + self.assertEqual('cs_bucket', cs_info._cs_bucket) + self.assertEqual('cs_remote_path', cs_info._cs_remote_path) + self.assertEqual('download_path', cs_info._download_path) + self.assertFalse(cs_info._version_in_cs) + self.assertFalse(cs_info._archive_info) + + +class TestGetRemotePath(fake_filesystem_unittest.TestCase): + def setUp(self): + self.setUpPyfakefs() + self.config_path = '/test/dep_config.json' + self.fs.CreateFile(self.config_path, contents='{}') + self.download_path = '/foo/download_path' + self.fs.CreateFile( + self.download_path, contents='1010110', st_mode=stat.S_IWOTH) + self.cs_info = cloud_storage_info.CloudStorageInfo( + 'cs_bucket', 'cs_hash', self.download_path, 'cs_remote_path', + version_in_cs='1.2.3.4',) + + def tearDown(self): + self.tearDownPyfakefs() + + @mock.patch( + 'py_utils.cloud_storage.GetIfHashChanged') + def testGetRemotePathNoArchive(self, cs_get_mock): + def _GetIfHashChangedMock(cs_path, download_path, bucket, file_hash): + del cs_path, bucket, file_hash + if not os.path.exists(download_path): + self.fs.CreateFile(download_path, contents='1010001010101010110101') + cs_get_mock.side_effect = _GetIfHashChangedMock + # All of the needed information is given, and the downloaded path exists + # after calling cloud storage. + self.assertEqual( + os.path.abspath(self.download_path), + self.cs_info.GetRemotePath()) + self.assertTrue(os.stat(self.download_path).st_mode & stat.S_IXUSR) + + # All of the needed information is given, but the downloaded path doesn't + # exists after calling cloud storage. + self.fs.RemoveObject(self.download_path) + cs_get_mock.side_effect = [True] + self.assertRaises( + exceptions.FileNotFoundError, self.cs_info.GetRemotePath) + + @mock.patch( + 'dependency_manager.dependency_manager_util.UnzipArchive') + @mock.patch( + 'dependency_manager.cloud_storage_info.cloud_storage.GetIfHashChanged') # pylint: disable=line-too-long + def testGetRemotePathWithArchive(self, cs_get_mock, unzip_mock): + def _GetIfHashChangedMock(cs_path, download_path, bucket, file_hash): + del cs_path, bucket, file_hash + if not os.path.exists(download_path): + self.fs.CreateFile(download_path, contents='1010001010101010110101') + cs_get_mock.side_effect = _GetIfHashChangedMock + + unzip_path = os.path.join( + os.path.dirname(self.download_path), 'unzip_dir') + path_within_archive = os.path.join('path', 'within', 'archive') + dep_path = os.path.join(unzip_path, path_within_archive) + def _UnzipFileMock(archive_file, unzip_location, tmp_location=None): + del archive_file, tmp_location + self.fs.CreateFile(dep_path) + self.fs.CreateFile(os.path.join(unzip_location, 'extra', 'path')) + self.fs.CreateFile(os.path.join(unzip_location, 'another_extra_path')) + unzip_mock.side_effect = _UnzipFileMock + + # Create a stale directory that's expected to get deleted + stale_unzip_path_glob = os.path.join( + os.path.dirname(self.download_path), 'unzip_dir_*') + stale_path = os.path.join( + os.path.dirname(self.download_path), 'unzip_dir_stale') + self.fs.CreateDirectory(stale_path) + self.fs.CreateFile(os.path.join(stale_path, 'some_file')) + + self.assertFalse(os.path.exists(dep_path)) + zip_info = archive_info.ArchiveInfo( + self.download_path, unzip_path, path_within_archive, + stale_unzip_path_glob) + self.cs_info = cloud_storage_info.CloudStorageInfo( + 'cs_bucket', 'cs_hash', self.download_path, 'cs_remote_path', + version_in_cs='1.2.3.4', archive_info=zip_info) + + self.assertFalse(unzip_mock.called) + self.assertEqual( + os.path.abspath(dep_path), + self.cs_info.GetRemotePath()) + self.assertTrue(os.path.exists(dep_path)) + self.assertTrue(stat.S_IMODE(os.stat(os.path.abspath(dep_path)).st_mode) & + (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)) + unzip_mock.assert_called_once_with(self.download_path, unzip_path) + + # Stale directory should have been deleted + self.assertFalse(os.path.exists(stale_path)) + + # Should not need to unzip a second time, but should return the same path. + unzip_mock.reset_mock() + self.assertTrue(os.path.exists(dep_path)) + self.assertEqual( + os.path.abspath(dep_path), + self.cs_info.GetRemotePath()) + self.assertTrue(stat.S_IMODE(os.stat(os.path.abspath(dep_path)).st_mode) & + (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)) + self.assertFalse(unzip_mock.called) + + + @mock.patch( + 'py_utils.cloud_storage.GetIfHashChanged') + def testGetRemotePathCloudStorageErrors(self, cs_get_mock): + cs_get_mock.side_effect = cloud_storage.CloudStorageError + self.assertRaises(cloud_storage.CloudStorageError, + self.cs_info.GetRemotePath) + + cs_get_mock.side_effect = cloud_storage.ServerError + self.assertRaises(cloud_storage.ServerError, + self.cs_info.GetRemotePath) + + cs_get_mock.side_effect = cloud_storage.NotFoundError + self.assertRaises(cloud_storage.NotFoundError, + self.cs_info.GetRemotePath) + + cs_get_mock.side_effect = cloud_storage.PermissionError + self.assertRaises(cloud_storage.PermissionError, + self.cs_info.GetRemotePath) + + cs_get_mock.side_effect = cloud_storage.CredentialsError + self.assertRaises(cloud_storage.CredentialsError, + self.cs_info.GetRemotePath) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info.py new file mode 100644 index 0000000..942d57e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info.py @@ -0,0 +1,128 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +class DependencyInfo(object): + def __init__(self, dependency, platform, config_path, local_path_info=None, + cloud_storage_info=None): + """ Container for the information needed for each dependency/platform pair + in the dependency_manager. + + Args: + Required: + dependency: Name of the dependency. + platform: Name of the platform to be run on. + config_path: Path to the config_path this information came from. Used + for error messages to improve debugging. + + Optional: + local_paths: A list of paths to search in order for a local file. + cloud_storage_info: An instance of CloudStorageInfo. + """ + # TODO(aiolos): update the above doc string for A) the usage of zip files + # and B) supporting lists of local_paths to be checked for most recently + # changed files. + if not dependency or not platform: + raise ValueError( + 'Must supply both a dependency and platform to DependencyInfo') + + self._dependency = dependency + self._platform = platform + self._config_paths = [config_path] + self._local_path_info = local_path_info + self._cloud_storage_info = cloud_storage_info + + def Update(self, new_dep_info): + """Add the information from |new_dep_info| to this instance. + """ + self._config_paths.extend(new_dep_info.config_paths) + if (self.dependency != new_dep_info.dependency or + self.platform != new_dep_info.platform): + raise ValueError( + 'Cannot update DependencyInfo with different dependency or platform.' + 'Existing dep: %s, existing platform: %s. New dep: %s, new platform:' + '%s. Config_paths conflicting: %s' % ( + self.dependency, self.platform, new_dep_info.dependency, + new_dep_info.platform, self.config_paths)) + if new_dep_info.has_cloud_storage_info: + if self.has_cloud_storage_info: + raise ValueError( + 'Overriding cloud storage data is not allowed when updating a ' + 'DependencyInfo. Conflict in dependency %s on platform %s in ' + 'config_paths: %s.' % (self.dependency, self.platform, + self.config_paths)) + else: + self._cloud_storage_info = new_dep_info._cloud_storage_info + if not self._local_path_info: + self._local_path_info = new_dep_info._local_path_info + else: + self._local_path_info.Update(new_dep_info._local_path_info) + + def GetRemotePath(self): + """Gets the path to a downloaded version of the dependency. + + May not download the file if it has already been downloaded. + Will unzip the downloaded file if specified in the config + via unzipped_hash. + + Returns: A path to an executable that was stored in cloud_storage, or None + if not found. + + Raises: + CredentialsError: If cloud_storage credentials aren't configured. + PermissionError: If cloud_storage credentials are configured, but not + with an account that has permission to download the needed file. + NotFoundError: If the needed file does not exist where expected in + cloud_storage or the downloaded zip file. + ServerError: If an internal server error is hit while downloading the + needed file. + CloudStorageError: If another error occured while downloading the remote + path. + FileNotFoundError: If the download was otherwise unsuccessful. + """ + if self.has_cloud_storage_info: + return self._cloud_storage_info.GetRemotePath() + return None + + def GetRemotePathVersion(self): + if self.has_cloud_storage_info: + return self._cloud_storage_info.version_in_cs + return None + + def GetLocalPath(self): + """Gets the path to a local version of the dependency. + + Returns: A path to a local dependency, or None if not found. + + """ + if self.has_local_path_info: + return self._local_path_info.GetLocalPath() + return None + + @property + def dependency(self): + return self._dependency + + @property + def platform(self): + return self._platform + + @property + def config_paths(self): + return self._config_paths + + @property + def local_path_info(self): + return self._local_path_info + + @property + def has_cloud_storage_info(self): + return bool(self._cloud_storage_info) + + @property + def has_local_path_info(self): + return bool(self._local_path_info) + + @property + def cloud_storage_info(self): + return self._cloud_storage_info diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info_unittest.py new file mode 100644 index 0000000..6117cd3 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_info_unittest.py @@ -0,0 +1,234 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +import dependency_manager + +class DependencyInfoTest(unittest.TestCase): + def testInitRequiredInfo(self): + # Must have a dependency, platform and file_path. + self.assertRaises(ValueError, dependency_manager.DependencyInfo, + None, None, None) + self.assertRaises(ValueError, dependency_manager.DependencyInfo, + 'dep', None, None) + self.assertRaises(ValueError, dependency_manager.DependencyInfo, + None, 'plat', None) + self.assertRaises(ValueError, dependency_manager.DependencyInfo, + None, None, 'config_path') + # Empty DependencyInfo. + empty_di = dependency_manager.DependencyInfo('dep', 'plat', 'config_path') + self.assertEqual('dep', empty_di.dependency) + self.assertEqual('plat', empty_di.platform) + self.assertEqual(['config_path'], empty_di.config_paths) + self.assertFalse(empty_di.has_local_path_info) + self.assertFalse(empty_di.has_cloud_storage_info) + + def testInitLocalPaths(self): + local_path_info = dependency_manager.LocalPathInfo(['path0', 'path1']) + dep_info = dependency_manager.DependencyInfo( + 'dep', 'platform', 'config_path', local_path_info + ) + self.assertEqual('dep', dep_info.dependency) + self.assertEqual('platform', dep_info.platform) + self.assertEqual(['config_path'], dep_info.config_paths) + self.assertEqual(local_path_info, dep_info._local_path_info) + self.assertFalse(dep_info.has_cloud_storage_info) + + def testInitCloudStorageInfo(self): + cs_info = dependency_manager.CloudStorageInfo( + 'cs_bucket', 'cs_hash', 'dowload_path', 'cs_remote_path') + dep_info = dependency_manager.DependencyInfo( + 'dep', 'platform', 'config_path', cloud_storage_info=cs_info) + self.assertEqual('dep', dep_info.dependency) + self.assertEqual('platform', dep_info.platform) + self.assertEqual(['config_path'], dep_info.config_paths) + self.assertFalse(dep_info.has_local_path_info) + self.assertTrue(dep_info.has_cloud_storage_info) + self.assertEqual(cs_info, dep_info._cloud_storage_info) + + def testInitAllInfo(self): + cs_info = dependency_manager.CloudStorageInfo( + 'cs_bucket', 'cs_hash', 'dowload_path', 'cs_remote_path') + dep_info = dependency_manager.DependencyInfo( + 'dep', 'platform', 'config_path', cloud_storage_info=cs_info) + self.assertEqual('dep', dep_info.dependency) + self.assertEqual('platform', dep_info.platform) + self.assertEqual(['config_path'], dep_info.config_paths) + self.assertFalse(dep_info.has_local_path_info) + self.assertTrue(dep_info.has_cloud_storage_info) + + + def testUpdateRequiredArgsConflicts(self): + lp_info = dependency_manager.LocalPathInfo(['path0', 'path2']) + dep_info1 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path1', local_path_info=lp_info) + dep_info2 = dependency_manager.DependencyInfo( + 'dep1', 'platform2', 'config_path2', local_path_info=lp_info) + dep_info3 = dependency_manager.DependencyInfo( + 'dep2', 'platform1', 'config_path3', local_path_info=lp_info) + self.assertRaises(ValueError, dep_info1.Update, dep_info2) + self.assertRaises(ValueError, dep_info1.Update, dep_info3) + self.assertRaises(ValueError, dep_info3.Update, dep_info2) + + def testUpdateMinimumCloudStorageInfo(self): + dep_info1 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path1') + + cs_info2 = dependency_manager.CloudStorageInfo( + cs_bucket='cs_bucket2', cs_hash='cs_hash2', + download_path='download_path2', cs_remote_path='cs_remote_path2') + dep_info2 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path2', cloud_storage_info=cs_info2) + + dep_info3 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path3') + + cs_info4 = dependency_manager.CloudStorageInfo( + cs_bucket='cs_bucket4', cs_hash='cs_hash4', + download_path='download_path4', cs_remote_path='cs_remote_path4') + dep_info4 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path4', cloud_storage_info=cs_info4) + + self.assertEqual('dep1', dep_info1.dependency) + self.assertEqual('platform1', dep_info1.platform) + self.assertEqual(['config_path1'], dep_info1.config_paths) + + dep_info1.Update(dep_info2) + self.assertFalse(dep_info1.has_local_path_info) + self.assertEqual('dep1', dep_info1.dependency) + self.assertEqual('platform1', dep_info1.platform) + self.assertEqual(['config_path1', 'config_path2'], dep_info1.config_paths) + + cs_info = dep_info1._cloud_storage_info + self.assertEqual(cs_info, cs_info2) + self.assertEqual('cs_bucket2', cs_info._cs_bucket) + self.assertEqual('cs_hash2', cs_info._cs_hash) + self.assertEqual('download_path2', cs_info._download_path) + self.assertEqual('cs_remote_path2', cs_info._cs_remote_path) + + dep_info1.Update(dep_info3) + self.assertEqual('dep1', dep_info1.dependency) + self.assertEqual('platform1', dep_info1.platform) + self.assertEqual(['config_path1', 'config_path2', 'config_path3'], + dep_info1.config_paths) + self.assertFalse(dep_info1.has_local_path_info) + cs_info = dep_info1._cloud_storage_info + self.assertEqual(cs_info, cs_info2) + self.assertEqual('cs_bucket2', cs_info._cs_bucket) + self.assertEqual('cs_hash2', cs_info._cs_hash) + self.assertEqual('download_path2', cs_info._download_path) + self.assertEqual('cs_remote_path2', cs_info._cs_remote_path) + + self.assertRaises(ValueError, dep_info1.Update, dep_info4) + + def testUpdateMaxCloudStorageInfo(self): + dep_info1 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path1') + + zip_info2 = dependency_manager.ArchiveInfo( + 'archive_path2', 'unzip_path2', 'path_withing_archive2') + cs_info2 = dependency_manager.CloudStorageInfo( + 'cs_bucket2', 'cs_hash2', 'download_path2', 'cs_remote_path2', + version_in_cs='2.1.1', archive_info=zip_info2) + dep_info2 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path2', cloud_storage_info=cs_info2) + + dep_info3 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path3') + + zip_info4 = dependency_manager.ArchiveInfo( + 'archive_path4', 'unzip_path4', 'path_withing_archive4') + cs_info4 = dependency_manager.CloudStorageInfo( + 'cs_bucket4', 'cs_hash4', 'download_path4', 'cs_remote_path4', + version_in_cs='4.2.1', archive_info=zip_info4) + dep_info4 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path4', cloud_storage_info=cs_info4) + + self.assertEqual('dep1', dep_info1.dependency) + self.assertEqual('platform1', dep_info1.platform) + self.assertEqual(['config_path1'], dep_info1.config_paths) + + dep_info1.Update(dep_info2) + self.assertFalse(dep_info1.has_local_path_info) + self.assertEqual('dep1', dep_info1.dependency) + self.assertEqual('platform1', dep_info1.platform) + self.assertEqual(['config_path1', 'config_path2'], dep_info1.config_paths) + + cs_info = dep_info1._cloud_storage_info + self.assertEqual(cs_info, cs_info2) + self.assertEqual('cs_bucket2', cs_info._cs_bucket) + self.assertEqual('cs_hash2', cs_info._cs_hash) + self.assertEqual('download_path2', cs_info._download_path) + self.assertEqual('cs_remote_path2', cs_info._cs_remote_path) + self.assertEqual('cs_remote_path2', cs_info._cs_remote_path) + + dep_info1.Update(dep_info3) + self.assertEqual('dep1', dep_info1.dependency) + self.assertEqual('platform1', dep_info1.platform) + self.assertEqual(['config_path1', 'config_path2', 'config_path3'], + dep_info1.config_paths) + self.assertFalse(dep_info1.has_local_path_info) + cs_info = dep_info1._cloud_storage_info + self.assertEqual(cs_info, cs_info2) + self.assertEqual('cs_bucket2', cs_info._cs_bucket) + self.assertEqual('cs_hash2', cs_info._cs_hash) + self.assertEqual('download_path2', cs_info._download_path) + self.assertEqual('cs_remote_path2', cs_info._cs_remote_path) + + self.assertRaises(ValueError, dep_info1.Update, dep_info4) + + def testUpdateAllInfo(self): + lp_info1 = dependency_manager.LocalPathInfo(['path1']) + dep_info1 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path1', local_path_info=lp_info1) + cs_info2 = dependency_manager.CloudStorageInfo( + cs_bucket='cs_bucket2', cs_hash='cs_hash2', + download_path='download_path2', cs_remote_path='cs_remote_path2') + lp_info2 = dependency_manager.LocalPathInfo(['path2']) + dep_info2 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path2', local_path_info=lp_info2, + cloud_storage_info=cs_info2) + lp_info3 = dependency_manager.LocalPathInfo(['path3']) + dep_info3 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path3', local_path_info=lp_info3) + lp_info4 = dependency_manager.LocalPathInfo(['path4']) + cs_info4 = dependency_manager.CloudStorageInfo( + cs_bucket='cs_bucket4', cs_hash='cs_hash4', + download_path='download_path4', cs_remote_path='cs_remote_path4') + dep_info4 = dependency_manager.DependencyInfo( + 'dep1', 'platform1', 'config_path4', local_path_info=lp_info4, + cloud_storage_info=cs_info4) + + self.assertTrue(dep_info1._local_path_info.IsPathInLocalPaths('path1')) + self.assertFalse(dep_info1._local_path_info.IsPathInLocalPaths('path2')) + self.assertFalse(dep_info1._local_path_info.IsPathInLocalPaths('path3')) + self.assertFalse(dep_info1._local_path_info.IsPathInLocalPaths('path4')) + + dep_info1.Update(dep_info2) + cs_info = dep_info1._cloud_storage_info + self.assertEqual(cs_info, cs_info2) + self.assertEqual('cs_bucket2', cs_info._cs_bucket) + self.assertEqual('cs_hash2', cs_info._cs_hash) + self.assertEqual('download_path2', cs_info._download_path) + self.assertEqual('cs_remote_path2', cs_info._cs_remote_path) + self.assertTrue(dep_info1._local_path_info.IsPathInLocalPaths('path1')) + self.assertTrue(dep_info1._local_path_info.IsPathInLocalPaths('path2')) + self.assertFalse(dep_info1._local_path_info.IsPathInLocalPaths('path3')) + self.assertFalse(dep_info1._local_path_info.IsPathInLocalPaths('path4')) + + dep_info1.Update(dep_info3) + cs_info = dep_info1._cloud_storage_info + self.assertEqual(cs_info, cs_info2) + self.assertEqual('cs_bucket2', cs_info._cs_bucket) + self.assertEqual('cs_hash2', cs_info._cs_hash) + self.assertEqual('download_path2', cs_info._download_path) + self.assertEqual('cs_remote_path2', cs_info._cs_remote_path) + self.assertTrue(dep_info1._local_path_info.IsPathInLocalPaths('path1')) + self.assertTrue(dep_info1._local_path_info.IsPathInLocalPaths('path2')) + self.assertTrue(dep_info1._local_path_info.IsPathInLocalPaths('path3')) + self.assertFalse(dep_info1._local_path_info.IsPathInLocalPaths('path4')) + + self.assertRaises(ValueError, dep_info1.Update, dep_info4) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_unittest.py new file mode 100644 index 0000000..86d17f7 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_unittest.py @@ -0,0 +1,527 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# pylint: disable=unused-argument + +import mock + +from pyfakefs import fake_filesystem_unittest +from py_utils import cloud_storage + +import dependency_manager +from dependency_manager import exceptions + + +class DependencyManagerTest(fake_filesystem_unittest.TestCase): + + def setUp(self): + self.lp_info012 = dependency_manager.LocalPathInfo( + ['path0', 'path1', 'path2']) + self.cloud_storage_info = dependency_manager.CloudStorageInfo( + 'cs_bucket', 'cs_hash', 'download_path', 'cs_remote_path') + + self.dep_info = dependency_manager.DependencyInfo( + 'dep', 'platform', 'config_file', local_path_info=self.lp_info012, + cloud_storage_info=self.cloud_storage_info) + self.setUpPyfakefs() + + def tearDown(self): + self.tearDownPyfakefs() + + # TODO(nednguyen): add a test that construct + # dependency_manager.DependencyManager from a list of DependencyInfo. + def testErrorInit(self): + with self.assertRaises(ValueError): + dependency_manager.DependencyManager(None) + with self.assertRaises(ValueError): + dependency_manager.DependencyManager('config_file?') + + def testInitialUpdateDependencies(self): + dep_manager = dependency_manager.DependencyManager([]) + + # Empty BaseConfig. + dep_manager._lookup_dict = {} + base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig) + base_config_mock.IterDependencyInfo.return_value = iter([]) + dep_manager._UpdateDependencies(base_config_mock) + self.assertFalse(dep_manager._lookup_dict) + + # One dependency/platform in a BaseConfig. + dep_manager._lookup_dict = {} + base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig) + dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep = 'dependency' + plat = 'platform' + dep_info.dependency = dep + dep_info.platform = plat + base_config_mock.IterDependencyInfo.return_value = iter([dep_info]) + expected_lookup_dict = {dep: {plat: dep_info}} + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info.Update.called) + + # One dependency multiple platforms in a BaseConfig. + dep_manager._lookup_dict = {} + base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig) + dep = 'dependency' + plat1 = 'platform1' + plat2 = 'platform2' + dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info1.dependency = dep + dep_info1.platform = plat1 + dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info2.dependency = dep + dep_info2.platform = plat2 + base_config_mock.IterDependencyInfo.return_value = iter([dep_info1, + dep_info2]) + expected_lookup_dict = {dep: {plat1: dep_info1, + plat2: dep_info2}} + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info1.Update.called) + self.assertFalse(dep_info2.Update.called) + + # Multiple dependencies, multiple platforms in a BaseConfig. + dep_manager._lookup_dict = {} + base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig) + dep1 = 'dependency1' + dep2 = 'dependency2' + plat1 = 'platform1' + plat2 = 'platform2' + dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info1.dependency = dep1 + dep_info1.platform = plat1 + dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info2.dependency = dep1 + dep_info2.platform = plat2 + dep_info3 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info3.dependency = dep2 + dep_info3.platform = plat2 + base_config_mock.IterDependencyInfo.return_value = iter( + [dep_info1, dep_info2, dep_info3]) + expected_lookup_dict = {dep1: {plat1: dep_info1, + plat2: dep_info2}, + dep2: {plat2: dep_info3}} + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info1.Update.called) + self.assertFalse(dep_info2.Update.called) + self.assertFalse(dep_info3.Update.called) + + def testFollowupUpdateDependenciesNoOverlap(self): + dep_manager = dependency_manager.DependencyManager([]) + dep = 'dependency' + dep1 = 'dependency1' + dep2 = 'dependency2' + dep3 = 'dependency3' + plat1 = 'platform1' + plat2 = 'platform2' + plat3 = 'platform3' + dep_info_a = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info_a.dependency = dep1 + dep_info_a.platform = plat1 + dep_info_b = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info_b.dependency = dep1 + dep_info_b.platform = plat2 + dep_info_c = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info_c.dependency = dep + dep_info_c.platform = plat1 + + start_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}} + base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig) + + # Empty BaseConfig. + dep_manager._lookup_dict = start_lookup_dict.copy() + base_config_mock.IterDependencyInfo.return_value = iter([]) + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(start_lookup_dict, dep_manager._lookup_dict) + + # One dependency/platform in a BaseConfig. + dep_manager._lookup_dict = start_lookup_dict.copy() + dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info.dependency = dep3 + dep_info.platform = plat1 + base_config_mock.IterDependencyInfo.return_value = iter([dep_info]) + expected_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}, + dep3: {plat3: dep_info}} + + dep_manager._UpdateDependencies(base_config_mock) + self.assertItemsEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info.Update.called) + self.assertFalse(dep_info_a.Update.called) + self.assertFalse(dep_info_b.Update.called) + self.assertFalse(dep_info_c.Update.called) + + # One dependency multiple platforms in a BaseConfig. + dep_manager._lookup_dict = start_lookup_dict.copy() + dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info1.dependency = dep2 + dep_info1.platform = plat1 + dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info2.dependency = dep2 + dep_info2.platform = plat2 + base_config_mock.IterDependencyInfo.return_value = iter([dep_info1, + dep_info2]) + expected_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}, + dep2: {plat1: dep_info1, + plat2: dep_info2}} + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info1.Update.called) + self.assertFalse(dep_info2.Update.called) + self.assertFalse(dep_info_a.Update.called) + self.assertFalse(dep_info_b.Update.called) + self.assertFalse(dep_info_c.Update.called) + + # Multiple dependencies, multiple platforms in a BaseConfig. + dep_manager._lookup_dict = start_lookup_dict.copy() + dep1 = 'dependency1' + plat1 = 'platform1' + plat2 = 'platform2' + dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info1.dependency = dep2 + dep_info1.platform = plat1 + dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info2.dependency = dep2 + dep_info2.platform = plat2 + dep_info3 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info3.dependency = dep3 + dep_info3.platform = plat2 + base_config_mock.IterDependencyInfo.return_value = iter( + [dep_info1, dep_info2, dep_info3]) + expected_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}, + dep2: {plat1: dep_info1, + plat2: dep_info2}, + dep3: {plat2: dep_info3}} + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info1.Update.called) + self.assertFalse(dep_info2.Update.called) + self.assertFalse(dep_info3.Update.called) + self.assertFalse(dep_info_a.Update.called) + self.assertFalse(dep_info_b.Update.called) + self.assertFalse(dep_info_c.Update.called) + + # Ensure the testing data wasn't corrupted. + self.assertEqual(start_lookup_dict, + {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}}) + + def testFollowupUpdateDependenciesWithCollisions(self): + dep_manager = dependency_manager.DependencyManager([]) + dep = 'dependency' + dep1 = 'dependency1' + dep2 = 'dependency2' + plat1 = 'platform1' + plat2 = 'platform2' + dep_info_a = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info_a.dependency = dep1 + dep_info_a.platform = plat1 + dep_info_b = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info_b.dependency = dep1 + dep_info_b.platform = plat2 + dep_info_c = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info_c.dependency = dep + dep_info_c.platform = plat1 + + start_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}} + base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig) + + # One dependency/platform. + dep_manager._lookup_dict = start_lookup_dict.copy() + dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info.dependency = dep + dep_info.platform = plat1 + base_config_mock.IterDependencyInfo.return_value = iter([dep_info]) + expected_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}} + + dep_manager._UpdateDependencies(base_config_mock) + self.assertItemsEqual(expected_lookup_dict, dep_manager._lookup_dict) + dep_info_a.Update.assert_called_once_with(dep_info) + self.assertFalse(dep_info.Update.called) + self.assertFalse(dep_info_b.Update.called) + self.assertFalse(dep_info_c.Update.called) + dep_info_a.reset_mock() + dep_info_b.reset_mock() + dep_info_c.reset_mock() + + # One dependency multiple platforms in a BaseConfig. + dep_manager._lookup_dict = start_lookup_dict.copy() + dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info1.dependency = dep1 + dep_info1.platform = plat1 + dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info2.dependency = dep2 + dep_info2.platform = plat2 + base_config_mock.IterDependencyInfo.return_value = iter([dep_info1, + dep_info2]) + expected_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}, + dep2: {plat2: dep_info2}} + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info1.Update.called) + self.assertFalse(dep_info2.Update.called) + self.assertFalse(dep_info_a.Update.called) + self.assertFalse(dep_info_b.Update.called) + dep_info_c.Update.assert_called_once_with(dep_info1) + dep_info_a.reset_mock() + dep_info_b.reset_mock() + dep_info_c.reset_mock() + + # Multiple dependencies, multiple platforms in a BaseConfig. + dep_manager._lookup_dict = start_lookup_dict.copy() + dep1 = 'dependency1' + plat1 = 'platform1' + plat2 = 'platform2' + dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info1.dependency = dep + dep_info1.platform = plat1 + dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info2.dependency = dep1 + dep_info2.platform = plat1 + dep_info3 = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info3.dependency = dep2 + dep_info3.platform = plat2 + base_config_mock.IterDependencyInfo.return_value = iter( + [dep_info1, dep_info2, dep_info3]) + expected_lookup_dict = {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}, + dep2: {plat2: dep_info3}} + dep_manager._UpdateDependencies(base_config_mock) + self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict) + self.assertFalse(dep_info1.Update.called) + self.assertFalse(dep_info2.Update.called) + self.assertFalse(dep_info3.Update.called) + self.assertFalse(dep_info_b.Update.called) + dep_info_a.Update.assert_called_once_with(dep_info1) + dep_info_c.Update.assert_called_once_with(dep_info2) + + # Collision error. + dep_manager._lookup_dict = start_lookup_dict.copy() + dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo) + dep_info.dependency = dep + dep_info.platform = plat1 + base_config_mock.IterDependencyInfo.return_value = iter([dep_info]) + dep_info_a.Update.side_effect = ValueError + self.assertRaises(ValueError, + dep_manager._UpdateDependencies, base_config_mock) + + # Ensure the testing data wasn't corrupted. + self.assertEqual(start_lookup_dict, + {dep: {plat1: dep_info_a, + plat2: dep_info_b}, + dep1: {plat1: dep_info_c}}) + + def testGetDependencyInfo(self): + dep_manager = dependency_manager.DependencyManager([]) + self.assertFalse(dep_manager._lookup_dict) + + # No dependencies in the dependency manager. + self.assertEqual(None, dep_manager._GetDependencyInfo('missing_dep', + 'missing_plat')) + + dep_manager._lookup_dict = {'dep1': {'plat1': 'dep_info11', + 'plat2': 'dep_info12', + 'plat3': 'dep_info13'}, + 'dep2': {'plat1': 'dep_info11', + 'plat2': 'dep_info21', + 'plat3': 'dep_info23', + 'default': 'dep_info2d'}, + 'dep3': {'plat1': 'dep_info31', + 'plat2': 'dep_info32', + 'default': 'dep_info3d'}} + # Dependency not in the dependency manager. + self.assertEqual(None, dep_manager._GetDependencyInfo( + 'missing_dep', 'missing_plat')) + # Dependency in the dependency manager, but not the platform. No default. + self.assertEqual(None, dep_manager._GetDependencyInfo( + 'dep1', 'missing_plat')) + # Dependency in the dependency manager, but not the platform, but a default + # exists. + self.assertEqual('dep_info2d', dep_manager._GetDependencyInfo( + 'dep2', 'missing_plat')) + # Dependency and platform in the dependency manager. A default exists. + self.assertEqual('dep_info23', dep_manager._GetDependencyInfo( + 'dep2', 'plat3')) + # Dependency and platform in the dependency manager. No default exists. + self.assertEqual('dep_info12', dep_manager._GetDependencyInfo( + 'dep1', 'plat2')) + + + + + + + + + + + + + + + + + + + @mock.patch( + 'dependency_manager.dependency_info.DependencyInfo.GetRemotePath') # pylint: disable=line-too-long + def testFetchPathUnititializedDependency( + self, cs_path_mock): + dep_manager = dependency_manager.DependencyManager([]) + self.assertFalse(cs_path_mock.call_args) + cs_path = 'cs_path' + cs_path_mock.return_value = cs_path + + # Empty lookup_dict + with self.assertRaises(exceptions.NoPathFoundError): + dep_manager.FetchPath('dep', 'plat_arch_x86') + + # Non-empty lookup dict that doesn't contain the dependency we're looking + # for. + dep_manager._lookup_dict = {'dep1': mock.MagicMock(), + 'dep2': mock.MagicMock()} + with self.assertRaises(exceptions.NoPathFoundError): + dep_manager.FetchPath('dep', 'plat_arch_x86') + + @mock.patch('os.path') + @mock.patch( + 'dependency_manager.DependencyManager._GetDependencyInfo') + @mock.patch( + 'dependency_manager.dependency_info.DependencyInfo.GetRemotePath') # pylint: disable=line-too-long + def testFetchPathLocalFile(self, cs_path_mock, dep_info_mock, path_mock): + dep_manager = dependency_manager.DependencyManager([]) + self.assertFalse(cs_path_mock.call_args) + cs_path = 'cs_path' + dep_info = self.dep_info + cs_path_mock.return_value = cs_path + # The DependencyInfo returned should be passed through to LocalPath. + dep_info_mock.return_value = dep_info + + # Non-empty lookup dict that contains the dependency we're looking for. + # Local path exists. + dep_manager._lookup_dict = {'dep': {'platform' : self.dep_info}, + 'dep2': mock.MagicMock()} + self.fs.CreateFile('path1') + found_path = dep_manager.FetchPath('dep', 'platform') + + self.assertEqual('path1', found_path) + self.assertFalse(cs_path_mock.call_args) + + + @mock.patch( + 'dependency_manager.dependency_info.DependencyInfo.GetRemotePath') # pylint: disable=line-too-long + def testFetchPathRemoteFile( + self, cs_path_mock): + dep_manager = dependency_manager.DependencyManager([]) + self.assertFalse(cs_path_mock.call_args) + cs_path = 'cs_path' + def FakeCSPath(): + self.fs.CreateFile(cs_path) + return cs_path + cs_path_mock.side_effect = FakeCSPath + + # Non-empty lookup dict that contains the dependency we're looking for. + # Local path doesn't exist, but cloud_storage_path is downloaded. + dep_manager._lookup_dict = {'dep': {'platform' : self.dep_info, + 'plat1': mock.MagicMock()}, + 'dep2': {'plat2': mock.MagicMock()}} + found_path = dep_manager.FetchPath('dep', 'platform') + self.assertEqual(cs_path, found_path) + + + @mock.patch( + 'dependency_manager.dependency_info.DependencyInfo.GetRemotePath') # pylint: disable=line-too-long + def testFetchPathError( + self, cs_path_mock): + dep_manager = dependency_manager.DependencyManager([]) + self.assertFalse(cs_path_mock.call_args) + cs_path_mock.return_value = None + dep_manager._lookup_dict = {'dep': {'platform' : self.dep_info, + 'plat1': mock.MagicMock()}, + 'dep2': {'plat2': mock.MagicMock()}} + # Non-empty lookup dict that contains the dependency we're looking for. + # Local path doesn't exist, and cloud_storage path wasn't successfully + # found. + self.assertRaises(exceptions.NoPathFoundError, + dep_manager.FetchPath, 'dep', 'platform') + + cs_path_mock.side_effect = cloud_storage.CredentialsError + self.assertRaises(cloud_storage.CredentialsError, + dep_manager.FetchPath, 'dep', 'platform') + + cs_path_mock.side_effect = cloud_storage.CloudStorageError + self.assertRaises(cloud_storage.CloudStorageError, + dep_manager.FetchPath, 'dep', 'platform') + + cs_path_mock.side_effect = cloud_storage.PermissionError + self.assertRaises(cloud_storage.PermissionError, + dep_manager.FetchPath, 'dep', 'platform') + + def testLocalPath(self): + dep_manager = dependency_manager.DependencyManager([]) + # Empty lookup_dict + with self.assertRaises(exceptions.NoPathFoundError): + dep_manager.LocalPath('dep', 'plat') + + def testLocalPathNoDependency(self): + # Non-empty lookup dict that doesn't contain the dependency we're looking + # for. + dep_manager = dependency_manager.DependencyManager([]) + dep_manager._lookup_dict = {'dep1': mock.MagicMock(), + 'dep2': mock.MagicMock()} + with self.assertRaises(exceptions.NoPathFoundError): + dep_manager.LocalPath('dep', 'plat') + + def testLocalPathExists(self): + # Non-empty lookup dict that contains the dependency we're looking for. + # Local path exists. + dep_manager = dependency_manager.DependencyManager([]) + dep_manager._lookup_dict = {'dependency' : {'platform': self.dep_info}, + 'dep1': mock.MagicMock(), + 'dep2': mock.MagicMock()} + self.fs.CreateFile('path1') + found_path = dep_manager.LocalPath('dependency', 'platform') + + self.assertEqual('path1', found_path) + + def testLocalPathMissingPaths(self): + # Non-empty lookup dict that contains the dependency we're looking for. + # Local path is found but doesn't exist. + dep_manager = dependency_manager.DependencyManager([]) + dep_manager._lookup_dict = {'dependency' : {'platform': self.dep_info}, + 'dep1': mock.MagicMock(), + 'dep2': mock.MagicMock()} + self.assertRaises(exceptions.NoPathFoundError, + dep_manager.LocalPath, 'dependency', 'platform') + + def testLocalPathNoPaths(self): + # Non-empty lookup dict that contains the dependency we're looking for. + # Local path isn't found. + dep_manager = dependency_manager.DependencyManager([]) + dep_info = dependency_manager.DependencyInfo( + 'dep', 'platform', 'config_file', + cloud_storage_info=self.cloud_storage_info) + dep_manager._lookup_dict = {'dependency' : {'platform': dep_info}, + 'dep1': mock.MagicMock(), + 'dep2': mock.MagicMock()} + self.assertRaises(exceptions.NoPathFoundError, + dep_manager.LocalPath, 'dependency', 'platform') + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util.py new file mode 100644 index 0000000..7ec2ec6 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util.py @@ -0,0 +1,103 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import shutil +import stat +import sys +import zipfile_2_7_13 as zipfile + +from dependency_manager import exceptions + + +def _WinReadOnlyHandler(func, path, execinfo): + if not os.access(path, os.W_OK): + os.chmod(path, stat.S_IWRITE) + func(path) + else: + raise execinfo[0], execinfo[1], execinfo[2] + + +def RemoveDir(dir_path): + assert os.path.isabs(dir_path) + if sys.platform.startswith('win'): + dir_path = u'\\\\?\\' + dir_path + if os.path.isdir(dir_path): + shutil.rmtree(dir_path, onerror=_WinReadOnlyHandler) + + +def VerifySafeArchive(archive): + def ResolvePath(path_name): + return os.path.realpath(os.path.abspath(path_name)) + # Must add pathsep to avoid false positives. + # Ex: /tmp/abc/bad_file.py starts with /tmp/a but not /tmp/a/ + base_path = ResolvePath(os.getcwd()) + os.path.sep + for member in archive.namelist(): + if not ResolvePath(os.path.join(base_path, member)).startswith(base_path): + raise exceptions.ArchiveError( + 'Archive %s contains a bad member: %s.' % (archive.filename, member)) + + +def GetModeFromPath(file_path): + return stat.S_IMODE(os.stat(file_path).st_mode) + + +def GetModeFromZipInfo(zip_info): + return zip_info.external_attr >> 16 + + +def SetUnzippedDirPermissions(archive, unzipped_dir): + """Set the file permissions in an unzipped archive. + + Designed to be called right after extractall() was called on |archive|. + Noop on Win. Otherwise sets the executable bit on files where needed. + + Args: + archive: A zipfile.ZipFile object opened for reading. + unzipped_dir: A path to a directory containing the unzipped contents + of |archive|. + """ + if sys.platform.startswith('win'): + # Windows doesn't have an executable bit, so don't mess with the ACLs. + return + for zip_info in archive.infolist(): + archive_acls = GetModeFromZipInfo(zip_info) + if archive_acls & stat.S_IXUSR: + # Only preserve owner execurable permissions. + unzipped_path = os.path.abspath( + os.path.join(unzipped_dir, zip_info.filename)) + mode = GetModeFromPath(unzipped_path) + os.chmod(unzipped_path, mode | stat.S_IXUSR) + + +def UnzipArchive(archive_path, unzip_path): + """Unzips a file if it is a zip file. + + Args: + archive_path: The downloaded file to unzip. + unzip_path: The destination directory to unzip to. + + Raises: + ValueError: If |archive_path| is not a zipfile. + """ + # TODO(aiolos): Add tests once the refactor is completed. crbug.com/551158 + if not (archive_path and zipfile.is_zipfile(archive_path)): + raise ValueError( + 'Attempting to unzip a non-archive file at %s' % archive_path) + if not os.path.exists(unzip_path): + os.makedirs(unzip_path) + try: + with zipfile.ZipFile(archive_path, 'r') as archive: + VerifySafeArchive(archive) + assert os.path.isabs(unzip_path) + unzip_path_without_prefix = unzip_path + if sys.platform.startswith('win'): + unzip_path = u'\\\\?\\' + unzip_path + archive.extractall(path=unzip_path) + SetUnzippedDirPermissions(archive, unzip_path) + except: + # Hack necessary because isdir doesn't work with escaped paths on Windows. + if unzip_path_without_prefix and os.path.isdir(unzip_path_without_prefix): + RemoveDir(unzip_path_without_prefix) + raise diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util_unittest.py new file mode 100644 index 0000000..c62bfd5 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/dependency_manager_util_unittest.py @@ -0,0 +1,193 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import shutil +import stat +import sys +import tempfile +import unittest +import uuid +import zipfile + +import mock + +from dependency_manager import dependency_manager_util +from dependency_manager import exceptions + + +class DependencyManagerUtilTest(unittest.TestCase): + # This class intentionally uses actual file I/O to test real system behavior. + + def setUp(self): + self.tmp_dir = os.path.abspath(tempfile.mkdtemp(prefix='telemetry')) + self.sub_dir = os.path.join(self.tmp_dir, 'sub_dir') + os.mkdir(self.sub_dir) + + self.read_only_path = (os.path.join(self.tmp_dir, 'read_only')) + with open(self.read_only_path, 'w+') as read_file: + read_file.write('Read-only file') + os.chmod(self.read_only_path, stat.S_IRUSR) + + self.writable_path = (os.path.join(self.tmp_dir, 'writable')) + with open(self.writable_path, 'w+') as writable_file: + writable_file.write('Writable file') + os.chmod(self.writable_path, stat.S_IRUSR | stat.S_IWUSR) + + self.executable_path = (os.path.join(self.tmp_dir, 'executable')) + with open(self.executable_path, 'w+') as executable_file: + executable_file.write('Executable file') + os.chmod(self.executable_path, stat.S_IRWXU) + + self.sub_read_only_path = (os.path.join(self.sub_dir, 'read_only')) + with open(self.sub_read_only_path, 'w+') as read_file: + read_file.write('Read-only sub file') + os.chmod(self.sub_read_only_path, stat.S_IRUSR) + + self.sub_writable_path = (os.path.join(self.sub_dir, 'writable')) + with open(self.sub_writable_path, 'w+') as writable_file: + writable_file.write('Writable sub file') + os.chmod(self.sub_writable_path, stat.S_IRUSR | stat.S_IWUSR) + + self.sub_executable_path = (os.path.join(self.sub_dir, 'executable')) + with open(self.sub_executable_path, 'w+') as executable_file: + executable_file.write('Executable sub file') + os.chmod(self.sub_executable_path, stat.S_IRWXU) + + self.AssertExpectedDirFiles(self.tmp_dir) + self.archive_path = self.CreateZipArchiveFromDir(self.tmp_dir) + + def tearDown(self): + if os.path.isdir(self.tmp_dir): + dependency_manager_util.RemoveDir(self.tmp_dir) + if os.path.isfile(self.archive_path): + os.remove(self.archive_path) + + def AssertExpectedDirFiles(self, top_dir): + sub_dir = os.path.join(top_dir, 'sub_dir') + read_only_path = (os.path.join(top_dir, 'read_only')) + writable_path = (os.path.join(top_dir, 'writable')) + executable_path = (os.path.join(top_dir, 'executable')) + sub_read_only_path = (os.path.join(sub_dir, 'read_only')) + sub_writable_path = (os.path.join(sub_dir, 'writable')) + sub_executable_path = (os.path.join(sub_dir, 'executable')) + # assert contents as expected + self.assertTrue(os.path.isdir(top_dir)) + self.assertTrue(os.path.isdir(sub_dir)) + self.assertTrue(os.path.isfile(read_only_path)) + self.assertTrue(os.path.isfile(writable_path)) + self.assertTrue(os.path.isfile(executable_path)) + self.assertTrue(os.path.isfile(sub_read_only_path)) + self.assertTrue(os.path.isfile(sub_writable_path)) + self.assertTrue(os.path.isfile(sub_executable_path)) + + # assert permissions as expected + self.assertTrue( + stat.S_IRUSR & stat.S_IMODE(os.stat(read_only_path).st_mode)) + self.assertTrue( + stat.S_IRUSR & stat.S_IMODE(os.stat(sub_read_only_path).st_mode)) + self.assertTrue( + stat.S_IRUSR & stat.S_IMODE(os.stat(writable_path).st_mode)) + self.assertTrue( + stat.S_IWUSR & stat.S_IMODE(os.stat(writable_path).st_mode)) + self.assertTrue( + stat.S_IRUSR & stat.S_IMODE(os.stat(sub_writable_path).st_mode)) + self.assertTrue( + stat.S_IWUSR & stat.S_IMODE(os.stat(sub_writable_path).st_mode)) + if not sys.platform.startswith('win'): + self.assertEqual( + stat.S_IRWXU, + stat.S_IRWXU & stat.S_IMODE(os.stat(executable_path).st_mode)) + self.assertEqual( + stat.S_IRWXU, + stat.S_IRWXU & stat.S_IMODE(os.stat(sub_executable_path).st_mode)) + + def CreateZipArchiveFromDir(self, dir_path): + try: + base_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4())) + archive_path = shutil.make_archive(base_path, 'zip', dir_path) + self.assertTrue(os.path.exists(archive_path)) + self.assertTrue(zipfile.is_zipfile(archive_path)) + except: + if os.path.isfile(archive_path): + os.remove(archive_path) + raise + return archive_path + + def testRemoveDirWithSubDir(self): + dependency_manager_util.RemoveDir(self.tmp_dir) + + self.assertFalse(os.path.exists(self.tmp_dir)) + self.assertFalse(os.path.exists(self.sub_dir)) + self.assertFalse(os.path.exists(self.read_only_path)) + self.assertFalse(os.path.exists(self.writable_path)) + self.assertFalse(os.path.isfile(self.executable_path)) + self.assertFalse(os.path.exists(self.sub_read_only_path)) + self.assertFalse(os.path.exists(self.sub_writable_path)) + self.assertFalse(os.path.isfile(self.sub_executable_path)) + + def testUnzipFile(self): + self.AssertExpectedDirFiles(self.tmp_dir) + unzip_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4())) + dependency_manager_util.UnzipArchive(self.archive_path, unzip_path) + self.AssertExpectedDirFiles(unzip_path) + self.AssertExpectedDirFiles(self.tmp_dir) + dependency_manager_util.RemoveDir(unzip_path) + + def testUnzipFileContainingLongPath(self): + try: + dir_path = self.tmp_dir + if sys.platform.startswith('win'): + dir_path = u'\\\\?\\' + dir_path + + archive_suffix = '' + # 260 is the Windows API path length limit. + while len(archive_suffix) < 260: + archive_suffix = os.path.join(archive_suffix, 'really') + contents_dir_path = os.path.join(dir_path, archive_suffix) + os.makedirs(contents_dir_path) + filename = os.path.join(contents_dir_path, 'longpath.txt') + open(filename, 'a').close() + + base_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4())) + archive_path = shutil.make_archive(base_path, 'zip', dir_path) + self.assertTrue(os.path.exists(archive_path)) + self.assertTrue(zipfile.is_zipfile(archive_path)) + except: + if os.path.isfile(archive_path): + os.remove(archive_path) + raise + + unzip_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4())) + dependency_manager_util.UnzipArchive(archive_path, unzip_path) + dependency_manager_util.RemoveDir(unzip_path) + + def testUnzipFileFailure(self): + unzip_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4())) + self.assertFalse(os.path.exists(unzip_path)) + with mock.patch( + 'dependency_manager.dependency_manager_util.zipfile.ZipFile.extractall' # pylint: disable=line-too-long + ) as zipfile_mock: + zipfile_mock.side_effect = IOError + self.assertRaises( + IOError, dependency_manager_util.UnzipArchive, self.archive_path, + unzip_path) + self.AssertExpectedDirFiles(self.tmp_dir) + self.assertFalse(os.path.exists(unzip_path)) + + def testVerifySafeArchivePasses(self): + with zipfile.ZipFile(self.archive_path) as archive: + dependency_manager_util.VerifySafeArchive(archive) + + def testVerifySafeArchiveFailsOnRelativePathWithPardir(self): + tmp_file = tempfile.NamedTemporaryFile(delete=False) + tmp_file_name = tmp_file.name + tmp_file.write('Bad file!') + tmp_file.close() + with zipfile.ZipFile(self.archive_path, 'w') as archive: + archive.write(tmp_file_name, '../../foo') + self.assertRaises( + exceptions.ArchiveError, dependency_manager_util.VerifySafeArchive, + archive) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/exceptions.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/exceptions.py new file mode 100644 index 0000000..d7863db --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/exceptions.py @@ -0,0 +1,52 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from py_utils import cloud_storage + + +CloudStorageError = cloud_storage.CloudStorageError + + +class UnsupportedConfigFormatError(ValueError): + def __init__(self, config_type, config_file): + if not config_type: + message = ('The json file at %s is unsupported by the dependency_manager ' + 'due to no specified config type' % config_file) + else: + message = ('The json file at %s has config type %s, which is unsupported ' + 'by the dependency manager.' % (config_file, config_type)) + super(UnsupportedConfigFormatError, self).__init__(message) + + +class EmptyConfigError(ValueError): + def __init__(self, file_path): + super(EmptyConfigError, self).__init__('Empty config at %s.' % file_path) + + +class FileNotFoundError(Exception): + def __init__(self, file_path): + super(FileNotFoundError, self).__init__('No file found at %s' % file_path) + + +class NoPathFoundError(Exception): + def __init__(self, dependency, platform): + super(NoPathFoundError, self).__init__( + 'No file could be found locally, and no file to download from cloud ' + 'storage for %s on platform %s' % (dependency, platform)) + + +class ReadWriteError(Exception): + pass + + +class CloudStorageUploadConflictError(CloudStorageError): + def __init__(self, bucket, path): + super(CloudStorageUploadConflictError, self).__init__( + 'File location %s already exists in bucket %s' % (path, bucket)) + + +class ArchiveError(Exception): + def __init__(self, msg): + super(ArchiveError, self).__init__(msg) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/local_path_info.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/local_path_info.py new file mode 100644 index 0000000..0103e8f --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/local_path_info.py @@ -0,0 +1,40 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os + + +class LocalPathInfo(object): + + def __init__(self, path_priority_groups): + self._path_priority_groups = self._ParseLocalPaths(path_priority_groups) + + def GetLocalPath(self): + for priority_group in self._path_priority_groups: + priority_group = filter(os.path.exists, priority_group) + if not priority_group: + continue + return max(priority_group, key=lambda path: os.stat(path).st_mtime) + return None + + def IsPathInLocalPaths(self, path): + return any( + path in priority_group for priority_group in self._path_priority_groups) + + def Update(self, local_path_info): + if not local_path_info: + return + for priority_group in local_path_info._path_priority_groups: + group_list = [] + for path in priority_group: + if not self.IsPathInLocalPaths(path): + group_list.append(path) + if group_list: + self._path_priority_groups.append(group_list) + + @staticmethod + def _ParseLocalPaths(local_paths): + if not local_paths: + return [] + return [[e] if isinstance(e, basestring) else e for e in local_paths] diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/manager.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/manager.py new file mode 100644 index 0000000..69ca550 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/manager.py @@ -0,0 +1,247 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import os + +from dependency_manager import base_config +from dependency_manager import exceptions + + +DEFAULT_TYPE = 'default' + + +class DependencyManager(object): + def __init__(self, configs, supported_config_types=None): + """Manages file dependencies found locally or in cloud_storage. + + Args: + configs: A list of instances of BaseConfig or it's subclasses, passed + in decreasing order of precedence. + supported_config_types: A list of whitelisted config_types. + No restrictions if None is specified. + + Raises: + ValueError: If |configs| is not a list of instances of BaseConfig or + its subclasses. + UnsupportedConfigFormatError: If supported_config_types is specified and + configs contains a config not in the supported config_types. + + Example: DependencyManager([config1, config2, config3]) + No requirements on the type of Config, and any dependencies that have + local files for the same platform will first look in those from + config1, then those from config2, and finally those from config3. + """ + if configs is None or type(configs) != list: + raise ValueError( + 'Must supply a list of config files to DependencyManager') + # self._lookup_dict is a dictionary with the following format: + # { dependency1: {platform1: dependency_info1, + # platform2: dependency_info2} + # dependency2: {platform1: dependency_info3, + # ...} + # ...} + # + # Where the dependencies and platforms are strings, and the + # dependency_info's are DependencyInfo instances. + self._lookup_dict = {} + self.supported_configs = supported_config_types or [] + for config in configs: + self._UpdateDependencies(config) + + + def FetchPathWithVersion(self, dependency, platform): + """Get a path to an executable for |dependency|, downloading as needed. + + A path to a default executable may be returned if a platform specific + version is not specified in the config(s). + + Args: + dependency: Name of the desired dependency, as given in the config(s) + used in this DependencyManager. + platform: Name of the platform the dependency will run on. Often of the + form 'os_architecture'. Must match those specified in the config(s) + used in this DependencyManager. + Returns: + , where: + is the path to an executable of |dependency| that will run + on |platform|, downloading from cloud storage if needed. + is the version of the executable at or None. + + Raises: + NoPathFoundError: If a local copy of the executable cannot be found and + a remote path could not be downloaded from cloud_storage. + CredentialsError: If cloud_storage credentials aren't configured. + PermissionError: If cloud_storage credentials are configured, but not + with an account that has permission to download the remote file. + NotFoundError: If the remote file does not exist where expected in + cloud_storage. + ServerError: If an internal server error is hit while downloading the + remote file. + CloudStorageError: If another error occured while downloading the remote + path. + FileNotFoundError: If an attempted download was otherwise unsuccessful. + + """ + dependency_info = self._GetDependencyInfo(dependency, platform) + if not dependency_info: + raise exceptions.NoPathFoundError(dependency, platform) + path = dependency_info.GetLocalPath() + version = None + if not path or not os.path.exists(path): + path = dependency_info.GetRemotePath() + if not path or not os.path.exists(path): + raise exceptions.NoPathFoundError(dependency, platform) + version = dependency_info.GetRemotePathVersion() + return path, version + + def FetchPath(self, dependency, platform): + """Get a path to an executable for |dependency|, downloading as needed. + + A path to a default executable may be returned if a platform specific + version is not specified in the config(s). + + Args: + dependency: Name of the desired dependency, as given in the config(s) + used in this DependencyManager. + platform: Name of the platform the dependency will run on. Often of the + form 'os_architecture'. Must match those specified in the config(s) + used in this DependencyManager. + Returns: + A path to an executable of |dependency| that will run on |platform|, + downloading from cloud storage if needed. + + Raises: + NoPathFoundError: If a local copy of the executable cannot be found and + a remote path could not be downloaded from cloud_storage. + CredentialsError: If cloud_storage credentials aren't configured. + PermissionError: If cloud_storage credentials are configured, but not + with an account that has permission to download the remote file. + NotFoundError: If the remote file does not exist where expected in + cloud_storage. + ServerError: If an internal server error is hit while downloading the + remote file. + CloudStorageError: If another error occured while downloading the remote + path. + FileNotFoundError: If an attempted download was otherwise unsuccessful. + + """ + path, _ = self.FetchPathWithVersion(dependency, platform) + return path + + def LocalPath(self, dependency, platform): + """Get a path to a locally stored executable for |dependency|. + + A path to a default executable may be returned if a platform specific + version is not specified in the config(s). + Will not download the executable. + + Args: + dependency: Name of the desired dependency, as given in the config(s) + used in this DependencyManager. + platform: Name of the platform the dependency will run on. Often of the + form 'os_architecture'. Must match those specified in the config(s) + used in this DependencyManager. + Returns: + A path to an executable for |dependency| that will run on |platform|. + + Raises: + NoPathFoundError: If a local copy of the executable cannot be found. + """ + dependency_info = self._GetDependencyInfo(dependency, platform) + if not dependency_info: + raise exceptions.NoPathFoundError(dependency, platform) + local_path = dependency_info.GetLocalPath() + if not local_path or not os.path.exists(local_path): + raise exceptions.NoPathFoundError(dependency, platform) + return local_path + + def PrefetchPaths(self, platform, dependencies=None, cloud_storage_retries=3): + if not dependencies: + dependencies = self._lookup_dict.keys() + + skipped_deps = [] + found_deps = [] + missing_deps = [] + for dependency in dependencies: + dependency_info = self._GetDependencyInfo(dependency, platform) + if not dependency_info: + # The dependency is only configured for other platforms. + skipped_deps.append(dependency) + logging.warning( + 'Dependency %s not configured for platform %s. Skipping prefetch.', + dependency, platform) + continue + local_path = dependency_info.GetLocalPath() + if local_path: + found_deps.append(dependency) + continue + fetched_path = None + for _ in range(0, cloud_storage_retries + 1): + try: + fetched_path = dependency_info.GetRemotePath() + except exceptions.CloudStorageError: + continue + break + if fetched_path: + found_deps.append(dependency) + else: + missing_deps.append(dependency) + logging.error( + 'Dependency %s could not be found or fetched from cloud storage for' + ' platform %s.', dependency, platform) + if missing_deps: + raise exceptions.NoPathFoundError(', '.join(missing_deps), platform) + return (found_deps, skipped_deps) + + def _UpdateDependencies(self, config): + """Add the dependency information stored in |config| to this instance. + + Args: + config: An instances of BaseConfig or a subclasses. + + Raises: + UnsupportedConfigFormatError: If supported_config_types was specified + and config is not in the supported config_types. + """ + if not isinstance(config, base_config.BaseConfig): + raise ValueError('Must use a BaseConfig or subclass instance with the ' + 'DependencyManager.') + if (self.supported_configs and + config.GetConfigType() not in self.supported_configs): + raise exceptions.UnsupportedConfigFormatError(config.GetConfigType(), + config.config_path) + for dep_info in config.IterDependencyInfo(): + dependency = dep_info.dependency + platform = dep_info.platform + if dependency not in self._lookup_dict: + self._lookup_dict[dependency] = {} + if platform not in self._lookup_dict[dependency]: + self._lookup_dict[dependency][platform] = dep_info + else: + self._lookup_dict[dependency][platform].Update(dep_info) + + + def _GetDependencyInfo(self, dependency, platform): + """Get information for |dependency| on |platform|, or a default if needed. + + Args: + dependency: Name of the desired dependency, as given in the config(s) + used in this DependencyManager. + platform: Name of the platform the dependency will run on. Often of the + form 'os_architecture'. Must match those specified in the config(s) + used in this DependencyManager. + + Returns: The dependency_info for |dependency| on |platform| if it exists. + Or the default version of |dependency| if it exists, or None if neither + exist. + """ + if not self._lookup_dict or dependency not in self._lookup_dict: + return None + dependency_dict = self._lookup_dict[dependency] + device_type = platform + if not device_type in dependency_dict: + device_type = DEFAULT_TYPE + return dependency_dict.get(device_type) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader.py new file mode 100644 index 0000000..e88b7c0 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader.py @@ -0,0 +1,108 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import os + +from py_utils import cloud_storage + +from dependency_manager import exceptions + + +BACKUP_PATH_EXTENSION = 'old' + + +class CloudStorageUploader(object): + def __init__(self, bucket, remote_path, local_path, cs_backup_path=None): + if not bucket or not remote_path or not local_path: + raise ValueError( + 'Attempted to partially initialize upload data with bucket %s, ' + 'remote_path %s, and local_path %s', bucket, remote_path, local_path) + if not os.path.exists(local_path): + raise ValueError('Attempting to initilize UploadInfo with missing ' + 'local path %s', local_path) + + self._cs_bucket = bucket + self._cs_remote_path = remote_path + self._local_path = local_path + self._cs_backup_path = (cs_backup_path or + '%s.%s' % (self._cs_remote_path, + BACKUP_PATH_EXTENSION)) + self._updated = False + self._backed_up = False + + def Upload(self, force=False): + """Upload all pending files and then write the updated config to disk. + + Will attempt to copy files existing in the upload location to a backup + location in the same bucket in cloud storage if |force| is True. + + Args: + force: True if files should be uploaded to cloud storage even if a + file already exists in the upload location. + + Raises: + CloudStorageUploadConflictError: If |force| is False and the potential + upload location of a file already exists. + CloudStorageError: If copying an existing file to the backup location + or uploading the new file fails. + """ + if cloud_storage.Exists(self._cs_bucket, self._cs_remote_path): + if not force: + #pylint: disable=nonstandard-exception + raise exceptions.CloudStorageUploadConflictError(self._cs_bucket, + self._cs_remote_path) + #pylint: enable=nonstandard-exception + logging.debug('A file already exists at upload path %s in self.cs_bucket' + ' %s', self._cs_remote_path, self._cs_bucket) + try: + cloud_storage.Copy(self._cs_bucket, self._cs_bucket, + self._cs_remote_path, self._cs_backup_path) + self._backed_up = True + except cloud_storage.CloudStorageError: + logging.error('Failed to copy existing file %s in cloud storage bucket ' + '%s to backup location %s', self._cs_remote_path, + self._cs_bucket, self._cs_backup_path) + raise + + try: + cloud_storage.Insert( + self._cs_bucket, self._cs_remote_path, self._local_path) + except cloud_storage.CloudStorageError: + logging.error('Failed to upload %s to %s in cloud_storage bucket %s', + self._local_path, self._cs_remote_path, self._cs_bucket) + raise + self._updated = True + + def Rollback(self): + """Attempt to undo the previous call to Upload. + + Does nothing if no previous call to Upload was made, or if nothing was + successfully changed. + + Returns: + True iff changes were successfully rolled back. + Raises: + CloudStorageError: If copying the backed up file to its original + location or removing the uploaded file fails. + """ + cloud_storage_changed = False + if self._backed_up: + cloud_storage.Copy(self._cs_bucket, self._cs_bucket, self._cs_backup_path, + self._cs_remote_path) + cloud_storage_changed = True + self._cs_backup_path = None + elif self._updated: + cloud_storage.Delete(self._cs_bucket, self._cs_remote_path) + cloud_storage_changed = True + self._updated = False + return cloud_storage_changed + + def __eq__(self, other, msg=None): + if type(self) != type(other): + return False + return (self._local_path == other._local_path and + self._cs_remote_path == other._cs_remote_path and + self._cs_bucket == other._cs_bucket) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader_unittest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader_unittest.py new file mode 100644 index 0000000..5c8e2a0 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/dependency_manager/uploader_unittest.py @@ -0,0 +1,91 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os + +from pyfakefs import fake_filesystem_unittest + +from dependency_manager import uploader + + +class CloudStorageUploaderTest(fake_filesystem_unittest.TestCase): + def setUp(self): + self.setUpPyfakefs() + self.bucket = 'cloud_storage_bucket' + self.local_path = os.path.abspath(os.path.join('path', 'to', 'dependency')) + self.fs.CreateFile(self.local_path) + self.remote_path = 'config_folder/remote_path' + + def testCloudStorageUploaderMissingData(self): + self.assertRaises(ValueError, uploader.CloudStorageUploader, + None, self.remote_path, self.local_path) + self.assertRaises(ValueError, uploader.CloudStorageUploader, + self.bucket, None, self.local_path) + self.assertRaises(ValueError, uploader.CloudStorageUploader, + self.bucket, self.remote_path, None) + + def testCloudStorageUploaderLocalFileMissing(self): + self.fs.RemoveObject(self.local_path) + self.assertRaises(ValueError, uploader.CloudStorageUploader, + self.bucket, self.remote_path, self.local_path) + + def testCloudStorageUploaderCreation(self): + upload_data = uploader.CloudStorageUploader( + self.bucket, self.remote_path, self.local_path) + expected_bucket = self.bucket + expected_remote_path = self.remote_path + expected_cs_backup_path = '%s.old' % expected_remote_path + expected_local_path = self.local_path + self.assertEqual(expected_bucket, upload_data._cs_bucket) + self.assertEqual(expected_remote_path, upload_data._cs_remote_path) + self.assertEqual(expected_local_path, upload_data._local_path) + self.assertEqual(expected_cs_backup_path, upload_data._cs_backup_path) + + def testCloudStorageUploaderEquality(self): + upload_data = uploader.CloudStorageUploader( + self.bucket, self.remote_path, self.local_path) + upload_data_exact = uploader.CloudStorageUploader( + self.bucket, self.remote_path, self.local_path) + upload_data_equal = uploader.CloudStorageUploader( + 'cloud_storage_bucket', + 'config_folder/remote_path', + os.path.abspath(os.path.join('path', 'to', 'dependency'))) + self.assertEqual(upload_data, upload_data) + self.assertEqual(upload_data, upload_data_exact) + self.assertEqual(upload_data_exact, upload_data) + self.assertEqual(upload_data, upload_data_equal) + self.assertEqual(upload_data_equal, upload_data) + + + def testCloudStorageUploaderInequality(self): + new_local_path = os.path.abspath(os.path.join('new', 'local', 'path')) + self.fs.CreateFile(new_local_path) + new_bucket = 'new_bucket' + new_remote_path = 'new_remote/path' + + upload_data = uploader.CloudStorageUploader( + self.bucket, self.remote_path, self.local_path) + upload_data_all_different = uploader.CloudStorageUploader( + new_bucket, new_remote_path, new_local_path) + upload_data_different_bucket = uploader.CloudStorageUploader( + new_bucket, self.remote_path, self.local_path) + upload_data_different_remote_path = uploader.CloudStorageUploader( + self.bucket, new_remote_path, self.local_path) + upload_data_different_local_path = uploader.CloudStorageUploader( + self.bucket, self.remote_path, new_local_path) + + self.assertNotEqual(upload_data, 'a string!') + self.assertNotEqual(upload_data, 0) + self.assertNotEqual(upload_data, 2354) + self.assertNotEqual(upload_data, None) + self.assertNotEqual(upload_data, upload_data_all_different) + self.assertNotEqual(upload_data_all_different, upload_data) + self.assertNotEqual(upload_data, upload_data_different_bucket) + self.assertNotEqual(upload_data_different_bucket, upload_data) + self.assertNotEqual(upload_data, upload_data_different_remote_path) + self.assertNotEqual(upload_data_different_remote_path, upload_data) + self.assertNotEqual(upload_data, upload_data_different_local_path) + self.assertNotEqual(upload_data_different_local_path, upload_data) + + #TODO: write unittests for upload and rollback diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/pylintrc b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/pylintrc new file mode 100644 index 0000000..4541fb8 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/dependency_manager/pylintrc @@ -0,0 +1,68 @@ +[MESSAGES CONTROL] + +# Disable the message, report, category or checker with the given id(s). +# TODO: Shrink this list to as small as possible. +disable= + design, + similarities, + + fixme, + locally-disabled, + locally-enabled, + missing-docstring, + no-member, + no-self-use, + protected-access, + star-args, + + +[REPORTS] + +# Don't write out full reports, just messages. +reports=no + + +[BASIC] + +# Regular expression which should only match correct function names. +function-rgx=^(?:(?PsetUp|tearDown|setUpModule|tearDownModule)|(?P_?[A-Z][a-zA-Z0-9]*))$ + +# Regular expression which should only match correct method names. +method-rgx=^(?:(?P_[a-z0-9_]+__|get|post|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass)|(?P(_{0,2}|test|assert)[A-Z][a-zA-Z0-9_]*))$ + +# Regular expression which should only match correct argument names. +argument-rgx=^[a-z][a-z0-9_]*$ + +# Regular expression which should only match correct variable names. +variable-rgx=^[a-z][a-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma. +good-names=main,_ + +# List of builtins function names that should not be used, separated by a comma. +bad-functions=apply,input,reduce + + +[VARIABLES] + +# Tells wether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching names used for dummy variables (i.e. not used). +dummy-variables-rgx=^\*{0,2}(_$|unused_) + + +[TYPECHECK] + +# Tells wether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + + +[FORMAT] + +# Maximum number of lines in a module. +max-module-lines=2000 + +# We use two spaces for indents, instead of the usual four spaces or tab. +indent-string=' ' diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/PRESUBMIT.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/PRESUBMIT.py new file mode 100644 index 0000000..289a5c6 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/PRESUBMIT.py @@ -0,0 +1,81 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Presubmit script for devil. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for +details on the presubmit API built into depot_tools. +""" + + +def _RunPylint(input_api, output_api): + return input_api.RunTests(input_api.canned_checks.RunPylint( + input_api, output_api, pylintrc='pylintrc')) + + +def _RunUnitTests(input_api, output_api): + def J(*dirs): + """Returns a path relative to presubmit directory.""" + return input_api.os_path.join( + input_api.PresubmitLocalPath(), 'devil', *dirs) + + test_env = dict(input_api.environ) + test_env.update({ + 'PYTHONDONTWRITEBYTECODE': '1', + 'PYTHONPATH': ':'.join([J(), J('..')]), + }) + + message_type = (output_api.PresubmitError if input_api.is_committing + else output_api.PresubmitPromptWarning) + + return input_api.RunTests([ + input_api.Command( + name='devil/bin/run_py_tests', + cmd=[ + input_api.os_path.join( + input_api.PresubmitLocalPath(), 'bin', 'run_py_tests')], + kwargs={'env': test_env}, + message=message_type)]) + + +def _EnsureNoPylibUse(input_api, output_api): + def other_python_files(f): + this_presubmit_file = input_api.os_path.join( + input_api.PresubmitLocalPath(), 'PRESUBMIT.py') + return (f.LocalPath().endswith('.py') + and not f.AbsoluteLocalPath() == this_presubmit_file) + + changed_files = input_api.AffectedSourceFiles(other_python_files) + import_error_re = input_api.re.compile( + r'(from pylib.* import)|(import pylib)') + + errors = [] + for f in changed_files: + errors.extend( + '%s:%d' % (f.LocalPath(), line_number) + for line_number, line_text in f.ChangedContents() + if import_error_re.search(line_text)) + + if errors: + return [output_api.PresubmitError( + 'pylib modules should not be imported from devil modules.', + items=errors)] + return [] + + +def CommonChecks(input_api, output_api): + output = [] + output += _RunPylint(input_api, output_api) + output += _RunUnitTests(input_api, output_api) + output += _EnsureNoPylibUse(input_api, output_api) + return output + + +def CheckChangeOnUpload(input_api, output_api): + return CommonChecks(input_api, output_api) + + +def CheckChangeOnCommit(input_api, output_api): + return CommonChecks(input_api, output_api) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/README.md b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/README.md new file mode 100644 index 0000000..852ac37 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/README.md @@ -0,0 +1,37 @@ + +## devil + +😈 + +devil is a library used by the Chromium developers to interact with Android +devices. It currently supports SDK level 16 and above. + +## Interfaces + +devil provides python APIs: + - [`devil.android.adb_wrapper`](docs/adb_wrapper.md) provides a thin wrapper + around the adb binary. Most functions and methods have direct analogues on + the adb command-line. + - [`devil.android.device_utils`](docs/device_utils.md) provides higher-level + functionality built on top of `adb_wrapper`. **This is the primary + mechanism through which chromium's scripts interact with devices.** + +## Utilities + +devil also provides command-line utilities: + - [`devil/utils/markdown.py`](docs/markdown.md) generated markdown + documentation for python modules. + +## Constraints and Caveats + +devil is used with python 2.7. Its compatibility with python 3 has not been +tested, and neither achieving nor maintaining said compatibility is currently +a priority. + +## Contributing + +Please see the [contributor's guide](https://github.com/catapult-project/catapult/blob/master/CONTRIBUTING.md). + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/__init__.py new file mode 100644 index 0000000..7de59c9 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/__init__.py @@ -0,0 +1,7 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging + +logging.getLogger('devil').addHandler(logging.NullHandler()) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/__init__.py new file mode 100644 index 0000000..50b23df --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper.py new file mode 100644 index 0000000..1a9b8c5 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper.py @@ -0,0 +1,164 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Module containing utilities for apk packages.""" + +import itertools +import re + +from devil import base_error +from devil.android.sdk import aapt + + +_MANIFEST_ATTRIBUTE_RE = re.compile( + r'\s*A: ([^\(\)= ]*)(?:\([^\(\)= ]*\))?=' + r'(?:"(.*)" \(Raw: .*\)|\(type.*?\)(.*))$') +_MANIFEST_ELEMENT_RE = re.compile(r'\s*(?:E|N): (\S*) .*$') + + +def GetPackageName(apk_path): + """Returns the package name of the apk.""" + return ApkHelper(apk_path).GetPackageName() + + +# TODO(jbudorick): Deprecate and remove this function once callers have been +# converted to ApkHelper.GetInstrumentationName +def GetInstrumentationName(apk_path): + """Returns the name of the Instrumentation in the apk.""" + return ApkHelper(apk_path).GetInstrumentationName() + + +def ToHelper(path_or_helper): + """Creates an ApkHelper unless one is already given.""" + if isinstance(path_or_helper, basestring): + return ApkHelper(path_or_helper) + return path_or_helper + + +def _ParseManifestFromApk(apk_path): + aapt_output = aapt.Dump('xmltree', apk_path, 'AndroidManifest.xml') + + parsed_manifest = {} + node_stack = [parsed_manifest] + indent = ' ' + + for line in aapt_output[1:]: + if len(line) == 0: + continue + + indent_depth = 0 + while line[(len(indent) * indent_depth):].startswith(indent): + indent_depth += 1 + + node_stack = node_stack[:indent_depth] + node = node_stack[-1] + + m = _MANIFEST_ELEMENT_RE.match(line[len(indent) * indent_depth:]) + if m: + manifest_key = m.group(1) + if manifest_key in node: + node[manifest_key] += [{}] + else: + node[manifest_key] = [{}] + node_stack += [node[manifest_key][-1]] + continue + + m = _MANIFEST_ATTRIBUTE_RE.match(line[len(indent) * indent_depth:]) + if m: + manifest_key = m.group(1) + if manifest_key in node: + raise base_error.BaseError( + "A single attribute should have one key and one value") + else: + node[manifest_key] = m.group(2) or m.group(3) + continue + + return parsed_manifest + + +class ApkHelper(object): + + def __init__(self, path): + self._apk_path = path + self._manifest = None + + @property + def path(self): + return self._apk_path + + def GetActivityName(self): + """Returns the name of the Activity in the apk.""" + manifest_info = self._GetManifest() + try: + activity = ( + manifest_info['manifest'][0]['application'][0]['activity'][0] + ['android:name']) + except KeyError: + return None + if '.' not in activity: + activity = '%s.%s' % (self.GetPackageName(), activity) + elif activity.startswith('.'): + activity = '%s%s' % (self.GetPackageName(), activity) + return activity + + def GetInstrumentationName( + self, default='android.test.InstrumentationTestRunner'): + """Returns the name of the Instrumentation in the apk.""" + all_instrumentations = self.GetAllInstrumentations(default=default) + if len(all_instrumentations) != 1: + raise base_error.BaseError( + 'There is more than one instrumentation. Expected one.') + else: + return all_instrumentations[0]['android:name'] + + def GetAllInstrumentations( + self, default='android.test.InstrumentationTestRunner'): + """Returns a list of all Instrumentations in the apk.""" + try: + return self._GetManifest()['manifest'][0]['instrumentation'] + except KeyError: + return [{'android:name': default}] + + def GetPackageName(self): + """Returns the package name of the apk.""" + manifest_info = self._GetManifest() + try: + return manifest_info['manifest'][0]['package'] + except KeyError: + raise Exception('Failed to determine package name of %s' % self._apk_path) + + def GetPermissions(self): + manifest_info = self._GetManifest() + try: + return [p['android:name'] for + p in manifest_info['manifest'][0]['uses-permission']] + except KeyError: + return [] + + def GetSplitName(self): + """Returns the name of the split of the apk.""" + manifest_info = self._GetManifest() + try: + return manifest_info['manifest'][0]['split'] + except KeyError: + return None + + def HasIsolatedProcesses(self): + """Returns whether any services exist that use isolatedProcess=true.""" + manifest_info = self._GetManifest() + try: + applications = manifest_info['manifest'][0].get('application', []) + services = itertools.chain( + *(application.get('service', []) for application in applications)) + return any( + int(s.get('android:isolatedProcess', '0'), 0) + for s in services) + except KeyError: + return False + + def _GetManifest(self): + if not self._manifest: + self._manifest = _ParseManifestFromApk(self._apk_path) + return self._manifest + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper_test.py new file mode 100644 index 0000000..f7d077d --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/apk_helper_test.py @@ -0,0 +1,169 @@ +#! /usr/bin/env python +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from devil import base_error +from devil import devil_env +from devil.android import apk_helper +from devil.utils import mock_calls + +with devil_env.SysPath(devil_env.PYMOCK_PATH): + import mock # pylint: disable=import-error + + +_MANIFEST_DUMP = """N: android=http://schemas.android.com/apk/res/android + E: manifest (line=1) + A: package="org.chromium.abc" (Raw: "org.chromium.abc") + A: split="random_split" (Raw: "random_split") + E: uses-permission (line=2) + A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET") + E: uses-permission (line=3) + A: android:name(0x01010003)="android.permission.READ_EXTERNAL_STORAGE" (Raw: "android.permission.READ_EXTERNAL_STORAGE") + E: uses-permission (line=4) + A: android:name(0x01010003)="android.permission.ACCESS_FINE_LOCATION" (Raw: "android.permission.ACCESS_FINE_LOCATION") + E: application (line=5) + E: activity (line=6) + A: android:name(0x01010003)="org.chromium.ActivityName" (Raw: "org.chromium.ActivityName") + A: android:exported(0x01010010)=(type 0x12)0xffffffff + E: service (line=7) + A: android:name(0x01010001)="org.chromium.RandomService" (Raw: "org.chromium.RandomService") + A: android:isolatedProcess(0x01010888)=(type 0x12)0xffffffff + E: instrumentation (line=8) + A: android:label(0x01010001)="abc" (Raw: "abc") + A: android:name(0x01010003)="org.chromium.RandomJUnit4TestRunner" (Raw: "org.chromium.RandomJUnit4TestRunner") + A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge") + A: junit4=(type 0x12)0xffffffff (Raw: "true") + E: instrumentation (line=9) + A: android:label(0x01010001)="abc" (Raw: "abc") + A: android:name(0x01010003)="org.chromium.RandomTestRunner" (Raw: "org.chromium.RandomTestRunner") + A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge") +""" + +_NO_ISOLATED_SERVICES = """N: android=http://schemas.android.com/apk/res/android + E: manifest (line=1) + A: package="org.chromium.abc" (Raw: "org.chromium.abc") + E: application (line=5) + E: activity (line=6) + A: android:name(0x01010003)="org.chromium.ActivityName" (Raw: "org.chromium.ActivityName") + A: android:exported(0x01010010)=(type 0x12)0xffffffff + E: service (line=7) + A: android:name(0x01010001)="org.chromium.RandomService" (Raw: "org.chromium.RandomService") +""" + +_NO_SERVICES = """N: android=http://schemas.android.com/apk/res/android + E: manifest (line=1) + A: package="org.chromium.abc" (Raw: "org.chromium.abc") + E: application (line=5) + E: activity (line=6) + A: android:name(0x01010003)="org.chromium.ActivityName" (Raw: "org.chromium.ActivityName") + A: android:exported(0x01010010)=(type 0x12)0xffffffff +""" + +_NO_APPLICATION = """N: android=http://schemas.android.com/apk/res/android + E: manifest (line=1) + A: package="org.chromium.abc" (Raw: "org.chromium.abc") +""" + +_SINGLE_INSTRUMENTATION_MANIFEST_DUMP = """N: android=http://schemas.android.com/apk/res/android + E: manifest (line=1) + A: package="org.chromium.xyz" (Raw: "org.chromium.xyz") + E: instrumentation (line=8) + A: android:label(0x01010001)="xyz" (Raw: "xyz") + A: android:name(0x01010003)="org.chromium.RandomTestRunner" (Raw: "org.chromium.RandomTestRunner") + A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge") +""" + +_SINGLE_J4_INSTRUMENTATION_MANIFEST_DUMP = """N: android=http://schemas.android.com/apk/res/android + E: manifest (line=1) + A: package="org.chromium.xyz" (Raw: "org.chromium.xyz") + E: instrumentation (line=8) + A: android:label(0x01010001)="xyz" (Raw: "xyz") + A: android:name(0x01010003)="org.chromium.RandomJ4TestRunner" (Raw: "org.chromium.RandomJ4TestRunner") + A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge") + A: junit4=(type 0x12)0xffffffff (Raw: "true") +""" + + +def _MockAaptDump(manifest_dump): + return mock.patch( + 'devil.android.sdk.aapt.Dump', + mock.Mock(side_effect=None, return_value=manifest_dump.split('\n'))) + +class ApkHelperTest(mock_calls.TestCase): + + def testGetInstrumentationName(self): + with _MockAaptDump(_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + with self.assertRaises(base_error.BaseError): + helper.GetInstrumentationName() + + def testGetActivityName(self): + with _MockAaptDump(_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + self.assertEquals( + helper.GetActivityName(), 'org.chromium.ActivityName') + + def testGetAllInstrumentations(self): + with _MockAaptDump(_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + all_instrumentations = helper.GetAllInstrumentations() + self.assertEquals(len(all_instrumentations), 2) + self.assertEquals(all_instrumentations[0]['android:name'], + 'org.chromium.RandomJUnit4TestRunner') + self.assertEquals(all_instrumentations[1]['android:name'], + 'org.chromium.RandomTestRunner') + + def testGetPackageName(self): + with _MockAaptDump(_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + self.assertEquals(helper.GetPackageName(), 'org.chromium.abc') + + def testGetPermssions(self): + with _MockAaptDump(_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + all_permissions = helper.GetPermissions() + self.assertEquals(len(all_permissions), 3) + self.assertTrue('android.permission.INTERNET' in all_permissions) + self.assertTrue( + 'android.permission.READ_EXTERNAL_STORAGE' in all_permissions) + self.assertTrue( + 'android.permission.ACCESS_FINE_LOCATION' in all_permissions) + + def testGetSplitName(self): + with _MockAaptDump(_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + self.assertEquals(helper.GetSplitName(), 'random_split') + + def testHasIsolatedProcesses_noApplication(self): + with _MockAaptDump(_NO_APPLICATION): + helper = apk_helper.ApkHelper("") + self.assertFalse(helper.HasIsolatedProcesses()) + + def testHasIsolatedProcesses_noServices(self): + with _MockAaptDump(_NO_SERVICES): + helper = apk_helper.ApkHelper("") + self.assertFalse(helper.HasIsolatedProcesses()) + + def testHasIsolatedProcesses_oneNotIsolatedProcess(self): + with _MockAaptDump(_NO_ISOLATED_SERVICES): + helper = apk_helper.ApkHelper("") + self.assertFalse(helper.HasIsolatedProcesses()) + + def testHasIsolatedProcesses_oneIsolatedProcess(self): + with _MockAaptDump(_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + self.assertTrue(helper.HasIsolatedProcesses()) + + def testGetSingleInstrumentationName(self): + with _MockAaptDump(_SINGLE_INSTRUMENTATION_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + self.assertEquals('org.chromium.RandomTestRunner', + helper.GetInstrumentationName()) + + def testGetSingleJUnit4InstrumentationName(self): + with _MockAaptDump(_SINGLE_J4_INSTRUMENTATION_MANIFEST_DUMP): + helper = apk_helper.ApkHelper("") + self.assertEquals('org.chromium.RandomJ4TestRunner', + helper.GetInstrumentationName()) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui.py new file mode 100644 index 0000000..2b04e8b --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui.py @@ -0,0 +1,243 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Provides functionality to interact with UI elements of an Android app.""" + +import collections +import re +from xml.etree import ElementTree as element_tree + +from devil.android import decorators +from devil.android import device_temp_file +from devil.utils import geometry +from devil.utils import timeout_retry + +_DEFAULT_SHORT_TIMEOUT = 10 +_DEFAULT_SHORT_RETRIES = 3 +_DEFAULT_LONG_TIMEOUT = 30 +_DEFAULT_LONG_RETRIES = 0 + +# Parse rectangle bounds given as: '[left,top][right,bottom]'. +_RE_BOUNDS = re.compile( + r'\[(?P\d+),(?P\d+)\]\[(?P\d+),(?P\d+)\]') + + +class _UiNode(object): + + def __init__(self, device, xml_node, package=None): + """Object to interact with a UI node from an xml snapshot. + + Note: there is usually no need to call this constructor directly. Instead, + use an AppUi object (below) to grab an xml screenshot from a device and + find nodes in it. + + Args: + device: A device_utils.DeviceUtils instance. + xml_node: An ElementTree instance of the node to interact with. + package: An optional package name for the app owning this node. + """ + self._device = device + self._xml_node = xml_node + self._package = package + + def _GetAttribute(self, key): + """Get the value of an attribute of this node.""" + return self._xml_node.attrib.get(key) + + @property + def bounds(self): + """Get a rectangle with the bounds of this UI node. + + Returns: + A geometry.Rectangle instance. + """ + d = _RE_BOUNDS.match(self._GetAttribute('bounds')).groupdict() + return geometry.Rectangle.FromDict({k: int(v) for k, v in d.iteritems()}) + + def Tap(self, point=None, dp_units=False): + """Send a tap event to the UI node. + + Args: + point: An optional geometry.Point instance indicating the location to + tap, relative to the bounds of the UI node, i.e. (0, 0) taps the + top-left corner. If ommited, the center of the node is tapped. + dp_units: If True, indicates that the coordinates of the point are given + in device-independent pixels; otherwise they are assumed to be "real" + pixels. This option has no effect when the point is ommited. + """ + if point is None: + point = self.bounds.center + else: + if dp_units: + point = (float(self._device.pixel_density) / 160) * point + point += self.bounds.top_left + + x, y = (str(int(v)) for v in point) + self._device.RunShellCommand(['input', 'tap', x, y], check_return=True) + + def Dump(self): + """Get a brief summary of the child nodes that can be found on this node. + + Returns: + A list of lines that can be logged or otherwise printed. + """ + summary = collections.defaultdict(set) + for node in self._xml_node.iter(): + package = node.get('package') or '(no package)' + label = node.get('resource-id') or '(no id)' + text = node.get('text') + if text: + label = '%s[%r]' % (label, text) + summary[package].add(label) + lines = [] + for package, labels in sorted(summary.iteritems()): + lines.append('- %s:' % package) + for label in sorted(labels): + lines.append(' - %s' % label) + return lines + + def __getitem__(self, key): + """Retrieve a child of this node by its index. + + Args: + key: An integer with the index of the child to retrieve. + Returns: + A UI node instance of the selected child. + Raises: + IndexError if the index is out of range. + """ + return type(self)(self._device, self._xml_node[key], package=self._package) + + def _Find(self, **kwargs): + """Find the first descendant node that matches a given criteria. + + Note: clients would usually call AppUi.GetUiNode or AppUi.WaitForUiNode + instead. + + For example: + + app = app_ui.AppUi(device, package='org.my.app') + app.GetUiNode(resource_id='some_element', text='hello') + + would retrieve the first matching node with both of the xml attributes: + + resource-id='org.my.app:id/some_element' + text='hello' + + As the example shows, if given and needed, the value of the resource_id key + is auto-completed with the package name specified in the AppUi constructor. + + Args: + Arguments are specified as key-value pairs, where keys correnspond to + attribute names in xml nodes (replacing any '-' with '_' to make them + valid identifiers). At least one argument must be supplied, and arguments + with a None value are ignored. + Returns: + A UI node instance of the first descendant node that matches ALL the + given key-value criteria; or None if no such node is found. + Raises: + TypeError if no search arguments are provided. + """ + matches_criteria = self._NodeMatcher(kwargs) + for node in self._xml_node.iter(): + if matches_criteria(node): + return type(self)(self._device, node, package=self._package) + return None + + def _NodeMatcher(self, kwargs): + # Auto-complete resource-id's using the package name if available. + resource_id = kwargs.get('resource_id') + if (resource_id is not None + and self._package is not None + and ':id/' not in resource_id): + kwargs['resource_id'] = '%s:id/%s' % (self._package, resource_id) + + criteria = [(k.replace('_', '-'), v) + for k, v in kwargs.iteritems() + if v is not None] + if not criteria: + raise TypeError('At least one search criteria should be specified') + return lambda node: all(node.get(k) == v for k, v in criteria) + + +class AppUi(object): + # timeout and retry arguments appear unused, but are handled by decorator. + # pylint: disable=unused-argument + + def __init__(self, device, package=None): + """Object to interact with the UI of an Android app. + + Args: + device: A device_utils.DeviceUtils instance. + package: An optional package name for the app. + """ + self._device = device + self._package = package + + @property + def package(self): + return self._package + + @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_SHORT_TIMEOUT, + _DEFAULT_SHORT_RETRIES) + def _GetRootUiNode(self, timeout=None, retries=None): + """Get a node pointing to the root of the UI nodes on screen. + + Note: This is currently implemented via adb calls to uiatomator and it + is *slow*, ~2 secs per call. Do not rely on low-level implementation + details that may change in the future. + + TODO(crbug.com/567217): Swap to a more efficient implementation. + + Args: + timeout: A number of seconds to wait for the uiautomator dump. + retries: Number of times to retry if the adb command fails. + Returns: + A UI node instance pointing to the root of the xml screenshot. + """ + with device_temp_file.DeviceTempFile(self._device.adb) as dtemp: + self._device.RunShellCommand(['uiautomator', 'dump', dtemp.name], + check_return=True) + xml_node = element_tree.fromstring( + self._device.ReadFile(dtemp.name, force_pull=True)) + return _UiNode(self._device, xml_node, package=self._package) + + def ScreenDump(self): + """Get a brief summary of the nodes that can be found on the screen. + + Returns: + A list of lines that can be logged or otherwise printed. + """ + return self._GetRootUiNode().Dump() + + def GetUiNode(self, **kwargs): + """Get the first node found matching a specified criteria. + + Args: + See _UiNode._Find. + Returns: + A UI node instance of the node if found, otherwise None. + """ + # pylint: disable=protected-access + return self._GetRootUiNode()._Find(**kwargs) + + @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_LONG_TIMEOUT, + _DEFAULT_LONG_RETRIES) + def WaitForUiNode(self, timeout=None, retries=None, **kwargs): + """Wait for a node matching a given criteria to appear on the screen. + + Args: + timeout: A number of seconds to wait for the matching node to appear. + retries: Number of times to retry in case of adb command errors. + For other args, to specify the search criteria, see _UiNode._Find. + Returns: + The UI node instance found. + Raises: + device_errors.CommandTimeoutError if the node is not found before the + timeout. + """ + def node_found(): + return self.GetUiNode(**kwargs) + + return timeout_retry.WaitFor(node_found) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui_test.py new file mode 100644 index 0000000..3472985 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/app_ui_test.py @@ -0,0 +1,191 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Unit tests for the app_ui module.""" + +import unittest +from xml.etree import ElementTree as element_tree + +from devil import devil_env +from devil.android import app_ui +from devil.android import device_errors +from devil.utils import geometry + +with devil_env.SysPath(devil_env.PYMOCK_PATH): + import mock # pylint: disable=import-error + + +MOCK_XML_LOADING = ''' + + + + +'''.strip() + + +MOCK_XML_LOADED = ''' + + + + + + + + + + + + + + + + + + +'''.strip() + + +class UiAppTest(unittest.TestCase): + + def setUp(self): + self.device = mock.Mock() + self.device.pixel_density = 320 # Each dp pixel is 2 real pixels. + self.app = app_ui.AppUi(self.device, package='com.example.app') + self._setMockXmlScreenshots([MOCK_XML_LOADED]) + + def _setMockXmlScreenshots(self, xml_docs): + """Mock self.app._GetRootUiNode to load nodes from some test xml_docs. + + Each time the method is called it will return a UI node for each string + given in |xml_docs|, or rise a time out error when the list is exhausted. + """ + # pylint: disable=protected-access + def get_mock_root_ui_node(value): + if isinstance(value, Exception): + raise value + return app_ui._UiNode( + self.device, element_tree.fromstring(value), self.app.package) + + xml_docs.append(device_errors.CommandTimeoutError('Timed out!')) + + self.app._GetRootUiNode = mock.Mock( + side_effect=(get_mock_root_ui_node(doc) for doc in xml_docs)) + + def assertNodeHasAttribs(self, node, attr): + # pylint: disable=protected-access + for key, value in attr.iteritems(): + self.assertEquals(node._GetAttribute(key), value) + + def assertTappedOnceAt(self, x, y): + self.device.RunShellCommand.assert_called_once_with( + ['input', 'tap', str(x), str(y)], check_return=True) + + def testFind_byText(self): + node = self.app.GetUiNode(text='Primary') + self.assertNodeHasAttribs(node, { + 'text': 'Primary', + 'content-desc': None, + 'resource-id': 'com.example.app:id/actionbar_title', + }) + self.assertEquals(node.bounds, geometry.Rectangle([121, 50], [1424, 178])) + + def testFind_byContentDesc(self): + node = self.app.GetUiNode(content_desc='Social') + self.assertNodeHasAttribs(node, { + 'text': None, + 'content-desc': 'Social', + 'resource-id': 'com.example.app:id/image_view', + }) + self.assertEquals(node.bounds, geometry.Rectangle([16, 466], [128, 578])) + + def testFind_byResourceId_autocompleted(self): + node = self.app.GetUiNode(resource_id='image_view') + self.assertNodeHasAttribs(node, { + 'content-desc': 'Primary', + 'resource-id': 'com.example.app:id/image_view', + }) + + def testFind_byResourceId_absolute(self): + node = self.app.GetUiNode(resource_id='com.example.app:id/image_view') + self.assertNodeHasAttribs(node, { + 'content-desc': 'Primary', + 'resource-id': 'com.example.app:id/image_view', + }) + + def testFind_byMultiple(self): + node = self.app.GetUiNode(resource_id='image_view', + content_desc='Promotions') + self.assertNodeHasAttribs(node, { + 'content-desc': 'Promotions', + 'resource-id': 'com.example.app:id/image_view', + }) + self.assertEquals(node.bounds, geometry.Rectangle([16, 578], [128, 690])) + + def testFind_notFound(self): + node = self.app.GetUiNode(resource_id='does_not_exist') + self.assertIsNone(node) + + def testFind_noArgsGiven(self): + # Same exception given by Python for a function call with not enough args. + with self.assertRaises(TypeError): + self.app.GetUiNode() + + def testGetChildren(self): + node = self.app.GetUiNode(resource_id='mini_drawer') + self.assertNodeHasAttribs( + node[0], {'resource-id': 'com.example.app:id/avatar'}) + self.assertNodeHasAttribs(node[1], {'content-desc': 'Primary'}) + self.assertNodeHasAttribs(node[2], {'content-desc': 'Social'}) + self.assertNodeHasAttribs(node[3], {'content-desc': 'Promotions'}) + with self.assertRaises(IndexError): + # pylint: disable=pointless-statement + node[4] + + def testTap_center(self): + node = self.app.GetUiNode(content_desc='Open navigation drawer') + node.Tap() + self.assertTappedOnceAt(56, 114) + + def testTap_topleft(self): + node = self.app.GetUiNode(content_desc='Open navigation drawer') + node.Tap(geometry.Point(0, 0)) + self.assertTappedOnceAt(0, 58) + + def testTap_withOffset(self): + node = self.app.GetUiNode(content_desc='Open navigation drawer') + node.Tap(geometry.Point(10, 20)) + self.assertTappedOnceAt(10, 78) + + def testTap_withOffsetInDp(self): + node = self.app.GetUiNode(content_desc='Open navigation drawer') + node.Tap(geometry.Point(10, 20), dp_units=True) + self.assertTappedOnceAt(20, 98) + + def testTap_dpUnitsIgnored(self): + node = self.app.GetUiNode(content_desc='Open navigation drawer') + node.Tap(dp_units=True) + self.assertTappedOnceAt(56, 114) # Still taps at center. + + @mock.patch('time.sleep', mock.Mock()) + def testWaitForUiNode_found(self): + self._setMockXmlScreenshots( + [MOCK_XML_LOADING, MOCK_XML_LOADING, MOCK_XML_LOADED]) + node = self.app.WaitForUiNode(resource_id='actionbar_title') + self.assertNodeHasAttribs(node, {'text': 'Primary'}) + + @mock.patch('time.sleep', mock.Mock()) + def testWaitForUiNode_notFound(self): + self._setMockXmlScreenshots( + [MOCK_XML_LOADING, MOCK_XML_LOADING, MOCK_XML_LOADING]) + with self.assertRaises(device_errors.CommandTimeoutError): + self.app.WaitForUiNode(resource_id='actionbar_title') diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils.py new file mode 100644 index 0000000..068c187 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils.py @@ -0,0 +1,711 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Provides a variety of device interactions with power. +""" +# pylint: disable=unused-argument + +import collections +import contextlib +import csv +import logging + +from devil.android import decorators +from devil.android import device_errors +from devil.android import device_utils +from devil.android.sdk import version_codes +from devil.utils import timeout_retry + +logger = logging.getLogger(__name__) + +_DEFAULT_TIMEOUT = 30 +_DEFAULT_RETRIES = 3 + + +_DEVICE_PROFILES = [ + { + 'name': ['Nexus 4'], + 'enable_command': ( + 'echo 0 > /sys/module/pm8921_charger/parameters/disabled && ' + 'dumpsys battery reset'), + 'disable_command': ( + 'echo 1 > /sys/module/pm8921_charger/parameters/disabled && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': None, + 'voltage': None, + 'current': None, + }, + { + 'name': ['Nexus 5'], + # Nexus 5 + # Setting the HIZ bit of the bq24192 causes the charger to actually ignore + # energy coming from USB. Setting the power_supply offline just updates the + # Android system to reflect that. + 'enable_command': ( + 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' + 'chmod 644 /sys/class/power_supply/usb/online && ' + 'echo 1 > /sys/class/power_supply/usb/online && ' + 'dumpsys battery reset'), + 'disable_command': ( + 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' + 'chmod 644 /sys/class/power_supply/usb/online && ' + 'echo 0 > /sys/class/power_supply/usb/online && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': None, + 'voltage': None, + 'current': None, + }, + { + 'name': ['Nexus 6'], + 'enable_command': ( + 'echo 1 > /sys/class/power_supply/battery/charging_enabled && ' + 'dumpsys battery reset'), + 'disable_command': ( + 'echo 0 > /sys/class/power_supply/battery/charging_enabled && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': ( + '/sys/class/power_supply/max170xx_battery/charge_counter_ext'), + 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now', + 'current': '/sys/class/power_supply/max170xx_battery/current_now', + }, + { + 'name': ['Nexus 9'], + 'enable_command': ( + 'echo Disconnected > ' + '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && ' + 'dumpsys battery reset'), + 'disable_command': ( + 'echo Connected > ' + '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': '/sys/class/power_supply/battery/charge_counter_ext', + 'voltage': '/sys/class/power_supply/battery/voltage_now', + 'current': '/sys/class/power_supply/battery/current_now', + }, + { + 'name': ['Nexus 10'], + 'enable_command': None, + 'disable_command': None, + 'charge_counter': None, + 'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now', + 'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now', + + }, + { + 'name': ['Nexus 5X'], + 'enable_command': ( + 'echo 1 > /sys/class/power_supply/battery/charging_enabled && ' + 'dumpsys battery reset'), + 'disable_command': ( + 'echo 0 > /sys/class/power_supply/battery/charging_enabled && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': None, + 'voltage': None, + 'current': None, + }, + { # Galaxy s5 + 'name': ['SM-G900H'], + 'enable_command': ( + 'chmod 644 /sys/class/power_supply/battery/test_mode && ' + 'chmod 644 /sys/class/power_supply/sec-charger/current_now && ' + 'echo 0 > /sys/class/power_supply/battery/test_mode && ' + 'echo 9999 > /sys/class/power_supply/sec-charger/current_now &&' + 'dumpsys battery reset'), + 'disable_command': ( + 'chmod 644 /sys/class/power_supply/battery/test_mode && ' + 'chmod 644 /sys/class/power_supply/sec-charger/current_now && ' + 'echo 1 > /sys/class/power_supply/battery/test_mode && ' + 'echo 0 > /sys/class/power_supply/sec-charger/current_now && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': None, + 'voltage': '/sys/class/power_supply/sec-fuelgauge/voltage_now', + 'current': '/sys/class/power_supply/sec-charger/current_now', + }, + { # Galaxy s6, Galaxy s6, Galaxy s6 edge + 'name': ['SM-G920F', 'SM-G920V', 'SM-G925V'], + 'enable_command': ( + 'chmod 644 /sys/class/power_supply/battery/test_mode && ' + 'chmod 644 /sys/class/power_supply/max77843-charger/current_now && ' + 'echo 0 > /sys/class/power_supply/battery/test_mode && ' + 'echo 9999 > /sys/class/power_supply/max77843-charger/current_now &&' + 'dumpsys battery reset'), + 'disable_command': ( + 'chmod 644 /sys/class/power_supply/battery/test_mode && ' + 'chmod 644 /sys/class/power_supply/max77843-charger/current_now && ' + 'echo 1 > /sys/class/power_supply/battery/test_mode && ' + 'echo 0 > /sys/class/power_supply/max77843-charger/current_now && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': None, + 'voltage': '/sys/class/power_supply/max77843-fuelgauge/voltage_now', + 'current': '/sys/class/power_supply/max77843-charger/current_now', + }, + { # Cherry Mobile One + 'name': ['W6210 (4560MMX_b fingerprint)'], + 'enable_command': ( + 'echo "0 0" > /proc/mtk_battery_cmd/current_cmd && ' + 'dumpsys battery reset'), + 'disable_command': ( + 'echo "0 1" > /proc/mtk_battery_cmd/current_cmd && ' + 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), + 'charge_counter': None, + 'voltage': None, + 'current': None, +}, +] + +# The list of useful dumpsys columns. +# Index of the column containing the format version. +_DUMP_VERSION_INDEX = 0 +# Index of the column containing the type of the row. +_ROW_TYPE_INDEX = 3 +# Index of the column containing the uid. +_PACKAGE_UID_INDEX = 4 +# Index of the column containing the application package. +_PACKAGE_NAME_INDEX = 5 +# The column containing the uid of the power data. +_PWI_UID_INDEX = 1 +# The column containing the type of consumption. Only consumption since last +# charge are of interest here. +_PWI_AGGREGATION_INDEX = 2 +_PWS_AGGREGATION_INDEX = _PWI_AGGREGATION_INDEX +# The column containing the amount of power used, in mah. +_PWI_POWER_CONSUMPTION_INDEX = 5 +_PWS_POWER_CONSUMPTION_INDEX = _PWI_POWER_CONSUMPTION_INDEX + +_MAX_CHARGE_ERROR = 20 + + +class BatteryUtils(object): + + def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, + default_retries=_DEFAULT_RETRIES): + """BatteryUtils constructor. + + Args: + device: A DeviceUtils instance. + default_timeout: An integer containing the default number of seconds to + wait for an operation to complete if no explicit value + is provided. + default_retries: An integer containing the default number or times an + operation should be retried on failure if no explicit + value is provided. + Raises: + TypeError: If it is not passed a DeviceUtils instance. + """ + if not isinstance(device, device_utils.DeviceUtils): + raise TypeError('Must be initialized with DeviceUtils object.') + self._device = device + self._cache = device.GetClientCache(self.__class__.__name__) + self._default_timeout = default_timeout + self._default_retries = default_retries + + @decorators.WithTimeoutAndRetriesFromInstance() + def SupportsFuelGauge(self, timeout=None, retries=None): + """Detect if fuel gauge chip is present. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + True if known fuel gauge files are present. + False otherwise. + """ + self._DiscoverDeviceProfile() + return (self._cache['profile']['enable_command'] != None + and self._cache['profile']['charge_counter'] != None) + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetFuelGaugeChargeCounter(self, timeout=None, retries=None): + """Get value of charge_counter on fuel gauge chip. + + Device must have charging disabled for this, not just battery updates + disabled. The only device that this currently works with is the nexus 5. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + value of charge_counter for fuel gauge chip in units of nAh. + + Raises: + device_errors.CommandFailedError: If fuel gauge chip not found. + """ + if self.SupportsFuelGauge(): + return int(self._device.ReadFile( + self._cache['profile']['charge_counter'])) + raise device_errors.CommandFailedError( + 'Unable to find fuel gauge.') + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetNetworkData(self, package, timeout=None, retries=None): + """Get network data for specific package. + + Args: + package: package name you want network data for. + timeout: timeout in seconds + retries: number of retries + + Returns: + Tuple of (sent_data, recieved_data) + None if no network data found + """ + # If device_utils clears cache, cache['uids'] doesn't exist + if 'uids' not in self._cache: + self._cache['uids'] = {} + if package not in self._cache['uids']: + self.GetPowerData() + if package not in self._cache['uids']: + logger.warning('No UID found for %s. Can\'t get network data.', + package) + return None + + network_data_path = '/proc/uid_stat/%s/' % self._cache['uids'][package] + try: + send_data = int(self._device.ReadFile(network_data_path + 'tcp_snd')) + # If ReadFile throws exception, it means no network data usage file for + # package has been recorded. Return 0 sent and 0 received. + except device_errors.AdbShellCommandFailedError: + logger.warning('No sent data found for package %s', package) + send_data = 0 + try: + recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv')) + except device_errors.AdbShellCommandFailedError: + logger.warning('No received data found for package %s', package) + recv_data = 0 + return (send_data, recv_data) + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetPowerData(self, timeout=None, retries=None): + """Get power data for device. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + Dict containing system power, and a per-package power dict keyed on + package names. + { + 'system_total': 23.1, + 'per_package' : { + package_name: { + 'uid': uid, + 'data': [1,2,3] + }, + } + } + """ + if 'uids' not in self._cache: + self._cache['uids'] = {} + dumpsys_output = self._device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True) + csvreader = csv.reader(dumpsys_output) + pwi_entries = collections.defaultdict(list) + system_total = None + for entry in csvreader: + if entry[_DUMP_VERSION_INDEX] not in ['8', '9']: + # Wrong dumpsys version. + raise device_errors.DeviceVersionError( + 'Dumpsys version must be 8 or 9. "%s" found.' + % entry[_DUMP_VERSION_INDEX]) + if _ROW_TYPE_INDEX < len(entry) and entry[_ROW_TYPE_INDEX] == 'uid': + current_package = entry[_PACKAGE_NAME_INDEX] + if (self._cache['uids'].get(current_package) + and self._cache['uids'].get(current_package) + != entry[_PACKAGE_UID_INDEX]): + raise device_errors.CommandFailedError( + 'Package %s found multiple times with different UIDs %s and %s' + % (current_package, self._cache['uids'][current_package], + entry[_PACKAGE_UID_INDEX])) + self._cache['uids'][current_package] = entry[_PACKAGE_UID_INDEX] + elif (_PWI_POWER_CONSUMPTION_INDEX < len(entry) + and entry[_ROW_TYPE_INDEX] == 'pwi' + and entry[_PWI_AGGREGATION_INDEX] == 'l'): + pwi_entries[entry[_PWI_UID_INDEX]].append( + float(entry[_PWI_POWER_CONSUMPTION_INDEX])) + elif (_PWS_POWER_CONSUMPTION_INDEX < len(entry) + and entry[_ROW_TYPE_INDEX] == 'pws' + and entry[_PWS_AGGREGATION_INDEX] == 'l'): + # This entry should only appear once. + assert system_total is None + system_total = float(entry[_PWS_POWER_CONSUMPTION_INDEX]) + + per_package = {p: {'uid': uid, 'data': pwi_entries[uid]} + for p, uid in self._cache['uids'].iteritems()} + return {'system_total': system_total, 'per_package': per_package} + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetBatteryInfo(self, timeout=None, retries=None): + """Gets battery info for the device. + + Args: + timeout: timeout in seconds + retries: number of retries + Returns: + A dict containing various battery information as reported by dumpsys + battery. + """ + result = {} + # Skip the first line, which is just a header. + for line in self._device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True)[1:]: + # If usb charging has been disabled, an extra line of header exists. + if 'UPDATES STOPPED' in line: + logger.warning('Dumpsys battery not receiving updates. ' + 'Run dumpsys battery reset if this is in error.') + elif ':' not in line: + logger.warning('Unknown line found in dumpsys battery: "%s"', line) + else: + k, v = line.split(':', 1) + result[k.strip()] = v.strip() + return result + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetCharging(self, timeout=None, retries=None): + """Gets the charging state of the device. + + Args: + timeout: timeout in seconds + retries: number of retries + Returns: + True if the device is charging, false otherwise. + """ + battery_info = self.GetBatteryInfo() + for k in ('AC powered', 'USB powered', 'Wireless powered'): + if (k in battery_info and + battery_info[k].lower() in ('true', '1', 'yes')): + return True + return False + + # TODO(rnephew): Make private when all use cases can use the context manager. + @decorators.WithTimeoutAndRetriesFromInstance() + def DisableBatteryUpdates(self, timeout=None, retries=None): + """Resets battery data and makes device appear like it is not + charging so that it will collect power data since last charge. + + Args: + timeout: timeout in seconds + retries: number of retries + + Raises: + device_errors.CommandFailedError: When resetting batterystats fails to + reset power values. + device_errors.DeviceVersionError: If device is not L or higher. + """ + def battery_updates_disabled(): + return self.GetCharging() is False + + self._ClearPowerData() + self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'], + check_return=True) + self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'], + check_return=True) + timeout_retry.WaitFor(battery_updates_disabled, wait_period=1) + + # TODO(rnephew): Make private when all use cases can use the context manager. + @decorators.WithTimeoutAndRetriesFromInstance() + def EnableBatteryUpdates(self, timeout=None, retries=None): + """Restarts device charging so that dumpsys no longer collects power data. + + Args: + timeout: timeout in seconds + retries: number of retries + + Raises: + device_errors.DeviceVersionError: If device is not L or higher. + """ + def battery_updates_enabled(): + return (self.GetCharging() + or not bool('UPDATES STOPPED' in self._device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True))) + + self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], + check_return=True) + timeout_retry.WaitFor(battery_updates_enabled, wait_period=1) + + @contextlib.contextmanager + def BatteryMeasurement(self, timeout=None, retries=None): + """Context manager that enables battery data collection. It makes + the device appear to stop charging so that dumpsys will start collecting + power data since last charge. Once the with block is exited, charging is + resumed and power data since last charge is no longer collected. + + Only for devices L and higher. + + Example usage: + with BatteryMeasurement(): + browser_actions() + get_power_data() # report usage within this block + after_measurements() # Anything that runs after power + # measurements are collected + + Args: + timeout: timeout in seconds + retries: number of retries + + Raises: + device_errors.DeviceVersionError: If device is not L or higher. + """ + if self._device.build_version_sdk < version_codes.LOLLIPOP: + raise device_errors.DeviceVersionError('Device must be L or higher.') + try: + self.DisableBatteryUpdates(timeout=timeout, retries=retries) + yield + finally: + self.EnableBatteryUpdates(timeout=timeout, retries=retries) + + def _DischargeDevice(self, percent, wait_period=120): + """Disables charging and waits for device to discharge given amount + + Args: + percent: level of charge to discharge. + + Raises: + ValueError: If percent is not between 1 and 99. + """ + battery_level = int(self.GetBatteryInfo().get('level')) + if not 0 < percent < 100: + raise ValueError('Discharge amount(%s) must be between 1 and 99' + % percent) + if battery_level is None: + logger.warning('Unable to find current battery level. Cannot discharge.') + return + # Do not discharge if it would make battery level too low. + if percent >= battery_level - 10: + logger.warning('Battery is too low or discharge amount requested is too ' + 'high. Cannot discharge phone %s percent.', percent) + return + + self._HardwareSetCharging(False) + + def device_discharged(): + self._HardwareSetCharging(True) + current_level = int(self.GetBatteryInfo().get('level')) + logger.info('current battery level: %s', current_level) + if battery_level - current_level >= percent: + return True + self._HardwareSetCharging(False) + return False + + timeout_retry.WaitFor(device_discharged, wait_period=wait_period) + + def ChargeDeviceToLevel(self, level, wait_period=60): + """Enables charging and waits for device to be charged to given level. + + Args: + level: level of charge to wait for. + wait_period: time in seconds to wait between checking. + Raises: + device_errors.DeviceChargingError: If error while charging is detected. + """ + self.SetCharging(True) + charge_status = { + 'charge_failure_count': 0, + 'last_charge_value': 0 + } + def device_charged(): + battery_level = self.GetBatteryInfo().get('level') + if battery_level is None: + logger.warning('Unable to find current battery level.') + battery_level = 100 + else: + logger.info('current battery level: %s', battery_level) + battery_level = int(battery_level) + + # Use > so that it will not reset if charge is going down. + if battery_level > charge_status['last_charge_value']: + charge_status['last_charge_value'] = battery_level + charge_status['charge_failure_count'] = 0 + else: + charge_status['charge_failure_count'] += 1 + + if (not battery_level >= level + and charge_status['charge_failure_count'] >= _MAX_CHARGE_ERROR): + raise device_errors.DeviceChargingError( + 'Device not charging properly. Current level:%s Previous level:%s' + % (battery_level, charge_status['last_charge_value'])) + return battery_level >= level + + timeout_retry.WaitFor(device_charged, wait_period=wait_period) + + def LetBatteryCoolToTemperature(self, target_temp, wait_period=180): + """Lets device sit to give battery time to cool down + Args: + temp: maximum temperature to allow in tenths of degrees c. + wait_period: time in seconds to wait between checking. + """ + def cool_device(): + temp = self.GetBatteryInfo().get('temperature') + if temp is None: + logger.warning('Unable to find current battery temperature.') + temp = 0 + else: + logger.info('Current battery temperature: %s', temp) + if int(temp) <= target_temp: + return True + else: + if 'Nexus 5' in self._cache['profile']['name']: + self._DischargeDevice(1) + return False + + self._DiscoverDeviceProfile() + self.EnableBatteryUpdates() + logger.info('Waiting for the device to cool down to %s (0.1 C)', + target_temp) + timeout_retry.WaitFor(cool_device, wait_period=wait_period) + + @decorators.WithTimeoutAndRetriesFromInstance() + def SetCharging(self, enabled, timeout=None, retries=None): + """Enables or disables charging on the device. + + Args: + enabled: A boolean indicating whether charging should be enabled or + disabled. + timeout: timeout in seconds + retries: number of retries + """ + if self.GetCharging() == enabled: + logger.warning('Device charging already in expected state: %s', enabled) + return + + self._DiscoverDeviceProfile() + if enabled: + if self._cache['profile']['enable_command']: + self._HardwareSetCharging(enabled) + else: + logger.info('Unable to enable charging via hardware. ' + 'Falling back to software enabling.') + self.EnableBatteryUpdates() + else: + if self._cache['profile']['enable_command']: + self._ClearPowerData() + self._HardwareSetCharging(enabled) + else: + logger.info('Unable to disable charging via hardware. ' + 'Falling back to software disabling.') + self.DisableBatteryUpdates() + + def _HardwareSetCharging(self, enabled, timeout=None, retries=None): + """Enables or disables charging on the device. + + Args: + enabled: A boolean indicating whether charging should be enabled or + disabled. + timeout: timeout in seconds + retries: number of retries + + Raises: + device_errors.CommandFailedError: If method of disabling charging cannot + be determined. + """ + self._DiscoverDeviceProfile() + if not self._cache['profile']['enable_command']: + raise device_errors.CommandFailedError( + 'Unable to find charging commands.') + + command = (self._cache['profile']['enable_command'] if enabled + else self._cache['profile']['disable_command']) + + def verify_charging(): + return self.GetCharging() == enabled + + self._device.RunShellCommand( + command, check_return=True, as_root=True, large_output=True) + timeout_retry.WaitFor(verify_charging, wait_period=1) + + @contextlib.contextmanager + def PowerMeasurement(self, timeout=None, retries=None): + """Context manager that enables battery power collection. + + Once the with block is exited, charging is resumed. Will attempt to disable + charging at the hardware level, and if that fails will fall back to software + disabling of battery updates. + + Only for devices L and higher. + + Example usage: + with PowerMeasurement(): + browser_actions() + get_power_data() # report usage within this block + after_measurements() # Anything that runs after power + # measurements are collected + + Args: + timeout: timeout in seconds + retries: number of retries + """ + try: + self.SetCharging(False, timeout=timeout, retries=retries) + yield + finally: + self.SetCharging(True, timeout=timeout, retries=retries) + + def _ClearPowerData(self): + """Resets battery data and makes device appear like it is not + charging so that it will collect power data since last charge. + + Returns: + True if power data cleared. + False if power data clearing is not supported (pre-L) + + Raises: + device_errors.DeviceVersionError: If power clearing is supported, + but fails. + """ + if self._device.build_version_sdk < version_codes.LOLLIPOP: + logger.warning('Dumpsys power data only available on 5.0 and above. ' + 'Cannot clear power data.') + return False + + self._device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True) + self._device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True) + + def test_if_clear(): + self._device.RunShellCommand( + ['dumpsys', 'batterystats', '--reset'], check_return=True) + battery_data = self._device.RunShellCommand( + ['dumpsys', 'batterystats', '--charged', '-c'], + check_return=True, large_output=True) + for line in battery_data: + l = line.split(',') + if (len(l) > _PWI_POWER_CONSUMPTION_INDEX + and l[_ROW_TYPE_INDEX] == 'pwi' + and float(l[_PWI_POWER_CONSUMPTION_INDEX]) != 0.0): + return False + return True + + try: + timeout_retry.WaitFor(test_if_clear, wait_period=1) + return True + finally: + self._device.RunShellCommand( + ['dumpsys', 'battery', 'reset'], check_return=True) + + def _DiscoverDeviceProfile(self): + """Checks and caches device information. + + Returns: + True if profile is found, false otherwise. + """ + + if 'profile' in self._cache: + return True + for profile in _DEVICE_PROFILES: + if self._device.product_model in profile['name']: + self._cache['profile'] = profile + return True + self._cache['profile'] = { + 'name': [], + 'enable_command': None, + 'disable_command': None, + 'charge_counter': None, + 'voltage': None, + 'current': None, + } + return False diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils_test.py new file mode 100644 index 0000000..beaba3b --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/battery_utils_test.py @@ -0,0 +1,694 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Unit tests for the contents of battery_utils.py +""" + +# pylint: disable=protected-access,unused-argument + +import logging +import unittest + +from devil import devil_env +from devil.android import battery_utils +from devil.android import device_errors +from devil.android import device_utils +from devil.android import device_utils_test +from devil.utils import mock_calls + +with devil_env.SysPath(devil_env.PYMOCK_PATH): + import mock # pylint: disable=import-error + +_DUMPSYS_OUTPUT = [ + '9,0,i,uid,1000,test_package1', + '9,0,i,uid,1001,test_package2', + '9,1000,l,pwi,uid,1', + '9,1001,l,pwi,uid,2', + '9,0,l,pws,1728,2000,190,207', +] + + +class BatteryUtilsTest(mock_calls.TestCase): + + _NEXUS_5 = { + 'name': 'Nexus 5', + 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT', + 'enable_command': ( + 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' + 'echo 1 > /sys/class/power_supply/usb/online'), + 'disable_command': ( + 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' + 'chmod 644 /sys/class/power_supply/usb/online && ' + 'echo 0 > /sys/class/power_supply/usb/online'), + 'charge_counter': None, + 'voltage': None, + 'current': None, + } + + _NEXUS_6 = { + 'name': 'Nexus 6', + 'witness_file': None, + 'enable_command': None, + 'disable_command': None, + 'charge_counter': ( + '/sys/class/power_supply/max170xx_battery/charge_counter_ext'), + 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now', + 'current': '/sys/class/power_supply/max170xx_battery/current_now', + } + + _NEXUS_10 = { + 'name': 'Nexus 10', + 'witness_file': None, + 'enable_command': None, + 'disable_command': None, + 'charge_counter': ( + '/sys/class/power_supply/ds2784-fuelgauge/charge_counter_ext'), + 'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now', + 'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now', + } + + def ShellError(self, output=None, status=1): + def action(cmd, *args, **kwargs): + raise device_errors.AdbShellCommandFailedError( + cmd, output, status, str(self.device)) + if output is None: + output = 'Permission denied\n' + return action + + def setUp(self): + self.adb = device_utils_test._AdbWrapperMock('0123456789abcdef') + self.device = device_utils.DeviceUtils( + self.adb, default_timeout=10, default_retries=0) + self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial']) + self.battery = battery_utils.BatteryUtils( + self.device, default_timeout=10, default_retries=0) + + +class BatteryUtilsInitTest(unittest.TestCase): + + def testInitWithDeviceUtil(self): + serial = '0fedcba987654321' + d = device_utils.DeviceUtils(serial) + b = battery_utils.BatteryUtils(d) + self.assertEqual(d, b._device) + + def testInitWithMissing_fails(self): + with self.assertRaises(TypeError): + battery_utils.BatteryUtils(None) + with self.assertRaises(TypeError): + battery_utils.BatteryUtils('') + + +class BatteryUtilsSetChargingTest(BatteryUtilsTest): + + @mock.patch('time.sleep', mock.Mock()) + def testHardwareSetCharging_enabled(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.device.RunShellCommand( + mock.ANY, check_return=True, as_root=True, large_output=True), []), + (self.call.battery.GetCharging(), False), + (self.call.battery.GetCharging(), True)): + self.battery._HardwareSetCharging(True) + + def testHardwareSetCharging_alreadyEnabled(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.device.RunShellCommand( + mock.ANY, check_return=True, as_root=True, large_output=True), []), + (self.call.battery.GetCharging(), True)): + self.battery._HardwareSetCharging(True) + + @mock.patch('time.sleep', mock.Mock()) + def testHardwareSetCharging_disabled(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.device.RunShellCommand( + mock.ANY, check_return=True, as_root=True, large_output=True), []), + (self.call.battery.GetCharging(), True), + (self.call.battery.GetCharging(), False)): + self.battery._HardwareSetCharging(False) + + +class BatteryUtilsSetBatteryMeasurementTest(BatteryUtilsTest): + + @mock.patch('time.sleep', mock.Mock()) + def testBatteryMeasurementWifi(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=22): + with self.assertCalls( + (self.call.battery._ClearPowerData(), True), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), + []), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'reset'], check_return=True), []), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True), [])): + with self.battery.BatteryMeasurement(): + pass + + @mock.patch('time.sleep', mock.Mock()) + def testBatteryMeasurementUsb(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=22): + with self.assertCalls( + (self.call.battery._ClearPowerData(), True), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), + []), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'reset'], check_return=True), []), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']), + (self.call.battery.GetCharging(), True)): + with self.battery.BatteryMeasurement(): + pass + + +class BatteryUtilsGetPowerData(BatteryUtilsTest): + + def testGetPowerData(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT)): + data = self.battery.GetPowerData() + check = { + 'system_total': 2000.0, + 'per_package': { + 'test_package1': {'uid': '1000', 'data': [1.0]}, + 'test_package2': {'uid': '1001', 'data': [2.0]} + } + } + self.assertEqual(data, check) + + def testGetPowerData_packageCollisionSame(self): + self.battery._cache['uids'] = {'test_package1': '1000'} + with self.assertCall( + self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT): + data = self.battery.GetPowerData() + check = { + 'system_total': 2000.0, + 'per_package': { + 'test_package1': {'uid': '1000', 'data': [1.0]}, + 'test_package2': {'uid': '1001', 'data': [2.0]} + } + } + self.assertEqual(data, check) + + def testGetPowerData_packageCollisionDifferent(self): + self.battery._cache['uids'] = {'test_package1': '1'} + with self.assertCall( + self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT): + with self.assertRaises(device_errors.CommandFailedError): + self.battery.GetPowerData() + + def testGetPowerData_cacheCleared(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT)): + self.battery._cache.clear() + data = self.battery.GetPowerData() + check = { + 'system_total': 2000.0, + 'per_package': { + 'test_package1': {'uid': '1000', 'data': [1.0]}, + 'test_package2': {'uid': '1001', 'data': [2.0]} + } + } + self.assertEqual(data, check) + + +class BatteryUtilsChargeDevice(BatteryUtilsTest): + + @mock.patch('time.sleep', mock.Mock()) + def testChargeDeviceToLevel_pass(self): + with self.assertCalls( + (self.call.battery.SetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '50'}), + (self.call.battery.GetBatteryInfo(), {'level': '100'})): + self.battery.ChargeDeviceToLevel(95) + + @mock.patch('time.sleep', mock.Mock()) + def testChargeDeviceToLevel_failureSame(self): + with self.assertCalls( + (self.call.battery.SetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '50'}), + (self.call.battery.GetBatteryInfo(), {'level': '50'}), + + (self.call.battery.GetBatteryInfo(), {'level': '50'})): + with self.assertRaises(device_errors.DeviceChargingError): + old_max = battery_utils._MAX_CHARGE_ERROR + try: + battery_utils._MAX_CHARGE_ERROR = 2 + self.battery.ChargeDeviceToLevel(95) + finally: + battery_utils._MAX_CHARGE_ERROR = old_max + + @mock.patch('time.sleep', mock.Mock()) + def testChargeDeviceToLevel_failureDischarge(self): + with self.assertCalls( + (self.call.battery.SetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '50'}), + (self.call.battery.GetBatteryInfo(), {'level': '49'}), + (self.call.battery.GetBatteryInfo(), {'level': '48'})): + with self.assertRaises(device_errors.DeviceChargingError): + old_max = battery_utils._MAX_CHARGE_ERROR + try: + battery_utils._MAX_CHARGE_ERROR = 2 + self.battery.ChargeDeviceToLevel(95) + finally: + battery_utils._MAX_CHARGE_ERROR = old_max + + +class BatteryUtilsDischargeDevice(BatteryUtilsTest): + + @mock.patch('time.sleep', mock.Mock()) + def testDischargeDevice_exact(self): + with self.assertCalls( + (self.call.battery.GetBatteryInfo(), {'level': '100'}), + (self.call.battery._HardwareSetCharging(False)), + (self.call.battery._HardwareSetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '99'})): + self.battery._DischargeDevice(1) + + @mock.patch('time.sleep', mock.Mock()) + def testDischargeDevice_over(self): + with self.assertCalls( + (self.call.battery.GetBatteryInfo(), {'level': '100'}), + (self.call.battery._HardwareSetCharging(False)), + (self.call.battery._HardwareSetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '50'})): + self.battery._DischargeDevice(1) + + @mock.patch('time.sleep', mock.Mock()) + def testDischargeDevice_takeslong(self): + with self.assertCalls( + (self.call.battery.GetBatteryInfo(), {'level': '100'}), + (self.call.battery._HardwareSetCharging(False)), + (self.call.battery._HardwareSetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '100'}), + (self.call.battery._HardwareSetCharging(False)), + (self.call.battery._HardwareSetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '99'}), + (self.call.battery._HardwareSetCharging(False)), + (self.call.battery._HardwareSetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '98'}), + (self.call.battery._HardwareSetCharging(False)), + (self.call.battery._HardwareSetCharging(True)), + (self.call.battery.GetBatteryInfo(), {'level': '97'})): + self.battery._DischargeDevice(3) + + @mock.patch('time.sleep', mock.Mock()) + def testDischargeDevice_dischargeTooClose(self): + with self.assertCalls( + (self.call.battery.GetBatteryInfo(), {'level': '100'})): + self.battery._DischargeDevice(99) + + @mock.patch('time.sleep', mock.Mock()) + def testDischargeDevice_percentageOutOfBounds(self): + with self.assertCalls( + (self.call.battery.GetBatteryInfo(), {'level': '100'})): + with self.assertRaises(ValueError): + self.battery._DischargeDevice(100) + with self.assertCalls( + (self.call.battery.GetBatteryInfo(), {'level': '100'})): + with self.assertRaises(ValueError): + self.battery._DischargeDevice(0) + + +class BatteryUtilsGetBatteryInfoTest(BatteryUtilsTest): + + def testGetBatteryInfo_normal(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True), + [ + 'Current Battery Service state:', + ' AC powered: false', + ' USB powered: true', + ' level: 100', + ' temperature: 321', + ])): + self.assertEquals( + { + 'AC powered': 'false', + 'USB powered': 'true', + 'level': '100', + 'temperature': '321', + }, + self.battery.GetBatteryInfo()) + + def testGetBatteryInfo_nothing(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True), [])): + self.assertEquals({}, self.battery.GetBatteryInfo()) + + +class BatteryUtilsGetChargingTest(BatteryUtilsTest): + + def testGetCharging_usb(self): + with self.assertCall( + self.call.battery.GetBatteryInfo(), {'USB powered': 'true'}): + self.assertTrue(self.battery.GetCharging()) + + def testGetCharging_usbFalse(self): + with self.assertCall( + self.call.battery.GetBatteryInfo(), {'USB powered': 'false'}): + self.assertFalse(self.battery.GetCharging()) + + def testGetCharging_ac(self): + with self.assertCall( + self.call.battery.GetBatteryInfo(), {'AC powered': 'true'}): + self.assertTrue(self.battery.GetCharging()) + + def testGetCharging_wireless(self): + with self.assertCall( + self.call.battery.GetBatteryInfo(), {'Wireless powered': 'true'}): + self.assertTrue(self.battery.GetCharging()) + + def testGetCharging_unknown(self): + with self.assertCall( + self.call.battery.GetBatteryInfo(), {'level': '42'}): + self.assertFalse(self.battery.GetCharging()) + + +class BatteryUtilsGetNetworkDataTest(BatteryUtilsTest): + + def testGetNetworkData_noDataUsage(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT), + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), + self.ShellError()), + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), + self.ShellError())): + self.assertEquals(self.battery.GetNetworkData('test_package1'), (0, 0)) + + def testGetNetworkData_badPackage(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT): + self.assertEqual(self.battery.GetNetworkData('asdf'), None) + + def testGetNetworkData_packageNotCached(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT), + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1), + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)): + self.assertEqual(self.battery.GetNetworkData('test_package1'), (1, 2)) + + def testGetNetworkData_packageCached(self): + self.battery._cache['uids'] = {'test_package1': '1000'} + with self.assertCalls( + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1), + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)): + self.assertEqual(self.battery.GetNetworkData('test_package1'), (1, 2)) + + def testGetNetworkData_clearedCache(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '-c'], + check_return=True, large_output=True), + _DUMPSYS_OUTPUT), + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1), + (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)): + self.battery._cache.clear() + self.assertEqual(self.battery.GetNetworkData('test_package1'), (1, 2)) + + +class BatteryUtilsLetBatteryCoolToTemperatureTest(BatteryUtilsTest): + + @mock.patch('time.sleep', mock.Mock()) + def testLetBatteryCoolToTemperature_startUnder(self): + self.battery._cache['profile'] = self._NEXUS_6 + with self.assertCalls( + (self.call.battery.EnableBatteryUpdates(), []), + (self.call.battery.GetBatteryInfo(), {'temperature': '500'})): + self.battery.LetBatteryCoolToTemperature(600) + + @mock.patch('time.sleep', mock.Mock()) + def testLetBatteryCoolToTemperature_startOver(self): + self.battery._cache['profile'] = self._NEXUS_6 + with self.assertCalls( + (self.call.battery.EnableBatteryUpdates(), []), + (self.call.battery.GetBatteryInfo(), {'temperature': '500'}), + (self.call.battery.GetBatteryInfo(), {'temperature': '400'})): + self.battery.LetBatteryCoolToTemperature(400) + + @mock.patch('time.sleep', mock.Mock()) + def testLetBatteryCoolToTemperature_nexus5Hot(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.battery.EnableBatteryUpdates(), []), + (self.call.battery.GetBatteryInfo(), {'temperature': '500'}), + (self.call.battery._DischargeDevice(1), []), + (self.call.battery.GetBatteryInfo(), {'temperature': '400'})): + self.battery.LetBatteryCoolToTemperature(400) + + @mock.patch('time.sleep', mock.Mock()) + def testLetBatteryCoolToTemperature_nexus5Cool(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.battery.EnableBatteryUpdates(), []), + (self.call.battery.GetBatteryInfo(), {'temperature': '400'})): + self.battery.LetBatteryCoolToTemperature(400) + + +class BatteryUtilsSupportsFuelGaugeTest(BatteryUtilsTest): + + def testSupportsFuelGauge_false(self): + self.battery._cache['profile'] = self._NEXUS_5 + self.assertFalse(self.battery.SupportsFuelGauge()) + + def testSupportsFuelGauge_trueMax(self): + self.battery._cache['profile'] = self._NEXUS_6 + # TODO(rnephew): Change this to assertTrue when we have support for + # disabling hardware charging on nexus 6. + self.assertFalse(self.battery.SupportsFuelGauge()) + + def testSupportsFuelGauge_trueDS(self): + self.battery._cache['profile'] = self._NEXUS_10 + # TODO(rnephew): Change this to assertTrue when we have support for + # disabling hardware charging on nexus 10. + self.assertFalse(self.battery.SupportsFuelGauge()) + + +class BatteryUtilsGetFuelGaugeChargeCounterTest(BatteryUtilsTest): + + def testGetFuelGaugeChargeCounter_noFuelGauge(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertRaises(device_errors.CommandFailedError): + self.battery.GetFuelGaugeChargeCounter() + + def testGetFuelGaugeChargeCounter_fuelGaugePresent(self): + self.battery._cache['profile'] = self._NEXUS_6 + with self.assertCalls( + (self.call.battery.SupportsFuelGauge(), True), + (self.call.device.ReadFile(mock.ANY), '123')): + self.assertEqual(self.battery.GetFuelGaugeChargeCounter(), 123) + + +class BatteryUtilsSetCharging(BatteryUtilsTest): + + @mock.patch('time.sleep', mock.Mock()) + def testSetCharging_softwareSetTrue(self): + self.battery._cache['profile'] = self._NEXUS_6 + with self.assertCalls( + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'reset'], check_return=True), []), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']), + (self.call.battery.GetCharging(), True)): + self.battery.SetCharging(True) + + @mock.patch('time.sleep', mock.Mock()) + def testSetCharging_softwareSetFalse(self): + self.battery._cache['profile'] = self._NEXUS_6 + with self.assertCalls( + (self.call.battery.GetCharging(), True), + (self.call.battery._ClearPowerData(), True), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), []), + (self.call.battery.GetCharging(), False)): + self.battery.SetCharging(False) + + @mock.patch('time.sleep', mock.Mock()) + def testSetCharging_hardwareSetTrue(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.battery.GetCharging(), False), + (self.call.battery._HardwareSetCharging(True))): + self.battery.SetCharging(True) + + @mock.patch('time.sleep', mock.Mock()) + def testSetCharging_hardwareSetFalse(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.battery.GetCharging(), True), + (self.call.battery._ClearPowerData(), True), + (self.call.battery._HardwareSetCharging(False))): + self.battery.SetCharging(False) + + def testSetCharging_expectedStateAlreadyTrue(self): + with self.assertCalls((self.call.battery.GetCharging(), True)): + self.battery.SetCharging(True) + + def testSetCharging_expectedStateAlreadyFalse(self): + with self.assertCalls((self.call.battery.GetCharging(), False)): + self.battery.SetCharging(False) + + +class BatteryUtilsPowerMeasurement(BatteryUtilsTest): + + def testPowerMeasurement_hardware(self): + self.battery._cache['profile'] = self._NEXUS_5 + with self.assertCalls( + (self.call.battery.GetCharging(), True), + (self.call.battery._ClearPowerData(), True), + (self.call.battery._HardwareSetCharging(False)), + (self.call.battery.GetCharging(), False), + (self.call.battery._HardwareSetCharging(True))): + with self.battery.PowerMeasurement(): + pass + + @mock.patch('time.sleep', mock.Mock()) + def testPowerMeasurement_software(self): + self.battery._cache['profile'] = self._NEXUS_6 + with self.assertCalls( + (self.call.battery.GetCharging(), True), + (self.call.battery._ClearPowerData(), True), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), []), + (self.call.battery.GetCharging(), False), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'reset'], check_return=True), []), + (self.call.battery.GetCharging(), False), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']), + (self.call.battery.GetCharging(), True)): + with self.battery.PowerMeasurement(): + pass + + +class BatteryUtilsDiscoverDeviceProfile(BatteryUtilsTest): + + def testDiscoverDeviceProfile_known(self): + with self.patch_call(self.call.device.product_model, + return_value='Nexus 4'): + self.battery._DiscoverDeviceProfile() + self.assertListEqual(self.battery._cache['profile']['name'], ["Nexus 4"]) + + def testDiscoverDeviceProfile_unknown(self): + with self.patch_call(self.call.device.product_model, + return_value='Other'): + self.battery._DiscoverDeviceProfile() + self.assertListEqual(self.battery._cache['profile']['name'], []) + + +class BatteryUtilsClearPowerData(BatteryUtilsTest): + + def testClearPowerData_preL(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=20): + self.assertFalse(self.battery._ClearPowerData()) + + def testClearPowerData_clearedL(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=22): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True), + []), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--reset'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--charged', '-c'], + check_return=True, large_output=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'reset'], check_return=True), [])): + self.assertTrue(self.battery._ClearPowerData()) + + @mock.patch('time.sleep', mock.Mock()) + def testClearPowerData_notClearedL(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=22): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True), + []), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--reset'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--charged', '-c'], + check_return=True, large_output=True), + ['9,1000,l,pwi,uid,0.0327']), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--reset'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--charged', '-c'], + check_return=True, large_output=True), + ['9,1000,l,pwi,uid,0.0327']), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--reset'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--charged', '-c'], + check_return=True, large_output=True), + ['9,1000,l,pwi,uid,0.0327']), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--reset'], check_return=True), []), + (self.call.device.RunShellCommand( + ['dumpsys', 'batterystats', '--charged', '-c'], + check_return=True, large_output=True), + ['9,1000,l,pwi,uid,0.0']), + (self.call.device.RunShellCommand( + ['dumpsys', 'battery', 'reset'], check_return=True), [])): + self.battery._ClearPowerData() + + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/__init__.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/__init__.py new file mode 100644 index 0000000..50b23df --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/chrome.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/chrome.py new file mode 100644 index 0000000..dca04bd --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/chrome.py @@ -0,0 +1,57 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import collections + +PackageInfo = collections.namedtuple( + 'PackageInfo', + ['package', 'activity', 'cmdline_file', 'devtools_socket']) + +PACKAGE_INFO = { + 'chrome_document': PackageInfo( + 'com.google.android.apps.chrome.document', + 'com.google.android.apps.chrome.document.ChromeLauncherActivity', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'chrome': PackageInfo( + 'com.google.android.apps.chrome', + 'com.google.android.apps.chrome.Main', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'chrome_beta': PackageInfo( + 'com.chrome.beta', + 'com.google.android.apps.chrome.Main', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'chrome_stable': PackageInfo( + 'com.android.chrome', + 'com.google.android.apps.chrome.Main', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'chrome_dev': PackageInfo( + 'com.chrome.dev', + 'com.google.android.apps.chrome.Main', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'chrome_canary': PackageInfo( + 'com.chrome.canary', + 'com.google.android.apps.chrome.Main', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'chrome_work': PackageInfo( + 'com.chrome.work', + 'com.google.android.apps.chrome.Main', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'chromium': PackageInfo( + 'org.chromium.chrome', + 'com.google.android.apps.chrome.Main', + 'chrome-command-line', + 'chrome_devtools_remote'), + 'content_shell': PackageInfo( + 'org.chromium.content_shell_apk', + '.ContentShellActivity', + 'content-shell-command-line', + 'content_shell_devtools_remote'), +} diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/file_system.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/file_system.py new file mode 100644 index 0000000..bffec61 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/constants/file_system.py @@ -0,0 +1,5 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +TEST_EXECUTABLE_DIR = '/data/local/tmp' diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators.py new file mode 100644 index 0000000..3844b49 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators.py @@ -0,0 +1,176 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Function/method decorators that provide timeout and retry logic. +""" + +import functools +import itertools +import sys + +from devil.android import device_errors +from devil.utils import cmd_helper +from devil.utils import reraiser_thread +from devil.utils import timeout_retry + +DEFAULT_TIMEOUT_ATTR = '_default_timeout' +DEFAULT_RETRIES_ATTR = '_default_retries' + + +def _TimeoutRetryWrapper( + f, timeout_func, retries_func, retry_if_func=timeout_retry.AlwaysRetry, + pass_values=False): + """ Wraps a funcion with timeout and retry handling logic. + + Args: + f: The function to wrap. + timeout_func: A callable that returns the timeout value. + retries_func: A callable that returns the retries value. + pass_values: If True, passes the values returned by |timeout_func| and + |retries_func| to the wrapped function as 'timeout' and + 'retries' kwargs, respectively. + Returns: + The wrapped function. + """ + @functools.wraps(f) + def timeout_retry_wrapper(*args, **kwargs): + timeout = timeout_func(*args, **kwargs) + retries = retries_func(*args, **kwargs) + if pass_values: + kwargs['timeout'] = timeout + kwargs['retries'] = retries + + @functools.wraps(f) + def impl(): + return f(*args, **kwargs) + try: + if timeout_retry.CurrentTimeoutThreadGroup(): + # Don't wrap if there's already an outer timeout thread. + return impl() + else: + desc = '%s(%s)' % (f.__name__, ', '.join(itertools.chain( + (str(a) for a in args), + ('%s=%s' % (k, str(v)) for k, v in kwargs.iteritems())))) + return timeout_retry.Run(impl, timeout, retries, desc=desc, + retry_if_func=retry_if_func) + except reraiser_thread.TimeoutError as e: + raise device_errors.CommandTimeoutError(str(e)), None, ( + sys.exc_info()[2]) + except cmd_helper.TimeoutError as e: + raise device_errors.CommandTimeoutError(str(e)), None, ( + sys.exc_info()[2]) + return timeout_retry_wrapper + + +def WithTimeoutAndRetries(f): + """A decorator that handles timeouts and retries. + + 'timeout' and 'retries' kwargs must be passed to the function. + + Args: + f: The function to decorate. + Returns: + The decorated function. + """ + get_timeout = lambda *a, **kw: kw['timeout'] + get_retries = lambda *a, **kw: kw['retries'] + return _TimeoutRetryWrapper(f, get_timeout, get_retries) + + +def WithTimeoutAndConditionalRetries(retry_if_func): + """Returns a decorator that handles timeouts and, in some cases, retries. + + 'timeout' and 'retries' kwargs must be passed to the function. + + Args: + retry_if_func: A unary callable that takes an exception and returns + whether failures should be retried. + Returns: + The actual decorator. + """ + def decorator(f): + get_timeout = lambda *a, **kw: kw['timeout'] + get_retries = lambda *a, **kw: kw['retries'] + return _TimeoutRetryWrapper( + f, get_timeout, get_retries, retry_if_func=retry_if_func) + return decorator + + +def WithExplicitTimeoutAndRetries(timeout, retries): + """Returns a decorator that handles timeouts and retries. + + The provided |timeout| and |retries| values are always used. + + Args: + timeout: The number of seconds to wait for the decorated function to + return. Always used. + retries: The number of times the decorated function should be retried on + failure. Always used. + Returns: + The actual decorator. + """ + def decorator(f): + get_timeout = lambda *a, **kw: timeout + get_retries = lambda *a, **kw: retries + return _TimeoutRetryWrapper(f, get_timeout, get_retries) + return decorator + + +def WithTimeoutAndRetriesDefaults(default_timeout, default_retries): + """Returns a decorator that handles timeouts and retries. + + The provided |default_timeout| and |default_retries| values are used only + if timeout and retries values are not provided. + + Args: + default_timeout: The number of seconds to wait for the decorated function + to return. Only used if a 'timeout' kwarg is not passed + to the decorated function. + default_retries: The number of times the decorated function should be + retried on failure. Only used if a 'retries' kwarg is not + passed to the decorated function. + Returns: + The actual decorator. + """ + def decorator(f): + get_timeout = lambda *a, **kw: kw.get('timeout', default_timeout) + get_retries = lambda *a, **kw: kw.get('retries', default_retries) + return _TimeoutRetryWrapper(f, get_timeout, get_retries, pass_values=True) + return decorator + + +def WithTimeoutAndRetriesFromInstance( + default_timeout_name=DEFAULT_TIMEOUT_ATTR, + default_retries_name=DEFAULT_RETRIES_ATTR, + min_default_timeout=None): + """Returns a decorator that handles timeouts and retries. + + The provided |default_timeout_name| and |default_retries_name| are used to + get the default timeout value and the default retries value from the object + instance if timeout and retries values are not provided. + + Note that this should only be used to decorate methods, not functions. + + Args: + default_timeout_name: The name of the default timeout attribute of the + instance. + default_retries_name: The name of the default retries attribute of the + instance. + min_timeout: Miniumum timeout to be used when using instance timeout. + Returns: + The actual decorator. + """ + def decorator(f): + def get_timeout(inst, *_args, **kwargs): + ret = getattr(inst, default_timeout_name) + if min_default_timeout is not None: + ret = max(min_default_timeout, ret) + return kwargs.get('timeout', ret) + + def get_retries(inst, *_args, **kwargs): + return kwargs.get('retries', getattr(inst, default_retries_name)) + return _TimeoutRetryWrapper(f, get_timeout, get_retries, pass_values=True) + return decorator + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators_test.py new file mode 100644 index 0000000..f60953e --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/decorators_test.py @@ -0,0 +1,332 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Unit tests for decorators.py. +""" + +# pylint: disable=W0613 + +import time +import traceback +import unittest + +from devil.android import decorators +from devil.android import device_errors +from devil.utils import reraiser_thread + +_DEFAULT_TIMEOUT = 30 +_DEFAULT_RETRIES = 3 + + +class DecoratorsTest(unittest.TestCase): + _decorated_function_called_count = 0 + + def testFunctionDecoratorDoesTimeouts(self): + """Tests that the base decorator handles the timeout logic.""" + DecoratorsTest._decorated_function_called_count = 0 + + @decorators.WithTimeoutAndRetries + def alwaysTimesOut(timeout=None, retries=None): + DecoratorsTest._decorated_function_called_count += 1 + time.sleep(100) + + start_time = time.time() + with self.assertRaises(device_errors.CommandTimeoutError): + alwaysTimesOut(timeout=1, retries=0) + elapsed_time = time.time() - start_time + self.assertTrue(elapsed_time >= 1) + self.assertEquals(1, DecoratorsTest._decorated_function_called_count) + + def testFunctionDecoratorDoesRetries(self): + """Tests that the base decorator handles the retries logic.""" + DecoratorsTest._decorated_function_called_count = 0 + + @decorators.WithTimeoutAndRetries + def alwaysRaisesCommandFailedError(timeout=None, retries=None): + DecoratorsTest._decorated_function_called_count += 1 + raise device_errors.CommandFailedError('testCommand failed') + + with self.assertRaises(device_errors.CommandFailedError): + alwaysRaisesCommandFailedError(timeout=30, retries=10) + self.assertEquals(11, DecoratorsTest._decorated_function_called_count) + + def testFunctionDecoratorRequiresParams(self): + """Tests that the base decorator requires timeout and retries params.""" + @decorators.WithTimeoutAndRetries + def requiresExplicitTimeoutAndRetries(timeout=None, retries=None): + return (timeout, retries) + + with self.assertRaises(KeyError): + requiresExplicitTimeoutAndRetries() + with self.assertRaises(KeyError): + requiresExplicitTimeoutAndRetries(timeout=10) + with self.assertRaises(KeyError): + requiresExplicitTimeoutAndRetries(retries=0) + expected_timeout = 10 + expected_retries = 1 + (actual_timeout, actual_retries) = ( + requiresExplicitTimeoutAndRetries(timeout=expected_timeout, + retries=expected_retries)) + self.assertEquals(expected_timeout, actual_timeout) + self.assertEquals(expected_retries, actual_retries) + + def testFunctionDecoratorTranslatesReraiserExceptions(self): + """Tests that the explicit decorator translates reraiser exceptions.""" + @decorators.WithTimeoutAndRetries + def alwaysRaisesProvidedException(exception, timeout=None, retries=None): + raise exception + + exception_desc = 'Reraiser thread timeout error' + with self.assertRaises(device_errors.CommandTimeoutError) as e: + alwaysRaisesProvidedException( + reraiser_thread.TimeoutError(exception_desc), + timeout=10, retries=1) + self.assertEquals(exception_desc, str(e.exception)) + + def testConditionalRetriesDecoratorRetries(self): + def do_not_retry_no_adb_error(exc): + return not isinstance(exc, device_errors.NoAdbError) + + actual_tries = [0] + + @decorators.WithTimeoutAndConditionalRetries(do_not_retry_no_adb_error) + def alwaysRaisesCommandFailedError(timeout=None, retries=None): + actual_tries[0] += 1 + raise device_errors.CommandFailedError('Command failed :(') + + with self.assertRaises(device_errors.CommandFailedError): + alwaysRaisesCommandFailedError(timeout=10, retries=10) + self.assertEquals(11, actual_tries[0]) + + def testConditionalRetriesDecoratorDoesntRetry(self): + def do_not_retry_no_adb_error(exc): + return not isinstance(exc, device_errors.NoAdbError) + + actual_tries = [0] + + @decorators.WithTimeoutAndConditionalRetries(do_not_retry_no_adb_error) + def alwaysRaisesNoAdbError(timeout=None, retries=None): + actual_tries[0] += 1 + raise device_errors.NoAdbError() + + with self.assertRaises(device_errors.NoAdbError): + alwaysRaisesNoAdbError(timeout=10, retries=10) + self.assertEquals(1, actual_tries[0]) + + def testDefaultsFunctionDecoratorDoesTimeouts(self): + """Tests that the defaults decorator handles timeout logic.""" + DecoratorsTest._decorated_function_called_count = 0 + + @decorators.WithTimeoutAndRetriesDefaults(1, 0) + def alwaysTimesOut(timeout=None, retries=None): + DecoratorsTest._decorated_function_called_count += 1 + time.sleep(100) + + start_time = time.time() + with self.assertRaises(device_errors.CommandTimeoutError): + alwaysTimesOut() + elapsed_time = time.time() - start_time + self.assertTrue(elapsed_time >= 1) + self.assertEquals(1, DecoratorsTest._decorated_function_called_count) + + DecoratorsTest._decorated_function_called_count = 0 + with self.assertRaises(device_errors.CommandTimeoutError): + alwaysTimesOut(timeout=2) + elapsed_time = time.time() - start_time + self.assertTrue(elapsed_time >= 2) + self.assertEquals(1, DecoratorsTest._decorated_function_called_count) + + def testDefaultsFunctionDecoratorDoesRetries(self): + """Tests that the defaults decorator handles retries logic.""" + DecoratorsTest._decorated_function_called_count = 0 + + @decorators.WithTimeoutAndRetriesDefaults(30, 10) + def alwaysRaisesCommandFailedError(timeout=None, retries=None): + DecoratorsTest._decorated_function_called_count += 1 + raise device_errors.CommandFailedError('testCommand failed') + + with self.assertRaises(device_errors.CommandFailedError): + alwaysRaisesCommandFailedError() + self.assertEquals(11, DecoratorsTest._decorated_function_called_count) + + DecoratorsTest._decorated_function_called_count = 0 + with self.assertRaises(device_errors.CommandFailedError): + alwaysRaisesCommandFailedError(retries=5) + self.assertEquals(6, DecoratorsTest._decorated_function_called_count) + + def testDefaultsFunctionDecoratorPassesValues(self): + """Tests that the defaults decorator passes timeout and retries kwargs.""" + @decorators.WithTimeoutAndRetriesDefaults(30, 10) + def alwaysReturnsTimeouts(timeout=None, retries=None): + return timeout + + self.assertEquals(30, alwaysReturnsTimeouts()) + self.assertEquals(120, alwaysReturnsTimeouts(timeout=120)) + + @decorators.WithTimeoutAndRetriesDefaults(30, 10) + def alwaysReturnsRetries(timeout=None, retries=None): + return retries + + self.assertEquals(10, alwaysReturnsRetries()) + self.assertEquals(1, alwaysReturnsRetries(retries=1)) + + def testDefaultsFunctionDecoratorTranslatesReraiserExceptions(self): + """Tests that the explicit decorator translates reraiser exceptions.""" + @decorators.WithTimeoutAndRetriesDefaults(30, 10) + def alwaysRaisesProvidedException(exception, timeout=None, retries=None): + raise exception + + exception_desc = 'Reraiser thread timeout error' + with self.assertRaises(device_errors.CommandTimeoutError) as e: + alwaysRaisesProvidedException( + reraiser_thread.TimeoutError(exception_desc)) + self.assertEquals(exception_desc, str(e.exception)) + + def testExplicitFunctionDecoratorDoesTimeouts(self): + """Tests that the explicit decorator handles timeout logic.""" + DecoratorsTest._decorated_function_called_count = 0 + + @decorators.WithExplicitTimeoutAndRetries(1, 0) + def alwaysTimesOut(): + DecoratorsTest._decorated_function_called_count += 1 + time.sleep(100) + + start_time = time.time() + with self.assertRaises(device_errors.CommandTimeoutError): + alwaysTimesOut() + elapsed_time = time.time() - start_time + self.assertTrue(elapsed_time >= 1) + self.assertEquals(1, DecoratorsTest._decorated_function_called_count) + + def testExplicitFunctionDecoratorDoesRetries(self): + """Tests that the explicit decorator handles retries logic.""" + DecoratorsTest._decorated_function_called_count = 0 + + @decorators.WithExplicitTimeoutAndRetries(30, 10) + def alwaysRaisesCommandFailedError(): + DecoratorsTest._decorated_function_called_count += 1 + raise device_errors.CommandFailedError('testCommand failed') + + with self.assertRaises(device_errors.CommandFailedError): + alwaysRaisesCommandFailedError() + self.assertEquals(11, DecoratorsTest._decorated_function_called_count) + + def testExplicitDecoratorTranslatesReraiserExceptions(self): + """Tests that the explicit decorator translates reraiser exceptions.""" + @decorators.WithExplicitTimeoutAndRetries(30, 10) + def alwaysRaisesProvidedException(exception): + raise exception + + exception_desc = 'Reraiser thread timeout error' + with self.assertRaises(device_errors.CommandTimeoutError) as e: + alwaysRaisesProvidedException( + reraiser_thread.TimeoutError(exception_desc)) + self.assertEquals(exception_desc, str(e.exception)) + + class _MethodDecoratorTestObject(object): + """An object suitable for testing the method decorator.""" + + def __init__(self, test_case, default_timeout=_DEFAULT_TIMEOUT, + default_retries=_DEFAULT_RETRIES): + self._test_case = test_case + self.default_timeout = default_timeout + self.default_retries = default_retries + self.function_call_counters = { + 'alwaysRaisesCommandFailedError': 0, + 'alwaysTimesOut': 0, + 'requiresExplicitTimeoutAndRetries': 0, + } + + @decorators.WithTimeoutAndRetriesFromInstance( + 'default_timeout', 'default_retries') + def alwaysTimesOut(self, timeout=None, retries=None): + self.function_call_counters['alwaysTimesOut'] += 1 + time.sleep(100) + self._test_case.assertFalse(True, msg='Failed to time out?') + + @decorators.WithTimeoutAndRetriesFromInstance( + 'default_timeout', 'default_retries') + def alwaysRaisesCommandFailedError(self, timeout=None, retries=None): + self.function_call_counters['alwaysRaisesCommandFailedError'] += 1 + raise device_errors.CommandFailedError('testCommand failed') + + # pylint: disable=no-self-use + + @decorators.WithTimeoutAndRetriesFromInstance( + 'default_timeout', 'default_retries') + def alwaysReturnsTimeout(self, timeout=None, retries=None): + return timeout + + @decorators.WithTimeoutAndRetriesFromInstance( + 'default_timeout', 'default_retries', min_default_timeout=100) + def alwaysReturnsTimeoutWithMin(self, timeout=None, retries=None): + return timeout + + @decorators.WithTimeoutAndRetriesFromInstance( + 'default_timeout', 'default_retries') + def alwaysReturnsRetries(self, timeout=None, retries=None): + return retries + + @decorators.WithTimeoutAndRetriesFromInstance( + 'default_timeout', 'default_retries') + def alwaysRaisesProvidedException(self, exception, timeout=None, + retries=None): + raise exception + + # pylint: enable=no-self-use + + def testMethodDecoratorDoesTimeout(self): + """Tests that the method decorator handles timeout logic.""" + test_obj = self._MethodDecoratorTestObject(self) + start_time = time.time() + with self.assertRaises(device_errors.CommandTimeoutError): + try: + test_obj.alwaysTimesOut(timeout=1, retries=0) + except: + traceback.print_exc() + raise + elapsed_time = time.time() - start_time + self.assertTrue(elapsed_time >= 1) + self.assertEquals(1, test_obj.function_call_counters['alwaysTimesOut']) + + def testMethodDecoratorDoesRetries(self): + """Tests that the method decorator handles retries logic.""" + test_obj = self._MethodDecoratorTestObject(self) + with self.assertRaises(device_errors.CommandFailedError): + try: + test_obj.alwaysRaisesCommandFailedError(retries=10) + except: + traceback.print_exc() + raise + self.assertEquals( + 11, test_obj.function_call_counters['alwaysRaisesCommandFailedError']) + + def testMethodDecoratorPassesValues(self): + """Tests that the method decorator passes timeout and retries kwargs.""" + test_obj = self._MethodDecoratorTestObject( + self, default_timeout=42, default_retries=31) + self.assertEquals(42, test_obj.alwaysReturnsTimeout()) + self.assertEquals(41, test_obj.alwaysReturnsTimeout(timeout=41)) + self.assertEquals(31, test_obj.alwaysReturnsRetries()) + self.assertEquals(32, test_obj.alwaysReturnsRetries(retries=32)) + + def testMethodDecoratorUsesMiniumumTimeout(self): + test_obj = self._MethodDecoratorTestObject( + self, default_timeout=42, default_retries=31) + self.assertEquals(100, test_obj.alwaysReturnsTimeoutWithMin()) + self.assertEquals(41, test_obj.alwaysReturnsTimeoutWithMin(timeout=41)) + + def testMethodDecoratorTranslatesReraiserExceptions(self): + test_obj = self._MethodDecoratorTestObject(self) + + exception_desc = 'Reraiser thread timeout error' + with self.assertRaises(device_errors.CommandTimeoutError) as e: + test_obj.alwaysRaisesProvidedException( + reraiser_thread.TimeoutError(exception_desc)) + self.assertEquals(exception_desc, str(e.exception)) + +if __name__ == '__main__': + unittest.main(verbosity=2) + diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist.py new file mode 100644 index 0000000..010e996 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist.py @@ -0,0 +1,80 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import logging +import os +import threading +import time + +logger = logging.getLogger(__name__) + + +class Blacklist(object): + + def __init__(self, path): + self._blacklist_lock = threading.RLock() + self._path = path + + def Read(self): + """Reads the blacklist from the blacklist file. + + Returns: + A dict containing bad devices. + """ + with self._blacklist_lock: + blacklist = dict() + if not os.path.exists(self._path): + return blacklist + + try: + with open(self._path, 'r') as f: + blacklist = json.load(f) + except (IOError, ValueError) as e: + logger.warning('Unable to read blacklist: %s', str(e)) + os.remove(self._path) + + if not isinstance(blacklist, dict): + logger.warning('Ignoring %s: %s (a dict was expected instead)', + self._path, blacklist) + blacklist = dict() + + return blacklist + + def Write(self, blacklist): + """Writes the provided blacklist to the blacklist file. + + Args: + blacklist: list of bad devices to write to the blacklist file. + """ + with self._blacklist_lock: + with open(self._path, 'w') as f: + json.dump(blacklist, f) + + def Extend(self, devices, reason='unknown'): + """Adds devices to blacklist file. + + Args: + devices: list of bad devices to be added to the blacklist file. + reason: string specifying the reason for blacklist (eg: 'unauthorized') + """ + timestamp = time.time() + event_info = { + 'timestamp': timestamp, + 'reason': reason, + } + device_dicts = {device: event_info for device in devices} + logger.info('Adding %s to blacklist %s for reason: %s', + ','.join(devices), self._path, reason) + with self._blacklist_lock: + blacklist = self.Read() + blacklist.update(device_dicts) + self.Write(blacklist) + + def Reset(self): + """Erases the blacklist file if it exists.""" + logger.info('Resetting blacklist %s', self._path) + with self._blacklist_lock: + if os.path.exists(self._path): + os.remove(self._path) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist_test.py new file mode 100644 index 0000000..bc44da5 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_blacklist_test.py @@ -0,0 +1,38 @@ +#! /usr/bin/env python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import tempfile +import unittest + +from devil.android import device_blacklist + + +class DeviceBlacklistTest(unittest.TestCase): + + def testBlacklistFileDoesNotExist(self): + with tempfile.NamedTemporaryFile() as blacklist_file: + # Allow the temporary file to be deleted. + pass + + test_blacklist = device_blacklist.Blacklist(blacklist_file.name) + self.assertEquals({}, test_blacklist.Read()) + + def testBlacklistFileIsEmpty(self): + try: + with tempfile.NamedTemporaryFile(delete=False) as blacklist_file: + # Allow the temporary file to be closed. + pass + + test_blacklist = device_blacklist.Blacklist(blacklist_file.name) + self.assertEquals({}, test_blacklist.Read()) + + finally: + if os.path.exists(blacklist_file.name): + os.remove(blacklist_file.name) + + +if __name__ == '__main__': + unittest.main() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors.py new file mode 100644 index 0000000..57f3615 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors.py @@ -0,0 +1,196 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Exception classes raised by AdbWrapper and DeviceUtils. + +The class hierarchy for device exceptions is: + + base_error.BaseError + +-- CommandFailedError + | +-- AdbCommandFailedError + | | +-- AdbShellCommandFailedError + | +-- FastbootCommandFailedError + | +-- DeviceVersionError + | +-- DeviceChargingError + +-- CommandTimeoutError + +-- DeviceUnreachableError + +-- NoDevicesError + +-- MultipleDevicesError + +-- NoAdbError + +""" + +from devil import base_error +from devil.utils import cmd_helper +from devil.utils import parallelizer + + +class CommandFailedError(base_error.BaseError): + """Exception for command failures.""" + + def __init__(self, message, device_serial=None): + device_leader = '(device: %s)' % device_serial + if device_serial is not None and not message.startswith(device_leader): + message = '%s %s' % (device_leader, message) + self.device_serial = device_serial + super(CommandFailedError, self).__init__(message) + + def __eq__(self, other): + return (super(CommandFailedError, self).__eq__(other) + and self.device_serial == other.device_serial) + + def __ne__(self, other): + return not self == other + + +class _BaseCommandFailedError(CommandFailedError): + """Base Exception for adb and fastboot command failures.""" + + def __init__(self, args, output, status=None, device_serial=None, + message=None): + self.args = args + self.output = output + self.status = status + if not message: + adb_cmd = ' '.join(cmd_helper.SingleQuote(arg) for arg in self.args) + message = ['adb %s: failed ' % adb_cmd] + if status: + message.append('with exit status %s ' % self.status) + if output: + message.append('and output:\n') + message.extend('- %s\n' % line for line in output.splitlines()) + else: + message.append('and no output.') + message = ''.join(message) + super(_BaseCommandFailedError, self).__init__(message, device_serial) + + def __eq__(self, other): + return (super(_BaseCommandFailedError, self).__eq__(other) + and self.args == other.args + and self.output == other.output + and self.status == other.status) + + def __ne__(self, other): + return not self == other + + def __reduce__(self): + """Support pickling.""" + result = [None, None, None, None, None] + super_result = super(_BaseCommandFailedError, self).__reduce__() + for i in range(len(super_result)): + result[i] = super_result[i] + + # Update the args used to reconstruct this exception. + result[1] = ( + self.args, self.output, self.status, self.device_serial, self.message) + return tuple(result) + + +class AdbCommandFailedError(_BaseCommandFailedError): + """Exception for adb command failures.""" + + def __init__(self, args, output, status=None, device_serial=None, + message=None): + super(AdbCommandFailedError, self).__init__( + args, output, status=status, message=message, + device_serial=device_serial) + + +class FastbootCommandFailedError(_BaseCommandFailedError): + """Exception for fastboot command failures.""" + + def __init__(self, args, output, status=None, device_serial=None, + message=None): + super(FastbootCommandFailedError, self).__init__( + args, output, status=status, message=message, + device_serial=device_serial) + + +class DeviceVersionError(CommandFailedError): + """Exception for device version failures.""" + + def __init__(self, message, device_serial=None): + super(DeviceVersionError, self).__init__(message, device_serial) + + +class AdbShellCommandFailedError(AdbCommandFailedError): + """Exception for shell command failures run via adb.""" + + def __init__(self, command, output, status, device_serial=None): + self.command = command + message = ['shell command run via adb failed on the device:\n', + ' command: %s\n' % command] + message.append(' exit status: %s\n' % status) + if output: + message.append(' output:\n') + if isinstance(output, basestring): + output_lines = output.splitlines() + else: + output_lines = output + message.extend(' - %s\n' % line for line in output_lines) + else: + message.append(" output: ''\n") + message = ''.join(message) + super(AdbShellCommandFailedError, self).__init__( + ['shell', command], output, status, device_serial, message) + + def __reduce__(self): + """Support pickling.""" + result = [None, None, None, None, None] + super_result = super(AdbShellCommandFailedError, self).__reduce__() + for i in range(len(super_result)): + result[i] = super_result[i] + + # Update the args used to reconstruct this exception. + result[1] = (self.command, self.output, self.status, self.device_serial) + return tuple(result) + + +class CommandTimeoutError(base_error.BaseError): + """Exception for command timeouts.""" + pass + + +class DeviceUnreachableError(base_error.BaseError): + """Exception for device unreachable failures.""" + pass + + +class NoDevicesError(base_error.BaseError): + """Exception for having no devices attached.""" + + def __init__(self, msg=None): + super(NoDevicesError, self).__init__( + msg or 'No devices attached.', is_infra_error=True) + + +class MultipleDevicesError(base_error.BaseError): + """Exception for having multiple attached devices without selecting one.""" + + def __init__(self, devices): + parallel_devices = parallelizer.Parallelizer(devices) + descriptions = parallel_devices.pMap( + lambda d: d.build_description).pGet(None) + msg = ('More than one device available. Use -d/--device to select a device ' + 'by serial.\n\nAvailable devices:\n') + for d, desc in zip(devices, descriptions): + msg += ' %s (%s)\n' % (d, desc) + + super(MultipleDevicesError, self).__init__(msg, is_infra_error=True) + + +class NoAdbError(base_error.BaseError): + """Exception for being unable to find ADB.""" + + def __init__(self, msg=None): + super(NoAdbError, self).__init__( + msg or 'Unable to find adb.', is_infra_error=True) + + +class DeviceChargingError(CommandFailedError): + """Exception for device charging errors.""" + + def __init__(self, message, device_serial=None): + super(DeviceChargingError, self).__init__(message, device_serial) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors_test.py new file mode 100644 index 0000000..68a4f16 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_errors_test.py @@ -0,0 +1,72 @@ +#! /usr/bin/env python +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import pickle +import sys +import unittest + +from devil.android import device_errors + + +class DeviceErrorsTest(unittest.TestCase): + + def assertIsPicklable(self, original): + pickled = pickle.dumps(original) + reconstructed = pickle.loads(pickled) + self.assertEquals(original, reconstructed) + + def testPicklable_AdbCommandFailedError(self): + original = device_errors.AdbCommandFailedError( + ['these', 'are', 'adb', 'args'], 'adb failure output', status=':(', + device_serial='0123456789abcdef') + self.assertIsPicklable(original) + + def testPicklable_AdbShellCommandFailedError(self): + original = device_errors.AdbShellCommandFailedError( + 'foo', 'erroneous foo output', '1', device_serial='0123456789abcdef') + self.assertIsPicklable(original) + + def testPicklable_CommandFailedError(self): + original = device_errors.CommandFailedError( + 'sample command failed') + self.assertIsPicklable(original) + + def testPicklable_CommandTimeoutError(self): + original = device_errors.CommandTimeoutError( + 'My fake command timed out :(') + self.assertIsPicklable(original) + + def testPicklable_DeviceChargingError(self): + original = device_errors.DeviceChargingError( + 'Fake device failed to charge') + self.assertIsPicklable(original) + + def testPicklable_DeviceUnreachableError(self): + original = device_errors.DeviceUnreachableError + self.assertIsPicklable(original) + + def testPicklable_FastbootCommandFailedError(self): + original = device_errors.FastbootCommandFailedError( + ['these', 'are', 'fastboot', 'args'], 'fastboot failure output', + status=':(', device_serial='0123456789abcdef') + self.assertIsPicklable(original) + + def testPicklable_MultipleDevicesError(self): + # TODO(jbudorick): Implement this after implementing a stable DeviceUtils + # fake. https://github.com/catapult-project/catapult/issues/3145 + pass + + def testPicklable_NoAdbError(self): + original = device_errors.NoAdbError() + self.assertIsPicklable(original) + + def testPicklable_NoDevicesError(self): + original = device_errors.NoDevicesError() + self.assertIsPicklable(original) + + + +if __name__ == '__main__': + sys.exit(unittest.main()) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_list.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_list.py new file mode 100644 index 0000000..0fbb0f1 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_list.py @@ -0,0 +1,52 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""A module to keep track of devices across builds.""" + +import json +import logging +import os + +logger = logging.getLogger(__name__) + + +def GetPersistentDeviceList(file_name): + """Returns a list of devices. + + Args: + file_name: the file name containing a list of devices. + + Returns: List of device serial numbers that were on the bot. + """ + if not os.path.isfile(file_name): + logger.warning("Device file %s doesn't exist.", file_name) + return [] + + try: + with open(file_name) as f: + devices = json.load(f) + if not isinstance(devices, list) or not all(isinstance(d, basestring) + for d in devices): + logger.warning('Unrecognized device file format: %s', devices) + return [] + return [d for d in devices if d != '(error)'] + except ValueError: + logger.exception( + 'Error reading device file %s. Falling back to old format.', file_name) + + # TODO(bpastene) Remove support for old unstructured file format. + with open(file_name) as f: + return [d for d in f.read().splitlines() if d != '(error)'] + + +def WritePersistentDeviceList(file_name, device_list): + path = os.path.dirname(file_name) + assert isinstance(device_list, list) + # If there is a problem with ADB "(error)" can be added to the device list. + # These should be removed before saving. + device_list = [d for d in device_list if d != '(error)'] + if not os.path.exists(path): + os.makedirs(path) + with open(file_name, 'w') as f: + json.dump(device_list, f) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_signal.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_signal.py new file mode 100644 index 0000000..2cec46d --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_signal.py @@ -0,0 +1,41 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Defines constants for signals that should be supported on devices. + +Note: Obtained by running `kill -l` on a user device. +""" + + +SIGHUP = 1 # Hangup +SIGINT = 2 # Interrupt +SIGQUIT = 3 # Quit +SIGILL = 4 # Illegal instruction +SIGTRAP = 5 # Trap +SIGABRT = 6 # Aborted +SIGBUS = 7 # Bus error +SIGFPE = 8 # Floating point exception +SIGKILL = 9 # Killed +SIGUSR1 = 10 # User signal 1 +SIGSEGV = 11 # Segmentation fault +SIGUSR2 = 12 # User signal 2 +SIGPIPE = 13 # Broken pipe +SIGALRM = 14 # Alarm clock +SIGTERM = 15 # Terminated +SIGSTKFLT = 16 # Stack fault +SIGCHLD = 17 # Child exited +SIGCONT = 18 # Continue +SIGSTOP = 19 # Stopped (signal) +SIGTSTP = 20 # Stopped +SIGTTIN = 21 # Stopped (tty input) +SIGTTOU = 22 # Stopped (tty output) +SIGURG = 23 # Urgent I/O condition +SIGXCPU = 24 # CPU time limit exceeded +SIGXFSZ = 25 # File size limit exceeded +SIGVTALRM = 26 # Virtual timer expired +SIGPROF = 27 # Profiling timer expired +SIGWINCH = 28 # Window size changed +SIGIO = 29 # I/O possible +SIGPWR = 30 # Power failure +SIGSYS = 31 # Bad system call diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_temp_file.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_temp_file.py new file mode 100644 index 0000000..4d0c7ad --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_temp_file.py @@ -0,0 +1,63 @@ +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""A temp file that automatically gets pushed and deleted from a device.""" + +# pylint: disable=W0622 + +import posixpath +import random +import threading + +from devil.android import device_errors +from devil.utils import cmd_helper + + +class DeviceTempFile(object): + + def __init__(self, adb, suffix='', prefix='temp_file', dir='/data/local/tmp'): + """Find an unused temporary file path on the device. + + When this object is closed, the file will be deleted on the device. + + Args: + adb: An instance of AdbWrapper + suffix: The suffix of the name of the temp file. + prefix: The prefix of the name of the temp file. + dir: The directory on the device where to place the temp file. + Raises: + ValueError if any of suffix, prefix, or dir are None. + """ + if None in (dir, prefix, suffix): + m = 'Provided None path component. (dir: %s, prefix: %s, suffix: %s)' % ( + dir, prefix, suffix) + raise ValueError(m) + + self._adb = adb + # Python's random module use 52-bit numbers according to its docs. + random_hex = hex(random.randint(0, 2 ** 52))[2:] + self.name = posixpath.join(dir, '%s-%s%s' % (prefix, random_hex, suffix)) + self.name_quoted = cmd_helper.SingleQuote(self.name) + + def close(self): + """Deletes the temporary file from the device.""" + # ignore exception if the file is already gone. + def delete_temporary_file(): + try: + self._adb.Shell('rm -f %s' % self.name_quoted, expect_status=None) + except device_errors.AdbCommandFailedError: + # file does not exist on Android version without 'rm -f' support (ICS) + pass + + # It shouldn't matter when the temp file gets deleted, so do so + # asynchronously. + threading.Thread( + target=delete_temporary_file, + name='delete_temporary_file(%s)' % self._adb.GetDeviceSerial()).start() + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_test_case.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_test_case.py new file mode 100644 index 0000000..1148b54 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_test_case.py @@ -0,0 +1,54 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import threading +import unittest + +from devil.android import device_errors +from devil.android import device_utils + +_devices_lock = threading.Lock() +_devices_condition = threading.Condition(_devices_lock) +_devices = set() + + +def PrepareDevices(*_args): + + raw_devices = device_utils.DeviceUtils.HealthyDevices() + live_devices = [] + for d in raw_devices: + try: + d.WaitUntilFullyBooted(timeout=5, retries=0) + live_devices.append(str(d)) + except (device_errors.CommandFailedError, + device_errors.CommandTimeoutError, + device_errors.DeviceUnreachableError): + pass + with _devices_lock: + _devices.update(set(live_devices)) + + if not _devices: + raise Exception('No live devices attached.') + + +class DeviceTestCase(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(DeviceTestCase, self).__init__(*args, **kwargs) + self.serial = None + + #override + def setUp(self): + super(DeviceTestCase, self).setUp() + with _devices_lock: + while not _devices: + _devices_condition.wait(5) + self.serial = _devices.pop() + + #override + def tearDown(self): + super(DeviceTestCase, self).tearDown() + with _devices_lock: + _devices.add(self.serial) + _devices_condition.notify() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils.py new file mode 100644 index 0000000..51f7194 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils.py @@ -0,0 +1,2654 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Provides a variety of device interactions based on adb. + +Eventually, this will be based on adb_wrapper. +""" +# pylint: disable=unused-argument + +import calendar +import collections +import itertools +import json +import logging +import multiprocessing +import os +import posixpath +import pprint +import re +import shutil +import stat +import tempfile +import time +import threading +import uuid +import zipfile + +from devil import base_error +from devil import devil_env +from devil.utils import cmd_helper +from devil.android import apk_helper +from devil.android import device_signal +from devil.android import decorators +from devil.android import device_errors +from devil.android import device_temp_file +from devil.android import install_commands +from devil.android import logcat_monitor +from devil.android import md5sum +from devil.android.constants import chrome +from devil.android.sdk import adb_wrapper +from devil.android.sdk import intent +from devil.android.sdk import keyevent +from devil.android.sdk import split_select +from devil.android.sdk import version_codes +from devil.utils import host_utils +from devil.utils import parallelizer +from devil.utils import reraiser_thread +from devil.utils import timeout_retry +from devil.utils import zip_utils + +logger = logging.getLogger(__name__) + +_DEFAULT_TIMEOUT = 30 +_DEFAULT_RETRIES = 3 + +# A sentinel object for default values +# TODO(jbudorick,perezju): revisit how default values are handled by +# the timeout_retry decorators. +DEFAULT = object() + +_RESTART_ADBD_SCRIPT = """ + trap '' HUP + trap '' TERM + trap '' PIPE + function restart() { + stop adbd + start adbd + } + restart & +""" + +# Not all permissions can be set. +_PERMISSIONS_BLACKLIST = [ + 'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS', + 'android.permission.ACCESS_MOCK_LOCATION', + 'android.permission.ACCESS_NETWORK_STATE', + 'android.permission.ACCESS_NOTIFICATION_POLICY', + 'android.permission.ACCESS_WIFI_STATE', + 'android.permission.AUTHENTICATE_ACCOUNTS', + 'android.permission.BLUETOOTH', + 'android.permission.BLUETOOTH_ADMIN', + 'android.permission.BROADCAST_STICKY', + 'android.permission.CHANGE_NETWORK_STATE', + 'android.permission.CHANGE_WIFI_MULTICAST_STATE', + 'android.permission.CHANGE_WIFI_STATE', + 'android.permission.DISABLE_KEYGUARD', + 'android.permission.DOWNLOAD_WITHOUT_NOTIFICATION', + 'android.permission.EXPAND_STATUS_BAR', + 'android.permission.GET_PACKAGE_SIZE', + 'android.permission.INSTALL_SHORTCUT', + 'android.permission.INTERNET', + 'android.permission.KILL_BACKGROUND_PROCESSES', + 'android.permission.MANAGE_ACCOUNTS', + 'android.permission.MODIFY_AUDIO_SETTINGS', + 'android.permission.NFC', + 'android.permission.READ_SYNC_SETTINGS', + 'android.permission.READ_SYNC_STATS', + 'android.permission.RECEIVE_BOOT_COMPLETED', + 'android.permission.RECORD_VIDEO', + 'android.permission.REORDER_TASKS', + 'android.permission.REQUEST_INSTALL_PACKAGES', + 'android.permission.RUN_INSTRUMENTATION', + 'android.permission.SET_ALARM', + 'android.permission.SET_TIME_ZONE', + 'android.permission.SET_WALLPAPER', + 'android.permission.SET_WALLPAPER_HINTS', + 'android.permission.TRANSMIT_IR', + 'android.permission.USE_CREDENTIALS', + 'android.permission.USE_FINGERPRINT', + 'android.permission.VIBRATE', + 'android.permission.WAKE_LOCK', + 'android.permission.WRITE_SYNC_SETTINGS', + 'com.android.browser.permission.READ_HISTORY_BOOKMARKS', + 'com.android.browser.permission.WRITE_HISTORY_BOOKMARKS', + 'com.android.launcher.permission.INSTALL_SHORTCUT', + 'com.chrome.permission.DEVICE_EXTRAS', + 'com.google.android.apps.now.CURRENT_ACCOUNT_ACCESS', + 'com.google.android.c2dm.permission.RECEIVE', + 'com.google.android.providers.gsf.permission.READ_GSERVICES', + 'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER', +] +for package_info in chrome.PACKAGE_INFO.itervalues(): + _PERMISSIONS_BLACKLIST.extend([ + '%s.permission.C2D_MESSAGE' % package_info.package, + '%s.permission.READ_WRITE_BOOKMARK_FOLDERS' % package_info.package, + '%s.TOS_ACKED' % package_info.package]) + +_CURRENT_FOCUS_CRASH_RE = re.compile( + r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') + +_GETPROP_RE = re.compile(r'\[(.*?)\]: \[(.*?)\]') + +# Regex to parse the long (-l) output of 'ls' command, c.f. +# https://github.com/landley/toybox/blob/master/toys/posix/ls.c#L446 +_LONG_LS_OUTPUT_RE = re.compile( + r'(?P[\w-]{10})\s+' # File permissions + r'(?:(?P\d+)\s+)?' # Number of links (optional) + r'(?P\w+)\s+' # Name of owner + r'(?P\w+)\s+' # Group of owner + r'(?:' # Either ... + r'(?P\d+),\s+' # Device major, and + r'(?P\d+)\s+' # Device minor + r'|' # .. or + r'(?P\d+)\s+' # Size in bytes + r')?' # .. or nothing + r'(?P\d{4}-\d\d-\d\d \d\d:\d\d)\s+' # Modification date/time + r'(?P.+?)' # File name + r'(?: -> (?P.+))?' # Symbolic link (optional) + r'$' # End of string +) +_LS_DATE_FORMAT = '%Y-%m-%d %H:%M' +_FILE_MODE_RE = re.compile(r'[dbclps-](?:[r-][w-][xSs-]){2}[r-][w-][xTt-]$') +_FILE_MODE_KIND = { + 'd': stat.S_IFDIR, 'b': stat.S_IFBLK, 'c': stat.S_IFCHR, + 'l': stat.S_IFLNK, 'p': stat.S_IFIFO, 's': stat.S_IFSOCK, + '-': stat.S_IFREG} +_FILE_MODE_PERMS = [ + stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR, + stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP, + stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH, +] +_FILE_MODE_SPECIAL = [ + ('s', stat.S_ISUID), + ('s', stat.S_ISGID), + ('t', stat.S_ISVTX), +] +_SELINUX_MODE = { + 'enforcing': True, + 'permissive': False, + 'disabled': None +} +# Some devices require different logic for checking if root is necessary +_SPECIAL_ROOT_DEVICE_LIST = [ + 'marlin', + 'sailfish', +] + + +@decorators.WithExplicitTimeoutAndRetries( + _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) +def GetAVDs(): + """Returns a list of Android Virtual Devices. + + Returns: + A list containing the configured AVDs. + """ + lines = cmd_helper.GetCmdOutput([ + os.path.join(devil_env.config.LocalPath('android_sdk'), + 'tools', 'android'), + 'list', 'avd']).splitlines() + avds = [] + for line in lines: + if 'Name:' not in line: + continue + key, value = (s.strip() for s in line.split(':', 1)) + if key == 'Name': + avds.append(value) + return avds + + +@decorators.WithExplicitTimeoutAndRetries( + _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) +def RestartServer(): + """Restarts the adb server. + + Raises: + CommandFailedError if we fail to kill or restart the server. + """ + def adb_killed(): + return not adb_wrapper.AdbWrapper.IsServerOnline() + + def adb_started(): + return adb_wrapper.AdbWrapper.IsServerOnline() + + adb_wrapper.AdbWrapper.KillServer() + if not timeout_retry.WaitFor(adb_killed, wait_period=1, max_tries=5): + # TODO(perezju): raise an exception after fixng http://crbug.com/442319 + logger.warning('Failed to kill adb server') + adb_wrapper.AdbWrapper.StartServer() + if not timeout_retry.WaitFor(adb_started, wait_period=1, max_tries=5): + raise device_errors.CommandFailedError('Failed to start adb server') + + +def _ParseModeString(mode_str): + """Parse a mode string, e.g. 'drwxrwxrwx', into a st_mode value. + + Effectively the reverse of |mode_to_string| in, e.g.: + https://github.com/landley/toybox/blob/master/lib/lib.c#L896 + """ + if not _FILE_MODE_RE.match(mode_str): + raise ValueError('Unexpected file mode %r', mode_str) + mode = _FILE_MODE_KIND[mode_str[0]] + for c, flag in zip(mode_str[1:], _FILE_MODE_PERMS): + if c != '-' and c.islower(): + mode |= flag + for c, (t, flag) in zip(mode_str[3::3], _FILE_MODE_SPECIAL): + if c.lower() == t: + mode |= flag + return mode + + +def _GetTimeStamp(): + """Return a basic ISO 8601 time stamp with the current local time.""" + return time.strftime('%Y%m%dT%H%M%S', time.localtime()) + + +def _JoinLines(lines): + # makes sure that the last line is also terminated, and is more memory + # efficient than first appending an end-line to each line and then joining + # all of them together. + return ''.join(s for line in lines for s in (line, '\n')) + + +def _CreateAdbWrapper(device): + if isinstance(device, adb_wrapper.AdbWrapper): + return device + else: + return adb_wrapper.AdbWrapper(device) + + +def _FormatPartialOutputError(output): + lines = output.splitlines() if isinstance(output, basestring) else output + message = ['Partial output found:'] + if len(lines) > 11: + message.extend('- %s' % line for line in lines[:5]) + message.extend('') + message.extend('- %s' % line for line in lines[-5:]) + else: + message.extend('- %s' % line for line in lines) + return '\n'.join(message) + + +class DeviceUtils(object): + + _MAX_ADB_COMMAND_LENGTH = 512 + _MAX_ADB_OUTPUT_LENGTH = 32768 + _LAUNCHER_FOCUSED_RE = re.compile( + r'\s*mCurrentFocus.*(Launcher|launcher).*') + _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') + + LOCAL_PROPERTIES_PATH = posixpath.join('/', 'data', 'local.prop') + + # Property in /data/local.prop that controls Java assertions. + JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' + + def __init__(self, device, enable_device_files_cache=False, + default_timeout=_DEFAULT_TIMEOUT, + default_retries=_DEFAULT_RETRIES): + """DeviceUtils constructor. + + Args: + device: Either a device serial, an existing AdbWrapper instance, or an + an existing AndroidCommands instance. + enable_device_files_cache: For PushChangedFiles(), cache checksums of + pushed files rather than recomputing them on a subsequent call. + default_timeout: An integer containing the default number of seconds to + wait for an operation to complete if no explicit value is provided. + default_retries: An integer containing the default number or times an + operation should be retried on failure if no explicit value is provided. + """ + self.adb = None + if isinstance(device, basestring): + self.adb = _CreateAdbWrapper(device) + elif isinstance(device, adb_wrapper.AdbWrapper): + self.adb = device + else: + raise ValueError('Unsupported device value: %r' % device) + self._commands_installed = None + self._default_timeout = default_timeout + self._default_retries = default_retries + self._enable_device_files_cache = enable_device_files_cache + self._cache = {} + self._client_caches = {} + self._cache_lock = threading.RLock() + assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR) + assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR) + + self._ClearCache() + + @property + def serial(self): + """Returns the device serial.""" + return self.adb.GetDeviceSerial() + + def __eq__(self, other): + """Checks whether |other| refers to the same device as |self|. + + Args: + other: The object to compare to. This can be a basestring, an instance + of adb_wrapper.AdbWrapper, or an instance of DeviceUtils. + Returns: + Whether |other| refers to the same device as |self|. + """ + return self.serial == str(other) + + def __lt__(self, other): + """Compares two instances of DeviceUtils. + + This merely compares their serial numbers. + + Args: + other: The instance of DeviceUtils to compare to. + Returns: + Whether |self| is less than |other|. + """ + return self.serial < other.serial + + def __str__(self): + """Returns the device serial.""" + return self.serial + + @decorators.WithTimeoutAndRetriesFromInstance() + def IsOnline(self, timeout=None, retries=None): + """Checks whether the device is online. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + True if the device is online, False otherwise. + + Raises: + CommandTimeoutError on timeout. + """ + try: + return self.adb.GetState() == 'device' + except base_error.BaseError as exc: + logger.info('Failed to get state: %s', exc) + return False + + @decorators.WithTimeoutAndRetriesFromInstance() + def HasRoot(self, timeout=None, retries=None): + """Checks whether or not adbd has root privileges. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + True if adbd has root privileges, False otherwise. + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + try: + if self.product_name in _SPECIAL_ROOT_DEVICE_LIST: + return self.GetProp('service.adb.root') == '1' + self.RunShellCommand(['ls', '/root'], check_return=True) + return True + except device_errors.AdbCommandFailedError: + return False + + def NeedsSU(self, timeout=DEFAULT, retries=DEFAULT): + """Checks whether 'su' is needed to access protected resources. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + True if 'su' is available on the device and is needed to to access + protected resources; False otherwise if either 'su' is not available + (e.g. because the device has a user build), or not needed (because adbd + already has root privileges). + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + if 'needs_su' not in self._cache: + cmd = '%s && ! ls /root' % self._Su('ls /root') + if self.product_name in _SPECIAL_ROOT_DEVICE_LIST: + if self.HasRoot(): + self._cache['needs_su'] = False + return False + cmd = 'which which && which su' + try: + self.RunShellCommand(cmd, shell=True, check_return=True, + timeout=self._default_timeout if timeout is DEFAULT else timeout, + retries=self._default_retries if retries is DEFAULT else retries) + self._cache['needs_su'] = True + except device_errors.AdbCommandFailedError: + self._cache['needs_su'] = False + return self._cache['needs_su'] + + + def _Su(self, command): + if self.build_version_sdk >= version_codes.MARSHMALLOW: + return 'su 0 %s' % command + return 'su -c %s' % command + + @decorators.WithTimeoutAndRetriesFromInstance() + def EnableRoot(self, timeout=None, retries=None): + """Restarts adbd with root privileges. + + Args: + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError if root could not be enabled. + CommandTimeoutError on timeout. + """ + if 'needs_su' in self._cache: + del self._cache['needs_su'] + + try: + self.adb.Root() + except device_errors.AdbCommandFailedError: + if self.IsUserBuild(): + raise device_errors.CommandFailedError( + 'Unable to root device with user build.', str(self)) + else: + raise # Failed probably due to some other reason. + + def device_online_with_root(): + try: + self.adb.WaitForDevice() + return self.GetProp('service.adb.root', cache=False) == '1' + except (device_errors.AdbCommandFailedError, + device_errors.DeviceUnreachableError): + return False + + timeout_retry.WaitFor(device_online_with_root, wait_period=1) + + @decorators.WithTimeoutAndRetriesFromInstance() + def IsUserBuild(self, timeout=None, retries=None): + """Checks whether or not the device is running a user build. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + True if the device is running a user build, False otherwise (i.e. if + it's running a userdebug build). + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + return self.build_type == 'user' + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetExternalStoragePath(self, timeout=None, retries=None): + """Get the device's path to its SD card. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + The device's path to its SD card. + + Raises: + CommandFailedError if the external storage path could not be determined. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + self._EnsureCacheInitialized() + if not self._cache['external_storage']: + raise device_errors.CommandFailedError('$EXTERNAL_STORAGE is not set', + str(self)) + return self._cache['external_storage'] + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetApplicationPaths(self, package, timeout=None, retries=None): + """Get the paths of the installed apks on the device for the given package. + + Args: + package: Name of the package. + + Returns: + List of paths to the apks on the device for the given package. + """ + return self._GetApplicationPathsInternal(package) + + def _GetApplicationPathsInternal(self, package, skip_cache=False): + cached_result = self._cache['package_apk_paths'].get(package) + if cached_result is not None and not skip_cache: + if package in self._cache['package_apk_paths_to_verify']: + self._cache['package_apk_paths_to_verify'].remove(package) + # Don't verify an app that is not thought to be installed. We are + # concerned only with apps we think are installed having been + # uninstalled manually. + if cached_result and not self.PathExists(cached_result): + cached_result = None + self._cache['package_apk_checksums'].pop(package, 0) + if cached_result is not None: + return list(cached_result) + # 'pm path' is liable to incorrectly exit with a nonzero number starting + # in Lollipop. + # TODO(jbudorick): Check if this is fixed as new Android versions are + # released to put an upper bound on this. + should_check_return = (self.build_version_sdk < version_codes.LOLLIPOP) + output = self.RunShellCommand( + ['pm', 'path', package], check_return=should_check_return) + apks = [] + for line in output: + if not line.startswith('package:'): + continue + apks.append(line[len('package:'):]) + if not apks and output: + raise device_errors.CommandFailedError( + 'pm path returned: %r' % '\n'.join(output), str(self)) + self._cache['package_apk_paths'][package] = list(apks) + return apks + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetApplicationVersion(self, package, timeout=None, retries=None): + """Get the version name of a package installed on the device. + + Args: + package: Name of the package. + + Returns: + A string with the version name or None if the package is not found + on the device. + """ + output = self.RunShellCommand( + ['dumpsys', 'package', package], check_return=True) + if not output: + return None + for line in output: + line = line.strip() + if line.startswith('versionName='): + return line[len('versionName='):] + raise device_errors.CommandFailedError( + 'Version name for %s not found on dumpsys output' % package, str(self)) + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetApplicationDataDirectory(self, package, timeout=None, retries=None): + """Get the data directory on the device for the given package. + + Args: + package: Name of the package. + + Returns: + The package's data directory. + Raises: + CommandFailedError if the package's data directory can't be found, + whether because it's not installed or otherwise. + """ + output = self._RunPipedShellCommand( + 'pm dump %s | grep dataDir=' % cmd_helper.SingleQuote(package)) + for line in output: + _, _, dataDir = line.partition('dataDir=') + if dataDir: + return dataDir + raise device_errors.CommandFailedError( + 'Could not find data directory for %s', package) + + @decorators.WithTimeoutAndRetriesFromInstance() + def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): + """Wait for the device to fully boot. + + This means waiting for the device to boot, the package manager to be + available, and the SD card to be ready. It can optionally mean waiting + for wifi to come up, too. + + Args: + wifi: A boolean indicating if we should wait for wifi to come up or not. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError on failure. + CommandTimeoutError if one of the component waits times out. + DeviceUnreachableError if the device becomes unresponsive. + """ + def sd_card_ready(): + try: + self.RunShellCommand(['test', '-d', self.GetExternalStoragePath()], + check_return=True) + return True + except device_errors.AdbCommandFailedError: + return False + + def pm_ready(): + try: + return self._GetApplicationPathsInternal('android', skip_cache=True) + except device_errors.CommandFailedError: + return False + + def boot_completed(): + try: + return self.GetProp('sys.boot_completed', cache=False) == '1' + except device_errors.CommandFailedError: + return False + + def wifi_enabled(): + return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'], + check_return=False) + + self.adb.WaitForDevice() + timeout_retry.WaitFor(sd_card_ready) + timeout_retry.WaitFor(pm_ready) + timeout_retry.WaitFor(boot_completed) + if wifi: + timeout_retry.WaitFor(wifi_enabled) + + REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT + + @decorators.WithTimeoutAndRetriesFromInstance( + min_default_timeout=REBOOT_DEFAULT_TIMEOUT) + def Reboot(self, block=True, wifi=False, timeout=None, retries=None): + """Reboot the device. + + Args: + block: A boolean indicating if we should wait for the reboot to complete. + wifi: A boolean indicating if we should wait for wifi to be enabled after + the reboot. The option has no effect unless |block| is also True. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + def device_offline(): + return not self.IsOnline() + + self.adb.Reboot() + self._ClearCache() + timeout_retry.WaitFor(device_offline, wait_period=1) + if block: + self.WaitUntilFullyBooted(wifi=wifi) + + INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT + + @decorators.WithTimeoutAndRetriesFromInstance( + min_default_timeout=INSTALL_DEFAULT_TIMEOUT) + def Install(self, apk, allow_downgrade=False, reinstall=False, + permissions=None, timeout=None, retries=None): + """Install an APK. + + Noop if an identical APK is already installed. + + Args: + apk: An ApkHelper instance or string containing the path to the APK. + allow_downgrade: A boolean indicating if we should allow downgrades. + reinstall: A boolean indicating if we should keep any existing app data. + permissions: Set of permissions to set. If not set, finds permissions with + apk helper. To set no permissions, pass []. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError if the installation fails. + CommandTimeoutError if the installation times out. + DeviceUnreachableError on missing device. + """ + self._InstallInternal(apk, None, allow_downgrade=allow_downgrade, + reinstall=reinstall, permissions=permissions) + + @decorators.WithTimeoutAndRetriesFromInstance( + min_default_timeout=INSTALL_DEFAULT_TIMEOUT) + def InstallSplitApk(self, base_apk, split_apks, allow_downgrade=False, + reinstall=False, allow_cached_props=False, + permissions=None, timeout=None, retries=None): + """Install a split APK. + + Noop if all of the APK splits are already installed. + + Args: + base_apk: An ApkHelper instance or string containing the path to the base + APK. + split_apks: A list of strings of paths of all of the APK splits. + allow_downgrade: A boolean indicating if we should allow downgrades. + reinstall: A boolean indicating if we should keep any existing app data. + allow_cached_props: Whether to use cached values for device properties. + permissions: Set of permissions to set. If not set, finds permissions with + apk helper. To set no permissions, pass []. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError if the installation fails. + CommandTimeoutError if the installation times out. + DeviceUnreachableError on missing device. + DeviceVersionError if device SDK is less than Android L. + """ + self._InstallInternal(base_apk, split_apks, reinstall=reinstall, + allow_cached_props=allow_cached_props, + permissions=permissions, + allow_downgrade=allow_downgrade) + + def _InstallInternal(self, base_apk, split_apks, allow_downgrade=False, + reinstall=False, allow_cached_props=False, + permissions=None): + if split_apks: + self._CheckSdkLevel(version_codes.LOLLIPOP) + + base_apk = apk_helper.ToHelper(base_apk) + + all_apks = [base_apk.path] + if split_apks: + all_apks += split_select.SelectSplits( + self, base_apk.path, split_apks, allow_cached_props=allow_cached_props) + if len(all_apks) == 1: + logger.warning('split-select did not select any from %s', split_apks) + + missing_apks = [apk for apk in all_apks if not os.path.exists(apk)] + if missing_apks: + raise device_errors.CommandFailedError( + 'Attempted to install non-existent apks: %s' + % pprint.pformat(missing_apks)) + + package_name = base_apk.GetPackageName() + device_apk_paths = self._GetApplicationPathsInternal(package_name) + + apks_to_install = None + host_checksums = None + if not device_apk_paths: + apks_to_install = all_apks + elif len(device_apk_paths) > 1 and not split_apks: + logger.warning( + 'Installing non-split APK when split APK was previously installed') + apks_to_install = all_apks + elif len(device_apk_paths) == 1 and split_apks: + logger.warning( + 'Installing split APK when non-split APK was previously installed') + apks_to_install = all_apks + else: + try: + apks_to_install, host_checksums = ( + self._ComputeStaleApks(package_name, all_apks)) + except EnvironmentError as e: + logger.warning('Error calculating md5: %s', e) + apks_to_install, host_checksums = all_apks, None + if apks_to_install and not reinstall: + self.Uninstall(package_name) + apks_to_install = all_apks + + if apks_to_install: + # Assume that we won't know the resulting device state. + self._cache['package_apk_paths'].pop(package_name, 0) + self._cache['package_apk_checksums'].pop(package_name, 0) + if split_apks: + partial = package_name if len(apks_to_install) < len(all_apks) else None + self.adb.InstallMultiple( + apks_to_install, partial=partial, reinstall=reinstall, + allow_downgrade=allow_downgrade) + else: + self.adb.Install( + base_apk.path, reinstall=reinstall, allow_downgrade=allow_downgrade) + if (permissions is None + and self.build_version_sdk >= version_codes.MARSHMALLOW): + permissions = base_apk.GetPermissions() + self.GrantPermissions(package_name, permissions) + # Upon success, we know the device checksums, but not their paths. + if host_checksums is not None: + self._cache['package_apk_checksums'][package_name] = host_checksums + else: + # Running adb install terminates running instances of the app, so to be + # consistent, we explicitly terminate it when skipping the install. + self.ForceStop(package_name) + + @decorators.WithTimeoutAndRetriesFromInstance() + def Uninstall(self, package_name, keep_data=False, timeout=None, + retries=None): + """Remove the app |package_name| from the device. + + This is a no-op if the app is not already installed. + + Args: + package_name: The package to uninstall. + keep_data: (optional) Whether to keep the data and cache directories. + timeout: Timeout in seconds. + retries: Number of retries. + + Raises: + CommandFailedError if the uninstallation fails. + CommandTimeoutError if the uninstallation times out. + DeviceUnreachableError on missing device. + """ + installed = self._GetApplicationPathsInternal(package_name) + if not installed: + return + try: + self.adb.Uninstall(package_name, keep_data) + self._cache['package_apk_paths'][package_name] = [] + self._cache['package_apk_checksums'][package_name] = set() + except: + # Clear cache since we can't be sure of the state. + self._cache['package_apk_paths'].pop(package_name, 0) + self._cache['package_apk_checksums'].pop(package_name, 0) + raise + + def _CheckSdkLevel(self, required_sdk_level): + """Raises an exception if the device does not have the required SDK level. + """ + if self.build_version_sdk < required_sdk_level: + raise device_errors.DeviceVersionError( + ('Requires SDK level %s, device is SDK level %s' % + (required_sdk_level, self.build_version_sdk)), + device_serial=self.serial) + + @decorators.WithTimeoutAndRetriesFromInstance() + def RunShellCommand(self, cmd, shell=False, check_return=False, cwd=None, + env=None, run_as=None, as_root=False, single_line=False, + large_output=False, raw_output=False, timeout=None, + retries=None): + """Run an ADB shell command. + + The command to run |cmd| should be a sequence of program arguments + (preferred) or a single string with a shell script to run. + + When |cmd| is a sequence, it is assumed to contain the name of the command + to run followed by its arguments. In this case, arguments are passed to the + command exactly as given, preventing any further processing by the shell. + This allows callers to easily pass arguments with spaces or special + characters without having to worry about quoting rules. Whenever possible, + it is recomended to pass |cmd| as a sequence. + + When |cmd| is passed as a single string, |shell| should be set to True. + The command will be interpreted and run by the shell on the device, + allowing the use of shell features such as pipes, wildcards, or variables. + Failing to set shell=True will issue a warning, but this will be changed + to a hard failure in the future (see: catapult:#3242). + + This behaviour is consistent with that of command runners in cmd_helper as + well as Python's own subprocess.Popen. + + TODO(perezju) Change the default of |check_return| to True when callers + have switched to the new behaviour. + + Args: + cmd: A sequence containing the command to run and its arguments, or a + string with a shell script to run (should also set shell=True). + shell: A boolean indicating whether shell features may be used in |cmd|. + check_return: A boolean indicating whether or not the return code should + be checked. + cwd: The device directory in which the command should be run. + env: The environment variables with which the command should be run. + run_as: A string containing the package as which the command should be + run. + as_root: A boolean indicating whether the shell command should be run + with root privileges. + single_line: A boolean indicating if only a single line of output is + expected. + large_output: Uses a work-around for large shell command output. Without + this large output will be truncated. + raw_output: Whether to only return the raw output + (no splitting into lines). + timeout: timeout in seconds + retries: number of retries + + Returns: + If single_line is False, the output of the command as a list of lines, + otherwise, a string with the unique line of output emmited by the command + (with the optional newline at the end stripped). + + Raises: + AdbCommandFailedError if check_return is True and the exit code of + the command run on the device is non-zero. + CommandFailedError if single_line is True but the output contains two or + more lines. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + def env_quote(key, value): + if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): + raise KeyError('Invalid shell variable name %r' % key) + # using double quotes here to allow interpolation of shell variables + return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) + + def run(cmd): + return self.adb.Shell(cmd) + + def handle_check_return(cmd): + try: + return run(cmd) + except device_errors.AdbCommandFailedError as exc: + if check_return: + raise + else: + return exc.output + + def handle_large_command(cmd): + if len(cmd) < self._MAX_ADB_COMMAND_LENGTH: + return handle_check_return(cmd) + else: + with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script: + self._WriteFileWithPush(script.name, cmd) + logger.info('Large shell command will be run from file: %s ...', + cmd[:self._MAX_ADB_COMMAND_LENGTH]) + return handle_check_return('sh %s' % script.name_quoted) + + def handle_large_output(cmd, large_output_mode): + if large_output_mode: + with device_temp_file.DeviceTempFile(self.adb) as large_output_file: + cmd = '( %s )>%s' % (cmd, large_output_file.name) + logger.debug('Large output mode enabled. Will write output to ' + 'device and read results from file.') + handle_large_command(cmd) + return self.ReadFile(large_output_file.name, force_pull=True) + else: + try: + return handle_large_command(cmd) + except device_errors.AdbCommandFailedError as exc: + if exc.status is None: + logger.error(_FormatPartialOutputError(exc.output)) + logger.warning('Attempting to run in large_output mode.') + logger.warning('Use RunShellCommand(..., large_output=True) for ' + 'shell commands that expect a lot of output.') + return handle_large_output(cmd, True) + else: + raise + + if isinstance(cmd, basestring): + if not shell: + logging.warning( + 'The command to run should preferably be passed as a sequence of' + ' args. If shell features are needed (pipes, wildcards, variables)' + ' clients should explicitly set shell=True.') + else: + cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) + if env: + env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) + cmd = '%s %s' % (env, cmd) + if cwd: + cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) + if run_as: + cmd = 'run-as %s sh -c %s' % (cmd_helper.SingleQuote(run_as), + cmd_helper.SingleQuote(cmd)) + if as_root and self.NeedsSU(): + # "su -c sh -c" allows using shell features in |cmd| + cmd = self._Su('sh -c %s' % cmd_helper.SingleQuote(cmd)) + + output = handle_large_output(cmd, large_output) + + if raw_output: + return output + + output = output.splitlines() + if single_line: + if not output: + return '' + elif len(output) == 1: + return output[0] + else: + msg = 'one line of output was expected, but got: %s' + raise device_errors.CommandFailedError(msg % output, str(self)) + else: + return output + + def _RunPipedShellCommand(self, script, **kwargs): + PIPESTATUS_LEADER = 'PIPESTATUS: ' + + script += '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER + kwargs.update(shell=True, check_return=True) + output = self.RunShellCommand(script, **kwargs) + pipestatus_line = output[-1] + + if not pipestatus_line.startswith(PIPESTATUS_LEADER): + logger.error('Pipe exit statuses of shell script missing.') + raise device_errors.AdbShellCommandFailedError( + script, output, status=None, + device_serial=self.serial) + + output = output[:-1] + statuses = [ + int(s) for s in pipestatus_line[len(PIPESTATUS_LEADER):].split()] + if any(statuses): + raise device_errors.AdbShellCommandFailedError( + script, output, status=statuses, + device_serial=self.serial) + return output + + @decorators.WithTimeoutAndRetriesFromInstance() + def KillAll(self, process_name, exact=False, signum=device_signal.SIGKILL, + as_root=False, blocking=False, quiet=False, + timeout=None, retries=None): + """Kill all processes with the given name on the device. + + Args: + process_name: A string containing the name of the process to kill. + exact: A boolean indicating whether to kill all processes matching + the string |process_name| exactly, or all of those which contain + |process_name| as a substring. Defaults to False. + signum: An integer containing the signal number to send to kill. Defaults + to SIGKILL (9). + as_root: A boolean indicating whether the kill should be executed with + root privileges. + blocking: A boolean indicating whether we should wait until all processes + with the given |process_name| are dead. + quiet: A boolean indicating whether to ignore the fact that no processes + to kill were found. + timeout: timeout in seconds + retries: number of retries + + Returns: + The number of processes attempted to kill. + + Raises: + CommandFailedError if no process was killed and |quiet| is False. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + procs_pids = self.GetPids(process_name) + if exact: + procs_pids = {process_name: procs_pids.get(process_name, [])} + pids = set(itertools.chain(*procs_pids.values())) + if not pids: + if quiet: + return 0 + else: + raise device_errors.CommandFailedError( + 'No process "%s"' % process_name, str(self)) + + logger.info( + 'KillAll(%r, ...) attempting to kill the following:', process_name) + for name, ids in procs_pids.iteritems(): + for i in ids: + logger.info(' %05s %s', str(i), name) + + cmd = ['kill', '-%d' % signum] + sorted(pids) + self.RunShellCommand(cmd, as_root=as_root, check_return=True) + + def all_pids_killed(): + procs_pids_remain = self.GetPids(process_name) + return not pids.intersection(itertools.chain(*procs_pids_remain.values())) + + if blocking: + timeout_retry.WaitFor(all_pids_killed, wait_period=0.1) + + return len(pids) + + @decorators.WithTimeoutAndRetriesFromInstance() + def StartActivity(self, intent_obj, blocking=False, trace_file_name=None, + force_stop=False, timeout=None, retries=None): + """Start package's activity on the device. + + Args: + intent_obj: An Intent object to send. + blocking: A boolean indicating whether we should wait for the activity to + finish launching. + trace_file_name: If present, a string that both indicates that we want to + profile the activity and contains the path to which the + trace should be saved. + force_stop: A boolean indicating whether we should stop the activity + before starting it. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError if the activity could not be started. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + cmd = ['am', 'start'] + if blocking: + cmd.append('-W') + if trace_file_name: + cmd.extend(['--start-profiler', trace_file_name]) + if force_stop: + cmd.append('-S') + cmd.extend(intent_obj.am_args) + for line in self.RunShellCommand(cmd, check_return=True): + if line.startswith('Error:'): + raise device_errors.CommandFailedError(line, str(self)) + + @decorators.WithTimeoutAndRetriesFromInstance() + def StartInstrumentation(self, component, finish=True, raw=False, + extras=None, timeout=None, retries=None): + if extras is None: + extras = {} + + cmd = ['am', 'instrument'] + if finish: + cmd.append('-w') + if raw: + cmd.append('-r') + for k, v in extras.iteritems(): + cmd.extend(['-e', str(k), str(v)]) + cmd.append(component) + + # Store the package name in a shell variable to help the command stay under + # the _MAX_ADB_COMMAND_LENGTH limit. + package = component.split('/')[0] + shell_snippet = 'p=%s;%s' % (package, + cmd_helper.ShrinkToSnippet(cmd, 'p', package)) + return self.RunShellCommand(shell_snippet, shell=True, check_return=True, + large_output=True) + + @decorators.WithTimeoutAndRetriesFromInstance() + def BroadcastIntent(self, intent_obj, timeout=None, retries=None): + """Send a broadcast intent. + + Args: + intent: An Intent to broadcast. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + cmd = ['am', 'broadcast'] + intent_obj.am_args + self.RunShellCommand(cmd, check_return=True) + + @decorators.WithTimeoutAndRetriesFromInstance() + def GoHome(self, timeout=None, retries=None): + """Return to the home screen and obtain launcher focus. + + This command launches the home screen and attempts to obtain + launcher focus until the timeout is reached. + + Args: + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + def is_launcher_focused(): + output = self.RunShellCommand(['dumpsys', 'window', 'windows'], + check_return=True, large_output=True) + return any(self._LAUNCHER_FOCUSED_RE.match(l) for l in output) + + def dismiss_popups(): + # There is a dialog present; attempt to get rid of it. + # Not all dialogs can be dismissed with back. + self.SendKeyEvent(keyevent.KEYCODE_ENTER) + self.SendKeyEvent(keyevent.KEYCODE_BACK) + return is_launcher_focused() + + # If Home is already focused, return early to avoid unnecessary work. + if is_launcher_focused(): + return + + self.StartActivity( + intent.Intent(action='android.intent.action.MAIN', + category='android.intent.category.HOME'), + blocking=True) + + if not is_launcher_focused(): + timeout_retry.WaitFor(dismiss_popups, wait_period=1) + + @decorators.WithTimeoutAndRetriesFromInstance() + def ForceStop(self, package, timeout=None, retries=None): + """Close the application. + + Args: + package: A string containing the name of the package to stop. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + if self.GetPids(package): + self.RunShellCommand(['am', 'force-stop', package], check_return=True) + + @decorators.WithTimeoutAndRetriesFromInstance() + def ClearApplicationState( + self, package, permissions=None, timeout=None, retries=None): + """Clear all state for the given package. + + Args: + package: A string containing the name of the package to stop. + permissions: List of permissions to set after clearing data. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + # Check that the package exists before clearing it for android builds below + # JB MR2. Necessary because calling pm clear on a package that doesn't exist + # may never return. + if ((self.build_version_sdk >= version_codes.JELLY_BEAN_MR2) + or self._GetApplicationPathsInternal(package)): + self.RunShellCommand(['pm', 'clear', package], check_return=True) + self.GrantPermissions(package, permissions) + + @decorators.WithTimeoutAndRetriesFromInstance() + def SendKeyEvent(self, keycode, timeout=None, retries=None): + """Sends a keycode to the device. + + See the devil.android.sdk.keyevent module for suitable keycode values. + + Args: + keycode: A integer keycode to send to the device. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + self.RunShellCommand(['input', 'keyevent', format(keycode, 'd')], + check_return=True) + + PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT + + @decorators.WithTimeoutAndRetriesFromInstance( + min_default_timeout=PUSH_CHANGED_FILES_DEFAULT_TIMEOUT) + def PushChangedFiles(self, host_device_tuples, timeout=None, + retries=None, delete_device_stale=False): + """Push files to the device, skipping files that don't need updating. + + When a directory is pushed, it is traversed recursively on the host and + all files in it are pushed to the device as needed. + Additionally, if delete_device_stale option is True, + files that exist on the device but don't exist on the host are deleted. + + Args: + host_device_tuples: A list of (host_path, device_path) tuples, where + |host_path| is an absolute path of a file or directory on the host + that should be minimially pushed to the device, and |device_path| is + an absolute path of the destination on the device. + timeout: timeout in seconds + retries: number of retries + delete_device_stale: option to delete stale files on device + + Raises: + CommandFailedError on failure. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + + all_changed_files = [] + all_stale_files = [] + missing_dirs = [] + cache_commit_funcs = [] + for h, d in host_device_tuples: + assert os.path.isabs(h) and posixpath.isabs(d) + h = os.path.realpath(h) + changed_files, up_to_date_files, stale_files, cache_commit_func = ( + self._GetChangedAndStaleFiles(h, d, delete_device_stale)) + all_changed_files += changed_files + all_stale_files += stale_files + cache_commit_funcs.append(cache_commit_func) + if changed_files and not up_to_date_files and not stale_files: + if os.path.isdir(h): + missing_dirs.append(d) + else: + missing_dirs.append(posixpath.dirname(d)) + + if delete_device_stale and all_stale_files: + self.RunShellCommand(['rm', '-f'] + all_stale_files, check_return=True) + + if all_changed_files: + if missing_dirs: + self.RunShellCommand(['mkdir', '-p'] + missing_dirs, check_return=True) + self._PushFilesImpl(host_device_tuples, all_changed_files) + for func in cache_commit_funcs: + func() + + def _GetChangedAndStaleFiles(self, host_path, device_path, track_stale=False): + """Get files to push and delete + + Args: + host_path: an absolute path of a file or directory on the host + device_path: an absolute path of a file or directory on the device + track_stale: whether to bother looking for stale files (slower) + + Returns: + a four-element tuple + 1st element: a list of (host_files_path, device_files_path) tuples to push + 2nd element: a list of host_files_path that are up-to-date + 3rd element: a list of stale files under device_path, or [] when + track_stale == False + 4th element: a cache commit function. + """ + try: + # Length calculations below assume no trailing /. + host_path = host_path.rstrip('/') + device_path = device_path.rstrip('/') + + specific_device_paths = [device_path] + ignore_other_files = not track_stale and os.path.isdir(host_path) + if ignore_other_files: + specific_device_paths = [] + for root, _, filenames in os.walk(host_path): + relative_dir = root[len(host_path) + 1:] + specific_device_paths.extend( + posixpath.join(device_path, relative_dir, f) for f in filenames) + + def calculate_host_checksums(): + return md5sum.CalculateHostMd5Sums([host_path]) + + def calculate_device_checksums(): + if self._enable_device_files_cache: + cache_entry = self._cache['device_path_checksums'].get(device_path) + if cache_entry and cache_entry[0] == ignore_other_files: + return dict(cache_entry[1]) + + sums = md5sum.CalculateDeviceMd5Sums(specific_device_paths, self) + + cache_entry = [ignore_other_files, sums] + self._cache['device_path_checksums'][device_path] = cache_entry + return dict(sums) + + host_checksums, device_checksums = reraiser_thread.RunAsync(( + calculate_host_checksums, + calculate_device_checksums)) + except EnvironmentError as e: + logger.warning('Error calculating md5: %s', e) + return ([(host_path, device_path)], [], [], lambda: 0) + + to_push = [] + up_to_date = [] + to_delete = [] + if os.path.isfile(host_path): + host_checksum = host_checksums.get(host_path) + device_checksum = device_checksums.get(device_path) + if host_checksum == device_checksum: + up_to_date.append(host_path) + else: + to_push.append((host_path, device_path)) + else: + for host_abs_path, host_checksum in host_checksums.iteritems(): + device_abs_path = posixpath.join( + device_path, os.path.relpath(host_abs_path, host_path)) + device_checksum = device_checksums.pop(device_abs_path, None) + if device_checksum == host_checksum: + up_to_date.append(host_abs_path) + else: + to_push.append((host_abs_path, device_abs_path)) + to_delete = device_checksums.keys() + + def cache_commit_func(): + new_sums = {posixpath.join(device_path, path[len(host_path) + 1:]): val + for path, val in host_checksums.iteritems()} + cache_entry = [ignore_other_files, new_sums] + self._cache['device_path_checksums'][device_path] = cache_entry + + return (to_push, up_to_date, to_delete, cache_commit_func) + + def _ComputeDeviceChecksumsForApks(self, package_name): + ret = self._cache['package_apk_checksums'].get(package_name) + if ret is None: + device_paths = self._GetApplicationPathsInternal(package_name) + file_to_checksums = md5sum.CalculateDeviceMd5Sums(device_paths, self) + ret = set(file_to_checksums.values()) + self._cache['package_apk_checksums'][package_name] = ret + return ret + + def _ComputeStaleApks(self, package_name, host_apk_paths): + def calculate_host_checksums(): + return md5sum.CalculateHostMd5Sums(host_apk_paths) + + def calculate_device_checksums(): + return self._ComputeDeviceChecksumsForApks(package_name) + + host_checksums, device_checksums = reraiser_thread.RunAsync(( + calculate_host_checksums, calculate_device_checksums)) + stale_apks = [k for (k, v) in host_checksums.iteritems() + if v not in device_checksums] + return stale_apks, set(host_checksums.values()) + + def _PushFilesImpl(self, host_device_tuples, files): + if not files: + return + + size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files) + file_count = len(files) + dir_size = sum(host_utils.GetRecursiveDiskUsage(h) + for h, _ in host_device_tuples) + dir_file_count = 0 + for h, _ in host_device_tuples: + if os.path.isdir(h): + dir_file_count += sum(len(f) for _r, _d, f in os.walk(h)) + else: + dir_file_count += 1 + + push_duration = self._ApproximateDuration( + file_count, file_count, size, False) + dir_push_duration = self._ApproximateDuration( + len(host_device_tuples), dir_file_count, dir_size, False) + zip_duration = self._ApproximateDuration(1, 1, size, True) + + if (dir_push_duration < push_duration and dir_push_duration < zip_duration + # TODO(jbudorick): Resume directory pushing once clients have switched + # to 1.0.36-compatible syntax. + and False): + self._PushChangedFilesIndividually(host_device_tuples) + elif push_duration < zip_duration: + self._PushChangedFilesIndividually(files) + elif self._commands_installed is False: + # Already tried and failed to install unzip command. + self._PushChangedFilesIndividually(files) + elif not self._PushChangedFilesZipped( + files, [d for _, d in host_device_tuples]): + self._PushChangedFilesIndividually(files) + + def _MaybeInstallCommands(self): + if self._commands_installed is None: + try: + if not install_commands.Installed(self): + install_commands.InstallCommands(self) + self._commands_installed = True + except device_errors.CommandFailedError as e: + logger.warning('unzip not available: %s', str(e)) + self._commands_installed = False + return self._commands_installed + + @staticmethod + def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping): + # We approximate the time to push a set of files to a device as: + # t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where + # t: total time (sec) + # c1: adb call time delay (sec) + # a: number of times adb is called (unitless) + # c2: push time delay (sec) + # f: number of files pushed via adb (unitless) + # c3: zip time delay (sec) + # c4: zip rate (bytes/sec) + # b: total number of bytes (bytes) + # c5: transfer rate (bytes/sec) + # c6: compression ratio (unitless) + + # All of these are approximations. + ADB_CALL_PENALTY = 0.1 # seconds + ADB_PUSH_PENALTY = 0.01 # seconds + ZIP_PENALTY = 2.0 # seconds + ZIP_RATE = 10000000.0 # bytes / second + TRANSFER_RATE = 2000000.0 # bytes / second + COMPRESSION_RATIO = 2.0 # unitless + + adb_call_time = ADB_CALL_PENALTY * adb_calls + adb_push_setup_time = ADB_PUSH_PENALTY * file_count + if is_zipping: + zip_time = ZIP_PENALTY + byte_count / ZIP_RATE + transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO) + else: + zip_time = 0 + transfer_time = byte_count / TRANSFER_RATE + return adb_call_time + adb_push_setup_time + zip_time + transfer_time + + def _PushChangedFilesIndividually(self, files): + for h, d in files: + self.adb.Push(h, d) + + def _PushChangedFilesZipped(self, files, dirs): + with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file: + zip_proc = multiprocessing.Process( + target=DeviceUtils._CreateDeviceZip, + args=(zip_file.name, files)) + zip_proc.start() + try: + # While it's zipping, ensure the unzip command exists on the device. + if not self._MaybeInstallCommands(): + zip_proc.terminate() + return False + + # Warm up NeedsSU cache while we're still zipping. + self.NeedsSU() + with device_temp_file.DeviceTempFile( + self.adb, suffix='.zip') as device_temp: + zip_proc.join() + self.adb.Push(zip_file.name, device_temp.name) + quoted_dirs = ' '.join(cmd_helper.SingleQuote(d) for d in dirs) + self.RunShellCommand( + 'unzip %s&&chmod -R 777 %s' % (device_temp.name, quoted_dirs), + shell=True, as_root=True, + env={'PATH': '%s:$PATH' % install_commands.BIN_DIR}, + check_return=True) + finally: + if zip_proc.is_alive(): + zip_proc.terminate() + return True + + @staticmethod + def _CreateDeviceZip(zip_path, host_device_tuples): + with zipfile.ZipFile(zip_path, 'w') as zip_file: + for host_path, device_path in host_device_tuples: + zip_utils.WriteToZipFile(zip_file, host_path, device_path) + + # TODO(nednguyen): remove this and migrate the callsite to PathExists(). + @decorators.WithTimeoutAndRetriesFromInstance() + def FileExists(self, device_path, timeout=None, retries=None): + """Checks whether the given file exists on the device. + + Arguments are the same as PathExists. + """ + return self.PathExists(device_path, timeout=timeout, retries=retries) + + @decorators.WithTimeoutAndRetriesFromInstance() + def PathExists(self, device_paths, as_root=False, timeout=None, retries=None): + """Checks whether the given path(s) exists on the device. + + Args: + device_path: A string containing the absolute path to the file on the + device, or an iterable of paths to check. + as_root: Whether root permissions should be use to check for the existence + of the given path(s). + timeout: timeout in seconds + retries: number of retries + + Returns: + True if the all given paths exist on the device, False otherwise. + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + paths = device_paths + if isinstance(paths, basestring): + paths = (paths,) + if not paths: + return True + cmd = ['test', '-e', paths[0]] + for p in paths[1:]: + cmd.extend(['-a', '-e', p]) + try: + self.RunShellCommand(cmd, as_root=as_root, check_return=True, + timeout=timeout, retries=retries) + return True + except device_errors.CommandFailedError: + return False + + @decorators.WithTimeoutAndRetriesFromInstance() + def RemovePath(self, device_path, force=False, recursive=False, + as_root=False, timeout=None, retries=None): + """Removes the given path(s) from the device. + + Args: + device_path: A string containing the absolute path to the file on the + device, or an iterable of paths to check. + force: Whether to remove the path(s) with force (-f). + recursive: Whether to remove any directories in the path(s) recursively. + as_root: Whether root permissions should be use to remove the given + path(s). + timeout: timeout in seconds + retries: number of retries + """ + args = ['rm'] + if force: + args.append('-f') + if recursive: + args.append('-r') + if isinstance(device_path, basestring): + args.append(device_path) + else: + args.extend(device_path) + self.RunShellCommand(args, as_root=as_root, check_return=True) + + + @decorators.WithTimeoutAndRetriesFromInstance() + def PullFile(self, device_path, host_path, timeout=None, retries=None): + """Pull a file from the device. + + Args: + device_path: A string containing the absolute path of the file to pull + from the device. + host_path: A string containing the absolute path of the destination on + the host. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError on failure. + CommandTimeoutError on timeout. + """ + # Create the base dir if it doesn't exist already + dirname = os.path.dirname(host_path) + if dirname and not os.path.exists(dirname): + os.makedirs(dirname) + self.adb.Pull(device_path, host_path) + + def _ReadFileWithPull(self, device_path): + try: + d = tempfile.mkdtemp() + host_temp_path = os.path.join(d, 'tmp_ReadFileWithPull') + self.adb.Pull(device_path, host_temp_path) + with open(host_temp_path, 'r') as host_temp: + return host_temp.read() + finally: + if os.path.exists(d): + shutil.rmtree(d) + + @decorators.WithTimeoutAndRetriesFromInstance() + def ReadFile(self, device_path, as_root=False, force_pull=False, + timeout=None, retries=None): + """Reads the contents of a file from the device. + + Args: + device_path: A string containing the absolute path of the file to read + from the device. + as_root: A boolean indicating whether the read should be executed with + root privileges. + force_pull: A boolean indicating whether to force the operation to be + performed by pulling a file from the device. The default is, when the + contents are short, to retrieve the contents using cat instead. + timeout: timeout in seconds + retries: number of retries + + Returns: + The contents of |device_path| as a string. Contents are intepreted using + universal newlines, so the caller will see them encoded as '\n'. Also, + all lines will be terminated. + + Raises: + AdbCommandFailedError if the file can't be read. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + def get_size(path): + return self.FileSize(path, as_root=as_root) + + if (not force_pull + and 0 < get_size(device_path) <= self._MAX_ADB_OUTPUT_LENGTH): + return _JoinLines(self.RunShellCommand( + ['cat', device_path], as_root=as_root, check_return=True)) + elif as_root and self.NeedsSU(): + with device_temp_file.DeviceTempFile(self.adb) as device_temp: + cmd = 'SRC=%s DEST=%s;cp "$SRC" "$DEST" && chmod 666 "$DEST"' % ( + cmd_helper.SingleQuote(device_path), + cmd_helper.SingleQuote(device_temp.name)) + self.RunShellCommand(cmd, shell=True, as_root=True, check_return=True) + return self._ReadFileWithPull(device_temp.name) + else: + return self._ReadFileWithPull(device_path) + + def _WriteFileWithPush(self, device_path, contents): + with tempfile.NamedTemporaryFile() as host_temp: + host_temp.write(contents) + host_temp.flush() + self.adb.Push(host_temp.name, device_path) + + @decorators.WithTimeoutAndRetriesFromInstance() + def WriteFile(self, device_path, contents, as_root=False, force_push=False, + timeout=None, retries=None): + """Writes |contents| to a file on the device. + + Args: + device_path: A string containing the absolute path to the file to write + on the device. + contents: A string containing the data to write to the device. + as_root: A boolean indicating whether the write should be executed with + root privileges (if available). + force_push: A boolean indicating whether to force the operation to be + performed by pushing a file to the device. The default is, when the + contents are short, to pass the contents using a shell script instead. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError if the file could not be written on the device. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + if not force_push and len(contents) < self._MAX_ADB_COMMAND_LENGTH: + # If the contents are small, for efficieny we write the contents with + # a shell command rather than pushing a file. + cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents), + cmd_helper.SingleQuote(device_path)) + self.RunShellCommand(cmd, shell=True, as_root=as_root, check_return=True) + elif as_root and self.NeedsSU(): + # Adb does not allow to "push with su", so we first push to a temp file + # on a safe location, and then copy it to the desired location with su. + with device_temp_file.DeviceTempFile(self.adb) as device_temp: + self._WriteFileWithPush(device_temp.name, contents) + # Here we need 'cp' rather than 'mv' because the temp and + # destination files might be on different file systems (e.g. + # on internal storage and an external sd card). + self.RunShellCommand(['cp', device_temp.name, device_path], + as_root=True, check_return=True) + else: + # If root is not needed, we can push directly to the desired location. + self._WriteFileWithPush(device_path, contents) + + def _ParseLongLsOutput(self, device_path, as_root=False, **kwargs): + """Run and scrape the output of 'ls -a -l' on a device directory.""" + device_path = posixpath.join(device_path, '') # Force trailing '/'. + output = self.RunShellCommand( + ['ls', '-a', '-l', device_path], as_root=as_root, + check_return=True, env={'TZ': 'utc'}, **kwargs) + if output and output[0].startswith('total '): + output.pop(0) # pylint: disable=maybe-no-member + + entries = [] + for line in output: + m = _LONG_LS_OUTPUT_RE.match(line) + if m: + if m.group('filename') not in ['.', '..']: + entries.append(m.groupdict()) + else: + logger.info('Skipping: %s', line) + + return entries + + def ListDirectory(self, device_path, as_root=False, **kwargs): + """List all files on a device directory. + + Mirroring os.listdir (and most client expectations) the resulting list + does not include the special entries '.' and '..' even if they are present + in the directory. + + Args: + device_path: A string containing the path of the directory on the device + to list. + as_root: A boolean indicating whether the to use root privileges to list + the directory contents. + timeout: timeout in seconds + retries: number of retries + + Returns: + A list of filenames for all entries contained in the directory. + + Raises: + AdbCommandFailedError if |device_path| does not specify a valid and + accessible directory in the device. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + entries = self._ParseLongLsOutput(device_path, as_root=as_root, **kwargs) + return [d['filename'] for d in entries] + + def StatDirectory(self, device_path, as_root=False, **kwargs): + """List file and stat info for all entries on a device directory. + + Implementation notes: this is currently implemented by parsing the output + of 'ls -a -l' on the device. Whether possible and convenient, we attempt to + make parsing strict and return values mirroring those of the standard |os| + and |stat| Python modules. + + Mirroring os.listdir (and most client expectations) the resulting list + does not include the special entries '.' and '..' even if they are present + in the directory. + + Args: + device_path: A string containing the path of the directory on the device + to list. + as_root: A boolean indicating whether the to use root privileges to list + the directory contents. + timeout: timeout in seconds + retries: number of retries + + Returns: + A list of dictionaries, each containing the following keys: + filename: A string with the file name. + st_mode: File permissions, use the stat module to interpret these. + st_nlink: Number of hard links (may be missing). + st_owner: A string with the user name of the owner. + st_group: A string with the group name of the owner. + st_rdev_pair: Device type as (major, minior) (only if inode device). + st_size: Size of file, in bytes (may be missing for non-regular files). + st_mtime: Time of most recent modification, in seconds since epoch + (although resolution is in minutes). + symbolic_link_to: If entry is a symbolic link, path where it points to; + missing otherwise. + + Raises: + AdbCommandFailedError if |device_path| does not specify a valid and + accessible directory in the device. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + entries = self._ParseLongLsOutput(device_path, as_root=as_root, **kwargs) + for d in entries: + for key, value in d.items(): + if value is None: + del d[key] # Remove missing fields. + d['st_mode'] = _ParseModeString(d['st_mode']) + d['st_mtime'] = calendar.timegm( + time.strptime(d['st_mtime'], _LS_DATE_FORMAT)) + for key in ['st_nlink', 'st_size', 'st_rdev_major', 'st_rdev_minor']: + if key in d: + d[key] = int(d[key]) + if 'st_rdev_major' in d and 'st_rdev_minor' in d: + d['st_rdev_pair'] = (d.pop('st_rdev_major'), d.pop('st_rdev_minor')) + return entries + + def StatPath(self, device_path, as_root=False, **kwargs): + """Get the stat attributes of a file or directory on the device. + + Args: + device_path: A string containing the path of a file or directory from + which to get attributes. + as_root: A boolean indicating whether the to use root privileges to + access the file information. + timeout: timeout in seconds + retries: number of retries + + Returns: + A dictionary with the stat info collected; see StatDirectory for details. + + Raises: + CommandFailedError if device_path cannot be found on the device. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + dirname, filename = posixpath.split(posixpath.normpath(device_path)) + for entry in self.StatDirectory(dirname, as_root=as_root, **kwargs): + if entry['filename'] == filename: + return entry + raise device_errors.CommandFailedError( + 'Cannot find file or directory: %r' % device_path, str(self)) + + def FileSize(self, device_path, as_root=False, **kwargs): + """Get the size of a file on the device. + + Note: This is implemented by parsing the output of the 'ls' command on + the device. On some Android versions, when passing a directory or special + file, the size is *not* reported and this function will throw an exception. + + Args: + device_path: A string containing the path of a file on the device. + as_root: A boolean indicating whether the to use root privileges to + access the file information. + timeout: timeout in seconds + retries: number of retries + + Returns: + The size of the file in bytes. + + Raises: + CommandFailedError if device_path cannot be found on the device, or + its size cannot be determited for some reason. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + entry = self.StatPath(device_path, as_root=as_root, **kwargs) + try: + return entry['st_size'] + except KeyError: + raise device_errors.CommandFailedError( + 'Could not determine the size of: %s' % device_path, str(self)) + + @decorators.WithTimeoutAndRetriesFromInstance() + def SetJavaAsserts(self, enabled, timeout=None, retries=None): + """Enables or disables Java asserts. + + Args: + enabled: A boolean indicating whether Java asserts should be enabled + or disabled. + timeout: timeout in seconds + retries: number of retries + + Returns: + True if the device-side property changed and a restart is required as a + result, False otherwise. + + Raises: + CommandTimeoutError on timeout. + """ + def find_property(lines, property_name): + for index, line in enumerate(lines): + if line.strip() == '': + continue + key_value = tuple(s.strip() for s in line.split('=', 1)) + if len(key_value) != 2: + continue + key, value = key_value + if key == property_name: + return index, value + return None, '' + + new_value = 'all' if enabled else '' + + # First ensure the desired property is persisted. + try: + properties = self.ReadFile(self.LOCAL_PROPERTIES_PATH).splitlines() + except device_errors.CommandFailedError: + properties = [] + index, value = find_property(properties, self.JAVA_ASSERT_PROPERTY) + if new_value != value: + if new_value: + new_line = '%s=%s' % (self.JAVA_ASSERT_PROPERTY, new_value) + if index is None: + properties.append(new_line) + else: + properties[index] = new_line + else: + assert index is not None # since new_value == '' and new_value != value + properties.pop(index) + self.WriteFile(self.LOCAL_PROPERTIES_PATH, _JoinLines(properties)) + + # Next, check the current runtime value is what we need, and + # if not, set it and report that a reboot is required. + value = self.GetProp(self.JAVA_ASSERT_PROPERTY) + if new_value != value: + self.SetProp(self.JAVA_ASSERT_PROPERTY, new_value) + return True + else: + return False + + def GetLanguage(self, cache=False): + """Returns the language setting on the device. + Args: + cache: Whether to use cached properties when available. + """ + return self.GetProp('persist.sys.language', cache=cache) + + def GetCountry(self, cache=False): + """Returns the country setting on the device. + + Args: + cache: Whether to use cached properties when available. + """ + return self.GetProp('persist.sys.country', cache=cache) + + @property + def screen_density(self): + """Returns the screen density of the device.""" + DPI_TO_DENSITY = { + 120: 'ldpi', + 160: 'mdpi', + 240: 'hdpi', + 320: 'xhdpi', + 480: 'xxhdpi', + 640: 'xxxhdpi', + } + return DPI_TO_DENSITY.get(self.pixel_density, 'tvdpi') + + @property + def pixel_density(self): + return int(self.GetProp('ro.sf.lcd_density', cache=True)) + + @property + def build_description(self): + """Returns the build description of the system. + + For example: + nakasi-user 4.4.4 KTU84P 1227136 release-keys + """ + return self.GetProp('ro.build.description', cache=True) + + @property + def build_fingerprint(self): + """Returns the build fingerprint of the system. + + For example: + google/nakasi/grouper:4.4.4/KTU84P/1227136:user/release-keys + """ + return self.GetProp('ro.build.fingerprint', cache=True) + + @property + def build_id(self): + """Returns the build ID of the system (e.g. 'KTU84P').""" + return self.GetProp('ro.build.id', cache=True) + + @property + def build_product(self): + """Returns the build product of the system (e.g. 'grouper').""" + return self.GetProp('ro.build.product', cache=True) + + @property + def build_type(self): + """Returns the build type of the system (e.g. 'user').""" + return self.GetProp('ro.build.type', cache=True) + + @property + def build_version_sdk(self): + """Returns the build version sdk of the system as a number (e.g. 19). + + For version code numbers see: + http://developer.android.com/reference/android/os/Build.VERSION_CODES.html + + For named constants see devil.android.sdk.version_codes + + Raises: + CommandFailedError if the build version sdk is not a number. + """ + value = self.GetProp('ro.build.version.sdk', cache=True) + try: + return int(value) + except ValueError: + raise device_errors.CommandFailedError( + 'Invalid build version sdk: %r' % value) + + @property + def product_cpu_abi(self): + """Returns the product cpu abi of the device (e.g. 'armeabi-v7a').""" + return self.GetProp('ro.product.cpu.abi', cache=True) + + @property + def product_model(self): + """Returns the name of the product model (e.g. 'Nexus 7').""" + return self.GetProp('ro.product.model', cache=True) + + @property + def product_name(self): + """Returns the product name of the device (e.g. 'nakasi').""" + return self.GetProp('ro.product.name', cache=True) + + @property + def product_board(self): + """Returns the product board name of the device (e.g. 'shamu').""" + return self.GetProp('ro.product.board', cache=True) + + def _EnsureCacheInitialized(self): + """Populates cache token, runs getprop and fetches $EXTERNAL_STORAGE.""" + if self._cache['token']: + return + with self._cache_lock: + if self._cache['token']: + return + # Change the token every time to ensure that it will match only the + # previously dumped cache. + token = str(uuid.uuid1()) + cmd = ( + 'c=/data/local/tmp/cache_token;' + 'echo $EXTERNAL_STORAGE;' + 'cat $c 2>/dev/null||echo;' + 'echo "%s">$c &&' % token + + 'getprop' + ) + output = self.RunShellCommand( + cmd, shell=True, check_return=True, large_output=True) + # Error-checking for this existing is done in GetExternalStoragePath(). + self._cache['external_storage'] = output[0] + self._cache['prev_token'] = output[1] + output = output[2:] + + prop_cache = self._cache['getprop'] + prop_cache.clear() + for key, value in _GETPROP_RE.findall(''.join(output)): + prop_cache[key] = value + self._cache['token'] = token + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetProp(self, property_name, cache=False, timeout=None, retries=None): + """Gets a property from the device. + + Args: + property_name: A string containing the name of the property to get from + the device. + cache: Whether to use cached properties when available. + timeout: timeout in seconds + retries: number of retries + + Returns: + The value of the device's |property_name| property. + + Raises: + CommandTimeoutError on timeout. + """ + assert isinstance(property_name, basestring), ( + "property_name is not a string: %r" % property_name) + + if cache: + # It takes ~120ms to query a single property, and ~130ms to query all + # properties. So, when caching we always query all properties. + self._EnsureCacheInitialized() + else: + # timeout and retries are handled down at run shell, because we don't + # want to apply them in the other branch when reading from the cache + value = self.RunShellCommand( + ['getprop', property_name], single_line=True, check_return=True, + timeout=timeout, retries=retries) + self._cache['getprop'][property_name] = value + # Non-existent properties are treated as empty strings by getprop. + return self._cache['getprop'].get(property_name, '') + + @decorators.WithTimeoutAndRetriesFromInstance() + def SetProp(self, property_name, value, check=False, timeout=None, + retries=None): + """Sets a property on the device. + + Args: + property_name: A string containing the name of the property to set on + the device. + value: A string containing the value to set to the property on the + device. + check: A boolean indicating whether to check that the property was + successfully set on the device. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError if check is true and the property was not correctly + set on the device (e.g. because it is not rooted). + CommandTimeoutError on timeout. + """ + assert isinstance(property_name, basestring), ( + "property_name is not a string: %r" % property_name) + assert isinstance(value, basestring), "value is not a string: %r" % value + + self.RunShellCommand(['setprop', property_name, value], check_return=True) + prop_cache = self._cache['getprop'] + if property_name in prop_cache: + del prop_cache[property_name] + # TODO(perezju) remove the option and make the check mandatory, but using a + # single shell script to both set- and getprop. + if check and value != self.GetProp(property_name, cache=False): + raise device_errors.CommandFailedError( + 'Unable to set property %r on the device to %r' + % (property_name, value), str(self)) + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetABI(self, timeout=None, retries=None): + """Gets the device main ABI. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + The device's main ABI name. + + Raises: + CommandTimeoutError on timeout. + """ + return self.GetProp('ro.product.cpu.abi', cache=True) + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetPids(self, process_name=None, timeout=None, retries=None): + """Returns the PIDs of processes containing the given name as substring. + + Note that the |process_name| is often the package name. + + Args: + process_name: A string containing the process name to get the PIDs for. + If missing returns PIDs for all processes. + timeout: timeout in seconds + retries: number of retries + + Returns: + A dict mapping process name to a list of PIDs for each process that + contained the provided |process_name|. + + Raises: + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + procs_pids = collections.defaultdict(list) + try: + ps_cmd = 'ps' + # ps behavior was changed in Android above N, http://crbug.com/686716 + if (self.build_version_sdk >= version_codes.NOUGAT_MR1 + and self.build_id[0] > 'N'): + ps_cmd = 'ps -e' + if process_name: + ps_output = self._RunPipedShellCommand( + '%s | grep -F %s' % (ps_cmd, cmd_helper.SingleQuote(process_name))) + else: + ps_output = self.RunShellCommand( + ps_cmd.split(), check_return=True, large_output=True) + except device_errors.AdbShellCommandFailedError as e: + if e.status and isinstance(e.status, list) and not e.status[0]: + # If ps succeeded but grep failed, there were no processes with the + # given name. + return procs_pids + else: + raise + + process_name = process_name or '' + for line in ps_output: + try: + ps_data = line.split() + pid, process = ps_data[1], ps_data[-1] + if process_name in process and pid != 'PID': + procs_pids[process].append(pid) + except IndexError: + pass + return procs_pids + + def GetApplicationPids(self, process_name, at_most_one=False, **kwargs): + """Returns the PID or PIDs of a given process name. + + Note that the |process_name|, often the package name, must match exactly. + + Args: + process_name: A string containing the process name to get the PIDs for. + at_most_one: A boolean indicating that at most one PID is expected to + be found. + timeout: timeout in seconds + retries: number of retries + + Returns: + A list of the PIDs for the named process. If at_most_one=True returns + the single PID found or None otherwise. + + Raises: + CommandFailedError if at_most_one=True and more than one PID is found + for the named process. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + pids = self.GetPids(process_name, **kwargs).get(process_name, []) + if at_most_one: + if len(pids) > 1: + raise device_errors.CommandFailedError( + 'Expected a single process but found PIDs: %s.' % ', '.join(pids), + device_serial=str(self)) + return pids[0] if pids else None + else: + return pids + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetEnforce(self, timeout=None, retries=None): + """Get the current mode of SELinux. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + True (enforcing), False (permissive), or None (disabled). + + Raises: + CommandFailedError on failure. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + output = self.RunShellCommand( + ['getenforce'], check_return=True, single_line=True).lower() + if output not in _SELINUX_MODE: + raise device_errors.CommandFailedError( + 'Unexpected getenforce output: %s' % output) + return _SELINUX_MODE[output] + + @decorators.WithTimeoutAndRetriesFromInstance() + def SetEnforce(self, enabled, timeout=None, retries=None): + """Modify the mode SELinux is running in. + + Args: + enabled: a boolean indicating whether to put SELinux in encorcing mode + (if True), or permissive mode (otherwise). + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError on failure. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + self.RunShellCommand( + ['setenforce', '1' if int(enabled) else '0'], as_root=True, + check_return=True) + + @decorators.WithTimeoutAndRetriesFromInstance() + def TakeScreenshot(self, host_path=None, timeout=None, retries=None): + """Takes a screenshot of the device. + + Args: + host_path: A string containing the path on the host to save the + screenshot to. If None, a file name in the current + directory will be generated. + timeout: timeout in seconds + retries: number of retries + + Returns: + The name of the file on the host to which the screenshot was saved. + + Raises: + CommandFailedError on failure. + CommandTimeoutError on timeout. + DeviceUnreachableError on missing device. + """ + if not host_path: + host_path = os.path.abspath('screenshot-%s-%s.png' % ( + self.serial, _GetTimeStamp())) + with device_temp_file.DeviceTempFile(self.adb, suffix='.png') as device_tmp: + self.RunShellCommand(['/system/bin/screencap', '-p', device_tmp.name], + check_return=True) + self.PullFile(device_tmp.name, host_path) + return host_path + + @decorators.WithTimeoutAndRetriesFromInstance() + def GetMemoryUsageForPid(self, pid, timeout=None, retries=None): + """Gets the memory usage for the given PID. + + Args: + pid: PID of the process. + timeout: timeout in seconds + retries: number of retries + + Returns: + A dict containing memory usage statistics for the PID. May include: + Size, Rss, Pss, Shared_Clean, Shared_Dirty, Private_Clean, + Private_Dirty, VmHWM + + Raises: + CommandTimeoutError on timeout. + """ + result = collections.defaultdict(int) + + try: + result.update(self._GetMemoryUsageForPidFromSmaps(pid)) + except device_errors.CommandFailedError: + logger.exception('Error getting memory usage from smaps') + + try: + result.update(self._GetMemoryUsageForPidFromStatus(pid)) + except device_errors.CommandFailedError: + logger.exception('Error getting memory usage from status') + + return result + + @decorators.WithTimeoutAndRetriesFromInstance() + def DismissCrashDialogIfNeeded(self, timeout=None, retries=None): + """Dismiss the error/ANR dialog if present. + + Returns: Name of the crashed package if a dialog is focused, + None otherwise. + """ + def _FindFocusedWindow(): + match = None + # TODO(jbudorick): Try to grep the output on the device instead of using + # large_output if/when DeviceUtils exposes a public interface for piped + # shell command handling. + for line in self.RunShellCommand(['dumpsys', 'window', 'windows'], + check_return=True, large_output=True): + match = re.match(_CURRENT_FOCUS_CRASH_RE, line) + if match: + break + return match + + match = _FindFocusedWindow() + if not match: + return None + package = match.group(2) + logger.warning('Trying to dismiss %s dialog for %s', *match.groups()) + self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT) + self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT) + self.SendKeyEvent(keyevent.KEYCODE_ENTER) + match = _FindFocusedWindow() + if match: + logger.error('Still showing a %s dialog for %s', *match.groups()) + return package + + def _GetMemoryUsageForPidFromSmaps(self, pid): + SMAPS_COLUMNS = ( + 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean', + 'Private_Dirty') + + showmap_out = self._RunPipedShellCommand( + 'showmap %d | grep TOTAL' % int(pid), as_root=True) + + split_totals = showmap_out[-1].split() + if (not split_totals + or len(split_totals) != 9 + or split_totals[-1] != 'TOTAL'): + raise device_errors.CommandFailedError( + 'Invalid output from showmap: %s' % '\n'.join(showmap_out)) + + return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals))) + + def _GetMemoryUsageForPidFromStatus(self, pid): + for line in self.ReadFile( + '/proc/%s/status' % str(pid), as_root=True).splitlines(): + if line.startswith('VmHWM:'): + return {'VmHWM': int(line.split()[1])} + raise device_errors.CommandFailedError( + 'Could not find memory peak value for pid %s', str(pid)) + + def GetLogcatMonitor(self, *args, **kwargs): + """Returns a new LogcatMonitor associated with this device. + + Parameters passed to this function are passed directly to + |logcat_monitor.LogcatMonitor| and are documented there. + """ + return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs) + + def GetClientCache(self, client_name): + """Returns client cache.""" + if client_name not in self._client_caches: + self._client_caches[client_name] = {} + return self._client_caches[client_name] + + def _ClearCache(self): + """Clears all caches.""" + for client in self._client_caches: + self._client_caches[client].clear() + self._cache = { + # Map of packageId -> list of on-device .apk paths + 'package_apk_paths': {}, + # Set of packageId that were loaded from LoadCacheData and not yet + # verified. + 'package_apk_paths_to_verify': set(), + # Map of packageId -> set of on-device .apk checksums + 'package_apk_checksums': {}, + # Map of property_name -> value + 'getprop': {}, + # Map of device_path -> [ignore_other_files, map of path->checksum] + 'device_path_checksums': {}, + # Location of sdcard ($EXTERNAL_STORAGE). + 'external_storage': None, + # Token used to detect when LoadCacheData is stale. + 'token': None, + 'prev_token': None, + } + + @decorators.WithTimeoutAndRetriesFromInstance() + def LoadCacheData(self, data, timeout=None, retries=None): + """Initializes the cache from data created using DumpCacheData. + + The cache is used only if its token matches the one found on the device. + This prevents a stale cache from being used (which can happen when sharing + devices). + + Args: + data: A previously serialized cache (string). + timeout: timeout in seconds + retries: number of retries + + Returns: + Whether the cache was loaded. + """ + obj = json.loads(data) + self._EnsureCacheInitialized() + given_token = obj.get('token') + if not given_token or self._cache['prev_token'] != given_token: + logger.warning('Stale cache detected. Not using it.') + return False + + self._cache['package_apk_paths'] = obj.get('package_apk_paths', {}) + # When using a cache across script invokations, verify that apps have + # not been uninstalled. + self._cache['package_apk_paths_to_verify'] = set( + self._cache['package_apk_paths'].iterkeys()) + + package_apk_checksums = obj.get('package_apk_checksums', {}) + for k, v in package_apk_checksums.iteritems(): + package_apk_checksums[k] = set(v) + self._cache['package_apk_checksums'] = package_apk_checksums + device_path_checksums = obj.get('device_path_checksums', {}) + self._cache['device_path_checksums'] = device_path_checksums + return True + + @decorators.WithTimeoutAndRetriesFromInstance() + def DumpCacheData(self, timeout=None, retries=None): + """Dumps the current cache state to a string. + + Args: + timeout: timeout in seconds + retries: number of retries + + Returns: + A serialized cache as a string. + """ + self._EnsureCacheInitialized() + obj = {} + obj['token'] = self._cache['token'] + obj['package_apk_paths'] = self._cache['package_apk_paths'] + obj['package_apk_checksums'] = self._cache['package_apk_checksums'] + # JSON can't handle sets. + for k, v in obj['package_apk_checksums'].iteritems(): + obj['package_apk_checksums'][k] = list(v) + obj['device_path_checksums'] = self._cache['device_path_checksums'] + return json.dumps(obj, separators=(',', ':')) + + @classmethod + def parallel(cls, devices, async=False): + """Creates a Parallelizer to operate over the provided list of devices. + + Args: + devices: A list of either DeviceUtils instances or objects from + from which DeviceUtils instances can be constructed. If None, + all attached devices will be used. + async: If true, returns a Parallelizer that runs operations + asynchronously. + + Returns: + A Parallelizer operating over |devices|. + """ + devices = [d if isinstance(d, cls) else cls(d) for d in devices] + if async: + return parallelizer.Parallelizer(devices) + else: + return parallelizer.SyncParallelizer(devices) + + @classmethod + def HealthyDevices(cls, blacklist=None, device_arg='default', **kwargs): + """Returns a list of DeviceUtils instances. + + Returns a list of DeviceUtils instances that are attached, not blacklisted, + and optionally filtered by --device flags or ANDROID_SERIAL environment + variable. + + Args: + blacklist: A DeviceBlacklist instance (optional). Device serials in this + blacklist will never be returned, but a warning will be logged if they + otherwise would have been. + device_arg: The value of the --device flag. This can be: + 'default' -> Same as [], but returns an empty list rather than raise a + NoDevicesError. + [] -> Returns all devices, unless $ANDROID_SERIAL is set. + None -> Use $ANDROID_SERIAL if set, otherwise looks for a single + attached device. Raises an exception if multiple devices are + attached. + 'serial' -> Returns an instance for the given serial, if not + blacklisted. + ['A', 'B', ...] -> Returns instances for the subset that is not + blacklisted. + A device serial, or a list of device serials (optional). + + Returns: + A list of DeviceUtils instances. + + Raises: + NoDevicesError: Raised when no non-blacklisted devices exist and + device_arg is passed. + MultipleDevicesError: Raise when multiple devices exist, but |device_arg| + is None. + """ + allow_no_devices = False + if device_arg == 'default': + allow_no_devices = True + device_arg = () + + select_multiple = True + if not (isinstance(device_arg, tuple) or isinstance(device_arg, list)): + select_multiple = False + if device_arg: + device_arg = (device_arg,) + + blacklisted_devices = blacklist.Read() if blacklist else [] + + # adb looks for ANDROID_SERIAL, so support it as well. + android_serial = os.environ.get('ANDROID_SERIAL') + if not device_arg and android_serial: + device_arg = (android_serial,) + + def blacklisted(serial): + if serial in blacklisted_devices: + logger.warning('Device %s is blacklisted.', serial) + return True + return False + + if device_arg: + devices = [cls(x, **kwargs) for x in device_arg if not blacklisted(x)] + else: + devices = [] + for adb in adb_wrapper.AdbWrapper.Devices(): + if not blacklisted(adb.GetDeviceSerial()): + devices.append(cls(_CreateAdbWrapper(adb), **kwargs)) + + if len(devices) == 0 and not allow_no_devices: + raise device_errors.NoDevicesError() + if len(devices) > 1 and not select_multiple: + raise device_errors.MultipleDevicesError(devices) + return sorted(devices) + + @decorators.WithTimeoutAndRetriesFromInstance() + def RestartAdbd(self, timeout=None, retries=None): + logger.info('Restarting adbd on device.') + with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script: + self.WriteFile(script.name, _RESTART_ADBD_SCRIPT) + self.RunShellCommand( + ['source', script.name], check_return=True, as_root=True) + self.adb.WaitForDevice() + + @decorators.WithTimeoutAndRetriesFromInstance() + def GrantPermissions(self, package, permissions, timeout=None, retries=None): + # Permissions only need to be set on M and above because of the changes to + # the permission model. + if not permissions or self.build_version_sdk < version_codes.MARSHMALLOW: + return + logger.info('Setting permissions for %s.', package) + permissions = [p for p in permissions if p not in _PERMISSIONS_BLACKLIST] + if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions + and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions): + permissions.append('android.permission.READ_EXTERNAL_STORAGE') + cmd = '&&'.join('pm grant %s %s' % (package, p) for p in permissions) + if cmd: + output = self.RunShellCommand(cmd, shell=True, check_return=True) + if output: + logger.warning('Possible problem when granting permissions. Blacklist ' + 'may need to be updated.') + for line in output: + logger.warning(' %s', line) + + @decorators.WithTimeoutAndRetriesFromInstance() + def IsScreenOn(self, timeout=None, retries=None): + """Determines if screen is on. + + Dumpsys input_method exposes screen on/off state. Below is an explination of + the states. + + Pre-L: + On: mScreenOn=true + Off: mScreenOn=false + L+: + On: mInteractive=true + Off: mInteractive=false + + Returns: + True if screen is on, false if it is off. + + Raises: + device_errors.CommandFailedError: If screen state cannot be found. + """ + if self.build_version_sdk < version_codes.LOLLIPOP: + input_check = 'mScreenOn' + check_value = 'mScreenOn=true' + else: + input_check = 'mInteractive' + check_value = 'mInteractive=true' + dumpsys_out = self._RunPipedShellCommand( + 'dumpsys input_method | grep %s' % input_check) + if not dumpsys_out: + raise device_errors.CommandFailedError( + 'Unable to detect screen state', str(self)) + return check_value in dumpsys_out[0] + + @decorators.WithTimeoutAndRetriesFromInstance() + def SetScreen(self, on, timeout=None, retries=None): + """Turns screen on and off. + + Args: + on: bool to decide state to switch to. True = on False = off. + """ + def screen_test(): + return self.IsScreenOn() == on + + if screen_test(): + logger.info('Screen already in expected state.') + return + self.SendKeyEvent(keyevent.KEYCODE_POWER) + timeout_retry.WaitFor(screen_test, wait_period=1) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_devicetest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_devicetest.py new file mode 100644 index 0000000..932e278 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_devicetest.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Unit tests for the contents of device_utils.py (mostly DeviceUtils). +The test will invoke real devices +""" + +import os +import posixpath +import sys +import tempfile +import unittest + +if __name__ == '__main__': + sys.path.append( + os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', ))) + +from devil.android import device_test_case +from devil.android import device_utils +from devil.android.sdk import adb_wrapper +from devil.utils import cmd_helper + +_OLD_CONTENTS = "foo" +_NEW_CONTENTS = "bar" +_DEVICE_DIR = "/data/local/tmp/device_utils_test" +_SUB_DIR = "sub" +_SUB_DIR1 = "sub1" +_SUB_DIR2 = "sub2" + + +class DeviceUtilsPushDeleteFilesTest(device_test_case.DeviceTestCase): + + def setUp(self): + super(DeviceUtilsPushDeleteFilesTest, self).setUp() + self.adb = adb_wrapper.AdbWrapper(self.serial) + self.adb.WaitForDevice() + self.device = device_utils.DeviceUtils( + self.adb, default_timeout=10, default_retries=0) + + @staticmethod + def _MakeTempFile(contents): + """Make a temporary file with the given contents. + + Args: + contents: string to write to the temporary file. + + Returns: + the tuple contains the absolute path to the file and the file name + """ + fi, path = tempfile.mkstemp(text=True) + with os.fdopen(fi, 'w') as f: + f.write(contents) + file_name = os.path.basename(path) + return (path, file_name) + + @staticmethod + def _MakeTempFileGivenDir(directory, contents): + """Make a temporary file under the given directory + with the given contents + + Args: + directory: the temp directory to create the file + contents: string to write to the temp file + + Returns: + the list contains the absolute path to the file and the file name + """ + fi, path = tempfile.mkstemp(dir=directory, text=True) + with os.fdopen(fi, 'w') as f: + f.write(contents) + file_name = os.path.basename(path) + return (path, file_name) + + @staticmethod + def _ChangeTempFile(path, contents): + with os.open(path, 'w') as f: + f.write(contents) + + @staticmethod + def _DeleteTempFile(path): + os.remove(path) + + def testPushChangedFiles_noFileChange(self): + (host_file_path, file_name) = self._MakeTempFile(_OLD_CONTENTS) + device_file_path = "%s/%s" % (_DEVICE_DIR, file_name) + self.adb.Push(host_file_path, device_file_path) + self.device.PushChangedFiles([(host_file_path, device_file_path)]) + result = self.device.RunShellCommand( + ['cat', device_file_path], check_return=True, single_line=True) + self.assertEqual(_OLD_CONTENTS, result) + + cmd_helper.RunCmd(['rm', host_file_path]) + self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True) + + def testPushChangedFiles_singleFileChange(self): + (host_file_path, file_name) = self._MakeTempFile(_OLD_CONTENTS) + device_file_path = "%s/%s" % (_DEVICE_DIR, file_name) + self.adb.Push(host_file_path, device_file_path) + + with open(host_file_path, 'w') as f: + f.write(_NEW_CONTENTS) + self.device.PushChangedFiles([(host_file_path, device_file_path)]) + result = self.device.RunShellCommand( + ['cat', device_file_path], check_return=True, single_line=True) + self.assertEqual(_NEW_CONTENTS, result) + + cmd_helper.RunCmd(['rm', host_file_path]) + self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True) + + def testDeleteFiles(self): + host_tmp_dir = tempfile.mkdtemp() + (host_file_path, file_name) = self._MakeTempFileGivenDir( + host_tmp_dir, _OLD_CONTENTS) + + device_file_path = "%s/%s" % (_DEVICE_DIR, file_name) + self.adb.Push(host_file_path, device_file_path) + + cmd_helper.RunCmd(['rm', host_file_path]) + self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)], + delete_device_stale=True) + filenames = self.device.ListDirectory(_DEVICE_DIR) + self.assertEqual([], filenames) + + cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir]) + self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True) + + def testPushAndDeleteFiles_noSubDir(self): + host_tmp_dir = tempfile.mkdtemp() + (host_file_path1, file_name1) = self._MakeTempFileGivenDir( + host_tmp_dir, _OLD_CONTENTS) + (host_file_path2, file_name2) = self._MakeTempFileGivenDir( + host_tmp_dir, _OLD_CONTENTS) + + device_file_path1 = "%s/%s" % (_DEVICE_DIR, file_name1) + device_file_path2 = "%s/%s" % (_DEVICE_DIR, file_name2) + self.adb.Push(host_file_path1, device_file_path1) + self.adb.Push(host_file_path2, device_file_path2) + + with open(host_file_path1, 'w') as f: + f.write(_NEW_CONTENTS) + cmd_helper.RunCmd(['rm', host_file_path2]) + + self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)], + delete_device_stale=True) + result = self.device.RunShellCommand( + ['cat', device_file_path1], check_return=True, single_line=True) + self.assertEqual(_NEW_CONTENTS, result) + + filenames = self.device.ListDirectory(_DEVICE_DIR) + self.assertEqual([file_name1], filenames) + + cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir]) + self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True) + + def testPushAndDeleteFiles_SubDir(self): + host_tmp_dir = tempfile.mkdtemp() + host_sub_dir1 = "%s/%s" % (host_tmp_dir, _SUB_DIR1) + host_sub_dir2 = "%s/%s/%s" % (host_tmp_dir, _SUB_DIR, _SUB_DIR2) + cmd_helper.RunCmd(['mkdir', '-p', host_sub_dir1]) + cmd_helper.RunCmd(['mkdir', '-p', host_sub_dir2]) + + (host_file_path1, file_name1) = self._MakeTempFileGivenDir( + host_tmp_dir, _OLD_CONTENTS) + (host_file_path2, file_name2) = self._MakeTempFileGivenDir( + host_tmp_dir, _OLD_CONTENTS) + (host_file_path3, file_name3) = self._MakeTempFileGivenDir( + host_sub_dir1, _OLD_CONTENTS) + (host_file_path4, file_name4) = self._MakeTempFileGivenDir( + host_sub_dir2, _OLD_CONTENTS) + + device_file_path1 = "%s/%s" % (_DEVICE_DIR, file_name1) + device_file_path2 = "%s/%s" % (_DEVICE_DIR, file_name2) + device_file_path3 = "%s/%s/%s" % (_DEVICE_DIR, _SUB_DIR1, file_name3) + device_file_path4 = "%s/%s/%s/%s" % (_DEVICE_DIR, _SUB_DIR, + _SUB_DIR2, file_name4) + + self.adb.Push(host_file_path1, device_file_path1) + self.adb.Push(host_file_path2, device_file_path2) + self.adb.Push(host_file_path3, device_file_path3) + self.adb.Push(host_file_path4, device_file_path4) + + with open(host_file_path1, 'w') as f: + f.write(_NEW_CONTENTS) + cmd_helper.RunCmd(['rm', host_file_path2]) + cmd_helper.RunCmd(['rm', host_file_path4]) + + self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)], + delete_device_stale=True) + result = self.device.RunShellCommand( + ['cat', device_file_path1], check_return=True, single_line=True) + self.assertEqual(_NEW_CONTENTS, result) + + filenames = self.device.ListDirectory(_DEVICE_DIR) + self.assertIn(file_name1, filenames) + self.assertIn(_SUB_DIR1, filenames) + self.assertIn(_SUB_DIR, filenames) + self.assertEqual(3, len(filenames)) + + result = self.device.RunShellCommand( + ['cat', device_file_path3], check_return=True, single_line=True) + self.assertEqual(_OLD_CONTENTS, result) + + filenames = self.device.ListDirectory( + posixpath.join(_DEVICE_DIR, _SUB_DIR, _SUB_DIR2)) + self.assertEqual([], filenames) + + cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir]) + self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True) + + def testRestartAdbd(self): + def get_adbd_pid(): + # TODO(catapult:#3215): Migrate to device.GetPids(). + ps_output = self.device.RunShellCommand(['ps'], check_return=True) + for ps_line in ps_output: + if 'adbd' in ps_line: + return ps_line.split()[1] + self.fail('Unable to find adbd') + + old_adbd_pid = get_adbd_pid() + self.device.RestartAdbd() + new_adbd_pid = get_adbd_pid() + self.assertNotEqual(old_adbd_pid, new_adbd_pid) + + def testEnableRoot(self): + self.device.SetProp('service.adb.root', '0') + self.device.RestartAdbd() + self.assertFalse(self.device.HasRoot()) + self.assertIn(self.device.GetProp('service.adb.root'), ('', '0')) + self.device.EnableRoot() + self.assertTrue(self.device.HasRoot()) + self.assertEquals(self.device.GetProp('service.adb.root'), '1') + + +if __name__ == '__main__': + unittest.main() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_test.py new file mode 100644 index 0000000..ebd3c62 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/device_utils_test.py @@ -0,0 +1,2908 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Unit tests for the contents of device_utils.py (mostly DeviceUtils). +""" + +# pylint: disable=protected-access +# pylint: disable=unused-argument + +import json +import logging +import os +import stat +import unittest + +from devil import devil_env +from devil.android import device_errors +from devil.android import device_signal +from devil.android import device_utils +from devil.android.sdk import adb_wrapper +from devil.android.sdk import intent +from devil.android.sdk import keyevent +from devil.android.sdk import version_codes +from devil.utils import cmd_helper +from devil.utils import mock_calls + +with devil_env.SysPath(devil_env.PYMOCK_PATH): + import mock # pylint: disable=import-error + + +class AnyStringWith(object): + def __init__(self, value): + self._value = value + + def __eq__(self, other): + return self._value in other + + def __repr__(self): + return '' % self._value + + +class _MockApkHelper(object): + + def __init__(self, path, package_name, perms=None): + self.path = path + self.package_name = package_name + self.perms = perms + + def GetPackageName(self): + return self.package_name + + def GetPermissions(self): + return self.perms + + +class _MockMultipleDevicesError(Exception): + pass + + +class DeviceUtilsInitTest(unittest.TestCase): + + def testInitWithStr(self): + serial_as_str = str('0123456789abcdef') + d = device_utils.DeviceUtils('0123456789abcdef') + self.assertEqual(serial_as_str, d.adb.GetDeviceSerial()) + + def testInitWithUnicode(self): + serial_as_unicode = unicode('fedcba9876543210') + d = device_utils.DeviceUtils(serial_as_unicode) + self.assertEqual(serial_as_unicode, d.adb.GetDeviceSerial()) + + def testInitWithAdbWrapper(self): + serial = '123456789abcdef0' + a = adb_wrapper.AdbWrapper(serial) + d = device_utils.DeviceUtils(a) + self.assertEqual(serial, d.adb.GetDeviceSerial()) + + def testInitWithMissing_fails(self): + with self.assertRaises(ValueError): + device_utils.DeviceUtils(None) + with self.assertRaises(ValueError): + device_utils.DeviceUtils('') + + +class DeviceUtilsGetAVDsTest(mock_calls.TestCase): + + def testGetAVDs(self): + mocked_attrs = { + 'android_sdk': '/my/sdk/path' + } + with mock.patch('devil.devil_env._Environment.LocalPath', + mock.Mock(side_effect=lambda a: mocked_attrs[a])): + with self.assertCall( + mock.call.devil.utils.cmd_helper.GetCmdOutput( + [mock.ANY, 'list', 'avd']), + 'Available Android Virtual Devices:\n' + ' Name: my_android5.0\n' + ' Path: /some/path/to/.android/avd/my_android5.0.avd\n' + ' Target: Android 5.0 (API level 21)\n' + ' Tag/ABI: default/x86\n' + ' Skin: WVGA800\n'): + self.assertEquals(['my_android5.0'], device_utils.GetAVDs()) + + +class DeviceUtilsRestartServerTest(mock_calls.TestCase): + + @mock.patch('time.sleep', mock.Mock()) + def testRestartServer_succeeds(self): + with self.assertCalls( + mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.KillServer(), + (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput( + ['pgrep', 'adb']), + (1, '')), + mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.StartServer(), + (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput( + ['pgrep', 'adb']), + (1, '')), + (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput( + ['pgrep', 'adb']), + (0, '123\n'))): + device_utils.RestartServer() + + +class MockTempFile(object): + + def __init__(self, name='/tmp/some/file'): + self.file = mock.MagicMock(spec=file) + self.file.name = name + self.file.name_quoted = cmd_helper.SingleQuote(name) + + def __enter__(self): + return self.file + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + @property + def name(self): + return self.file.name + + +class _PatchedFunction(object): + + def __init__(self, patched=None, mocked=None): + self.patched = patched + self.mocked = mocked + + +def _AdbWrapperMock(test_serial, is_ready=True): + adb = mock.Mock(spec=adb_wrapper.AdbWrapper) + adb.__str__ = mock.Mock(return_value=test_serial) + adb.GetDeviceSerial.return_value = test_serial + adb.is_ready = is_ready + return adb + + +class DeviceUtilsTest(mock_calls.TestCase): + + def setUp(self): + self.adb = _AdbWrapperMock('0123456789abcdef') + self.device = device_utils.DeviceUtils( + self.adb, default_timeout=10, default_retries=0) + self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial']) + + def AdbCommandError(self, args=None, output=None, status=None, msg=None): + if args is None: + args = ['[unspecified]'] + return mock.Mock(side_effect=device_errors.AdbCommandFailedError( + args, output, status, msg, str(self.device))) + + def CommandError(self, msg=None): + if msg is None: + msg = 'Command failed' + return mock.Mock(side_effect=device_errors.CommandFailedError( + msg, str(self.device))) + + def ShellError(self, output=None, status=1): + def action(cmd, *args, **kwargs): + raise device_errors.AdbShellCommandFailedError( + cmd, output, status, str(self.device)) + if output is None: + output = 'Permission denied\n' + return action + + def TimeoutError(self, msg=None): + if msg is None: + msg = 'Operation timed out' + return mock.Mock(side_effect=device_errors.CommandTimeoutError( + msg, str(self.device))) + + def EnsureCacheInitialized(self, props=None, sdcard='/sdcard'): + props = props or [] + ret = [sdcard, 'TOKEN'] + props + return (self.call.device.RunShellCommand( + AnyStringWith('getprop'), + shell=True, check_return=True, large_output=True), ret) + + +class DeviceUtilsEqTest(DeviceUtilsTest): + + def testEq_equal_deviceUtils(self): + other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef')) + self.assertTrue(self.device == other) + self.assertTrue(other == self.device) + + def testEq_equal_adbWrapper(self): + other = adb_wrapper.AdbWrapper('0123456789abcdef') + self.assertTrue(self.device == other) + self.assertTrue(other == self.device) + + def testEq_equal_string(self): + other = '0123456789abcdef' + self.assertTrue(self.device == other) + self.assertTrue(other == self.device) + + def testEq_devicesNotEqual(self): + other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdee')) + self.assertFalse(self.device == other) + self.assertFalse(other == self.device) + + def testEq_identity(self): + self.assertTrue(self.device == self.device) + + def testEq_serialInList(self): + devices = [self.device] + self.assertTrue('0123456789abcdef' in devices) + + +class DeviceUtilsLtTest(DeviceUtilsTest): + + def testLt_lessThan(self): + other = device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')) + self.assertTrue(self.device < other) + self.assertTrue(other > self.device) + + def testLt_greaterThan_lhs(self): + other = device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')) + self.assertFalse(self.device < other) + self.assertFalse(other > self.device) + + def testLt_equal(self): + other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef')) + self.assertFalse(self.device < other) + self.assertFalse(other > self.device) + + def testLt_sorted(self): + devices = [ + device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')), + device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')), + ] + sorted_devices = sorted(devices) + self.assertEquals('0000000000000000', + sorted_devices[0].adb.GetDeviceSerial()) + self.assertEquals('ffffffffffffffff', + sorted_devices[1].adb.GetDeviceSerial()) + + +class DeviceUtilsStrTest(DeviceUtilsTest): + + def testStr_returnsSerial(self): + with self.assertCalls( + (self.call.adb.GetDeviceSerial(), '0123456789abcdef')): + self.assertEqual('0123456789abcdef', str(self.device)) + + +class DeviceUtilsIsOnlineTest(DeviceUtilsTest): + + def testIsOnline_true(self): + with self.assertCall(self.call.adb.GetState(), 'device'): + self.assertTrue(self.device.IsOnline()) + + def testIsOnline_false(self): + with self.assertCall(self.call.adb.GetState(), 'offline'): + self.assertFalse(self.device.IsOnline()) + + def testIsOnline_error(self): + with self.assertCall(self.call.adb.GetState(), self.CommandError()): + self.assertFalse(self.device.IsOnline()) + + +class DeviceUtilsHasRootTest(DeviceUtilsTest): + + def testHasRoot_true(self): + with self.patch_call(self.call.device.product_name, + return_value='notasailfish'), ( + self.assertCall(self.call.adb.Shell('ls /root'), 'foo\n')): + self.assertTrue(self.device.HasRoot()) + + def testhasRootSpecial_true(self): + with self.patch_call(self.call.device.product_name, + return_value='sailfish'), ( + self.assertCall(self.call.adb.Shell('getprop service.adb.root'), + '1\n')): + self.assertTrue(self.device.HasRoot()) + + def testHasRoot_false(self): + with self.patch_call(self.call.device.product_name, + return_value='notasailfish'), ( + self.assertCall(self.call.adb.Shell('ls /root'), + self.ShellError())): + self.assertFalse(self.device.HasRoot()) + + def testHasRootSpecial_false(self): + with self.patch_call(self.call.device.product_name, + return_value='sailfish'), ( + self.assertCall(self.call.adb.Shell('getprop service.adb.root'), + '\n')): + self.assertFalse(self.device.HasRoot()) + + +class DeviceUtilsEnableRootTest(DeviceUtilsTest): + + def testEnableRoot_succeeds(self): + with self.assertCalls( + self.call.adb.Root(), + self.call.adb.WaitForDevice(), + (self.call.device.GetProp('service.adb.root', cache=False), '1')): + self.device.EnableRoot() + + def testEnableRoot_userBuild(self): + with self.assertCalls( + (self.call.adb.Root(), self.AdbCommandError()), + (self.call.device.IsUserBuild(), True)): + with self.assertRaises(device_errors.CommandFailedError): + self.device.EnableRoot() + + def testEnableRoot_rootFails(self): + with self.assertCalls( + (self.call.adb.Root(), self.AdbCommandError()), + (self.call.device.IsUserBuild(), False)): + with self.assertRaises(device_errors.AdbCommandFailedError): + self.device.EnableRoot() + + +class DeviceUtilsIsUserBuildTest(DeviceUtilsTest): + + def testIsUserBuild_yes(self): + with self.assertCall( + self.call.device.GetProp('ro.build.type', cache=True), 'user'): + self.assertTrue(self.device.IsUserBuild()) + + def testIsUserBuild_no(self): + with self.assertCall( + self.call.device.GetProp('ro.build.type', cache=True), 'userdebug'): + self.assertFalse(self.device.IsUserBuild()) + + +class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsTest): + + def testGetExternalStoragePath_succeeds(self): + with self.assertCalls( + self.EnsureCacheInitialized(sdcard='/fake/storage/path')): + self.assertEquals('/fake/storage/path', + self.device.GetExternalStoragePath()) + + def testGetExternalStoragePath_fails(self): + with self.assertCalls( + self.EnsureCacheInitialized(sdcard='')): + with self.assertRaises(device_errors.CommandFailedError): + self.device.GetExternalStoragePath() + + +class DeviceUtilsGetApplicationPathsInternalTest(DeviceUtilsTest): + + def testGetApplicationPathsInternal_exists(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), + (self.call.device.RunShellCommand( + ['pm', 'path', 'android'], check_return=True), + ['package:/path/to/android.apk'])): + self.assertEquals(['/path/to/android.apk'], + self.device._GetApplicationPathsInternal('android')) + + def testGetApplicationPathsInternal_notExists(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), + (self.call.device.RunShellCommand( + ['pm', 'path', 'not.installed.app'], check_return=True), + '')): + self.assertEquals([], + self.device._GetApplicationPathsInternal('not.installed.app')) + + def testGetApplicationPathsInternal_garbageFirstLine(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), + (self.call.device.RunShellCommand( + ['pm', 'path', 'android'], check_return=True), + ['garbage first line'])): + with self.assertRaises(device_errors.CommandFailedError): + self.device._GetApplicationPathsInternal('android') + + def testGetApplicationPathsInternal_fails(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), + (self.call.device.RunShellCommand( + ['pm', 'path', 'android'], check_return=True), + self.CommandError('ERROR. Is package manager running?\n'))): + with self.assertRaises(device_errors.CommandFailedError): + self.device._GetApplicationPathsInternal('android') + + +class DeviceUtils_GetApplicationVersionTest(DeviceUtilsTest): + + def test_GetApplicationVersion_exists(self): + with self.assertCalls( + (self.call.adb.Shell('dumpsys package com.android.chrome'), + 'Packages:\n' + ' Package [com.android.chrome] (3901ecfb):\n' + ' userId=1234 gids=[123, 456, 789]\n' + ' pkg=Package{1fecf634 com.android.chrome}\n' + ' versionName=45.0.1234.7\n')): + self.assertEquals('45.0.1234.7', + self.device.GetApplicationVersion('com.android.chrome')) + + def test_GetApplicationVersion_notExists(self): + with self.assertCalls( + (self.call.adb.Shell('dumpsys package com.android.chrome'), '')): + self.assertEquals(None, + self.device.GetApplicationVersion('com.android.chrome')) + + def test_GetApplicationVersion_fails(self): + with self.assertCalls( + (self.call.adb.Shell('dumpsys package com.android.chrome'), + 'Packages:\n' + ' Package [com.android.chrome] (3901ecfb):\n' + ' userId=1234 gids=[123, 456, 789]\n' + ' pkg=Package{1fecf634 com.android.chrome}\n')): + with self.assertRaises(device_errors.CommandFailedError): + self.device.GetApplicationVersion('com.android.chrome') + + +class DeviceUtilsGetApplicationDataDirectoryTest(DeviceUtilsTest): + + def testGetApplicationDataDirectory_exists(self): + with self.assertCall( + self.call.device._RunPipedShellCommand( + 'pm dump foo.bar.baz | grep dataDir='), + ['dataDir=/data/data/foo.bar.baz']): + self.assertEquals( + '/data/data/foo.bar.baz', + self.device.GetApplicationDataDirectory('foo.bar.baz')) + + def testGetApplicationDataDirectory_notExists(self): + with self.assertCall( + self.call.device._RunPipedShellCommand( + 'pm dump foo.bar.baz | grep dataDir='), + self.ShellError()): + with self.assertRaises(device_errors.CommandFailedError): + self.device.GetApplicationDataDirectory('foo.bar.baz') + + +@mock.patch('time.sleep', mock.Mock()) +class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest): + + def testWaitUntilFullyBooted_succeedsNoWifi(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), ''), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + ['package:/some/fake/path']), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), '1')): + self.device.WaitUntilFullyBooted(wifi=False) + + def testWaitUntilFullyBooted_succeedsWithWifi(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), ''), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + ['package:/some/fake/path']), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), '1'), + # wifi_enabled + (self.call.adb.Shell('dumpsys wifi'), + 'stuff\nWi-Fi is enabled\nmore stuff\n')): + self.device.WaitUntilFullyBooted(wifi=True) + + def testWaitUntilFullyBooted_deviceNotInitiallyAvailable(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), self.AdbCommandError()), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), self.AdbCommandError()), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), self.AdbCommandError()), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), self.AdbCommandError()), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), ''), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + ['package:/some/fake/path']), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), '1')): + self.device.WaitUntilFullyBooted(wifi=False) + + def testWaitUntilFullyBooted_deviceBrieflyOffline(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), ''), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + ['package:/some/fake/path']), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), + self.AdbCommandError()), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), '1')): + self.device.WaitUntilFullyBooted(wifi=False) + + def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), self.CommandError())): + with self.assertRaises(device_errors.CommandFailedError): + self.device.WaitUntilFullyBooted(wifi=False) + + def testWaitUntilFullyBooted_sdCardReadyFails_notExists(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), + self.TimeoutError())): + with self.assertRaises(device_errors.CommandTimeoutError): + self.device.WaitUntilFullyBooted(wifi=False) + + def testWaitUntilFullyBooted_devicePmFails(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), ''), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + self.CommandError()), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + self.CommandError()), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + self.TimeoutError())): + with self.assertRaises(device_errors.CommandTimeoutError): + self.device.WaitUntilFullyBooted(wifi=False) + + def testWaitUntilFullyBooted_bootFails(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), ''), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + ['package:/some/fake/path']), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), '0'), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), '0'), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), + self.TimeoutError())): + with self.assertRaises(device_errors.CommandTimeoutError): + self.device.WaitUntilFullyBooted(wifi=False) + + def testWaitUntilFullyBooted_wifiFails(self): + with self.assertCalls( + self.call.adb.WaitForDevice(), + # sd_card_ready + (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), + (self.call.adb.Shell('test -d /fake/storage/path'), ''), + # pm_ready + (self.call.device._GetApplicationPathsInternal('android', + skip_cache=True), + ['package:/some/fake/path']), + # boot_completed + (self.call.device.GetProp('sys.boot_completed', cache=False), '1'), + # wifi_enabled + (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'), + # wifi_enabled + (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'), + # wifi_enabled + (self.call.adb.Shell('dumpsys wifi'), self.TimeoutError())): + with self.assertRaises(device_errors.CommandTimeoutError): + self.device.WaitUntilFullyBooted(wifi=True) + + +@mock.patch('time.sleep', mock.Mock()) +class DeviceUtilsRebootTest(DeviceUtilsTest): + + def testReboot_nonBlocking(self): + with self.assertCalls( + self.call.adb.Reboot(), + (self.call.device.IsOnline(), True), + (self.call.device.IsOnline(), False)): + self.device.Reboot(block=False) + + def testReboot_blocking(self): + with self.assertCalls( + self.call.adb.Reboot(), + (self.call.device.IsOnline(), True), + (self.call.device.IsOnline(), False), + self.call.device.WaitUntilFullyBooted(wifi=False)): + self.device.Reboot(block=True) + + def testReboot_blockUntilWifi(self): + with self.assertCalls( + self.call.adb.Reboot(), + (self.call.device.IsOnline(), True), + (self.call.device.IsOnline(), False), + self.call.device.WaitUntilFullyBooted(wifi=True)): + self.device.Reboot(block=True, wifi=True) + + +class DeviceUtilsInstallTest(DeviceUtilsTest): + + mock_apk = _MockApkHelper('/fake/test/app.apk', 'test.package', ['p1']) + + def testInstall_noPriorInstall(self): + with self.patch_call(self.call.device.build_version_sdk, return_value=23): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), []), + self.call.adb.Install('/fake/test/app.apk', reinstall=False, + allow_downgrade=False), + (self.call.device.GrantPermissions('test.package', ['p1']), [])): + self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0) + + def testInstall_permissionsPreM(self): + with self.patch_call(self.call.device.build_version_sdk, return_value=20): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), []), + (self.call.adb.Install('/fake/test/app.apk', reinstall=False, + allow_downgrade=False))): + self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0) + + def testInstall_findPermissions(self): + with self.patch_call(self.call.device.build_version_sdk, return_value=23): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), []), + (self.call.adb.Install('/fake/test/app.apk', reinstall=False, + allow_downgrade=False)), + (self.call.device.GrantPermissions('test.package', ['p1']), [])): + self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0) + + def testInstall_passPermissions(self): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), []), + (self.call.adb.Install('/fake/test/app.apk', reinstall=False, + allow_downgrade=False)), + (self.call.device.GrantPermissions('test.package', ['p1', 'p2']), [])): + self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0, + permissions=['p1', 'p2']) + + def testInstall_differentPriorInstall(self): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), + ['/fake/data/app/test.package.apk']), + (self.call.device._ComputeStaleApks('test.package', + ['/fake/test/app.apk']), + (['/fake/test/app.apk'], None)), + self.call.device.Uninstall('test.package'), + self.call.adb.Install('/fake/test/app.apk', reinstall=False, + allow_downgrade=False)): + self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0, + permissions=[]) + + def testInstall_differentPriorInstall_reinstall(self): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), + ['/fake/data/app/test.package.apk']), + (self.call.device._ComputeStaleApks('test.package', + ['/fake/test/app.apk']), + (['/fake/test/app.apk'], None)), + self.call.adb.Install('/fake/test/app.apk', reinstall=True, + allow_downgrade=False)): + self.device.Install(DeviceUtilsInstallTest.mock_apk, + reinstall=True, retries=0, permissions=[]) + + def testInstall_identicalPriorInstall_reinstall(self): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), + ['/fake/data/app/test.package.apk']), + (self.call.device._ComputeStaleApks('test.package', + ['/fake/test/app.apk']), + ([], None)), + (self.call.device.ForceStop('test.package'))): + self.device.Install(DeviceUtilsInstallTest.mock_apk, + reinstall=True, retries=0, permissions=[]) + + def testInstall_missingApk(self): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), False)): + with self.assertRaises(device_errors.CommandFailedError): + self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0) + + def testInstall_fails(self): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), []), + (self.call.adb.Install('/fake/test/app.apk', reinstall=False, + allow_downgrade=False), + self.CommandError('Failure\r\n'))): + with self.assertRaises(device_errors.CommandFailedError): + self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0) + + def testInstall_downgrade(self): + with self.assertCalls( + (mock.call.os.path.exists('/fake/test/app.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), + ['/fake/data/app/test.package.apk']), + (self.call.device._ComputeStaleApks('test.package', + ['/fake/test/app.apk']), + (['/fake/test/app.apk'], None)), + self.call.adb.Install('/fake/test/app.apk', reinstall=True, + allow_downgrade=True)): + self.device.Install(DeviceUtilsInstallTest.mock_apk, + reinstall=True, retries=0, permissions=[], allow_downgrade=True) + + +class DeviceUtilsInstallSplitApkTest(DeviceUtilsTest): + + mock_apk = _MockApkHelper('base.apk', 'test.package', ['p1']) + + def testInstallSplitApk_noPriorInstall(self): + with self.assertCalls( + (self.call.device._CheckSdkLevel(21)), + (mock.call.devil.android.sdk.split_select.SelectSplits( + self.device, 'base.apk', + ['split1.apk', 'split2.apk', 'split3.apk'], + allow_cached_props=False), + ['split2.apk']), + (mock.call.os.path.exists('base.apk'), True), + (mock.call.os.path.exists('split2.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), []), + (self.call.adb.InstallMultiple( + ['base.apk', 'split2.apk'], partial=None, reinstall=False, + allow_downgrade=False))): + self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk, + ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[], retries=0) + + def testInstallSplitApk_partialInstall(self): + with self.assertCalls( + (self.call.device._CheckSdkLevel(21)), + (mock.call.devil.android.sdk.split_select.SelectSplits( + self.device, 'base.apk', + ['split1.apk', 'split2.apk', 'split3.apk'], + allow_cached_props=False), + ['split2.apk']), + (mock.call.os.path.exists('base.apk'), True), + (mock.call.os.path.exists('split2.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), + ['base-on-device.apk', 'split2-on-device.apk']), + (self.call.device._ComputeStaleApks('test.package', + ['base.apk', 'split2.apk']), + (['split2.apk'], None)), + (self.call.adb.InstallMultiple( + ['split2.apk'], partial='test.package', reinstall=True, + allow_downgrade=False))): + self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk, + ['split1.apk', 'split2.apk', 'split3.apk'], + reinstall=True, permissions=[], retries=0) + + def testInstallSplitApk_downgrade(self): + with self.assertCalls( + (self.call.device._CheckSdkLevel(21)), + (mock.call.devil.android.sdk.split_select.SelectSplits( + self.device, 'base.apk', + ['split1.apk', 'split2.apk', 'split3.apk'], + allow_cached_props=False), + ['split2.apk']), + (mock.call.os.path.exists('base.apk'), True), + (mock.call.os.path.exists('split2.apk'), True), + (self.call.device._GetApplicationPathsInternal('test.package'), + ['base-on-device.apk', 'split2-on-device.apk']), + (self.call.device._ComputeStaleApks('test.package', + ['base.apk', 'split2.apk']), + (['split2.apk'], None)), + (self.call.adb.InstallMultiple( + ['split2.apk'], partial='test.package', reinstall=True, + allow_downgrade=True))): + self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk, + ['split1.apk', 'split2.apk', 'split3.apk'], + reinstall=True, permissions=[], retries=0, + allow_downgrade=True) + + def testInstallSplitApk_missingSplit(self): + with self.assertCalls( + (self.call.device._CheckSdkLevel(21)), + (mock.call.devil.android.sdk.split_select.SelectSplits( + self.device, 'base.apk', + ['split1.apk', 'split2.apk', 'split3.apk'], + allow_cached_props=False), + ['split2.apk']), + (mock.call.os.path.exists('base.apk'), True), + (mock.call.os.path.exists('split2.apk'), False)): + with self.assertRaises(device_errors.CommandFailedError): + self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk, + ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[], + retries=0) + + +class DeviceUtilsUninstallTest(DeviceUtilsTest): + + def testUninstall_callsThrough(self): + with self.assertCalls( + (self.call.device._GetApplicationPathsInternal('test.package'), + ['/path.apk']), + self.call.adb.Uninstall('test.package', True)): + self.device.Uninstall('test.package', True) + + def testUninstall_noop(self): + with self.assertCalls( + (self.call.device._GetApplicationPathsInternal('test.package'), [])): + self.device.Uninstall('test.package', True) + + +class DeviceUtilsSuTest(DeviceUtilsTest): + + def testSu_preM(self): + with self.patch_call( + self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP_MR1): + self.assertEquals('su -c foo', self.device._Su('foo')) + + def testSu_mAndAbove(self): + with self.patch_call( + self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + self.assertEquals('su 0 foo', self.device._Su('foo')) + + +class DeviceUtilsRunShellCommandTest(DeviceUtilsTest): + + def setUp(self): + super(DeviceUtilsRunShellCommandTest, self).setUp() + self.device.NeedsSU = mock.Mock(return_value=False) + + def testRunShellCommand_commandAsList(self): + with self.assertCall(self.call.adb.Shell('pm list packages'), ''): + self.device.RunShellCommand( + ['pm', 'list', 'packages'], check_return=True) + + def testRunShellCommand_commandAsListQuoted(self): + with self.assertCall(self.call.adb.Shell("echo 'hello world' '$10'"), ''): + self.device.RunShellCommand( + ['echo', 'hello world', '$10'], check_return=True) + + def testRunShellCommand_commandAsString(self): + with self.assertCall(self.call.adb.Shell('echo "$VAR"'), ''): + self.device.RunShellCommand( + 'echo "$VAR"', shell=True, check_return=True) + + def testNewRunShellImpl_withEnv(self): + with self.assertCall( + self.call.adb.Shell('VAR=some_string echo "$VAR"'), ''): + self.device.RunShellCommand( + 'echo "$VAR"', shell=True, check_return=True, + env={'VAR': 'some_string'}) + + def testNewRunShellImpl_withEnvQuoted(self): + with self.assertCall( + self.call.adb.Shell('PATH="$PATH:/other/path" run_this'), ''): + self.device.RunShellCommand( + ['run_this'], check_return=True, env={'PATH': '$PATH:/other/path'}) + + def testNewRunShellImpl_withEnv_failure(self): + with self.assertRaises(KeyError): + self.device.RunShellCommand( + ['some_cmd'], check_return=True, env={'INVALID NAME': 'value'}) + + def testNewRunShellImpl_withCwd(self): + with self.assertCall(self.call.adb.Shell('cd /some/test/path && ls'), ''): + self.device.RunShellCommand( + ['ls'], check_return=True, cwd='/some/test/path') + + def testNewRunShellImpl_withCwdQuoted(self): + with self.assertCall( + self.call.adb.Shell("cd '/some test/path with/spaces' && ls"), ''): + self.device.RunShellCommand( + ['ls'], check_return=True, cwd='/some test/path with/spaces') + + def testRunShellCommand_withHugeCmd(self): + payload = 'hi! ' * 1024 + expected_cmd = "echo '%s'" % payload + with self.assertCalls( + (mock.call.devil.android.device_temp_file.DeviceTempFile( + self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')), + self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd), + (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')): + self.assertEquals( + [payload], + self.device.RunShellCommand(['echo', payload], check_return=True)) + + def testRunShellCommand_withHugeCmdAndSu(self): + payload = 'hi! ' * 1024 + expected_cmd_without_su = """sh -c 'echo '"'"'%s'"'"''""" % payload + expected_cmd = 'su -c %s' % expected_cmd_without_su + with self.assertCalls( + (self.call.device.NeedsSU(), True), + (self.call.device._Su(expected_cmd_without_su), expected_cmd), + (mock.call.devil.android.device_temp_file.DeviceTempFile( + self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')), + self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd), + (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')): + self.assertEquals( + [payload], + self.device.RunShellCommand( + ['echo', payload], check_return=True, as_root=True)) + + def testRunShellCommand_withSu(self): + expected_cmd_without_su = "sh -c 'setprop service.adb.root 0'" + expected_cmd = 'su -c %s' % expected_cmd_without_su + with self.assertCalls( + (self.call.device.NeedsSU(), True), + (self.call.device._Su(expected_cmd_without_su), expected_cmd), + (self.call.adb.Shell(expected_cmd), '')): + self.device.RunShellCommand( + ['setprop', 'service.adb.root', '0'], + check_return=True, as_root=True) + + def testRunShellCommand_withRunAs(self): + expected_cmd_without_run_as = "sh -c 'mkdir -p files'" + expected_cmd = ( + 'run-as org.devil.test_package %s' % expected_cmd_without_run_as) + with self.assertCall(self.call.adb.Shell(expected_cmd), ''): + self.device.RunShellCommand( + ['mkdir', '-p', 'files'], + check_return=True, run_as='org.devil.test_package') + + def testRunShellCommand_withRunAsAndSu(self): + expected_cmd_with_nothing = "sh -c 'mkdir -p files'" + expected_cmd_with_run_as = ( + 'run-as org.devil.test_package %s' % expected_cmd_with_nothing) + expected_cmd_without_su = ( + 'sh -c %s' % cmd_helper.SingleQuote(expected_cmd_with_run_as)) + expected_cmd = 'su -c %s' % expected_cmd_without_su + with self.assertCalls( + (self.call.device.NeedsSU(), True), + (self.call.device._Su(expected_cmd_without_su), expected_cmd), + (self.call.adb.Shell(expected_cmd), '')): + self.device.RunShellCommand( + ['mkdir', '-p', 'files'], + check_return=True, run_as='org.devil.test_package', + as_root=True) + + def testRunShellCommand_manyLines(self): + cmd = 'ls /some/path' + with self.assertCall(self.call.adb.Shell(cmd), 'file1\nfile2\nfile3\n'): + self.assertEquals( + ['file1', 'file2', 'file3'], + self.device.RunShellCommand(cmd.split(), check_return=True)) + + def testRunShellCommand_manyLinesRawOutput(self): + cmd = 'ls /some/path' + with self.assertCall(self.call.adb.Shell(cmd), '\rfile1\nfile2\r\nfile3\n'): + self.assertEquals( + '\rfile1\nfile2\r\nfile3\n', + self.device.RunShellCommand( + cmd.split(), check_return=True, raw_output=True)) + + def testRunShellCommand_singleLine_success(self): + cmd = 'echo $VALUE' + with self.assertCall(self.call.adb.Shell(cmd), 'some value\n'): + self.assertEquals( + 'some value', + self.device.RunShellCommand( + cmd, shell=True, check_return=True, single_line=True)) + + def testRunShellCommand_singleLine_successEmptyLine(self): + cmd = 'echo $VALUE' + with self.assertCall(self.call.adb.Shell(cmd), '\n'): + self.assertEquals( + '', + self.device.RunShellCommand( + cmd, shell=True, check_return=True, single_line=True)) + + def testRunShellCommand_singleLine_successWithoutEndLine(self): + cmd = 'echo -n $VALUE' + with self.assertCall(self.call.adb.Shell(cmd), 'some value'): + self.assertEquals( + 'some value', + self.device.RunShellCommand( + cmd, shell=True, check_return=True, single_line=True)) + + def testRunShellCommand_singleLine_successNoOutput(self): + cmd = 'echo -n $VALUE' + with self.assertCall(self.call.adb.Shell(cmd), ''): + self.assertEquals( + '', + self.device.RunShellCommand( + cmd, shell=True, check_return=True, single_line=True)) + + def testRunShellCommand_singleLine_failTooManyLines(self): + cmd = 'echo $VALUE' + with self.assertCall(self.call.adb.Shell(cmd), + 'some value\nanother value\n'): + with self.assertRaises(device_errors.CommandFailedError): + self.device.RunShellCommand( + cmd, shell=True, check_return=True, single_line=True) + + def testRunShellCommand_checkReturn_success(self): + cmd = 'echo $ANDROID_DATA' + output = '/data\n' + with self.assertCall(self.call.adb.Shell(cmd), output): + self.assertEquals( + [output.rstrip()], + self.device.RunShellCommand(cmd, shell=True, check_return=True)) + + def testRunShellCommand_checkReturn_failure(self): + cmd = 'ls /root' + output = 'opendir failed, Permission denied\n' + with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)): + with self.assertRaises(device_errors.AdbCommandFailedError): + self.device.RunShellCommand(cmd.split(), check_return=True) + + def testRunShellCommand_checkReturn_disabled(self): + cmd = 'ls /root' + output = 'opendir failed, Permission denied\n' + with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)): + self.assertEquals( + [output.rstrip()], + self.device.RunShellCommand(cmd.split(), check_return=False)) + + def testRunShellCommand_largeOutput_enabled(self): + cmd = 'echo $VALUE' + temp_file = MockTempFile('/sdcard/temp-123') + cmd_redirect = '( %s )>%s' % (cmd, temp_file.name) + with self.assertCalls( + (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb), + temp_file), + (self.call.adb.Shell(cmd_redirect)), + (self.call.device.ReadFile(temp_file.name, force_pull=True), + 'something')): + self.assertEquals( + ['something'], + self.device.RunShellCommand( + cmd, shell=True, large_output=True, check_return=True)) + + def testRunShellCommand_largeOutput_disabledNoTrigger(self): + cmd = 'something' + with self.assertCall(self.call.adb.Shell(cmd), self.ShellError('')): + with self.assertRaises(device_errors.AdbCommandFailedError): + self.device.RunShellCommand([cmd], check_return=True) + + def testRunShellCommand_largeOutput_disabledTrigger(self): + cmd = 'echo $VALUE' + temp_file = MockTempFile('/sdcard/temp-123') + cmd_redirect = '( %s )>%s' % (cmd, temp_file.name) + with self.assertCalls( + (self.call.adb.Shell(cmd), self.ShellError('', None)), + (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb), + temp_file), + (self.call.adb.Shell(cmd_redirect)), + (self.call.device.ReadFile(mock.ANY, force_pull=True), + 'something')): + self.assertEquals( + ['something'], + self.device.RunShellCommand(cmd, shell=True, check_return=True)) + + +class DeviceUtilsRunPipedShellCommandTest(DeviceUtilsTest): + + def testRunPipedShellCommand_success(self): + with self.assertCall( + self.call.device.RunShellCommand( + 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"', + shell=True, check_return=True), + ['This line contains foo', 'PIPESTATUS: 0 0']): + self.assertEquals(['This line contains foo'], + self.device._RunPipedShellCommand('ps | grep foo')) + + def testRunPipedShellCommand_firstCommandFails(self): + with self.assertCall( + self.call.device.RunShellCommand( + 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"', + shell=True, check_return=True), + ['PIPESTATUS: 1 0']): + with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec: + self.device._RunPipedShellCommand('ps | grep foo') + self.assertEquals([1, 0], ec.exception.status) + + def testRunPipedShellCommand_secondCommandFails(self): + with self.assertCall( + self.call.device.RunShellCommand( + 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"', + shell=True, check_return=True), + ['PIPESTATUS: 0 1']): + with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec: + self.device._RunPipedShellCommand('ps | grep foo') + self.assertEquals([0, 1], ec.exception.status) + + def testRunPipedShellCommand_outputCutOff(self): + with self.assertCall( + self.call.device.RunShellCommand( + 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"', + shell=True, check_return=True), + ['foo.bar'] * 256 + ['foo.ba']): + with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec: + self.device._RunPipedShellCommand('ps | grep foo') + self.assertIs(None, ec.exception.status) + + +@mock.patch('time.sleep', mock.Mock()) +class DeviceUtilsKillAllTest(DeviceUtilsTest): + + def testKillAll_noMatchingProcessesFailure(self): + with self.assertCall(self.call.device.GetPids('test_process'), {}): + with self.assertRaises(device_errors.CommandFailedError): + self.device.KillAll('test_process') + + def testKillAll_noMatchingProcessesQuiet(self): + with self.assertCall(self.call.device.GetPids('test_process'), {}): + self.assertEqual(0, self.device.KillAll('test_process', quiet=True)) + + def testKillAll_nonblocking(self): + with self.assertCalls( + (self.call.device.GetPids('some.process'), + {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.adb.Shell('kill -9 1234 5678'), '')): + self.assertEquals( + 2, self.device.KillAll('some.process', blocking=False)) + + def testKillAll_blocking(self): + with self.assertCalls( + (self.call.device.GetPids('some.process'), + {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.adb.Shell('kill -9 1234 5678'), ''), + (self.call.device.GetPids('some.process'), + {'some.processing.thing': ['5678']}), + (self.call.device.GetPids('some.process'), + {'some.process': ['1111']})): # Other instance with different pid. + self.assertEquals( + 2, self.device.KillAll('some.process', blocking=True)) + + def testKillAll_exactNonblocking(self): + with self.assertCalls( + (self.call.device.GetPids('some.process'), + {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.adb.Shell('kill -9 1234'), '')): + self.assertEquals( + 1, self.device.KillAll('some.process', exact=True, blocking=False)) + + def testKillAll_exactBlocking(self): + with self.assertCalls( + (self.call.device.GetPids('some.process'), + {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.adb.Shell('kill -9 1234'), ''), + (self.call.device.GetPids('some.process'), + {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.device.GetPids('some.process'), + {'some.processing.thing': ['5678']})): + self.assertEquals( + 1, self.device.KillAll('some.process', exact=True, blocking=True)) + + def testKillAll_root(self): + with self.assertCalls( + (self.call.device.GetPids('some.process'), {'some.process': ['1234']}), + (self.call.device.NeedsSU(), True), + (self.call.device._Su("sh -c 'kill -9 1234'"), + "su -c sh -c 'kill -9 1234'"), + (self.call.adb.Shell("su -c sh -c 'kill -9 1234'"), '')): + self.assertEquals( + 1, self.device.KillAll('some.process', as_root=True)) + + def testKillAll_sigterm(self): + with self.assertCalls( + (self.call.device.GetPids('some.process'), + {'some.process': ['1234']}), + (self.call.adb.Shell('kill -15 1234'), '')): + self.assertEquals( + 1, self.device.KillAll('some.process', signum=device_signal.SIGTERM)) + + def testKillAll_multipleInstances(self): + with self.assertCalls( + (self.call.device.GetPids('some.process'), + {'some.process': ['1234', '4567']}), + (self.call.adb.Shell('kill -15 1234 4567'), '')): + self.assertEquals( + 2, self.device.KillAll('some.process', signum=device_signal.SIGTERM)) + + +class DeviceUtilsStartActivityTest(DeviceUtilsTest): + + def testStartActivity_actionOnly(self): + test_intent = intent.Intent(action='android.intent.action.VIEW') + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_success(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main') + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_failure(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main') + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main'), + 'Error: Failed to start test activity'): + with self.assertRaises(device_errors.CommandFailedError): + self.device.StartActivity(test_intent) + + def testStartActivity_blocking(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main') + with self.assertCall( + self.call.adb.Shell('am start ' + '-W ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent, blocking=True) + + def testStartActivity_withCategory(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main', + category='android.intent.category.HOME') + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-c android.intent.category.HOME ' + '-n test.package/.Main'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_withMultipleCategories(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main', + category=['android.intent.category.HOME', + 'android.intent.category.BROWSABLE']) + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-c android.intent.category.HOME ' + '-c android.intent.category.BROWSABLE ' + '-n test.package/.Main'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_withData(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main', + data='http://www.google.com/') + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-d http://www.google.com/ ' + '-n test.package/.Main'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_withStringExtra(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main', + extras={'foo': 'test'}) + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main ' + '--es foo test'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_withBoolExtra(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main', + extras={'foo': True}) + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main ' + '--ez foo True'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_withIntExtra(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main', + extras={'foo': 123}) + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main ' + '--ei foo 123'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + def testStartActivity_withTraceFile(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main') + with self.assertCall( + self.call.adb.Shell('am start ' + '--start-profiler test_trace_file.out ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent, + trace_file_name='test_trace_file.out') + + def testStartActivity_withForceStop(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main') + with self.assertCall( + self.call.adb.Shell('am start ' + '-S ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent, force_stop=True) + + def testStartActivity_withFlags(self): + test_intent = intent.Intent(action='android.intent.action.VIEW', + package='test.package', + activity='.Main', + flags=[ + intent.FLAG_ACTIVITY_NEW_TASK, + intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + ]) + with self.assertCall( + self.call.adb.Shell('am start ' + '-a android.intent.action.VIEW ' + '-n test.package/.Main ' + '-f 0x10200000'), + 'Starting: Intent { act=android.intent.action.VIEW }'): + self.device.StartActivity(test_intent) + + +class DeviceUtilsStartInstrumentationTest(DeviceUtilsTest): + + def testStartInstrumentation_nothing(self): + with self.assertCalls( + self.call.device.RunShellCommand( + 'p=test.package;am instrument "$p"/.TestInstrumentation', + shell=True, check_return=True, large_output=True)): + self.device.StartInstrumentation( + 'test.package/.TestInstrumentation', + finish=False, raw=False, extras=None) + + def testStartInstrumentation_finish(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + 'p=test.package;am instrument -w "$p"/.TestInstrumentation', + shell=True, check_return=True, large_output=True), + ['OK (1 test)'])): + output = self.device.StartInstrumentation( + 'test.package/.TestInstrumentation', + finish=True, raw=False, extras=None) + self.assertEquals(['OK (1 test)'], output) + + def testStartInstrumentation_raw(self): + with self.assertCalls( + self.call.device.RunShellCommand( + 'p=test.package;am instrument -r "$p"/.TestInstrumentation', + shell=True, check_return=True, large_output=True)): + self.device.StartInstrumentation( + 'test.package/.TestInstrumentation', + finish=False, raw=True, extras=None) + + def testStartInstrumentation_extras(self): + with self.assertCalls( + self.call.device.RunShellCommand( + 'p=test.package;am instrument -e "$p".foo Foo -e bar \'Val \'"$p" ' + '"$p"/.TestInstrumentation', + shell=True, check_return=True, large_output=True)): + self.device.StartInstrumentation( + 'test.package/.TestInstrumentation', + finish=False, raw=False, extras={'test.package.foo': 'Foo', + 'bar': 'Val test.package'}) + + +class DeviceUtilsBroadcastIntentTest(DeviceUtilsTest): + + def testBroadcastIntent_noExtras(self): + test_intent = intent.Intent(action='test.package.with.an.INTENT') + with self.assertCall( + self.call.adb.Shell('am broadcast -a test.package.with.an.INTENT'), + 'Broadcasting: Intent { act=test.package.with.an.INTENT } '): + self.device.BroadcastIntent(test_intent) + + def testBroadcastIntent_withExtra(self): + test_intent = intent.Intent(action='test.package.with.an.INTENT', + extras={'foo': 'bar value'}) + with self.assertCall( + self.call.adb.Shell( + "am broadcast -a test.package.with.an.INTENT --es foo 'bar value'"), + 'Broadcasting: Intent { act=test.package.with.an.INTENT } '): + self.device.BroadcastIntent(test_intent) + + def testBroadcastIntent_withExtra_noValue(self): + test_intent = intent.Intent(action='test.package.with.an.INTENT', + extras={'foo': None}) + with self.assertCall( + self.call.adb.Shell( + 'am broadcast -a test.package.with.an.INTENT --esn foo'), + 'Broadcasting: Intent { act=test.package.with.an.INTENT } '): + self.device.BroadcastIntent(test_intent) + + +class DeviceUtilsGoHomeTest(DeviceUtilsTest): + + def testGoHome_popupsExist(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), []), + (self.call.device.RunShellCommand( + ['am', 'start', '-W', '-a', 'android.intent.action.MAIN', + '-c', 'android.intent.category.HOME'], check_return=True), + 'Starting: Intent { act=android.intent.action.MAIN }\r\n'''), + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), []), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '66'], check_return=True)), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '4'], check_return=True)), + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), + ['mCurrentFocus Launcher'])): + self.device.GoHome() + + def testGoHome_willRetry(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), []), + (self.call.device.RunShellCommand( + ['am', 'start', '-W', '-a', 'android.intent.action.MAIN', + '-c', 'android.intent.category.HOME'], check_return=True), + 'Starting: Intent { act=android.intent.action.MAIN }\r\n'''), + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), []), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '66'], check_return=True,)), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '4'], check_return=True)), + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), []), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '66'], check_return=True)), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '4'], check_return=True)), + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), + self.TimeoutError())): + with self.assertRaises(device_errors.CommandTimeoutError): + self.device.GoHome() + + def testGoHome_alreadyFocused(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), + ['mCurrentFocus Launcher']): + self.device.GoHome() + + def testGoHome_alreadyFocusedAlternateCase(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), + [' mCurrentFocus .launcher/.']): + self.device.GoHome() + + def testGoHome_obtainsFocusAfterGoingHome(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), []), + (self.call.device.RunShellCommand( + ['am', 'start', '-W', '-a', 'android.intent.action.MAIN', + '-c', 'android.intent.category.HOME'], check_return=True), + 'Starting: Intent { act=android.intent.action.MAIN }\r\n'''), + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), + ['mCurrentFocus Launcher'])): + self.device.GoHome() + + +class DeviceUtilsForceStopTest(DeviceUtilsTest): + + def testForceStop(self): + with self.assertCalls( + (self.call.device.GetPids('test.package'), {'test.package': [1111]}), + (self.call.device.RunShellCommand( + ['am', 'force-stop', 'test.package'], + check_return=True), + ['Success'])): + self.device.ForceStop('test.package') + + def testForceStop_NoProcessFound(self): + with self.assertCall( + self.call.device.GetPids('test.package'), {}): + self.device.ForceStop('test.package') + + +class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest): + + def testClearApplicationState_setPermissions(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'), + (self.call.device._GetApplicationPathsInternal('this.package.exists'), + ['/data/app/this.package.exists.apk']), + (self.call.device.RunShellCommand( + ['pm', 'clear', 'this.package.exists'], + check_return=True), + ['Success']), + (self.call.device.GrantPermissions( + 'this.package.exists', ['p1']), [])): + self.device.ClearApplicationState( + 'this.package.exists', permissions=['p1']) + + def testClearApplicationState_packageDoesntExist(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '11'), + (self.call.device._GetApplicationPathsInternal('does.not.exist'), + [])): + self.device.ClearApplicationState('does.not.exist') + + def testClearApplicationState_packageDoesntExistOnAndroidJBMR2OrAbove(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'), + (self.call.device.RunShellCommand( + ['pm', 'clear', 'this.package.does.not.exist'], + check_return=True), + ['Failed'])): + self.device.ClearApplicationState('this.package.does.not.exist') + + def testClearApplicationState_packageExists(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'), + (self.call.device._GetApplicationPathsInternal('this.package.exists'), + ['/data/app/this.package.exists.apk']), + (self.call.device.RunShellCommand( + ['pm', 'clear', 'this.package.exists'], + check_return=True), + ['Success'])): + self.device.ClearApplicationState('this.package.exists') + + def testClearApplicationState_packageExistsOnAndroidJBMR2OrAbove(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'), + (self.call.device.RunShellCommand( + ['pm', 'clear', 'this.package.exists'], + check_return=True), + ['Success'])): + self.device.ClearApplicationState('this.package.exists') + + +class DeviceUtilsSendKeyEventTest(DeviceUtilsTest): + + def testSendKeyEvent(self): + with self.assertCall(self.call.adb.Shell('input keyevent 66'), ''): + self.device.SendKeyEvent(66) + + +class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsTest): + + def testPushChangedFilesIndividually_empty(self): + test_files = [] + with self.assertCalls(): + self.device._PushChangedFilesIndividually(test_files) + + def testPushChangedFilesIndividually_single(self): + test_files = [('/test/host/path', '/test/device/path')] + with self.assertCalls(self.call.adb.Push(*test_files[0])): + self.device._PushChangedFilesIndividually(test_files) + + def testPushChangedFilesIndividually_multiple(self): + test_files = [ + ('/test/host/path/file1', '/test/device/path/file1'), + ('/test/host/path/file2', '/test/device/path/file2')] + with self.assertCalls( + self.call.adb.Push(*test_files[0]), + self.call.adb.Push(*test_files[1])): + self.device._PushChangedFilesIndividually(test_files) + + +class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsTest): + + def testPushChangedFilesZipped_noUnzipCommand(self): + test_files = [('/test/host/path/file1', '/test/device/path/file1')] + mock_zip_temp = mock.mock_open() + mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip' + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp), + (mock.call.multiprocessing.Process( + target=device_utils.DeviceUtils._CreateDeviceZip, + args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()), + (self.call.device._MaybeInstallCommands(), False)): + self.assertFalse(self.device._PushChangedFilesZipped(test_files, + ['/test/dir'])) + + def _testPushChangedFilesZipped_spec(self, test_files): + mock_zip_temp = mock.mock_open() + mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip' + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp), + (mock.call.multiprocessing.Process( + target=device_utils.DeviceUtils._CreateDeviceZip, + args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()), + (self.call.device._MaybeInstallCommands(), True), + (self.call.device.NeedsSU(), True), + (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb, + suffix='.zip'), + MockTempFile('/test/sdcard/foo123.zip')), + self.call.adb.Push( + '/test/temp/file/tmp.zip', '/test/sdcard/foo123.zip'), + self.call.device.RunShellCommand( + 'unzip /test/sdcard/foo123.zip&&chmod -R 777 /test/dir', + shell=True, as_root=True, + env={'PATH': '/data/local/tmp/bin:$PATH'}, + check_return=True)): + self.assertTrue(self.device._PushChangedFilesZipped(test_files, + ['/test/dir'])) + + def testPushChangedFilesZipped_single(self): + self._testPushChangedFilesZipped_spec( + [('/test/host/path/file1', '/test/device/path/file1')]) + + def testPushChangedFilesZipped_multiple(self): + self._testPushChangedFilesZipped_spec( + [('/test/host/path/file1', '/test/device/path/file1'), + ('/test/host/path/file2', '/test/device/path/file2')]) + + +class DeviceUtilsPathExistsTest(DeviceUtilsTest): + + def testPathExists_pathExists(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['test', '-e', '/path/file exists'], + as_root=False, check_return=True, timeout=10, retries=0), + []): + self.assertTrue(self.device.PathExists('/path/file exists')) + + def testPathExists_multiplePathExists(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['test', '-e', '/path 1', '-a', '-e', '/path2'], + as_root=False, check_return=True, timeout=10, retries=0), + []): + self.assertTrue(self.device.PathExists(('/path 1', '/path2'))) + + def testPathExists_pathDoesntExist(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['test', '-e', '/path/file.not.exists'], + as_root=False, check_return=True, timeout=10, retries=0), + self.ShellError()): + self.assertFalse(self.device.PathExists('/path/file.not.exists')) + + def testPathExists_asRoot(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['test', '-e', '/root/path/exists'], + as_root=True, check_return=True, timeout=10, retries=0), + self.ShellError()): + self.assertFalse( + self.device.PathExists('/root/path/exists', as_root=True)) + + def testFileExists_pathDoesntExist(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['test', '-e', '/path/file.not.exists'], + as_root=False, check_return=True, timeout=10, retries=0), + self.ShellError()): + self.assertFalse(self.device.FileExists('/path/file.not.exists')) + + +class DeviceUtilsRemovePathTest(DeviceUtilsTest): + + def testRemovePath_regular(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['rm', 'some file'], as_root=False, check_return=True), + []): + self.device.RemovePath('some file') + + def testRemovePath_withForce(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['rm', '-f', 'some file'], as_root=False, check_return=True), + []): + self.device.RemovePath('some file', force=True) + + def testRemovePath_recursively(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['rm', '-r', '/remove/this/dir'], as_root=False, check_return=True), + []): + self.device.RemovePath('/remove/this/dir', recursive=True) + + def testRemovePath_withRoot(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['rm', 'some file'], as_root=True, check_return=True), + []): + self.device.RemovePath('some file', as_root=True) + + def testRemovePath_manyPaths(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['rm', 'eeny', 'meeny', 'miny', 'moe'], + as_root=False, check_return=True), + []): + self.device.RemovePath(['eeny', 'meeny', 'miny', 'moe']) + + +class DeviceUtilsPullFileTest(DeviceUtilsTest): + + def testPullFile_existsOnDevice(self): + with mock.patch('os.path.exists', return_value=True): + with self.assertCall( + self.call.adb.Pull('/data/app/test.file.exists', + '/test/file/host/path')): + self.device.PullFile('/data/app/test.file.exists', + '/test/file/host/path') + + def testPullFile_doesntExistOnDevice(self): + with mock.patch('os.path.exists', return_value=True): + with self.assertCall( + self.call.adb.Pull('/data/app/test.file.does.not.exist', + '/test/file/host/path'), + self.CommandError('remote object does not exist')): + with self.assertRaises(device_errors.CommandFailedError): + self.device.PullFile('/data/app/test.file.does.not.exist', + '/test/file/host/path') + + +class DeviceUtilsReadFileTest(DeviceUtilsTest): + + def testReadFileWithPull_success(self): + tmp_host_dir = '/tmp/dir/on.host/' + tmp_host = MockTempFile('/tmp/dir/on.host/tmp_ReadFileWithPull') + tmp_host.file.read.return_value = 'some interesting contents' + with self.assertCalls( + (mock.call.tempfile.mkdtemp(), tmp_host_dir), + (self.call.adb.Pull('/path/to/device/file', mock.ANY)), + (mock.call.__builtin__.open(mock.ANY, 'r'), tmp_host), + (mock.call.os.path.exists(tmp_host_dir), True), + (mock.call.shutil.rmtree(tmp_host_dir), None)): + self.assertEquals('some interesting contents', + self.device._ReadFileWithPull('/path/to/device/file')) + tmp_host.file.read.assert_called_once_with() + + def testReadFileWithPull_rejected(self): + tmp_host_dir = '/tmp/dir/on.host/' + with self.assertCalls( + (mock.call.tempfile.mkdtemp(), tmp_host_dir), + (self.call.adb.Pull('/path/to/device/file', mock.ANY), + self.CommandError()), + (mock.call.os.path.exists(tmp_host_dir), True), + (mock.call.shutil.rmtree(tmp_host_dir), None)): + with self.assertRaises(device_errors.CommandFailedError): + self.device._ReadFileWithPull('/path/to/device/file') + + def testReadFile_exists(self): + with self.assertCalls( + (self.call.device.FileSize('/read/this/test/file', as_root=False), 256), + (self.call.device.RunShellCommand( + ['cat', '/read/this/test/file'], + as_root=False, check_return=True), + ['this is a test file'])): + self.assertEqual('this is a test file\n', + self.device.ReadFile('/read/this/test/file')) + + def testReadFile_exists2(self): + # Same as testReadFile_exists, but uses Android N ls output. + with self.assertCalls( + (self.call.device.FileSize('/read/this/test/file', as_root=False), 256), + (self.call.device.RunShellCommand( + ['cat', '/read/this/test/file'], + as_root=False, check_return=True), + ['this is a test file'])): + self.assertEqual('this is a test file\n', + self.device.ReadFile('/read/this/test/file')) + + def testReadFile_doesNotExist(self): + with self.assertCall( + self.call.device.FileSize('/this/file/does.not.exist', as_root=False), + self.CommandError('File does not exist')): + with self.assertRaises(device_errors.CommandFailedError): + self.device.ReadFile('/this/file/does.not.exist') + + def testReadFile_zeroSize(self): + with self.assertCalls( + (self.call.device.FileSize('/this/file/has/zero/size', as_root=False), + 0), + (self.call.device._ReadFileWithPull('/this/file/has/zero/size'), + 'but it has contents\n')): + self.assertEqual('but it has contents\n', + self.device.ReadFile('/this/file/has/zero/size')) + + def testReadFile_withSU(self): + with self.assertCalls( + (self.call.device.FileSize( + '/this/file/can.be.read.with.su', as_root=True), 256), + (self.call.device.RunShellCommand( + ['cat', '/this/file/can.be.read.with.su'], + as_root=True, check_return=True), + ['this is a test file', 'read with su'])): + self.assertEqual( + 'this is a test file\nread with su\n', + self.device.ReadFile('/this/file/can.be.read.with.su', + as_root=True)) + + def testReadFile_withPull(self): + contents = 'a' * 123456 + with self.assertCalls( + (self.call.device.FileSize('/read/this/big/test/file', as_root=False), + 123456), + (self.call.device._ReadFileWithPull('/read/this/big/test/file'), + contents)): + self.assertEqual( + contents, self.device.ReadFile('/read/this/big/test/file')) + + def testReadFile_withPullAndSU(self): + contents = 'b' * 123456 + with self.assertCalls( + (self.call.device.FileSize( + '/this/big/file/can.be.read.with.su', as_root=True), 123456), + (self.call.device.NeedsSU(), True), + (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb), + MockTempFile('/sdcard/tmp/on.device')), + self.call.device.RunShellCommand( + 'SRC=/this/big/file/can.be.read.with.su DEST=/sdcard/tmp/on.device;' + 'cp "$SRC" "$DEST" && chmod 666 "$DEST"', + shell=True, as_root=True, check_return=True), + (self.call.device._ReadFileWithPull('/sdcard/tmp/on.device'), + contents)): + self.assertEqual( + contents, + self.device.ReadFile('/this/big/file/can.be.read.with.su', + as_root=True)) + + def testReadFile_forcePull(self): + contents = 'a' * 123456 + with self.assertCall( + self.call.device._ReadFileWithPull('/read/this/big/test/file'), + contents): + self.assertEqual( + contents, + self.device.ReadFile('/read/this/big/test/file', force_pull=True)) + + +class DeviceUtilsWriteFileTest(DeviceUtilsTest): + + def testWriteFileWithPush_success(self): + tmp_host = MockTempFile('/tmp/file/on.host') + contents = 'some interesting contents' + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(), tmp_host), + self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file')): + self.device._WriteFileWithPush('/path/to/device/file', contents) + tmp_host.file.write.assert_called_once_with(contents) + + def testWriteFileWithPush_rejected(self): + tmp_host = MockTempFile('/tmp/file/on.host') + contents = 'some interesting contents' + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(), tmp_host), + (self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file'), + self.CommandError())): + with self.assertRaises(device_errors.CommandFailedError): + self.device._WriteFileWithPush('/path/to/device/file', contents) + + def testWriteFile_withPush(self): + contents = 'some large contents ' * 26 # 20 * 26 = 520 chars + with self.assertCalls( + self.call.device._WriteFileWithPush('/path/to/device/file', contents)): + self.device.WriteFile('/path/to/device/file', contents) + + def testWriteFile_withPushForced(self): + contents = 'tiny contents' + with self.assertCalls( + self.call.device._WriteFileWithPush('/path/to/device/file', contents)): + self.device.WriteFile('/path/to/device/file', contents, force_push=True) + + def testWriteFile_withPushAndSU(self): + contents = 'some large contents ' * 26 # 20 * 26 = 520 chars + with self.assertCalls( + (self.call.device.NeedsSU(), True), + (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb), + MockTempFile('/sdcard/tmp/on.device')), + self.call.device._WriteFileWithPush('/sdcard/tmp/on.device', contents), + self.call.device.RunShellCommand( + ['cp', '/sdcard/tmp/on.device', '/path/to/device/file'], + as_root=True, check_return=True)): + self.device.WriteFile('/path/to/device/file', contents, as_root=True) + + def testWriteFile_withEcho(self): + with self.assertCall(self.call.adb.Shell( + "echo -n the.contents > /test/file/to.write"), ''): + self.device.WriteFile('/test/file/to.write', 'the.contents') + + def testWriteFile_withEchoAndQuotes(self): + with self.assertCall(self.call.adb.Shell( + "echo -n 'the contents' > '/test/file/to write'"), ''): + self.device.WriteFile('/test/file/to write', 'the contents') + + def testWriteFile_withEchoAndSU(self): + expected_cmd_without_su = "sh -c 'echo -n contents > /test/file'" + expected_cmd = 'su -c %s' % expected_cmd_without_su + with self.assertCalls( + (self.call.device.NeedsSU(), True), + (self.call.device._Su(expected_cmd_without_su), expected_cmd), + (self.call.adb.Shell(expected_cmd), + '')): + self.device.WriteFile('/test/file', 'contents', as_root=True) + + +class DeviceUtilsStatDirectoryTest(DeviceUtilsTest): + # Note: Also tests ListDirectory in testStatDirectory_fileList. + + EXAMPLE_LS_OUTPUT = [ + 'total 12345', + 'drwxr-xr-x 19 root root 0 1970-04-06 18:03 .', + 'drwxr-xr-x 19 root root 0 1970-04-06 18:03 ..', + 'drwxr-xr-x 6 root root 1970-01-01 00:00 some_dir', + '-rw-r--r-- 1 root root 723 1971-01-01 07:04 some_file', + '-rw-r----- 1 root root 327 2009-02-13 23:30 My Music File', + # Older Android versions do not print st_nlink + 'lrwxrwxrwx root root 1970-01-01 00:00 lnk -> /some/path', + 'srwxrwx--- system system 2016-05-31 17:25 a_socket1', + 'drwxrwxrwt system misc 1970-11-23 02:25 tmp', + 'drwxr-s--- system shell 1970-11-23 02:24 my_cmd', + 'cr--r----- root system 10, 183 1971-01-01 07:04 random', + 'brw------- root root 7, 0 1971-01-01 07:04 block_dev', + '-rwS------ root shell 157404 2015-04-13 15:44 silly', + ] + + FILENAMES = [ + 'some_dir', 'some_file', 'My Music File', 'lnk', 'a_socket1', + 'tmp', 'my_cmd', 'random', 'block_dev', 'silly'] + + def getStatEntries(self, path_given='/', path_listed='/'): + with self.assertCall( + self.call.device.RunShellCommand( + ['ls', '-a', '-l', path_listed], + check_return=True, as_root=False, env={'TZ': 'utc'}), + self.EXAMPLE_LS_OUTPUT): + entries = self.device.StatDirectory(path_given) + return {f['filename']: f for f in entries} + + def getListEntries(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['ls', '-a', '-l', '/'], + check_return=True, as_root=False, env={'TZ': 'utc'}), + self.EXAMPLE_LS_OUTPUT): + return self.device.ListDirectory('/') + + def testStatDirectory_forceTrailingSlash(self): + self.getStatEntries(path_given='/foo/bar/', path_listed='/foo/bar/') + self.getStatEntries(path_given='/foo/bar', path_listed='/foo/bar/') + + def testStatDirectory_fileList(self): + self.assertItemsEqual(self.getStatEntries().keys(), self.FILENAMES) + self.assertItemsEqual(self.getListEntries(), self.FILENAMES) + + def testStatDirectory_fileModes(self): + expected_modes = ( + ('some_dir', stat.S_ISDIR), + ('some_file', stat.S_ISREG), + ('lnk', stat.S_ISLNK), + ('a_socket1', stat.S_ISSOCK), + ('block_dev', stat.S_ISBLK), + ('random', stat.S_ISCHR), + ) + entries = self.getStatEntries() + for filename, check in expected_modes: + self.assertTrue(check(entries[filename]['st_mode'])) + + def testStatDirectory_filePermissions(self): + should_have = ( + ('some_file', stat.S_IWUSR), # Owner can write. + ('tmp', stat.S_IXOTH), # Others can execute. + ('tmp', stat.S_ISVTX), # Has sticky bit. + ('my_cmd', stat.S_ISGID), # Has set-group-ID bit. + ('silly', stat.S_ISUID), # Has set UID bit. + ) + should_not_have = ( + ('some_file', stat.S_IWOTH), # Others can't write. + ('block_dev', stat.S_IRGRP), # Group can't read. + ('silly', stat.S_IXUSR), # Owner can't execute. + ) + entries = self.getStatEntries() + for filename, bit in should_have: + self.assertTrue(entries[filename]['st_mode'] & bit) + for filename, bit in should_not_have: + self.assertFalse(entries[filename]['st_mode'] & bit) + + def testStatDirectory_numHardLinks(self): + entries = self.getStatEntries() + self.assertEqual(entries['some_dir']['st_nlink'], 6) + self.assertEqual(entries['some_file']['st_nlink'], 1) + self.assertFalse('st_nlink' in entries['tmp']) + + def testStatDirectory_fileOwners(self): + entries = self.getStatEntries() + self.assertEqual(entries['some_dir']['st_owner'], 'root') + self.assertEqual(entries['my_cmd']['st_owner'], 'system') + self.assertEqual(entries['my_cmd']['st_group'], 'shell') + self.assertEqual(entries['tmp']['st_group'], 'misc') + + def testStatDirectory_fileSize(self): + entries = self.getStatEntries() + self.assertEqual(entries['some_file']['st_size'], 723) + self.assertEqual(entries['My Music File']['st_size'], 327) + # Sizes are sometimes not reported for non-regular files, don't try to + # guess the size in those cases. + self.assertFalse('st_size' in entries['some_dir']) + + def testStatDirectory_fileDateTime(self): + entries = self.getStatEntries() + self.assertEqual(entries['some_dir']['st_mtime'], 0) # Epoch! + self.assertEqual(entries['My Music File']['st_mtime'], 1234567800) + + def testStatDirectory_deviceType(self): + entries = self.getStatEntries() + self.assertEqual(entries['random']['st_rdev_pair'], (10, 183)) + self.assertEqual(entries['block_dev']['st_rdev_pair'], (7, 0)) + + def testStatDirectory_symbolicLinks(self): + entries = self.getStatEntries() + self.assertEqual(entries['lnk']['symbolic_link_to'], '/some/path') + for d in entries.itervalues(): + self.assertEqual('symbolic_link_to' in d, stat.S_ISLNK(d['st_mode'])) + + +class DeviceUtilsStatPathTest(DeviceUtilsTest): + + EXAMPLE_DIRECTORY = [ + {'filename': 'foo.txt', 'st_size': 123, 'st_time': 456}, + {'filename': 'some_dir', 'st_time': 0} + ] + INDEX = {e['filename']: e for e in EXAMPLE_DIRECTORY} + + def testStatPath_file(self): + with self.assertCall( + self.call.device.StatDirectory('/data/local/tmp', as_root=False), + self.EXAMPLE_DIRECTORY): + self.assertEquals(self.INDEX['foo.txt'], + self.device.StatPath('/data/local/tmp/foo.txt')) + + def testStatPath_directory(self): + with self.assertCall( + self.call.device.StatDirectory('/data/local/tmp', as_root=False), + self.EXAMPLE_DIRECTORY): + self.assertEquals(self.INDEX['some_dir'], + self.device.StatPath('/data/local/tmp/some_dir')) + + def testStatPath_directoryWithTrailingSlash(self): + with self.assertCall( + self.call.device.StatDirectory('/data/local/tmp', as_root=False), + self.EXAMPLE_DIRECTORY): + self.assertEquals(self.INDEX['some_dir'], + self.device.StatPath('/data/local/tmp/some_dir/')) + + def testStatPath_doesNotExist(self): + with self.assertCall( + self.call.device.StatDirectory('/data/local/tmp', as_root=False), + self.EXAMPLE_DIRECTORY): + with self.assertRaises(device_errors.CommandFailedError): + self.device.StatPath('/data/local/tmp/does.not.exist.txt') + + +class DeviceUtilsFileSizeTest(DeviceUtilsTest): + + EXAMPLE_DIRECTORY = [ + {'filename': 'foo.txt', 'st_size': 123, 'st_mtime': 456}, + {'filename': 'some_dir', 'st_mtime': 0} + ] + + def testFileSize_file(self): + with self.assertCall( + self.call.device.StatDirectory('/data/local/tmp', as_root=False), + self.EXAMPLE_DIRECTORY): + self.assertEquals(123, + self.device.FileSize('/data/local/tmp/foo.txt')) + + def testFileSize_doesNotExist(self): + with self.assertCall( + self.call.device.StatDirectory('/data/local/tmp', as_root=False), + self.EXAMPLE_DIRECTORY): + with self.assertRaises(device_errors.CommandFailedError): + self.device.FileSize('/data/local/tmp/does.not.exist.txt') + + def testFileSize_directoryWithNoSize(self): + with self.assertCall( + self.call.device.StatDirectory('/data/local/tmp', as_root=False), + self.EXAMPLE_DIRECTORY): + with self.assertRaises(device_errors.CommandFailedError): + self.device.FileSize('/data/local/tmp/some_dir') + + +class DeviceUtilsSetJavaAssertsTest(DeviceUtilsTest): + + def testSetJavaAsserts_enable(self): + with self.assertCalls( + (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH), + 'some.example.prop=with an example value\n' + 'some.other.prop=value_ok\n'), + self.call.device.WriteFile( + self.device.LOCAL_PROPERTIES_PATH, + 'some.example.prop=with an example value\n' + 'some.other.prop=value_ok\n' + 'dalvik.vm.enableassertions=all\n'), + (self.call.device.GetProp('dalvik.vm.enableassertions'), ''), + self.call.device.SetProp('dalvik.vm.enableassertions', 'all')): + self.assertTrue(self.device.SetJavaAsserts(True)) + + def testSetJavaAsserts_disable(self): + with self.assertCalls( + (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH), + 'some.example.prop=with an example value\n' + 'dalvik.vm.enableassertions=all\n' + 'some.other.prop=value_ok\n'), + self.call.device.WriteFile( + self.device.LOCAL_PROPERTIES_PATH, + 'some.example.prop=with an example value\n' + 'some.other.prop=value_ok\n'), + (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all'), + self.call.device.SetProp('dalvik.vm.enableassertions', '')): + self.assertTrue(self.device.SetJavaAsserts(False)) + + def testSetJavaAsserts_alreadyEnabled(self): + with self.assertCalls( + (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH), + 'some.example.prop=with an example value\n' + 'dalvik.vm.enableassertions=all\n' + 'some.other.prop=value_ok\n'), + (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')): + self.assertFalse(self.device.SetJavaAsserts(True)) + + def testSetJavaAsserts_malformedLocalProp(self): + with self.assertCalls( + (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH), + 'some.example.prop=with an example value\n' + 'malformed_property\n' + 'dalvik.vm.enableassertions=all\n' + 'some.other.prop=value_ok\n'), + (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')): + self.assertFalse(self.device.SetJavaAsserts(True)) + + +class DeviceUtilsEnsureCacheInitializedTest(DeviceUtilsTest): + + def testEnsureCacheInitialized_noCache_success(self): + self.assertIsNone(self.device._cache['token']) + with self.assertCall( + self.call.device.RunShellCommand( + AnyStringWith('getprop'), + shell=True, check_return=True, large_output=True), + ['/sdcard', 'TOKEN']): + self.device._EnsureCacheInitialized() + self.assertIsNotNone(self.device._cache['token']) + + def testEnsureCacheInitialized_noCache_failure(self): + self.assertIsNone(self.device._cache['token']) + with self.assertCall( + self.call.device.RunShellCommand( + AnyStringWith('getprop'), + shell=True, check_return=True, large_output=True), + self.TimeoutError()): + with self.assertRaises(device_errors.CommandTimeoutError): + self.device._EnsureCacheInitialized() + self.assertIsNone(self.device._cache['token']) + + def testEnsureCacheInitialized_cache(self): + self.device._cache['token'] = 'TOKEN' + with self.assertCalls(): + self.device._EnsureCacheInitialized() + self.assertIsNotNone(self.device._cache['token']) + + +class DeviceUtilsGetPropTest(DeviceUtilsTest): + + def testGetProp_exists(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['getprop', 'test.property'], check_return=True, single_line=True, + timeout=self.device._default_timeout, + retries=self.device._default_retries), + 'property_value'): + self.assertEqual('property_value', + self.device.GetProp('test.property')) + + def testGetProp_doesNotExist(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['getprop', 'property.does.not.exist'], + check_return=True, single_line=True, + timeout=self.device._default_timeout, + retries=self.device._default_retries), + ''): + self.assertEqual('', self.device.GetProp('property.does.not.exist')) + + def testGetProp_cachedRoProp(self): + with self.assertCalls( + self.EnsureCacheInitialized(props=['[ro.build.type]: [userdebug]'])): + self.assertEqual('userdebug', + self.device.GetProp('ro.build.type', cache=True)) + self.assertEqual('userdebug', + self.device.GetProp('ro.build.type', cache=True)) + + +class DeviceUtilsSetPropTest(DeviceUtilsTest): + + def testSetProp(self): + with self.assertCall( + self.call.device.RunShellCommand( + ['setprop', 'test.property', 'test value'], check_return=True)): + self.device.SetProp('test.property', 'test value') + + def testSetProp_check_succeeds(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['setprop', 'test.property', 'new_value'], check_return=True)), + (self.call.device.GetProp('test.property', cache=False), 'new_value')): + self.device.SetProp('test.property', 'new_value', check=True) + + def testSetProp_check_fails(self): + with self.assertCalls( + (self.call.device.RunShellCommand( + ['setprop', 'test.property', 'new_value'], check_return=True)), + (self.call.device.GetProp('test.property', cache=False), 'old_value')): + with self.assertRaises(device_errors.CommandFailedError): + self.device.SetProp('test.property', 'new_value', check=True) + + +class DeviceUtilsGetPidsTest(DeviceUtilsTest): + def setUp(self): + super(DeviceUtilsGetPidsTest, self).setUp() + self.sample_output = [ + 'USER PID PPID VSIZE RSS WCHAN PC NAME', + 'user 1001 100 1024 1024 ffffffff 00000000 one.match', + 'user 1002 100 1024 1024 ffffffff 00000000 two.match', + 'user 1003 100 1024 1024 ffffffff 00000000 three.match', + 'user 1234 100 1024 1024 ffffffff 00000000 my$process', + 'user 1000 100 1024 1024 ffffffff 00000000 foo', + 'user 1236 100 1024 1024 ffffffff 00000000 foo', + ] + + def _grepOutput(self, substring): + return [line for line in self.sample_output if substring in line] + + def testGetPids_sdkGreaterThanNougatMR1(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=(version_codes.NOUGAT_MR1 + 1)): + with self.patch_call(self.call.device.build_id, + return_value='ZZZ99Z'): + with self.assertCall( + self.call.device._RunPipedShellCommand( + 'ps -e | grep -F example.process'), []): + self.device.GetPids('example.process') + + def testGetPids_noMatches(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F does.not.match'), + self._grepOutput('does.not.match')): + self.assertEqual({}, self.device.GetPids('does.not.match')) + + def testGetPids_oneMatch(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F one.match'), + self._grepOutput('one.match')): + self.assertEqual( + {'one.match': ['1001']}, + self.device.GetPids('one.match')) + + def testGetPids_multipleMatches(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F match'), + self._grepOutput('match')): + self.assertEqual( + {'one.match': ['1001'], + 'two.match': ['1002'], + 'three.match': ['1003']}, + self.device.GetPids('match')) + + def testGetPids_quotable(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand("ps | grep -F 'my$process'"), + self._grepOutput('my$process')): + self.assertEqual( + {'my$process': ['1234']}, self.device.GetPids('my$process')) + + def testGetPids_multipleInstances(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F foo'), + self._grepOutput('foo')): + self.assertEqual( + {'foo': ['1000', '1236']}, + self.device.GetPids('foo')) + + def testGetPids_allProcesses(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device.RunShellCommand( + ['ps'], check_return=True, large_output=True), + self.sample_output): + self.assertEqual( + {'one.match': ['1001'], + 'two.match': ['1002'], + 'three.match': ['1003'], + 'my$process': ['1234'], + 'foo': ['1000', '1236']}, + self.device.GetPids()) + + def testGetApplicationPids_notFound(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F match'), + self._grepOutput('match')): + # No PIDs found, process name should be exact match. + self.assertEqual([], self.device.GetApplicationPids('match')) + + def testGetApplicationPids_foundOne(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F one.match'), + self._grepOutput('one.match')): + self.assertEqual(['1001'], self.device.GetApplicationPids('one.match')) + + def testGetApplicationPids_foundMany(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F foo'), + self._grepOutput('foo')): + self.assertEqual( + ['1000', '1236'], + self.device.GetApplicationPids('foo')) + + def testGetApplicationPids_atMostOneNotFound(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F match'), + self._grepOutput('match')): + # No PIDs found, process name should be exact match. + self.assertEqual( + None, + self.device.GetApplicationPids('match', at_most_one=True)) + + def testGetApplicationPids_atMostOneFound(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F one.match'), + self._grepOutput('one.match')): + self.assertEqual( + '1001', + self.device.GetApplicationPids('one.match', at_most_one=True)) + + def testGetApplicationPids_atMostOneFoundTooMany(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertRaises(device_errors.CommandFailedError): + with self.assertCall( + self.call.device._RunPipedShellCommand('ps | grep -F foo'), + self._grepOutput('foo')): + self.device.GetApplicationPids('foo', at_most_one=True) + + +class DeviceUtilsGetSetEnforce(DeviceUtilsTest): + + def testGetEnforce_Enforcing(self): + with self.assertCall(self.call.adb.Shell('getenforce'), 'Enforcing'): + self.assertEqual(True, self.device.GetEnforce()) + + def testGetEnforce_Permissive(self): + with self.assertCall(self.call.adb.Shell('getenforce'), 'Permissive'): + self.assertEqual(False, self.device.GetEnforce()) + + def testGetEnforce_Disabled(self): + with self.assertCall(self.call.adb.Shell('getenforce'), 'Disabled'): + self.assertEqual(None, self.device.GetEnforce()) + + def testSetEnforce_Enforcing(self): + with self.assertCalls( + (self.call.device.NeedsSU(), False), + (self.call.adb.Shell('setenforce 1'), '')): + self.device.SetEnforce(enabled=True) + + def testSetEnforce_Permissive(self): + with self.assertCalls( + (self.call.device.NeedsSU(), False), + (self.call.adb.Shell('setenforce 0'), '')): + self.device.SetEnforce(enabled=False) + + def testSetEnforce_EnforcingWithInt(self): + with self.assertCalls( + (self.call.device.NeedsSU(), False), + (self.call.adb.Shell('setenforce 1'), '')): + self.device.SetEnforce(enabled=1) + + def testSetEnforce_PermissiveWithInt(self): + with self.assertCalls( + (self.call.device.NeedsSU(), False), + (self.call.adb.Shell('setenforce 0'), '')): + self.device.SetEnforce(enabled=0) + + def testSetEnforce_EnforcingWithStr(self): + with self.assertCalls( + (self.call.device.NeedsSU(), False), + (self.call.adb.Shell('setenforce 1'), '')): + self.device.SetEnforce(enabled='1') + + def testSetEnforce_PermissiveWithStr(self): + with self.assertCalls( + (self.call.device.NeedsSU(), False), + (self.call.adb.Shell('setenforce 0'), '')): + self.device.SetEnforce(enabled='0') # Not recommended but it works! + + +class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest): + + def testTakeScreenshot_fileNameProvided(self): + with self.assertCalls( + (mock.call.devil.android.device_temp_file.DeviceTempFile( + self.adb, suffix='.png'), + MockTempFile('/tmp/path/temp-123.png')), + (self.call.adb.Shell('/system/bin/screencap -p /tmp/path/temp-123.png'), + ''), + self.call.device.PullFile('/tmp/path/temp-123.png', + '/test/host/screenshot.png')): + self.device.TakeScreenshot('/test/host/screenshot.png') + + +class DeviceUtilsGetMemoryUsageForPidTest(DeviceUtilsTest): + + def setUp(self): + super(DeviceUtilsGetMemoryUsageForPidTest, self).setUp() + + def testGetMemoryUsageForPid_validPid(self): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'showmap 1234 | grep TOTAL', as_root=True), + ['100 101 102 103 104 105 106 107 TOTAL']), + (self.call.device.ReadFile('/proc/1234/status', as_root=True), + 'VmHWM: 1024 kB\n')): + self.assertEqual( + { + 'Size': 100, + 'Rss': 101, + 'Pss': 102, + 'Shared_Clean': 103, + 'Shared_Dirty': 104, + 'Private_Clean': 105, + 'Private_Dirty': 106, + 'VmHWM': 1024 + }, + self.device.GetMemoryUsageForPid(1234)) + + def testGetMemoryUsageForPid_noSmaps(self): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'showmap 4321 | grep TOTAL', as_root=True), + ['cannot open /proc/4321/smaps: No such file or directory']), + (self.call.device.ReadFile('/proc/4321/status', as_root=True), + 'VmHWM: 1024 kb\n')): + self.assertEquals({'VmHWM': 1024}, self.device.GetMemoryUsageForPid(4321)) + + def testGetMemoryUsageForPid_noStatus(self): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'showmap 4321 | grep TOTAL', as_root=True), + ['100 101 102 103 104 105 106 107 TOTAL']), + (self.call.device.ReadFile('/proc/4321/status', as_root=True), + self.CommandError())): + self.assertEquals( + { + 'Size': 100, + 'Rss': 101, + 'Pss': 102, + 'Shared_Clean': 103, + 'Shared_Dirty': 104, + 'Private_Clean': 105, + 'Private_Dirty': 106, + }, + self.device.GetMemoryUsageForPid(4321)) + + +class DeviceUtilsDismissCrashDialogIfNeededTest(DeviceUtilsTest): + + def testDismissCrashDialogIfNeeded_crashedPageckageNotFound(self): + sample_dumpsys_output = ''' +WINDOW MANAGER WINDOWS (dumpsys window windows) + Window #11 Window{f8b647a u0 SearchPanel}: + mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5 + mOwnerUid=100 mShowToOwnerOnly=false package=com.android.systemui appop=NONE + mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100 + Requested w=1080 h=1920 mLayoutSeq=426 + mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000 +''' + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), sample_dumpsys_output.split('\n'))): + package_name = self.device.DismissCrashDialogIfNeeded() + self.assertIsNone(package_name) + + def testDismissCrashDialogIfNeeded_crashedPageckageFound(self): + sample_dumpsys_output = ''' +WINDOW MANAGER WINDOWS (dumpsys window windows) + Window #11 Window{f8b647a u0 SearchPanel}: + mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5 + mOwnerUid=102 mShowToOwnerOnly=false package=com.android.systemui appop=NONE + mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100 + Requested w=1080 h=1920 mLayoutSeq=426 + mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000 + mHasPermanentDpad=false + mCurrentFocus=Window{3a27740f u0 Application Error: com.android.chrome} + mFocusedApp=AppWindowToken{470af6f token=Token{272ec24e ActivityRecord{t894}}} +''' + with self.assertCalls( + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), sample_dumpsys_output.split('\n')), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '22'], check_return=True)), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '22'], check_return=True)), + (self.call.device.RunShellCommand( + ['input', 'keyevent', '66'], check_return=True)), + (self.call.device.RunShellCommand( + ['dumpsys', 'window', 'windows'], check_return=True, + large_output=True), [])): + package_name = self.device.DismissCrashDialogIfNeeded() + self.assertEqual(package_name, 'com.android.chrome') + + +class DeviceUtilsClientCache(DeviceUtilsTest): + + def testClientCache_twoCaches(self): + self.device._cache['test'] = 0 + client_cache_one = self.device.GetClientCache('ClientOne') + client_cache_one['test'] = 1 + client_cache_two = self.device.GetClientCache('ClientTwo') + client_cache_two['test'] = 2 + self.assertEqual(self.device._cache['test'], 0) + self.assertEqual(client_cache_one, {'test': 1}) + self.assertEqual(client_cache_two, {'test': 2}) + self.device._ClearCache() + self.assertTrue('test' not in self.device._cache) + self.assertEqual(client_cache_one, {}) + self.assertEqual(client_cache_two, {}) + + def testClientCache_multipleInstances(self): + client_cache_one = self.device.GetClientCache('ClientOne') + client_cache_one['test'] = 1 + client_cache_two = self.device.GetClientCache('ClientOne') + self.assertEqual(client_cache_one, {'test': 1}) + self.assertEqual(client_cache_two, {'test': 1}) + self.device._ClearCache() + self.assertEqual(client_cache_one, {}) + self.assertEqual(client_cache_two, {}) + + +class DeviceUtilsHealthyDevicesTest(mock_calls.TestCase): + + def testHealthyDevices_emptyBlacklist_defaultDeviceArg(self): + test_serials = ['0123456789abcdef', 'fedcba9876543210'] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials])): + blacklist = mock.NonCallableMock(**{'Read.return_value': []}) + devices = device_utils.DeviceUtils.HealthyDevices(blacklist) + for serial, device in zip(test_serials, devices): + self.assertTrue(isinstance(device, device_utils.DeviceUtils)) + self.assertEquals(serial, device.adb.GetDeviceSerial()) + + def testHealthyDevices_blacklist_defaultDeviceArg(self): + test_serials = ['0123456789abcdef', 'fedcba9876543210'] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials])): + blacklist = mock.NonCallableMock( + **{'Read.return_value': ['fedcba9876543210']}) + devices = device_utils.DeviceUtils.HealthyDevices(blacklist) + self.assertEquals(1, len(devices)) + self.assertTrue(isinstance(devices[0], device_utils.DeviceUtils)) + self.assertEquals('0123456789abcdef', devices[0].adb.GetDeviceSerial()) + + def testHealthyDevices_noneDeviceArg_multiple_attached(self): + test_serials = ['0123456789abcdef', 'fedcba9876543210'] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials]), + (mock.call.devil.android.device_errors.MultipleDevicesError(mock.ANY), + _MockMultipleDevicesError())): + with self.assertRaises(_MockMultipleDevicesError): + device_utils.DeviceUtils.HealthyDevices(device_arg=None) + + def testHealthyDevices_noneDeviceArg_one_attached(self): + test_serials = ['0123456789abcdef'] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials])): + devices = device_utils.DeviceUtils.HealthyDevices(device_arg=None) + self.assertEquals(1, len(devices)) + + def testHealthyDevices_noneDeviceArg_no_attached(self): + test_serials = [] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials])): + with self.assertRaises(device_errors.NoDevicesError): + device_utils.DeviceUtils.HealthyDevices(device_arg=None) + + def testHealthyDevices_noneDeviceArg_multiple_attached_ANDROID_SERIAL(self): + try: + os.environ['ANDROID_SERIAL'] = '0123456789abcdef' + with self.assertCalls(): # Should skip adb devices when device is known. + device_utils.DeviceUtils.HealthyDevices(device_arg=None) + finally: + del os.environ['ANDROID_SERIAL'] + + def testHealthyDevices_stringDeviceArg(self): + with self.assertCalls(): # Should skip adb devices when device is known. + devices = device_utils.DeviceUtils.HealthyDevices( + device_arg='0123456789abcdef') + self.assertEquals(1, len(devices)) + + def testHealthyDevices_EmptyListDeviceArg_multiple_attached(self): + test_serials = ['0123456789abcdef', 'fedcba9876543210'] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials])): + devices = device_utils.DeviceUtils.HealthyDevices(device_arg=()) + self.assertEquals(2, len(devices)) + + def testHealthyDevices_EmptyListDeviceArg_ANDROID_SERIAL(self): + try: + os.environ['ANDROID_SERIAL'] = '0123456789abcdef' + with self.assertCalls(): # Should skip adb devices when device is known. + devices = device_utils.DeviceUtils.HealthyDevices(device_arg=()) + finally: + del os.environ['ANDROID_SERIAL'] + self.assertEquals(1, len(devices)) + + def testHealthyDevices_EmptyListDeviceArg_no_attached(self): + test_serials = [] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials])): + with self.assertRaises(device_errors.NoDevicesError): + device_utils.DeviceUtils.HealthyDevices(device_arg=[]) + + def testHealthyDevices_ListDeviceArg(self): + device_arg = ['0123456789abcdef', 'fedcba9876543210'] + try: + os.environ['ANDROID_SERIAL'] = 'should-not-apply' + with self.assertCalls(): # Should skip adb devices when device is known. + devices = device_utils.DeviceUtils.HealthyDevices(device_arg=device_arg) + finally: + del os.environ['ANDROID_SERIAL'] + self.assertEquals(2, len(devices)) + + +class DeviceUtilsRestartAdbdTest(DeviceUtilsTest): + + def testAdbdRestart(self): + mock_temp_file = '/sdcard/temp-123.sh' + with self.assertCalls( + (mock.call.devil.android.device_temp_file.DeviceTempFile( + self.adb, suffix='.sh'), MockTempFile(mock_temp_file)), + self.call.device.WriteFile(mock.ANY, mock.ANY), + (self.call.device.RunShellCommand( + ['source', mock_temp_file], check_return=True, as_root=True)), + self.call.adb.WaitForDevice()): + self.device.RestartAdbd() + + +class DeviceUtilsGrantPermissionsTest(DeviceUtilsTest): + + def testGrantPermissions_none(self): + self.device.GrantPermissions('package', []) + + def testGrantPermissions_underM(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + self.device.GrantPermissions('package', ['p1']) + + def testGrantPermissions_one(self): + permissions_cmd = 'pm grant package p1' + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + with self.assertCalls( + (self.call.device.RunShellCommand( + permissions_cmd, shell=True, check_return=True), [])): + self.device.GrantPermissions('package', ['p1']) + + def testGrantPermissions_multiple(self): + permissions_cmd = 'pm grant package p1&&pm grant package p2' + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + with self.assertCalls( + (self.call.device.RunShellCommand( + permissions_cmd, shell=True, check_return=True), [])): + self.device.GrantPermissions('package', ['p1', 'p2']) + + def testGrantPermissions_WriteExtrnalStorage(self): + permissions_cmd = ( + 'pm grant package android.permission.WRITE_EXTERNAL_STORAGE&&' + 'pm grant package android.permission.READ_EXTERNAL_STORAGE') + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + with self.assertCalls( + (self.call.device.RunShellCommand( + permissions_cmd, shell=True, check_return=True), [])): + self.device.GrantPermissions( + 'package', ['android.permission.WRITE_EXTERNAL_STORAGE']) + + def testGrantPermissions_BlackList(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + self.device.GrantPermissions( + 'package', ['android.permission.ACCESS_MOCK_LOCATION']) + + +class DeviecUtilsIsScreenOn(DeviceUtilsTest): + + _L_SCREEN_ON = ['test=test mInteractive=true'] + _K_SCREEN_ON = ['test=test mScreenOn=true'] + _L_SCREEN_OFF = ['mInteractive=false'] + _K_SCREEN_OFF = ['mScreenOn=false'] + + def testIsScreenOn_onPreL(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.KITKAT): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_ON)): + self.assertTrue(self.device.IsScreenOn()) + + def testIsScreenOn_onL(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'dumpsys input_method | grep mInteractive'), self._L_SCREEN_ON)): + self.assertTrue(self.device.IsScreenOn()) + + def testIsScreenOn_offPreL(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.KITKAT): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_OFF)): + self.assertFalse(self.device.IsScreenOn()) + + def testIsScreenOn_offL(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'dumpsys input_method | grep mInteractive'), self._L_SCREEN_OFF)): + self.assertFalse(self.device.IsScreenOn()) + + def testIsScreenOn_noOutput(self): + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.LOLLIPOP): + with self.assertCalls( + (self.call.device._RunPipedShellCommand( + 'dumpsys input_method | grep mInteractive'), [])): + with self.assertRaises(device_errors.CommandFailedError): + self.device.IsScreenOn() + + +class DeviecUtilsSetScreen(DeviceUtilsTest): + + @mock.patch('time.sleep', mock.Mock()) + def testSetScren_alreadySet(self): + with self.assertCalls( + (self.call.device.IsScreenOn(), False)): + self.device.SetScreen(False) + + @mock.patch('time.sleep', mock.Mock()) + def testSetScreen_on(self): + with self.assertCalls( + (self.call.device.IsScreenOn(), False), + (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None), + (self.call.device.IsScreenOn(), True)): + self.device.SetScreen(True) + + @mock.patch('time.sleep', mock.Mock()) + def testSetScreen_off(self): + with self.assertCalls( + (self.call.device.IsScreenOn(), True), + (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None), + (self.call.device.IsScreenOn(), False)): + self.device.SetScreen(False) + + @mock.patch('time.sleep', mock.Mock()) + def testSetScreen_slow(self): + with self.assertCalls( + (self.call.device.IsScreenOn(), True), + (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None), + (self.call.device.IsScreenOn(), True), + (self.call.device.IsScreenOn(), True), + (self.call.device.IsScreenOn(), False)): + self.device.SetScreen(False) + +class DeviecUtilsLoadCacheData(DeviceUtilsTest): + + def testTokenMissing(self): + with self.assertCalls( + self.EnsureCacheInitialized()): + self.assertFalse(self.device.LoadCacheData('{}')) + + def testTokenStale(self): + with self.assertCalls( + self.EnsureCacheInitialized()): + self.assertFalse(self.device.LoadCacheData('{"token":"foo"}')) + + def testTokenMatches(self): + with self.assertCalls( + self.EnsureCacheInitialized()): + self.assertTrue(self.device.LoadCacheData('{"token":"TOKEN"}')) + + def testDumpThenLoad(self): + with self.assertCalls( + self.EnsureCacheInitialized()): + data = json.loads(self.device.DumpCacheData()) + data['token'] = 'TOKEN' + self.assertTrue(self.device.LoadCacheData(json.dumps(data))) + + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils.py new file mode 100644 index 0000000..3bd3ee8 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils.py @@ -0,0 +1,256 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Provides a variety of device interactions based on fastboot.""" +# pylint: disable=unused-argument + +import collections +import contextlib +import fnmatch +import logging +import os +import re + +from devil.android import decorators +from devil.android import device_errors +from devil.android.sdk import fastboot +from devil.utils import timeout_retry + +logger = logging.getLogger(__name__) + +_DEFAULT_TIMEOUT = 30 +_DEFAULT_RETRIES = 3 +_FASTBOOT_REBOOT_TIMEOUT = 10 * _DEFAULT_TIMEOUT +_KNOWN_PARTITIONS = collections.OrderedDict([ + ('bootloader', {'image': 'bootloader*.img', 'restart': True}), + ('radio', {'image': 'radio*.img', 'restart': True}), + ('boot', {'image': 'boot.img'}), + ('recovery', {'image': 'recovery.img'}), + ('system', {'image': 'system.img'}), + ('userdata', {'image': 'userdata.img', 'wipe_only': True}), + ('cache', {'image': 'cache.img', 'wipe_only': True}), + ('vendor', {'image': 'vendor*.img', 'optional': True}), + ]) +ALL_PARTITIONS = _KNOWN_PARTITIONS.keys() + + +def _FindAndVerifyPartitionsAndImages(partitions, directory): + """Validate partitions and images. + + Validate all partition names and partition directories. Cannot stop mid + flash so its important to validate everything first. + + Args: + Partitions: partitions to be tested. + directory: directory containing the images. + + Returns: + Dictionary with exact partition, image name mapping. + """ + + files = os.listdir(directory) + return_dict = collections.OrderedDict() + + def find_file(pattern): + for filename in files: + if fnmatch.fnmatch(filename, pattern): + return os.path.join(directory, filename) + return None + for partition in partitions: + partition_info = _KNOWN_PARTITIONS[partition] + image_file = find_file(partition_info['image']) + if image_file: + return_dict[partition] = image_file + elif not partition_info.get('optional'): + raise device_errors.FastbootCommandFailedError( + 'Failed to flash device. Could not find image for %s.', + partition_info['image']) + return return_dict + + +class FastbootUtils(object): + + _FASTBOOT_WAIT_TIME = 1 + _BOARD_VERIFICATION_FILE = 'android-info.txt' + + def __init__(self, device, fastbooter=None, default_timeout=_DEFAULT_TIMEOUT, + default_retries=_DEFAULT_RETRIES): + """FastbootUtils constructor. + + Example Usage to flash a device: + fastboot = fastboot_utils.FastbootUtils(device) + fastboot.FlashDevice('/path/to/build/directory') + + Args: + device: A DeviceUtils instance. + fastbooter: Optional fastboot object. If none is passed, one will + be created. + default_timeout: An integer containing the default number of seconds to + wait for an operation to complete if no explicit value is provided. + default_retries: An integer containing the default number or times an + operation should be retried on failure if no explicit value is provided. + """ + self._device = device + self._board = device.product_board + self._serial = str(device) + self._default_timeout = default_timeout + self._default_retries = default_retries + if fastbooter: + self.fastboot = fastbooter + else: + self.fastboot = fastboot.Fastboot(self._serial) + + @decorators.WithTimeoutAndRetriesFromInstance() + def WaitForFastbootMode(self, timeout=None, retries=None): + """Wait for device to boot into fastboot mode. + + This waits for the device serial to show up in fastboot devices output. + """ + def fastboot_mode(): + return self._serial in self.fastboot.Devices() + + timeout_retry.WaitFor(fastboot_mode, wait_period=self._FASTBOOT_WAIT_TIME) + + @decorators.WithTimeoutAndRetriesFromInstance( + min_default_timeout=_FASTBOOT_REBOOT_TIMEOUT) + def EnableFastbootMode(self, timeout=None, retries=None): + """Reboots phone into fastboot mode. + + Roots phone if needed, then reboots phone into fastboot mode and waits. + """ + self._device.EnableRoot() + self._device.adb.Reboot(to_bootloader=True) + self.WaitForFastbootMode() + + @decorators.WithTimeoutAndRetriesFromInstance( + min_default_timeout=_FASTBOOT_REBOOT_TIMEOUT) + def Reboot( + self, bootloader=False, wait_for_reboot=True, timeout=None, retries=None): + """Reboots out of fastboot mode. + + It reboots the phone either back into fastboot, or to a regular boot. It + then blocks until the device is ready. + + Args: + bootloader: If set to True, reboots back into bootloader. + """ + if bootloader: + self.fastboot.RebootBootloader() + self.WaitForFastbootMode() + else: + self.fastboot.Reboot() + if wait_for_reboot: + self._device.WaitUntilFullyBooted(timeout=_FASTBOOT_REBOOT_TIMEOUT) + + def _VerifyBoard(self, directory): + """Validate as best as possible that the android build matches the device. + + Goes through build files and checks if the board name is mentioned in the + |self._BOARD_VERIFICATION_FILE| or in the build archive. + + Args: + directory: directory where build files are located. + """ + files = os.listdir(directory) + board_regex = re.compile(r'require board=(\w+)') + if self._BOARD_VERIFICATION_FILE in files: + with open(os.path.join(directory, self._BOARD_VERIFICATION_FILE)) as f: + for line in f: + m = board_regex.match(line) + if m: + board_name = m.group(1) + if board_name == self._board: + return True + elif board_name: + return False + else: + logger.warning('No board type found in %s.', + self._BOARD_VERIFICATION_FILE) + else: + logger.warning('%s not found. Unable to use it to verify device.', + self._BOARD_VERIFICATION_FILE) + + zip_regex = re.compile(r'.*%s.*\.zip' % re.escape(self._board)) + for f in files: + if zip_regex.match(f): + return True + + return False + + def _FlashPartitions(self, partitions, directory, wipe=False, force=False): + """Flashes all given partiitons with all given images. + + Args: + partitions: List of partitions to flash. + directory: Directory where all partitions can be found. + wipe: If set to true, will automatically detect if cache and userdata + partitions are sent, and if so ignore them. + force: boolean to decide to ignore board name safety checks. + + Raises: + device_errors.CommandFailedError(): If image cannot be found or if bad + partition name is give. + """ + if not self._VerifyBoard(directory): + if force: + logger.warning('Could not verify build is meant to be installed on ' + 'the current device type, but force flag is set. ' + 'Flashing device. Possibly dangerous operation.') + else: + raise device_errors.CommandFailedError( + 'Could not verify build is meant to be installed on the current ' + 'device type. Run again with force=True to force flashing with an ' + 'unverified board.') + + flash_image_files = _FindAndVerifyPartitionsAndImages(partitions, directory) + partitions = flash_image_files.keys() + for partition in partitions: + if _KNOWN_PARTITIONS[partition].get('wipe_only') and not wipe: + logger.info( + 'Not flashing in wipe mode. Skipping partition %s.', partition) + else: + logger.info( + 'Flashing %s with %s', partition, flash_image_files[partition]) + self.fastboot.Flash(partition, flash_image_files[partition]) + if _KNOWN_PARTITIONS[partition].get('restart', False): + self.Reboot(bootloader=True) + + @contextlib.contextmanager + def FastbootMode(self, wait_for_reboot=True, timeout=None, retries=None): + """Context manager that enables fastboot mode, and reboots after. + + Example usage: + with FastbootMode(): + Flash Device + # Anything that runs after flashing. + """ + self.EnableFastbootMode() + self.fastboot.SetOemOffModeCharge(False) + try: + yield self + finally: + self.fastboot.SetOemOffModeCharge(True) + self.Reboot(wait_for_reboot=wait_for_reboot) + + def FlashDevice(self, directory, partitions=None, wipe=False): + """Flash device with build in |directory|. + + Directory must contain bootloader, radio, boot, recovery, system, userdata, + and cache .img files from an android build. This is a dangerous operation so + use with care. + + Args: + fastboot: A FastbootUtils instance. + directory: Directory with build files. + wipe: Wipes cache and userdata if set to true. + partitions: List of partitions to flash. Defaults to all. + """ + if partitions is None: + partitions = ALL_PARTITIONS + # If a device is wiped, then it will no longer have adb keys so it cannot be + # communicated with to verify that it is rebooted. It is up to the user of + # this script to ensure that the adb keys are set on the device after using + # this to wipe a device. + with self.FastbootMode(wait_for_reboot=not wipe): + self._FlashPartitions(partitions, directory, wipe=wipe) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils_test.py new file mode 100644 index 0000000..0562974 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/fastboot_utils_test.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Unit tests for the contents of fastboot_utils.py +""" + +# pylint: disable=protected-access,unused-argument + +import collections +import io +import logging +import unittest + +from devil import devil_env +from devil.android import device_errors +from devil.android import device_utils +from devil.android import fastboot_utils +from devil.android.sdk import fastboot +from devil.utils import mock_calls + +with devil_env.SysPath(devil_env.PYMOCK_PATH): + import mock # pylint: disable=import-error + +_BOARD = 'board_type' +_SERIAL = '0123456789abcdef' +_PARTITIONS = [ + 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', 'cache'] +_IMAGES = collections.OrderedDict([ + ('bootloader', 'bootloader.img'), + ('radio', 'radio.img'), + ('boot', 'boot.img'), + ('recovery', 'recovery.img'), + ('system', 'system.img'), + ('userdata', 'userdata.img'), + ('cache', 'cache.img') +]) +_VALID_FILES = [_BOARD + '.zip', 'android-info.txt'] +_INVALID_FILES = ['test.zip', 'android-info.txt'] + + +class MockFile(object): + + def __init__(self, name='/tmp/some/file'): + self.file = mock.MagicMock(spec=file) + self.file.name = name + + def __enter__(self): + return self.file + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + @property + def name(self): + return self.file.name + + +def _FastbootWrapperMock(test_serial): + fastbooter = mock.Mock(spec=fastboot.Fastboot) + fastbooter.__str__ = mock.Mock(return_value=test_serial) + fastbooter.Devices.return_value = [test_serial] + return fastbooter + + +def _DeviceUtilsMock(test_serial): + device = mock.Mock(spec=device_utils.DeviceUtils) + device.__str__ = mock.Mock(return_value=test_serial) + device.product_board = mock.Mock(return_value=_BOARD) + device.adb = mock.Mock() + return device + + +class FastbootUtilsTest(mock_calls.TestCase): + + def setUp(self): + self.device_utils_mock = _DeviceUtilsMock(_SERIAL) + self.fastboot_wrapper = _FastbootWrapperMock(_SERIAL) + self.fastboot = fastboot_utils.FastbootUtils( + self.device_utils_mock, fastbooter=self.fastboot_wrapper, + default_timeout=2, default_retries=0) + self.fastboot._board = _BOARD + + +class FastbootUtilsInitTest(FastbootUtilsTest): + + def testInitWithDeviceUtil(self): + f = fastboot_utils.FastbootUtils(self.device_utils_mock) + self.assertEqual(str(self.device_utils_mock), str(f._device)) + + def testInitWithMissing_fails(self): + with self.assertRaises(AttributeError): + fastboot_utils.FastbootUtils(None) + with self.assertRaises(AttributeError): + fastboot_utils.FastbootUtils('') + + def testPartitionOrdering(self): + parts = ['bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', + 'cache', 'vendor'] + self.assertListEqual(fastboot_utils.ALL_PARTITIONS, parts) + + +class FastbootUtilsWaitForFastbootMode(FastbootUtilsTest): + + # If this test fails by timing out after 1 second. + @mock.patch('time.sleep', mock.Mock()) + def testWaitForFastbootMode(self): + self.fastboot.WaitForFastbootMode() + + +class FastbootUtilsEnableFastbootMode(FastbootUtilsTest): + + def testEnableFastbootMode(self): + with self.assertCalls( + self.call.fastboot._device.EnableRoot(), + self.call.fastboot._device.adb.Reboot(to_bootloader=True), + self.call.fastboot.WaitForFastbootMode()): + self.fastboot.EnableFastbootMode() + + +class FastbootUtilsReboot(FastbootUtilsTest): + + def testReboot_bootloader(self): + with self.assertCalls( + self.call.fastboot.fastboot.RebootBootloader(), + self.call.fastboot.WaitForFastbootMode()): + self.fastboot.Reboot(bootloader=True) + + def testReboot_normal(self): + with self.assertCalls( + self.call.fastboot.fastboot.Reboot(), + self.call.fastboot._device.WaitUntilFullyBooted(timeout=mock.ANY)): + self.fastboot.Reboot() + + +class FastbootUtilsFlashPartitions(FastbootUtilsTest): + + def testFlashPartitions_wipe(self): + with self.assertCalls( + (self.call.fastboot._VerifyBoard('test'), True), + (mock.call.devil.android.fastboot_utils. + _FindAndVerifyPartitionsAndImages(_PARTITIONS, 'test'), _IMAGES), + (self.call.fastboot.fastboot.Flash('bootloader', 'bootloader.img')), + (self.call.fastboot.Reboot(bootloader=True)), + (self.call.fastboot.fastboot.Flash('radio', 'radio.img')), + (self.call.fastboot.Reboot(bootloader=True)), + (self.call.fastboot.fastboot.Flash('boot', 'boot.img')), + (self.call.fastboot.fastboot.Flash('recovery', 'recovery.img')), + (self.call.fastboot.fastboot.Flash('system', 'system.img')), + (self.call.fastboot.fastboot.Flash('userdata', 'userdata.img')), + (self.call.fastboot.fastboot.Flash('cache', 'cache.img'))): + self.fastboot._FlashPartitions(_PARTITIONS, 'test', wipe=True) + + def testFlashPartitions_noWipe(self): + with self.assertCalls( + (self.call.fastboot._VerifyBoard('test'), True), + (mock.call.devil.android.fastboot_utils. + _FindAndVerifyPartitionsAndImages(_PARTITIONS, 'test'), _IMAGES), + (self.call.fastboot.fastboot.Flash('bootloader', 'bootloader.img')), + (self.call.fastboot.Reboot(bootloader=True)), + (self.call.fastboot.fastboot.Flash('radio', 'radio.img')), + (self.call.fastboot.Reboot(bootloader=True)), + (self.call.fastboot.fastboot.Flash('boot', 'boot.img')), + (self.call.fastboot.fastboot.Flash('recovery', 'recovery.img')), + (self.call.fastboot.fastboot.Flash('system', 'system.img'))): + self.fastboot._FlashPartitions(_PARTITIONS, 'test') + + +class FastbootUtilsFastbootMode(FastbootUtilsTest): + + def testFastbootMode_goodWait(self): + with self.assertCalls( + self.call.fastboot.EnableFastbootMode(), + self.call.fastboot.fastboot.SetOemOffModeCharge(False), + self.call.fastboot.fastboot.SetOemOffModeCharge(True), + self.call.fastboot.Reboot(wait_for_reboot=True)): + with self.fastboot.FastbootMode() as fbm: + self.assertEqual(self.fastboot, fbm) + + def testFastbootMode_goodNoWait(self): + with self.assertCalls( + self.call.fastboot.EnableFastbootMode(), + self.call.fastboot.fastboot.SetOemOffModeCharge(False), + self.call.fastboot.fastboot.SetOemOffModeCharge(True), + self.call.fastboot.Reboot(wait_for_reboot=False)): + with self.fastboot.FastbootMode(wait_for_reboot=False) as fbm: + self.assertEqual(self.fastboot, fbm) + + def testFastbootMode_exception(self): + with self.assertCalls( + self.call.fastboot.EnableFastbootMode(), + self.call.fastboot.fastboot.SetOemOffModeCharge(False), + self.call.fastboot.fastboot.SetOemOffModeCharge(True), + self.call.fastboot.Reboot(wait_for_reboot=True)): + with self.assertRaises(NotImplementedError): + with self.fastboot.FastbootMode() as fbm: + self.assertEqual(self.fastboot, fbm) + raise NotImplementedError + + def testFastbootMode_exceptionInEnableFastboot(self): + self.fastboot.EnableFastbootMode = mock.Mock() + self.fastboot.EnableFastbootMode.side_effect = NotImplementedError + with self.assertRaises(NotImplementedError): + with self.fastboot.FastbootMode(): + pass + + +class FastbootUtilsVerifyBoard(FastbootUtilsTest): + + def testVerifyBoard_bothValid(self): + mock_file = io.StringIO(u'require board=%s\n' % _BOARD) + with mock.patch('__builtin__.open', return_value=mock_file, create=True): + with mock.patch('os.listdir', return_value=_VALID_FILES): + self.assertTrue(self.fastboot._VerifyBoard('test')) + + def testVerifyBoard_BothNotValid(self): + mock_file = io.StringIO(u'abc') + with mock.patch('__builtin__.open', return_value=mock_file, create=True): + with mock.patch('os.listdir', return_value=_INVALID_FILES): + self.assertFalse(self.assertFalse(self.fastboot._VerifyBoard('test'))) + + def testVerifyBoard_FileNotFoundZipValid(self): + with mock.patch('os.listdir', return_value=[_BOARD + '.zip']): + self.assertTrue(self.fastboot._VerifyBoard('test')) + + def testVerifyBoard_ZipNotFoundFileValid(self): + mock_file = io.StringIO(u'require board=%s\n' % _BOARD) + with mock.patch('__builtin__.open', return_value=mock_file, create=True): + with mock.patch('os.listdir', return_value=['android-info.txt']): + self.assertTrue(self.fastboot._VerifyBoard('test')) + + def testVerifyBoard_zipNotValidFileIs(self): + mock_file = io.StringIO(u'require board=%s\n' % _BOARD) + with mock.patch('__builtin__.open', return_value=mock_file, create=True): + with mock.patch('os.listdir', return_value=_INVALID_FILES): + self.assertTrue(self.fastboot._VerifyBoard('test')) + + def testVerifyBoard_fileNotValidZipIs(self): + mock_file = io.StringIO(u'require board=WrongBoard') + with mock.patch('__builtin__.open', return_value=mock_file, create=True): + with mock.patch('os.listdir', return_value=_VALID_FILES): + self.assertFalse(self.fastboot._VerifyBoard('test')) + + def testVerifyBoard_noBoardInFileValidZip(self): + mock_file = io.StringIO(u'Regex wont match') + with mock.patch('__builtin__.open', return_value=mock_file, create=True): + with mock.patch('os.listdir', return_value=_VALID_FILES): + self.assertTrue(self.fastboot._VerifyBoard('test')) + + def testVerifyBoard_noBoardInFileInvalidZip(self): + mock_file = io.StringIO(u'Regex wont match') + with mock.patch('__builtin__.open', return_value=mock_file, create=True): + with mock.patch('os.listdir', return_value=_INVALID_FILES): + self.assertFalse(self.fastboot._VerifyBoard('test')) + + +class FastbootUtilsFindAndVerifyPartitionsAndImages(FastbootUtilsTest): + + def testFindAndVerifyPartitionsAndImages_validNoVendor(self): + PARTITIONS = [ + 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', + 'cache', 'vendor' + ] + files = [ + 'bootloader-test-.img', + 'radio123.img', + 'boot.img', + 'recovery.img', + 'system.img', + 'userdata.img', + 'cache.img' + ] + img_check = collections.OrderedDict([ + ('bootloader', 'test/bootloader-test-.img'), + ('radio', 'test/radio123.img'), + ('boot', 'test/boot.img'), + ('recovery', 'test/recovery.img'), + ('system', 'test/system.img'), + ('userdata', 'test/userdata.img'), + ('cache', 'test/cache.img'), + ]) + parts_check = [ + 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', + 'cache' + ] + with mock.patch('os.listdir', return_value=files): + imgs = fastboot_utils._FindAndVerifyPartitionsAndImages( + PARTITIONS, 'test') + parts = imgs.keys() + self.assertDictEqual(imgs, img_check) + self.assertListEqual(parts, parts_check) + + def testFindAndVerifyPartitionsAndImages_validVendor(self): + PARTITIONS = [ + 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', + 'cache', 'vendor' + ] + files = [ + 'bootloader-test-.img', + 'radio123.img', + 'boot.img', + 'recovery.img', + 'system.img', + 'userdata.img', + 'cache.img', + 'vendor.img' + ] + img_check = { + 'bootloader': 'test/bootloader-test-.img', + 'radio': 'test/radio123.img', + 'boot': 'test/boot.img', + 'recovery': 'test/recovery.img', + 'system': 'test/system.img', + 'userdata': 'test/userdata.img', + 'cache': 'test/cache.img', + 'vendor': 'test/vendor.img', + } + parts_check = [ + 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', + 'cache', 'vendor' + ] + + with mock.patch('os.listdir', return_value=files): + imgs = fastboot_utils._FindAndVerifyPartitionsAndImages( + PARTITIONS, 'test') + parts = imgs.keys() + self.assertDictEqual(imgs, img_check) + self.assertListEqual(parts, parts_check) + + def testFindAndVerifyPartitionsAndImages_badPartition(self): + with mock.patch('os.listdir', return_value=['test']): + with self.assertRaises(KeyError): + fastboot_utils._FindAndVerifyPartitionsAndImages(['test'], 'test') + + def testFindAndVerifyPartitionsAndImages_noFile(self): + with mock.patch('os.listdir', return_value=['test']): + with self.assertRaises(device_errors.FastbootCommandFailedError): + fastboot_utils._FindAndVerifyPartitionsAndImages(['cache'], 'test') + + +class FastbootUtilsFlashDevice(FastbootUtilsTest): + + def testFlashDevice_wipe(self): + with self.assertCalls( + self.call.fastboot.EnableFastbootMode(), + self.call.fastboot.fastboot.SetOemOffModeCharge(False), + self.call.fastboot._FlashPartitions(mock.ANY, 'test', wipe=True), + self.call.fastboot.fastboot.SetOemOffModeCharge(True), + self.call.fastboot.Reboot(wait_for_reboot=False)): + self.fastboot.FlashDevice('test', wipe=True) + + def testFlashDevice_noWipe(self): + with self.assertCalls( + self.call.fastboot.EnableFastbootMode(), + self.call.fastboot.fastboot.SetOemOffModeCharge(False), + self.call.fastboot._FlashPartitions(mock.ANY, 'test', wipe=False), + self.call.fastboot.fastboot.SetOemOffModeCharge(True), + self.call.fastboot.Reboot(wait_for_reboot=True)): + self.fastboot.FlashDevice('test', wipe=False) + + def testFlashDevice_partitions(self): + with self.assertCalls( + self.call.fastboot.EnableFastbootMode(), + self.call.fastboot.fastboot.SetOemOffModeCharge(False), + self.call.fastboot._FlashPartitions(['boot'], 'test', wipe=False), + self.call.fastboot.fastboot.SetOemOffModeCharge(True), + self.call.fastboot.Reboot(wait_for_reboot=True)): + self.fastboot.FlashDevice('test', partitions=['boot'], wipe=False) + + +if __name__ == '__main__': + logging.getLogger().setLevel(logging.DEBUG) + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer.py new file mode 100644 index 0000000..b2ee8b1 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer.py @@ -0,0 +1,300 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import contextlib +import logging +import posixpath +import re + +from devil.android.sdk import version_codes + + +logger = logging.getLogger(__name__) + + +_CMDLINE_DIR = '/data/local/tmp' +_CMDLINE_DIR_LEGACY = '/data/local' +_RE_NEEDS_QUOTING = re.compile(r'[^\w-]') # Not in: alphanumeric or hyphens. +_QUOTES = '"\'' # Either a single or a double quote. +_ESCAPE = '\\' # A backslash. + + +@contextlib.contextmanager +def CustomCommandLineFlags(device, cmdline_name, flags): + """Context manager to change Chrome's command line temporarily. + + Example: + + with flag_changer.TemporaryCommandLineFlags(device, name, flags): + # Launching Chrome will use the provided flags. + + # Previous set of flags on the device is now restored. + + Args: + device: A DeviceUtils instance. + cmdline_name: Name of the command line file where to store flags. + flags: A sequence of command line flags to set. + """ + # On Android N and above, we need to temporarily set SELinux to permissive + # so that Chrome is allowed to read the command line file. + # TODO(crbug.com/699082): Remove when a solution to avoid this is implemented. + needs_permissive = ( + device.build_version_sdk >= version_codes.NOUGAT and + device.GetEnforce()) + if needs_permissive: + device.SetEnforce(enabled=False) + try: + changer = FlagChanger(device, cmdline_name) + try: + changer.ReplaceFlags(flags) + yield + finally: + changer.Restore() + finally: + if needs_permissive: + device.SetEnforce(enabled=True) + + +class FlagChanger(object): + """Changes the flags Chrome runs with. + + Flags can be temporarily set for a particular set of unit tests. These + tests should call Restore() to revert the flags to their original state + once the tests have completed. + """ + + def __init__(self, device, cmdline_file): + """Initializes the FlagChanger and records the original arguments. + + Args: + device: A DeviceUtils instance. + cmdline_file: Name of the command line file where to store flags. + """ + self._device = device + + if posixpath.sep in cmdline_file: + raise ValueError( + 'cmdline_file should be a file name only, do not include path' + ' separators in: %s' % cmdline_file) + self._cmdline_path = posixpath.join(_CMDLINE_DIR, cmdline_file) + + cmdline_path_legacy = posixpath.join(_CMDLINE_DIR_LEGACY, cmdline_file) + if self._device.PathExists(cmdline_path_legacy): + logging.warning( + 'Removing legacy command line file %r.', cmdline_path_legacy) + self._device.RemovePath(cmdline_path_legacy, as_root=True) + + self._state_stack = [None] # Actual state is set by GetCurrentFlags(). + self.GetCurrentFlags() + + def GetCurrentFlags(self): + """Read the current flags currently stored in the device. + + Also updates the internal state of the flag_changer. + + Returns: + A list of flags. + """ + if self._device.PathExists(self._cmdline_path): + command_line = self._device.ReadFile(self._cmdline_path).strip() + else: + command_line = '' + flags = _ParseFlags(command_line) + + # Store the flags as a set to facilitate adding and removing flags. + self._state_stack[-1] = set(flags) + return flags + + def ReplaceFlags(self, flags): + """Replaces the flags in the command line with the ones provided. + Saves the current flags state on the stack, so a call to Restore will + change the state back to the one preceeding the call to ReplaceFlags. + + Args: + flags: A sequence of command line flags to set, eg. ['--single-process']. + Note: this should include flags only, not the name of a command + to run (ie. there is no need to start the sequence with 'chrome'). + + Returns: + A list with the flags now stored on the device. + """ + new_flags = set(flags) + self._state_stack.append(new_flags) + return self._UpdateCommandLineFile() + + def AddFlags(self, flags): + """Appends flags to the command line if they aren't already there. + Saves the current flags state on the stack, so a call to Restore will + change the state back to the one preceeding the call to AddFlags. + + Args: + flags: A sequence of flags to add on, eg. ['--single-process']. + + Returns: + A list with the flags now stored on the device. + """ + return self.PushFlags(add=flags) + + def RemoveFlags(self, flags): + """Removes flags from the command line, if they exist. + Saves the current flags state on the stack, so a call to Restore will + change the state back to the one preceeding the call to RemoveFlags. + + Note that calling RemoveFlags after AddFlags will result in having + two nested states. + + Args: + flags: A sequence of flags to remove, eg. ['--single-process']. Note + that we expect a complete match when removing flags; if you want + to remove a switch with a value, you must use the exact string + used to add it in the first place. + + Returns: + A list with the flags now stored on the device. + """ + return self.PushFlags(remove=flags) + + def PushFlags(self, add=None, remove=None): + """Appends and removes flags to/from the command line if they aren't already + there. Saves the current flags state on the stack, so a call to Restore + will change the state back to the one preceeding the call to PushFlags. + + Args: + add: A list of flags to add on, eg. ['--single-process']. + remove: A list of flags to remove, eg. ['--single-process']. Note that we + expect a complete match when removing flags; if you want to remove + a switch with a value, you must use the exact string used to add + it in the first place. + + Returns: + A list with the flags now stored on the device. + """ + new_flags = self._state_stack[-1].copy() + if add: + new_flags.update(add) + if remove: + new_flags.difference_update(remove) + return self.ReplaceFlags(new_flags) + + def Restore(self): + """Restores the flags to their state prior to the last AddFlags or + RemoveFlags call. + + Returns: + A list with the flags now stored on the device. + """ + # The initial state must always remain on the stack. + assert len(self._state_stack) > 1, ( + "Mismatch between calls to Add/RemoveFlags and Restore") + self._state_stack.pop() + return self._UpdateCommandLineFile() + + def _UpdateCommandLineFile(self): + """Writes out the command line to the file, or removes it if empty. + + Returns: + A list with the flags now stored on the device. + """ + command_line = _SerializeFlags(self._state_stack[-1]) + if command_line is not None: + self._device.WriteFile(self._cmdline_path, command_line) + else: + self._device.RemovePath(self._cmdline_path, force=True) + + current_flags = self.GetCurrentFlags() + logger.info('Flags now set on the device: %s', current_flags) + return current_flags + + +def _ParseFlags(line): + """Parse the string containing the command line into a list of flags. + + It's a direct port of CommandLine.java::tokenizeQuotedArguments. + + The first token is assumed to be the (unused) program name and stripped off + from the list of flags. + + Args: + line: A string containing the entire command line. The first token is + assumed to be the program name. + + Returns: + A list of flags, with quoting removed. + """ + flags = [] + current_quote = None + current_flag = None + + for c in line: + # Detect start or end of quote block. + if (current_quote is None and c in _QUOTES) or c == current_quote: + if current_flag is not None and current_flag[-1] == _ESCAPE: + # Last char was a backslash; pop it, and treat c as a literal. + current_flag = current_flag[:-1] + c + else: + current_quote = c if current_quote is None else None + elif current_quote is None and c.isspace(): + if current_flag is not None: + flags.append(current_flag) + current_flag = None + else: + if current_flag is None: + current_flag = '' + current_flag += c + + if current_flag is not None: + if current_quote is not None: + logger.warning('Unterminated quoted argument: ' + current_flag) + flags.append(current_flag) + + # Return everything but the program name. + return flags[1:] + + +def _SerializeFlags(flags): + """Serialize a sequence of flags into a command line string. + + Args: + flags: A sequence of strings with individual flags. + + Returns: + A line with the command line contents to save; or None if the sequence of + flags is empty. + """ + if flags: + # The first command line argument doesn't matter as we are not actually + # launching the chrome executable using this command line. + args = ['_'] + args.extend(_QuoteFlag(f) for f in flags) + return ' '.join(args) + else: + return None + + +def _QuoteFlag(flag): + """Validate and quote a single flag. + + Args: + A string with the flag to quote. + + Returns: + A string with the flag quoted so that it can be parsed by the algorithm + in _ParseFlags; or None if the flag does not appear to be valid. + """ + if '=' in flag: + key, value = flag.split('=', 1) + else: + key, value = flag, None + + if not flag or _RE_NEEDS_QUOTING.search(key): + # Probably not a valid flag, but quote the whole thing so it can be + # parsed back correctly. + return '"%s"' % flag.replace('"', r'\"') + + if value is None: + return key + + if _RE_NEEDS_QUOTING.search(value): + value = '"%s"' % value.replace('"', r'\"') + return '='.join([key, value]) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_devicetest.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_devicetest.py new file mode 100644 index 0000000..b75504b --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_devicetest.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +""" +Unit tests for the contents of flag_changer.py. +The test will invoke real devices +""" + +import os +import posixpath +import sys +import unittest + +if __name__ == '__main__': + sys.path.append( + os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', ))) + +from devil.android import device_test_case +from devil.android import device_utils +from devil.android import flag_changer +from devil.android.sdk import adb_wrapper + + +_CMDLINE_FILE = 'dummy-command-line' + + +class FlagChangerTest(device_test_case.DeviceTestCase): + + def setUp(self): + super(FlagChangerTest, self).setUp() + self.adb = adb_wrapper.AdbWrapper(self.serial) + self.adb.WaitForDevice() + self.device = device_utils.DeviceUtils( + self.adb, default_timeout=10, default_retries=0) + # pylint: disable=protected-access + self.cmdline_path = posixpath.join(flag_changer._CMDLINE_DIR, _CMDLINE_FILE) + self.cmdline_path_legacy = posixpath.join( + flag_changer._CMDLINE_DIR_LEGACY, _CMDLINE_FILE) + + def tearDown(self): + super(FlagChangerTest, self).tearDown() + self.device.RemovePath( + [self.cmdline_path, self.cmdline_path_legacy], force=True, as_root=True) + + def testFlagChanger_restoreFlags(self): + if not self.device.HasRoot(): + self.skipTest('Test needs a rooted device') + + # Write some custom chrome command line flags. + self.device.WriteFile( + self.cmdline_path, 'chrome --some --old --flags') + + # Write some more flags on a command line file in the legacy location. + self.device.WriteFile( + self.cmdline_path_legacy, 'some --stray --flags', as_root=True) + self.assertTrue(self.device.PathExists(self.cmdline_path_legacy)) + + changer = flag_changer.FlagChanger(self.device, _CMDLINE_FILE) + + # Legacy command line file is removed, ensuring Chrome picks up the + # right file. + self.assertFalse(self.device.PathExists(self.cmdline_path_legacy)) + + # Write some new files, and check they are set. + new_flags = ['--my', '--new', '--flags=with special value'] + self.assertItemsEqual( + changer.ReplaceFlags(new_flags), + new_flags) + + # Restore and go back to the old flags. + self.assertItemsEqual( + changer.Restore(), + ['--some', '--old', '--flags']) + + def testFlagChanger_removeFlags(self): + self.device.RemovePath(self.cmdline_path, force=True) + self.assertFalse(self.device.PathExists(self.cmdline_path)) + + with flag_changer.CustomCommandLineFlags( + self.device, _CMDLINE_FILE, ['--some', '--flags']): + self.assertTrue(self.device.PathExists(self.cmdline_path)) + + self.assertFalse(self.device.PathExists(self.cmdline_path)) + + +if __name__ == '__main__': + unittest.main() diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_test.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_test.py new file mode 100644 index 0000000..5342cf4 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/flag_changer_test.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import posixpath +import unittest + +from devil.android import flag_changer + + +_CMDLINE_FILE = 'chrome-command-line' + + +class _FakeDevice(object): + def __init__(self): + self.build_type = 'user' + self.has_root = True + self.file_system = {} + + def HasRoot(self): + return self.has_root + + def PathExists(self, filepath): + return filepath in self.file_system + + def RemovePath(self, path, **_kwargs): + self.file_system.pop(path) + + def WriteFile(self, path, contents, **_kwargs): + self.file_system[path] = contents + + def ReadFile(self, path, **_kwargs): + return self.file_system[path] + + +class FlagChangerTest(unittest.TestCase): + def setUp(self): + self.device = _FakeDevice() + # pylint: disable=protected-access + self.cmdline_path = posixpath.join(flag_changer._CMDLINE_DIR, _CMDLINE_FILE) + self.cmdline_path_legacy = posixpath.join( + flag_changer._CMDLINE_DIR_LEGACY, _CMDLINE_FILE) + + def testFlagChanger_removeLegacyCmdLine(self): + self.device.WriteFile(self.cmdline_path_legacy, 'chrome --old --stuff') + self.assertTrue(self.device.PathExists(self.cmdline_path_legacy)) + + changer = flag_changer.FlagChanger(self.device, 'chrome-command-line') + self.assertEquals( + changer._cmdline_path, # pylint: disable=protected-access + self.cmdline_path) + self.assertFalse(self.device.PathExists(self.cmdline_path_legacy)) + + def testFlagChanger_mustBeFileName(self): + with self.assertRaises(ValueError): + flag_changer.FlagChanger(self.device, '/data/local/chrome-command-line') + + +class ParseSerializeFlagsTest(unittest.TestCase): + def _testQuoteFlag(self, flag, expected_quoted_flag): + # Start with an unquoted flag, check that it's quoted as expected. + # pylint: disable=protected-access + quoted_flag = flag_changer._QuoteFlag(flag) + self.assertEqual(quoted_flag, expected_quoted_flag) + # Check that it survives a round-trip. + parsed_flags = flag_changer._ParseFlags('_ %s' % quoted_flag) + self.assertEqual(len(parsed_flags), 1) + self.assertEqual(flag, parsed_flags[0]) + + def testQuoteFlag_simple(self): + self._testQuoteFlag('--simple-flag', '--simple-flag') + + def testQuoteFlag_withSimpleValue(self): + self._testQuoteFlag('--key=value', '--key=value') + + def testQuoteFlag_withQuotedValue1(self): + self._testQuoteFlag('--key=valueA valueB', '--key="valueA valueB"') + + def testQuoteFlag_withQuotedValue2(self): + self._testQuoteFlag( + '--key=this "should" work', r'--key="this \"should\" work"') + + def testQuoteFlag_withQuotedValue3(self): + self._testQuoteFlag( + "--key=this is 'fine' too", '''--key="this is 'fine' too"''') + + def testQuoteFlag_withQuotedValue4(self): + self._testQuoteFlag( + "--key='I really want to keep these quotes'", + '''--key="'I really want to keep these quotes'"''') + + def testQuoteFlag_withQuotedValue5(self): + self._testQuoteFlag( + "--this is a strange=flag", '"--this is a strange=flag"') + + def testQuoteFlag_withEmptyValue(self): + self._testQuoteFlag('--some-flag=', '--some-flag=') + + def _testParseCmdLine(self, command_line, expected_flags): + # Start with a command line, check that flags are parsed as expected. + # pylint: disable=protected-access + flags = flag_changer._ParseFlags(command_line) + self.assertItemsEqual(flags, expected_flags) + + # Check that flags survive a round-trip. + # Note: Although new_command_line and command_line may not match, they + # should describe the same set of flags. + new_command_line = flag_changer._SerializeFlags(flags) + new_flags = flag_changer._ParseFlags(new_command_line) + self.assertItemsEqual(new_flags, expected_flags) + + def testParseCmdLine_simple(self): + self._testParseCmdLine( + 'chrome --foo --bar="a b" --baz=true --fine="ok"', + ['--foo', '--bar=a b', '--baz=true', '--fine=ok']) + + def testParseCmdLine_withFancyQuotes(self): + self._testParseCmdLine( + r'''_ --foo="this 'is' ok" + --bar='this \'is\' too' + --baz="this \'is\' tricky" + ''', + ["--foo=this 'is' ok", + "--bar=this 'is' too", + r"--baz=this \'is\' tricky"]) + + def testParseCmdLine_withUnterminatedQuote(self): + self._testParseCmdLine( + '_ --foo --bar="I forgot something', + ['--foo', '--bar=I forgot something']) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/forwarder.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/forwarder.py new file mode 100644 index 0000000..76c56ec --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/forwarder.py @@ -0,0 +1,467 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# pylint: disable=W0212 + +import fcntl +import logging +import os +import psutil + +from devil import base_error +from devil import devil_env +from devil.android import device_errors +from devil.android.constants import file_system +from devil.android.sdk import adb_wrapper +from devil.android.valgrind_tools import base_tool +from devil.utils import cmd_helper + +logger = logging.getLogger(__name__) + +# If passed as the device port, this will tell the forwarder to allocate +# a dynamic port on the device. The actual port can then be retrieved with +# Forwarder.DevicePortForHostPort. +DYNAMIC_DEVICE_PORT = 0 + + +def _GetProcessStartTime(pid): + return psutil.Process(pid).create_time + + +def _LogMapFailureDiagnostics(device): + # The host forwarder daemon logs to /tmp/host_forwarder_log, so print the end + # of that. + try: + with open('/tmp/host_forwarder_log') as host_forwarder_log: + logger.info('Last 50 lines of the host forwarder daemon log:') + for line in host_forwarder_log.read().splitlines()[-50:]: + logger.info(' %s', line) + except Exception: # pylint: disable=broad-except + # Grabbing the host forwarder log is best-effort. Ignore all errors. + logger.warning('Failed to get the contents of host_forwarder_log.') + + # The device forwarder daemon logs to the logcat, so print the end of that. + try: + logger.info('Last 50 lines of logcat:') + for logcat_line in device.adb.Logcat(dump=True)[-50:]: + logger.info(' %s', logcat_line) + except (device_errors.CommandFailedError, + device_errors.DeviceUnreachableError): + # Grabbing the device forwarder log is also best-effort. Ignore all errors. + logger.warning('Failed to get the contents of the logcat.') + + # Log alive device forwarders. + try: + ps_out = device.RunShellCommand(['ps'], check_return=True) + logger.info('Currently running device_forwarders:') + for line in ps_out: + if 'device_forwarder' in line: + logger.info(' %s', line) + except (device_errors.CommandFailedError, + device_errors.DeviceUnreachableError): + logger.warning('Failed to list currently running device_forwarder ' + 'instances.') + + +class _FileLock(object): + """With statement-aware implementation of a file lock. + + File locks are needed for cross-process synchronization when the + multiprocessing Python module is used. + """ + + def __init__(self, path): + self._fd = -1 + self._path = path + + def __enter__(self): + self._fd = os.open(self._path, os.O_RDONLY | os.O_CREAT) + if self._fd < 0: + raise Exception('Could not open file %s for reading' % self._path) + fcntl.flock(self._fd, fcntl.LOCK_EX) + + def __exit__(self, _exception_type, _exception_value, traceback): + fcntl.flock(self._fd, fcntl.LOCK_UN) + os.close(self._fd) + + +class HostForwarderError(base_error.BaseError): + """Exception for failures involving host_forwarder.""" + + def __init__(self, message): + super(HostForwarderError, self).__init__(message) + + +class Forwarder(object): + """Thread-safe class to manage port forwards from the device to the host.""" + + _DEVICE_FORWARDER_FOLDER = (file_system.TEST_EXECUTABLE_DIR + + '/forwarder/') + _DEVICE_FORWARDER_PATH = (file_system.TEST_EXECUTABLE_DIR + + '/forwarder/device_forwarder') + _LOCK_PATH = '/tmp/chrome.forwarder.lock' + # Defined in host_forwarder_main.cc + _HOST_FORWARDER_LOG = '/tmp/host_forwarder_log' + + _TIMEOUT = 60 # seconds + + _instance = None + + @staticmethod + def Map(port_pairs, device, tool=None): + """Runs the forwarder. + + Args: + port_pairs: A list of tuples (device_port, host_port) to forward. Note + that you can specify 0 as a device_port, in which case a + port will by dynamically assigned on the device. You can + get the number of the assigned port using the + DevicePortForHostPort method. + device: A DeviceUtils instance. + tool: Tool class to use to get wrapper, if necessary, for executing the + forwarder (see valgrind_tools.py). + + Raises: + Exception on failure to forward the port. + """ + if not tool: + tool = base_tool.BaseTool() + with _FileLock(Forwarder._LOCK_PATH): + instance = Forwarder._GetInstanceLocked(tool) + instance._InitDeviceLocked(device, tool) + + device_serial = str(device) + map_arg_lists = [ + ['--adb=' + adb_wrapper.AdbWrapper.GetAdbPath(), + '--serial-id=' + device_serial, + '--map', str(device_port), str(host_port)] + for device_port, host_port in port_pairs] + logger.info('Forwarding using commands: %s', map_arg_lists) + + for map_arg_list in map_arg_lists: + try: + map_cmd = [instance._host_forwarder_path] + map_arg_list + (exit_code, output) = cmd_helper.GetCmdStatusAndOutputWithTimeout( + map_cmd, Forwarder._TIMEOUT) + except cmd_helper.TimeoutError as e: + raise HostForwarderError( + '`%s` timed out:\n%s' % (' '.join(map_cmd), e.output)) + except OSError as e: + if e.errno == 2: + raise HostForwarderError( + 'Unable to start host forwarder. ' + 'Make sure you have built host_forwarder.') + else: raise + if exit_code != 0: + try: + instance._KillDeviceLocked(device, tool) + except (device_errors.CommandFailedError, + device_errors.DeviceUnreachableError): + # We don't want the failure to kill the device forwarder to + # supersede the original failure to map. + logging.warning( + 'Failed to kill the device forwarder after map failure: %s', + str(e)) + _LogMapFailureDiagnostics(device) + formatted_output = ('\n'.join(output) if isinstance(output, list) + else output) + raise HostForwarderError( + '`%s` exited with %d:\n%s' % ( + ' '.join(map_cmd), + exit_code, + formatted_output)) + tokens = output.split(':') + if len(tokens) != 2: + raise HostForwarderError( + 'Unexpected host forwarder output "%s", ' + 'expected "device_port:host_port"' % output) + device_port = int(tokens[0]) + host_port = int(tokens[1]) + serial_with_port = (device_serial, device_port) + instance._device_to_host_port_map[serial_with_port] = host_port + instance._host_to_device_port_map[host_port] = serial_with_port + logger.info('Forwarding device port: %d to host port: %d.', + device_port, host_port) + + @staticmethod + def UnmapDevicePort(device_port, device): + """Unmaps a previously forwarded device port. + + Args: + device: A DeviceUtils instance. + device_port: A previously forwarded port (through Map()). + """ + with _FileLock(Forwarder._LOCK_PATH): + Forwarder._UnmapDevicePortLocked(device_port, device) + + @staticmethod + def UnmapAllDevicePorts(device): + """Unmaps all the previously forwarded ports for the provided device. + + Args: + device: A DeviceUtils instance. + port_pairs: A list of tuples (device_port, host_port) to unmap. + """ + with _FileLock(Forwarder._LOCK_PATH): + instance = Forwarder._GetInstanceLocked(None) + unmap_all_cmd = [ + instance._host_forwarder_path, + '--adb=%s' % adb_wrapper.AdbWrapper.GetAdbPath(), + '--serial-id=%s' % device.serial, + '--unmap-all' + ] + try: + exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout( + unmap_all_cmd, Forwarder._TIMEOUT) + except cmd_helper.TimeoutError as e: + raise HostForwarderError( + '`%s` timed out:\n%s' % (' '.join(unmap_all_cmd), e.output)) + if exit_code != 0: + error_msg = [ + '`%s` exited with %d' % (' '.join(unmap_all_cmd), exit_code)] + if isinstance(output, list): + error_msg += output + else: + error_msg += [output] + raise HostForwarderError('\n'.join(error_msg)) + + # Clean out any entries from the device & host map. + device_map = instance._device_to_host_port_map + host_map = instance._host_to_device_port_map + for device_serial_and_port, host_port in device_map.items(): + device_serial = device_serial_and_port[0] + if device_serial == device.serial: + del device_map[device_serial_and_port] + del host_map[host_port] + + # Kill the device forwarder. + tool = base_tool.BaseTool() + instance._KillDeviceLocked(device, tool) + + @staticmethod + def DevicePortForHostPort(host_port): + """Returns the device port that corresponds to a given host port.""" + with _FileLock(Forwarder._LOCK_PATH): + serial_and_port = Forwarder._GetInstanceLocked( + None)._host_to_device_port_map.get(host_port) + return serial_and_port[1] if serial_and_port else None + + @staticmethod + def RemoveHostLog(): + if os.path.exists(Forwarder._HOST_FORWARDER_LOG): + os.unlink(Forwarder._HOST_FORWARDER_LOG) + + @staticmethod + def GetHostLog(): + if not os.path.exists(Forwarder._HOST_FORWARDER_LOG): + return '' + with file(Forwarder._HOST_FORWARDER_LOG, 'r') as f: + return f.read() + + @staticmethod + def _GetInstanceLocked(tool): + """Returns the singleton instance. + + Note that the global lock must be acquired before calling this method. + + Args: + tool: Tool class to use to get wrapper, if necessary, for executing the + forwarder (see valgrind_tools.py). + """ + if not Forwarder._instance: + Forwarder._instance = Forwarder(tool) + return Forwarder._instance + + def __init__(self, tool): + """Constructs a new instance of Forwarder. + + Note that Forwarder is a singleton therefore this constructor should be + called only once. + + Args: + tool: Tool class to use to get wrapper, if necessary, for executing the + forwarder (see valgrind_tools.py). + """ + assert not Forwarder._instance + self._tool = tool + self._initialized_devices = set() + self._device_to_host_port_map = dict() + self._host_to_device_port_map = dict() + self._host_forwarder_path = devil_env.config.FetchPath('forwarder_host') + assert os.path.exists(self._host_forwarder_path), 'Please build forwarder2' + self._InitHostLocked() + + @staticmethod + def _UnmapDevicePortLocked(device_port, device): + """Internal method used by UnmapDevicePort(). + + Note that the global lock must be acquired before calling this method. + """ + instance = Forwarder._GetInstanceLocked(None) + serial = str(device) + serial_with_port = (serial, device_port) + if not serial_with_port in instance._device_to_host_port_map: + logger.error('Trying to unmap non-forwarded port %d', device_port) + return + + host_port = instance._device_to_host_port_map[serial_with_port] + del instance._device_to_host_port_map[serial_with_port] + del instance._host_to_device_port_map[host_port] + + unmap_cmd = [ + instance._host_forwarder_path, + '--adb=%s' % adb_wrapper.AdbWrapper.GetAdbPath(), + '--serial-id=%s' % serial, + '--unmap', str(device_port) + ] + try: + (exit_code, output) = cmd_helper.GetCmdStatusAndOutputWithTimeout( + unmap_cmd, Forwarder._TIMEOUT) + except cmd_helper.TimeoutError as e: + raise HostForwarderError( + '`%s` timed out:\n%s' % (' '.join(unmap_cmd), e.output)) + if exit_code != 0: + logger.error( + '`%s` exited with %d:\n%s', + ' '.join(unmap_cmd), + exit_code, + '\n'.join(output) if isinstance(output, list) else output) + + @staticmethod + def _GetPidForLock(): + """Returns the PID used for host_forwarder initialization. + + The PID of the "sharder" is used to handle multiprocessing. The "sharder" + is the initial process that forks that is the parent process. + """ + return os.getpgrp() + + def _InitHostLocked(self): + """Initializes the host forwarder daemon. + + Note that the global lock must be acquired before calling this method. This + method kills any existing host_forwarder process that could be stale. + """ + # See if the host_forwarder daemon was already initialized by a concurrent + # process or thread (in case multi-process sharding is not used). + pid_for_lock = Forwarder._GetPidForLock() + fd = os.open(Forwarder._LOCK_PATH, os.O_RDWR | os.O_CREAT) + with os.fdopen(fd, 'r+') as pid_file: + pid_with_start_time = pid_file.readline() + if pid_with_start_time: + (pid, process_start_time) = pid_with_start_time.split(':') + if pid == str(pid_for_lock): + if process_start_time == str(_GetProcessStartTime(pid_for_lock)): + return + self._KillHostLocked() + pid_file.seek(0) + pid_file.write( + '%s:%s' % (pid_for_lock, str(_GetProcessStartTime(pid_for_lock)))) + pid_file.truncate() + + def _InitDeviceLocked(self, device, tool): + """Initializes the device_forwarder daemon for a specific device (once). + + Note that the global lock must be acquired before calling this method. This + method kills any existing device_forwarder daemon on the device that could + be stale, pushes the latest version of the daemon (to the device) and starts + it. + + Args: + device: A DeviceUtils instance. + tool: Tool class to use to get wrapper, if necessary, for executing the + forwarder (see valgrind_tools.py). + """ + device_serial = str(device) + if device_serial in self._initialized_devices: + return + try: + self._KillDeviceLocked(device, tool) + except device_errors.CommandFailedError: + logger.warning('Failed to kill device forwarder. Rebooting.') + device.Reboot() + forwarder_device_path_on_host = devil_env.config.FetchPath( + 'forwarder_device', device=device) + forwarder_device_path_on_device = ( + Forwarder._DEVICE_FORWARDER_FOLDER + if os.path.isdir(forwarder_device_path_on_host) + else Forwarder._DEVICE_FORWARDER_PATH) + device.PushChangedFiles([( + forwarder_device_path_on_host, + forwarder_device_path_on_device)]) + + cmd = [Forwarder._DEVICE_FORWARDER_PATH] + wrapper = tool.GetUtilWrapper() + if wrapper: + cmd.insert(0, wrapper) + device.RunShellCommand( + cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER}, + check_return=True) + self._initialized_devices.add(device_serial) + + @staticmethod + def KillHost(): + """Kills the forwarder process running on the host.""" + with _FileLock(Forwarder._LOCK_PATH): + Forwarder._GetInstanceLocked(None)._KillHostLocked() + + def _KillHostLocked(self): + """Kills the forwarder process running on the host. + + Note that the global lock must be acquired before calling this method. + """ + logger.info('Killing host_forwarder.') + try: + kill_cmd = [self._host_forwarder_path, '--kill-server'] + (exit_code, _o) = cmd_helper.GetCmdStatusAndOutputWithTimeout( + kill_cmd, Forwarder._TIMEOUT) + if exit_code != 0: + kill_cmd = ['pkill', '-9', 'host_forwarder'] + (exit_code, output) = cmd_helper.GetCmdStatusAndOutputWithTimeout( + kill_cmd, Forwarder._TIMEOUT) + if exit_code != 0: + raise HostForwarderError( + '%s exited with %d:\n%s' % ( + self._host_forwarder_path, + exit_code, + '\n'.join(output) if isinstance(output, list) else output)) + except cmd_helper.TimeoutError as e: + raise HostForwarderError( + '`%s` timed out:\n%s' % (' '.join(kill_cmd), e.output)) + + @staticmethod + def KillDevice(device, tool=None): + """Kills the forwarder process running on the device. + + Args: + device: Instance of DeviceUtils for talking to the device. + tool: Wrapper tool (e.g. valgrind) that can be used to execute the device + forwarder (see valgrind_tools.py). + """ + with _FileLock(Forwarder._LOCK_PATH): + Forwarder._GetInstanceLocked(None)._KillDeviceLocked( + device, tool or base_tool.BaseTool()) + + def _KillDeviceLocked(self, device, tool): + """Kills the forwarder process running on the device. + + Note that the global lock must be acquired before calling this method. + + Args: + device: Instance of DeviceUtils for talking to the device. + tool: Wrapper tool (e.g. valgrind) that can be used to execute the device + forwarder (see valgrind_tools.py). + """ + logger.info('Killing device_forwarder.') + self._initialized_devices.discard(device.serial) + if not device.FileExists(Forwarder._DEVICE_FORWARDER_PATH): + return + + cmd = [Forwarder._DEVICE_FORWARDER_PATH, '--kill-server'] + wrapper = tool.GetUtilWrapper() + if wrapper: + cmd.insert(0, wrapper) + device.RunShellCommand( + cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER}, + check_return=True) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/install_commands.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/install_commands.py new file mode 100644 index 0000000..c8da869 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/install_commands.py @@ -0,0 +1,57 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import posixpath + +from devil import devil_env +from devil.android import device_errors +from devil.android.constants import file_system + +BIN_DIR = '%s/bin' % file_system.TEST_EXECUTABLE_DIR +_FRAMEWORK_DIR = '%s/framework' % file_system.TEST_EXECUTABLE_DIR + +_COMMANDS = { + 'unzip': 'org.chromium.android.commands.unzip.Unzip', +} + +_SHELL_COMMAND_FORMAT = ( +"""#!/system/bin/sh +base=%s +export CLASSPATH=$base/framework/chromium_commands.jar +exec app_process $base/bin %s $@ +""") + + +def Installed(device): + paths = [posixpath.join(BIN_DIR, c) for c in _COMMANDS] + paths.append(posixpath.join(_FRAMEWORK_DIR, 'chromium_commands.jar')) + return device.PathExists(paths) + + +def InstallCommands(device): + if device.IsUserBuild(): + raise device_errors.CommandFailedError( + 'chromium_commands currently requires a userdebug build.', + device_serial=device.adb.GetDeviceSerial()) + + chromium_commands_jar_path = devil_env.config.FetchPath('chromium_commands') + if not os.path.exists(chromium_commands_jar_path): + raise device_errors.CommandFailedError( + '%s not found. Please build chromium_commands.' + % chromium_commands_jar_path) + + device.RunShellCommand( + ['mkdir', '-p', BIN_DIR, _FRAMEWORK_DIR], check_return=True) + for command, main_class in _COMMANDS.iteritems(): + shell_command = _SHELL_COMMAND_FORMAT % ( + file_system.TEST_EXECUTABLE_DIR, main_class) + shell_file = '%s/%s' % (BIN_DIR, command) + device.WriteFile(shell_file, shell_command) + device.RunShellCommand( + ['chmod', '755', shell_file], check_return=True) + + device.adb.Push( + chromium_commands_jar_path, + '%s/chromium_commands.jar' % _FRAMEWORK_DIR) diff --git a/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/logcat_monitor.py b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/logcat_monitor.py new file mode 100644 index 0000000..0aece87 --- /dev/null +++ b/love2dToAPK/tools/tools/adb/systrace/catapult/devil/devil/android/logcat_monitor.py @@ -0,0 +1,255 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# pylint: disable=unused-argument + +import errno +import logging +import os +import re +import shutil +import tempfile +import threading +import time + +from devil.android import decorators +from devil.android import device_errors +from devil.android.sdk import adb_wrapper +from devil.utils import reraiser_thread + +logger = logging.getLogger(__name__) + + +class LogcatMonitor(object): + + _RECORD_ITER_TIMEOUT = 2.0 + _RECORD_THREAD_JOIN_WAIT = 5.0 + _WAIT_TIME = 0.2 + _THREADTIME_RE_FORMAT = ( + r'(?P\S*) +(?P