mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Add micro_wake_word component (#6136)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -199,6 +199,7 @@ esphome/components/mcp9808/* @k7hpn | |||||||
| esphome/components/md5/* @esphome/core | esphome/components/md5/* @esphome/core | ||||||
| esphome/components/mdns/* @esphome/core | esphome/components/mdns/* @esphome/core | ||||||
| esphome/components/media_player/* @jesserockz | esphome/components/media_player/* @jesserockz | ||||||
|  | esphome/components/micro_wake_word/* @jesserockz @kahrendt | ||||||
| esphome/components/micronova/* @jorre05 | esphome/components/micronova/* @jorre05 | ||||||
| esphome/components/microphone/* @jesserockz | esphome/components/microphone/* @jesserockz | ||||||
| esphome/components/mics_4514/* @jesserockz | esphome/components/mics_4514/* @jesserockz | ||||||
|   | |||||||
							
								
								
									
										363
									
								
								esphome/components/micro_wake_word/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								esphome/components/micro_wake_word/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,363 @@ | |||||||
|  | import logging | ||||||
|  |  | ||||||
|  | import json | ||||||
|  | import hashlib | ||||||
|  | from urllib.parse import urljoin | ||||||
|  | from pathlib import Path | ||||||
|  | import requests | ||||||
|  |  | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | import esphome.codegen as cg | ||||||
|  |  | ||||||
|  | from esphome.core import CORE, HexInt, EsphomeError | ||||||
|  |  | ||||||
|  | from esphome.components import esp32, microphone | ||||||
|  | from esphome import automation, git, external_files | ||||||
|  | from esphome.automation import register_action, register_condition | ||||||
|  |  | ||||||
|  |  | ||||||
|  | from esphome.const import ( | ||||||
|  |     __version__, | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_MICROPHONE, | ||||||
|  |     CONF_MODEL, | ||||||
|  |     CONF_URL, | ||||||
|  |     CONF_FILE, | ||||||
|  |     CONF_PATH, | ||||||
|  |     CONF_REF, | ||||||
|  |     CONF_REFRESH, | ||||||
|  |     CONF_TYPE, | ||||||
|  |     CONF_USERNAME, | ||||||
|  |     CONF_PASSWORD, | ||||||
|  |     CONF_RAW_DATA_ID, | ||||||
|  |     TYPE_GIT, | ||||||
|  |     TYPE_LOCAL, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@kahrendt", "@jesserockz"] | ||||||
|  | DEPENDENCIES = ["microphone"] | ||||||
|  | DOMAIN = "micro_wake_word" | ||||||
|  |  | ||||||
|  | CONF_PROBABILITY_CUTOFF = "probability_cutoff" | ||||||
|  | CONF_SLIDING_WINDOW_AVERAGE_SIZE = "sliding_window_average_size" | ||||||
|  | CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected" | ||||||
|  |  | ||||||
|  | TYPE_HTTP = "http" | ||||||
|  |  | ||||||
|  | micro_wake_word_ns = cg.esphome_ns.namespace("micro_wake_word") | ||||||
|  |  | ||||||
|  | MicroWakeWord = micro_wake_word_ns.class_("MicroWakeWord", cg.Component) | ||||||
|  |  | ||||||
|  | StartAction = micro_wake_word_ns.class_("StartAction", automation.Action) | ||||||
|  | StopAction = micro_wake_word_ns.class_("StopAction", automation.Action) | ||||||
|  |  | ||||||
|  | IsRunningCondition = micro_wake_word_ns.class_( | ||||||
|  |     "IsRunningCondition", automation.Condition | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _validate_json_filename(value): | ||||||
|  |     value = cv.string(value) | ||||||
|  |     if not value.endswith(".json"): | ||||||
|  |         raise cv.Invalid("Manifest filename must end with .json") | ||||||
|  |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _process_git_source(config): | ||||||
|  |     repo_dir, _ = git.clone_or_update( | ||||||
|  |         url=config[CONF_URL], | ||||||
|  |         ref=config.get(CONF_REF), | ||||||
|  |         refresh=config[CONF_REFRESH], | ||||||
|  |         domain=DOMAIN, | ||||||
|  |         username=config.get(CONF_USERNAME), | ||||||
|  |         password=config.get(CONF_PASSWORD), | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     if not (repo_dir / config[CONF_FILE]).exists(): | ||||||
|  |         raise cv.Invalid("File does not exist in repository") | ||||||
|  |  | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CV_GIT_SCHEMA = cv.GIT_SCHEMA | ||||||
|  | if isinstance(CV_GIT_SCHEMA, dict): | ||||||
|  |     CV_GIT_SCHEMA = cv.Schema(CV_GIT_SCHEMA) | ||||||
|  |  | ||||||
|  | GIT_SCHEMA = cv.All( | ||||||
|  |     CV_GIT_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.Required(CONF_FILE): _validate_json_filename, | ||||||
|  |             cv.Optional(CONF_REFRESH, default="1d"): cv.All( | ||||||
|  |                 cv.string, cv.source_refresh | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     ), | ||||||
|  |     _process_git_source, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | KEY_WAKE_WORD = "wake_word" | ||||||
|  | KEY_AUTHOR = "author" | ||||||
|  | KEY_WEBSITE = "website" | ||||||
|  | KEY_VERSION = "version" | ||||||
|  | KEY_MICRO = "micro" | ||||||
|  |  | ||||||
|  | MANIFEST_SCHEMA_V1 = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_TYPE): "micro", | ||||||
|  |         cv.Required(KEY_WAKE_WORD): cv.string, | ||||||
|  |         cv.Required(KEY_AUTHOR): cv.string, | ||||||
|  |         cv.Required(KEY_WEBSITE): cv.url, | ||||||
|  |         cv.Required(KEY_VERSION): cv.All(cv.int_, 1), | ||||||
|  |         cv.Required(CONF_MODEL): cv.string, | ||||||
|  |         cv.Required(KEY_MICRO): cv.Schema( | ||||||
|  |             { | ||||||
|  |                 cv.Required(CONF_PROBABILITY_CUTOFF): cv.float_, | ||||||
|  |                 cv.Required(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.positive_int, | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _compute_local_file_path(config: dict) -> Path: | ||||||
|  |     url = config[CONF_URL] | ||||||
|  |     h = hashlib.new("sha256") | ||||||
|  |     h.update(url.encode()) | ||||||
|  |     key = h.hexdigest()[:8] | ||||||
|  |     base_dir = external_files.compute_local_file_dir(DOMAIN) | ||||||
|  |     return base_dir / key | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _download_file(url: str, path: Path) -> bytes: | ||||||
|  |     if not external_files.has_remote_file_changed(url, path): | ||||||
|  |         _LOGGER.debug("Remote file has not changed, skipping download") | ||||||
|  |         return path.read_bytes() | ||||||
|  |  | ||||||
|  |     try: | ||||||
|  |         req = requests.get( | ||||||
|  |             url, | ||||||
|  |             timeout=external_files.NETWORK_TIMEOUT, | ||||||
|  |             headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"}, | ||||||
|  |         ) | ||||||
|  |         req.raise_for_status() | ||||||
|  |     except requests.exceptions.RequestException as e: | ||||||
|  |         raise cv.Invalid(f"Could not download file from {url}: {e}") from e | ||||||
|  |  | ||||||
|  |     path.parent.mkdir(parents=True, exist_ok=True) | ||||||
|  |     path.write_bytes(req.content) | ||||||
|  |     return req.content | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _process_http_source(config): | ||||||
|  |     url = config[CONF_URL] | ||||||
|  |     path = _compute_local_file_path(config) | ||||||
|  |  | ||||||
|  |     json_path = path / "manifest.json" | ||||||
|  |  | ||||||
|  |     json_contents = _download_file(url, json_path) | ||||||
|  |  | ||||||
|  |     manifest_data = json.loads(json_contents) | ||||||
|  |     if not isinstance(manifest_data, dict): | ||||||
|  |         raise cv.Invalid("Manifest file must contain a JSON object") | ||||||
|  |  | ||||||
|  |     try: | ||||||
|  |         MANIFEST_SCHEMA_V1(manifest_data) | ||||||
|  |     except cv.Invalid as e: | ||||||
|  |         raise cv.Invalid(f"Invalid manifest file: {e}") from e | ||||||
|  |  | ||||||
|  |     model = manifest_data[CONF_MODEL] | ||||||
|  |     model_url = urljoin(url, model) | ||||||
|  |  | ||||||
|  |     model_path = path / model | ||||||
|  |  | ||||||
|  |     _download_file(str(model_url), model_path) | ||||||
|  |  | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
|  | HTTP_SCHEMA = cv.All( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_URL): cv.url, | ||||||
|  |     }, | ||||||
|  |     _process_http_source, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | LOCAL_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_PATH): cv.All(_validate_json_filename, cv.file_), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _validate_source_model_name(value): | ||||||
|  |     if not isinstance(value, str): | ||||||
|  |         raise cv.Invalid("Model name must be a string") | ||||||
|  |  | ||||||
|  |     if value.endswith(".json"): | ||||||
|  |         raise cv.Invalid("Model name must not end with .json") | ||||||
|  |  | ||||||
|  |     return MODEL_SOURCE_SCHEMA( | ||||||
|  |         { | ||||||
|  |             CONF_TYPE: TYPE_HTTP, | ||||||
|  |             CONF_URL: f"https://github.com/esphome/micro-wake-word-models/raw/main/models/{value}.json", | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _validate_source_shorthand(value): | ||||||
|  |     if not isinstance(value, str): | ||||||
|  |         raise cv.Invalid("Shorthand only for strings") | ||||||
|  |  | ||||||
|  |     try:  # Test for model name | ||||||
|  |         return _validate_source_model_name(value) | ||||||
|  |     except cv.Invalid: | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     try:  # Test for local path | ||||||
|  |         return MODEL_SOURCE_SCHEMA({CONF_TYPE: TYPE_LOCAL, CONF_PATH: value}) | ||||||
|  |     except cv.Invalid: | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     try:  # Test for http url | ||||||
|  |         return MODEL_SOURCE_SCHEMA({CONF_TYPE: TYPE_HTTP, CONF_URL: value}) | ||||||
|  |     except cv.Invalid: | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     git_file = git.GitFile.from_shorthand(value) | ||||||
|  |  | ||||||
|  |     conf = { | ||||||
|  |         CONF_TYPE: TYPE_GIT, | ||||||
|  |         CONF_URL: git_file.git_url, | ||||||
|  |         CONF_FILE: git_file.filename, | ||||||
|  |     } | ||||||
|  |     if git_file.ref: | ||||||
|  |         conf[CONF_REF] = git_file.ref | ||||||
|  |  | ||||||
|  |     try: | ||||||
|  |         return MODEL_SOURCE_SCHEMA(conf) | ||||||
|  |     except cv.Invalid as e: | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             f"Could not find file '{git_file.filename}' in the repository. Please make sure it exists." | ||||||
|  |         ) from e | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MODEL_SOURCE_SCHEMA = cv.Any( | ||||||
|  |     _validate_source_shorthand, | ||||||
|  |     cv.typed_schema( | ||||||
|  |         { | ||||||
|  |             TYPE_GIT: GIT_SCHEMA, | ||||||
|  |             TYPE_LOCAL: LOCAL_SCHEMA, | ||||||
|  |             TYPE_HTTP: HTTP_SCHEMA, | ||||||
|  |         } | ||||||
|  |     ), | ||||||
|  |     msg="Not a valid model name, local path, http(s) url, or github shorthand", | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(MicroWakeWord), | ||||||
|  |             cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone), | ||||||
|  |             cv.Optional(CONF_PROBABILITY_CUTOFF): cv.float_, | ||||||
|  |             cv.Optional(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.positive_int, | ||||||
|  |             cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation( | ||||||
|  |                 single=True | ||||||
|  |             ), | ||||||
|  |             cv.Required(CONF_MODEL): MODEL_SOURCE_SCHEMA, | ||||||
|  |             cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), | ||||||
|  |         } | ||||||
|  |     ).extend(cv.COMPONENT_SCHEMA), | ||||||
|  |     cv.only_with_esp_idf, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _load_model_data(manifest_path: Path): | ||||||
|  |     with open(manifest_path, encoding="utf-8") as f: | ||||||
|  |         manifest = json.load(f) | ||||||
|  |  | ||||||
|  |     try: | ||||||
|  |         MANIFEST_SCHEMA_V1(manifest) | ||||||
|  |     except cv.Invalid as e: | ||||||
|  |         raise EsphomeError(f"Invalid manifest file: {e}") from e | ||||||
|  |  | ||||||
|  |     model_path = urljoin(str(manifest_path), manifest[CONF_MODEL]) | ||||||
|  |  | ||||||
|  |     with open(model_path, "rb") as f: | ||||||
|  |         model = f.read() | ||||||
|  |  | ||||||
|  |     return manifest, model | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |  | ||||||
|  |     mic = await cg.get_variable(config[CONF_MICROPHONE]) | ||||||
|  |     cg.add(var.set_microphone(mic)) | ||||||
|  |  | ||||||
|  |     if on_wake_word_detection_config := config.get(CONF_ON_WAKE_WORD_DETECTED): | ||||||
|  |         await automation.build_automation( | ||||||
|  |             var.get_wake_word_detected_trigger(), | ||||||
|  |             [(cg.std_string, "wake_word")], | ||||||
|  |             on_wake_word_detection_config, | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     esp32.add_idf_component( | ||||||
|  |         name="esp-tflite-micro", | ||||||
|  |         repo="https://github.com/espressif/esp-tflite-micro", | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     cg.add_build_flag("-DTF_LITE_STATIC_MEMORY") | ||||||
|  |     cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON") | ||||||
|  |     cg.add_build_flag("-DESP_NN") | ||||||
|  |  | ||||||
|  |     model_config = config.get(CONF_MODEL) | ||||||
|  |     data = [] | ||||||
|  |     if model_config[CONF_TYPE] == TYPE_GIT: | ||||||
|  |         # compute path to model file | ||||||
|  |         key = f"{model_config[CONF_URL]}@{model_config.get(CONF_REF)}" | ||||||
|  |         base_dir = Path(CORE.data_dir) / DOMAIN | ||||||
|  |         h = hashlib.new("sha256") | ||||||
|  |         h.update(key.encode()) | ||||||
|  |         file: Path = base_dir / h.hexdigest()[:8] / model_config[CONF_FILE] | ||||||
|  |  | ||||||
|  |     elif model_config[CONF_TYPE] == TYPE_LOCAL: | ||||||
|  |         file = model_config[CONF_PATH] | ||||||
|  |  | ||||||
|  |     elif model_config[CONF_TYPE] == TYPE_HTTP: | ||||||
|  |         file = _compute_local_file_path(model_config) / "manifest.json" | ||||||
|  |  | ||||||
|  |     manifest, data = _load_model_data(file) | ||||||
|  |  | ||||||
|  |     rhs = [HexInt(x) for x in data] | ||||||
|  |     prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) | ||||||
|  |     cg.add(var.set_model_start(prog_arr)) | ||||||
|  |  | ||||||
|  |     probability_cutoff = config.get( | ||||||
|  |         CONF_PROBABILITY_CUTOFF, manifest[KEY_MICRO][CONF_PROBABILITY_CUTOFF] | ||||||
|  |     ) | ||||||
|  |     cg.add(var.set_probability_cutoff(probability_cutoff)) | ||||||
|  |     sliding_window_average_size = config.get( | ||||||
|  |         CONF_SLIDING_WINDOW_AVERAGE_SIZE, | ||||||
|  |         manifest[KEY_MICRO][CONF_SLIDING_WINDOW_AVERAGE_SIZE], | ||||||
|  |     ) | ||||||
|  |     cg.add(var.set_sliding_window_average_size(sliding_window_average_size)) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_wake_word(manifest[KEY_WAKE_WORD])) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MICRO_WAKE_WORD_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(MicroWakeWord)}) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @register_action("micro_wake_word.start", StartAction, MICRO_WAKE_WORD_ACTION_SCHEMA) | ||||||
|  | @register_action("micro_wake_word.stop", StopAction, MICRO_WAKE_WORD_ACTION_SCHEMA) | ||||||
|  | @register_condition( | ||||||
|  |     "micro_wake_word.is_running", IsRunningCondition, MICRO_WAKE_WORD_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | async def micro_wake_word_action_to_code(config, action_id, template_arg, args): | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg) | ||||||
|  |     await cg.register_parented(var, config[CONF_ID]) | ||||||
|  |     return var | ||||||
| @@ -0,0 +1,493 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP_IDF | ||||||
|  |  | ||||||
|  | // Converted audio_preprocessor_int8.tflite | ||||||
|  | // From https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/examples/micro_speech/models accessed | ||||||
|  | // January 2024 | ||||||
|  | // | ||||||
|  | // Copyright 2023 The TensorFlow Authors. All Rights Reserved. | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micro_wake_word { | ||||||
|  |  | ||||||
|  | const unsigned char G_AUDIO_PREPROCESSOR_INT8_TFLITE[] = { | ||||||
|  |     0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, | ||||||
|  |     0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x88, 0x00, | ||||||
|  |     0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0xcc, 0x1f, 0x00, 0x00, 0x03, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe2, 0xeb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, | ||||||
|  |     0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, | ||||||
|  |     0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x94, 0xff, | ||||||
|  |     0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75, | ||||||
|  |     0x74, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc2, 0xf5, 0xff, 0xff, | ||||||
|  |     0x04, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, | ||||||
|  |     0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xdc, 0xff, 0xff, 0xff, 0x2d, 0x00, | ||||||
|  |     0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, | ||||||
|  |     0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, | ||||||
|  |     0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, | ||||||
|  |     0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x2e, 0x00, | ||||||
|  |     0x00, 0x00, 0x9c, 0x0d, 0x00, 0x00, 0x94, 0x0d, 0x00, 0x00, 0xc4, 0x09, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00, 0x48, | ||||||
|  |     0x09, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x00, 0xf8, 0x08, 0x00, 0x00, | ||||||
|  |     0xec, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x24, 0x07, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x38, 0x04, 0x00, | ||||||
|  |     0x00, 0xb0, 0x01, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x60, 0x01, | ||||||
|  |     0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x2c, | ||||||
|  |     0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, | ||||||
|  |     0x04, 0x01, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, | ||||||
|  |     0x00, 0xdc, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xbc, 0x00, | ||||||
|  |     0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x94, | ||||||
|  |     0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff, | ||||||
|  |     0x04, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, | ||||||
|  |     0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, | ||||||
|  |     0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||||||
|  |     0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x31, 0x32, 0x2e, 0x30, 0x00, | ||||||
|  |     0x00, 0x56, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x38, 0x2e, 0x30, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xe1, 0xff, 0xff, 0xd8, 0xe1, 0xff, 0xff, 0xdc, | ||||||
|  |     0xe1, 0xff, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe4, 0xe1, 0xff, 0xff, 0xe8, 0xe1, 0xff, 0xff, 0xec, 0xe1, 0xff, 0xff, | ||||||
|  |     0xf0, 0xe1, 0xff, 0xff, 0xf4, 0xe1, 0xff, 0xff, 0xf8, 0xe1, 0xff, 0xff, 0xfc, 0xe1, 0xff, 0xff, 0x00, 0xe2, 0xff, | ||||||
|  |     0xff, 0x04, 0xe2, 0xff, 0xff, 0x08, 0xe2, 0xff, 0xff, 0x0c, 0xe2, 0xff, 0xff, 0x10, 0xe2, 0xff, 0xff, 0x14, 0xe2, | ||||||
|  |     0xff, 0xff, 0x18, 0xe2, 0xff, 0xff, 0x1c, 0xe2, 0xff, 0xff, 0x20, 0xe2, 0xff, 0xff, 0x24, 0xe2, 0xff, 0xff, 0x28, | ||||||
|  |     0xe2, 0xff, 0xff, 0x2c, 0xe2, 0xff, 0xff, 0x30, 0xe2, 0xff, 0xff, 0xd2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, | ||||||
|  |     0x04, 0x00, 0x00, 0x00, 0x9a, 0x02, 0x00, 0x00, 0xe2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x01, 0x00, 0x00, 0xf2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0xff, | ||||||
|  |     0xff, 0xff, 0x02, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, | ||||||
|  |     0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x22, 0xf8, 0xff, 0xff, | ||||||
|  |     0x04, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x61, 0x05, 0x00, 0x00, 0x00, 0x00, 0x23, 0x0b, 0x41, | ||||||
|  |     0x01, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0e, 0x80, 0x05, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0xd1, 0x0c, 0x63, 0x04, 0x00, 0x00, 0x00, 0x00, 0x34, 0x0c, 0x3f, 0x04, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x81, 0x0c, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0d, 0x77, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x0f, | ||||||
|  |     0xa9, 0x08, 0x01, 0x02, 0x7f, 0x0b, 0x22, 0x05, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0e, 0xd1, 0x08, 0xdb, 0x02, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x03, 0x0d, 0x4a, 0x07, 0xad, 0x01, 0x2c, 0x0c, 0xc6, 0x06, 0x79, 0x01, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x45, 0x0c, 0x29, 0x07, 0x23, 0x02, 0x34, 0x0d, 0x5b, 0x08, 0x96, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x0e, 0x48, | ||||||
|  |     0x0a, 0xbd, 0x05, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x0c, 0x88, 0x08, 0x43, 0x04, | ||||||
|  |     0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0b, 0xd3, 0x07, 0xcb, 0x03, 0xd2, 0x0f, 0xe7, | ||||||
|  |     0x0b, 0x09, 0x08, 0x39, 0x04, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x0c, 0x14, 0x09, | ||||||
|  |     0x75, 0x05, 0xe2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x0e, 0xdd, 0x0a, 0x6b, 0x07, 0x03, | ||||||
|  |     0x04, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0d, 0x09, 0x0a, 0xc9, 0x06, 0x93, 0x03, 0x65, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0d, 0x25, 0x0a, 0x12, 0x07, 0x07, 0x04, 0x05, 0x01, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x0a, 0x0e, 0x17, 0x0b, 0x2c, 0x08, 0x49, 0x05, 0x6d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x98, 0x0f, 0xcb, 0x0c, 0x04, 0x0a, 0x44, 0x07, 0x8b, 0x04, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x0f, 0x87, | ||||||
|  |     0x0c, 0xe7, 0x09, 0x4e, 0x07, 0xba, 0x04, 0x2d, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x0f, 0x23, 0x0d, 0xa7, 0x0a, | ||||||
|  |     0x30, 0x08, 0xbe, 0x05, 0x52, 0x03, 0xeb, 0x00, 0x89, 0x0e, 0x2c, 0x0c, 0xd4, 0x09, 0x81, 0x07, 0x33, 0x05, 0xe9, | ||||||
|  |     0x02, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0e, 0x29, 0x0c, 0xf1, 0x09, 0xbe, 0x07, 0x90, 0x05, 0x65, 0x03, | ||||||
|  |     0x3f, 0x01, 0x1d, 0x0f, 0xff, 0x0c, 0xe5, 0x0a, 0xcf, 0x08, 0xbc, 0x06, 0xae, 0x04, 0xa3, 0x02, 0x9c, 0x00, 0x99, | ||||||
|  |     0x0e, 0x99, 0x0c, 0x9d, 0x0a, 0xa4, 0x08, 0xaf, 0x06, 0xbd, 0x04, 0xcf, 0x02, 0xe4, 0x00, 0xfc, 0x0e, 0x17, 0x0d, | ||||||
|  |     0x36, 0x0b, 0x57, 0x09, 0x7c, 0x07, 0xa4, 0x05, 0xcf, 0x03, 0xfd, 0x01, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x62, 0x0e, 0x98, 0x0c, 0xd2, 0x0a, 0x0e, 0x09, 0x4d, 0x07, 0x8f, 0x05, 0xd4, 0x03, 0x1b, 0x02, | ||||||
|  |     0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x0e, 0x00, 0x0d, 0x52, 0x0b, 0xa6, 0x09, 0xfd, 0x07, 0x56, 0x06, 0xb1, | ||||||
|  |     0x04, 0x0f, 0x03, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x0f, 0x37, 0x0e, 0x9e, 0x0c, | ||||||
|  |     0x08, 0x0b, 0x73, 0x09, 0xe1, 0x07, 0x52, 0x06, 0xc4, 0x04, 0x38, 0x03, 0xaf, 0x01, 0x28, 0x00, 0xa3, 0x0e, 0x1f, | ||||||
|  |     0x0d, 0x9e, 0x0b, 0x1f, 0x0a, 0xa2, 0x08, 0x27, 0x07, 0xae, 0x05, 0x37, 0x04, 0xc2, 0x02, 0x4e, 0x01, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0xdd, 0x0f, 0x6d, 0x0e, 0xff, 0x0c, 0x93, 0x0b, 0x29, 0x0a, 0xc1, 0x08, 0x5a, 0x07, 0xf5, 0x05, 0x92, | ||||||
|  |     0x04, 0x30, 0x03, 0xd1, 0x01, 0x73, 0x00, 0x16, 0x0f, 0xbc, 0x0d, 0x62, 0x0c, 0x0b, 0x0b, 0xb5, 0x09, 0x61, 0x08, | ||||||
|  |     0x0e, 0x07, 0xbd, 0x05, 0x6d, 0x04, 0x1f, 0x03, 0xd3, 0x01, 0x88, 0x00, 0x3e, 0x0f, 0xf6, 0x0d, 0xaf, 0x0c, 0x6a, | ||||||
|  |     0x0b, 0x27, 0x0a, 0xe4, 0x08, 0xa3, 0x07, 0x64, 0x06, 0x26, 0x05, 0xe9, 0x03, 0xae, 0x02, 0x74, 0x01, 0x3b, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0f, 0xce, 0x0d, 0x99, 0x0c, 0x66, 0x0b, 0x34, 0x0a, 0x03, | ||||||
|  |     0x09, 0xd3, 0x07, 0xa5, 0x06, 0x78, 0x05, 0x4c, 0x04, 0x22, 0x03, 0xf8, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0xa9, 0x0f, 0x83, 0x0e, 0x5f, 0x0d, 0x3b, 0x0c, 0x19, 0x0b, 0xf8, 0x09, 0xd8, 0x08, 0xb9, 0x07, 0x9b, 0x06, 0x7e, | ||||||
|  |     0x05, 0x63, 0x04, 0x48, 0x03, 0x2f, 0x02, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xfa, 0xff, 0xff, 0x04, 0x00, | ||||||
|  |     0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x04, 0xbe, 0x0e, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x7f, 0x0a, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x2e, 0x03, 0x9c, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x03, 0xc0, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x7e, | ||||||
|  |     0x03, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x88, 0x09, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x56, 0x07, | ||||||
|  |     0xfe, 0x0d, 0x80, 0x04, 0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x16, 0x01, 0x2e, 0x07, 0x24, 0x0d, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0xfc, 0x02, 0xb5, 0x08, 0x52, 0x0e, 0xd3, 0x03, 0x39, 0x09, 0x86, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xba, 0x03, | ||||||
|  |     0xd6, 0x08, 0xdc, 0x0d, 0xcb, 0x02, 0xa4, 0x07, 0x69, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x01, 0xb7, 0x05, 0x42, | ||||||
|  |     0x0a, 0xba, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x03, 0x77, 0x07, 0xbc, 0x0b, 0xf1, 0x0f, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x04, 0x2c, 0x08, 0x34, 0x0c, 0x2d, 0x00, 0x18, 0x04, 0xf6, | ||||||
|  |     0x07, 0xc6, 0x0b, 0x89, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0xeb, 0x06, 0x8a, 0x0a, | ||||||
|  |     0x1d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x01, 0x22, 0x05, 0x94, 0x08, 0xfc, 0x0b, 0x59, | ||||||
|  |     0x0f, 0x00, 0x00, 0x00, 0x00, 0xac, 0x02, 0xf6, 0x05, 0x36, 0x09, 0x6c, 0x0c, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0xbe, 0x02, 0xda, 0x05, 0xed, 0x08, 0xf8, 0x0b, 0xfa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xf5, | ||||||
|  |     0x01, 0xe8, 0x04, 0xd3, 0x07, 0xb6, 0x0a, 0x92, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, | ||||||
|  |     0x34, 0x03, 0xfb, 0x05, 0xbb, 0x08, 0x74, 0x0b, 0x27, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x78, 0x03, 0x18, | ||||||
|  |     0x06, 0xb1, 0x08, 0x45, 0x0b, 0xd2, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0xdc, 0x02, 0x58, 0x05, 0xcf, 0x07, | ||||||
|  |     0x41, 0x0a, 0xad, 0x0c, 0x14, 0x0f, 0x76, 0x01, 0xd3, 0x03, 0x2b, 0x06, 0x7e, 0x08, 0xcc, 0x0a, 0x16, 0x0d, 0x5a, | ||||||
|  |     0x0f, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x01, 0xd6, 0x03, 0x0e, 0x06, 0x41, 0x08, 0x6f, 0x0a, 0x9a, 0x0c, 0xc0, 0x0e, | ||||||
|  |     0xe2, 0x00, 0x00, 0x03, 0x1a, 0x05, 0x30, 0x07, 0x43, 0x09, 0x51, 0x0b, 0x5c, 0x0d, 0x63, 0x0f, 0x66, 0x01, 0x66, | ||||||
|  |     0x03, 0x62, 0x05, 0x5b, 0x07, 0x50, 0x09, 0x42, 0x0b, 0x30, 0x0d, 0x1b, 0x0f, 0x03, 0x01, 0xe8, 0x02, 0xc9, 0x04, | ||||||
|  |     0xa8, 0x06, 0x83, 0x08, 0x5b, 0x0a, 0x30, 0x0c, 0x02, 0x0e, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x9d, 0x01, 0x67, 0x03, 0x2d, 0x05, 0xf1, 0x06, 0xb2, 0x08, 0x70, 0x0a, 0x2b, 0x0c, 0xe4, 0x0d, 0x9a, 0x0f, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0xff, 0x02, 0xad, 0x04, 0x59, 0x06, 0x02, 0x08, 0xa9, 0x09, 0x4e, 0x0b, 0xf0, | ||||||
|  |     0x0c, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0xc8, 0x01, 0x61, 0x03, 0xf7, 0x04, | ||||||
|  |     0x8c, 0x06, 0x1e, 0x08, 0xad, 0x09, 0x3b, 0x0b, 0xc7, 0x0c, 0x50, 0x0e, 0xd7, 0x0f, 0x5c, 0x01, 0xe0, 0x02, 0x61, | ||||||
|  |     0x04, 0xe0, 0x05, 0x5d, 0x07, 0xd8, 0x08, 0x51, 0x0a, 0xc8, 0x0b, 0x3d, 0x0d, 0xb1, 0x0e, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x22, 0x00, 0x92, 0x01, 0x00, 0x03, 0x6c, 0x04, 0xd6, 0x05, 0x3e, 0x07, 0xa5, 0x08, 0x0a, 0x0a, 0x6d, 0x0b, 0xcf, | ||||||
|  |     0x0c, 0x2e, 0x0e, 0x8c, 0x0f, 0xe9, 0x00, 0x43, 0x02, 0x9d, 0x03, 0xf4, 0x04, 0x4a, 0x06, 0x9e, 0x07, 0xf1, 0x08, | ||||||
|  |     0x42, 0x0a, 0x92, 0x0b, 0xe0, 0x0c, 0x2c, 0x0e, 0x77, 0x0f, 0xc1, 0x00, 0x09, 0x02, 0x50, 0x03, 0x95, 0x04, 0xd8, | ||||||
|  |     0x05, 0x1b, 0x07, 0x5c, 0x08, 0x9b, 0x09, 0xd9, 0x0a, 0x16, 0x0c, 0x51, 0x0d, 0x8b, 0x0e, 0xc4, 0x0f, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x31, 0x02, 0x66, 0x03, 0x99, 0x04, 0xcb, 0x05, 0xfc, 0x06, 0x2c, | ||||||
|  |     0x08, 0x5a, 0x09, 0x87, 0x0a, 0xb3, 0x0b, 0xdd, 0x0c, 0x07, 0x0e, 0x2f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, | ||||||
|  |     0x7c, 0x01, 0xa0, 0x02, 0xc4, 0x03, 0xe6, 0x04, 0x07, 0x06, 0x27, 0x07, 0x46, 0x08, 0x64, 0x09, 0x81, 0x0a, 0x9c, | ||||||
|  |     0x0b, 0xb7, 0x0c, 0xd0, 0x0d, 0xe8, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x2a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, | ||||||
|  |     0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, | ||||||
|  |     0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x20, 0x00, 0x24, 0x00, 0x26, 0x00, 0x2a, 0x00, | ||||||
|  |     0x2e, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x5a, | ||||||
|  |     0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9a, 0x00, 0xa6, 0x00, | ||||||
|  |     0xb0, 0x00, 0xbc, 0x00, 0xc8, 0x00, 0xd4, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x8a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, | ||||||
|  |     0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, | ||||||
|  |     0x1c, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x30, 0x00, 0x34, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x44, | ||||||
|  |     0x00, 0x4c, 0x00, 0x50, 0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, | ||||||
|  |     0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xc4, 0x00, 0xd0, 0x00, 0xdc, 0x00, 0xe8, | ||||||
|  |     0x00, 0xf4, 0x00, 0x00, 0x01, 0x0c, 0x01, 0x1c, 0x01, 0x2c, 0x01, 0x00, 0x00, 0xea, 0xfd, 0xff, 0xff, 0x04, 0x00, | ||||||
|  |     0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, | ||||||
|  |     0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, | ||||||
|  |     0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, | ||||||
|  |     0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, | ||||||
|  |     0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4a, 0xfe, 0xff, 0xff, 0x04, | ||||||
|  |     0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x7c, 0x7f, 0x79, 0x7f, 0x76, 0x7f, 0xfa, 0xff, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x70, 0x7f, 0xf4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0xe9, 0xff, 0xfe, 0xff, 0x00, 0x00, 0x4b, 0x7f, 0xd0, | ||||||
|  |     0xff, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x7f, 0xa0, 0xff, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x7e, 0x42, 0xff, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0xfd, 0x7d, 0x86, 0xfe, 0x04, 0x00, 0x00, 0x00, 0x87, 0x7c, 0x1d, 0xfd, 0x12, 0x00, 0x00, 0x00, 0xb6, | ||||||
|  |     0x79, 0x7f, 0xfa, 0x3e, 0x00, 0x00, 0x00, 0x73, 0x74, 0xf9, 0xf5, 0xca, 0x00, 0x00, 0x00, 0x36, 0x6b, 0x33, 0xef, | ||||||
|  |     0x32, 0x02, 0x00, 0x00, 0x9b, 0x5c, 0x87, 0xe7, 0xce, 0x04, 0x00, 0x00, 0xf0, 0x48, 0xde, 0xe2, 0xa0, 0x07, 0x00, | ||||||
|  |     0x00, 0x6e, 0x33, 0x8a, 0xe4, 0xa4, 0x08, 0x00, 0x00, 0x9c, 0x20, 0x22, 0xeb, 0x4c, 0x07, 0x00, 0x00, 0x0a, 0x13, | ||||||
|  |     0x7d, 0xf2, 0x02, 0x05, 0x00, 0x00, 0x89, 0x0a, 0x17, 0xf8, 0x06, 0x03, 0x00, 0x00, 0xa6, 0x05, 0xa0, 0xfb, 0xb4, | ||||||
|  |     0x01, 0x00, 0x00, 0xfa, 0x02, 0xac, 0xfd, 0xe8, 0x00, 0x00, 0x00, 0x8e, 0x01, 0xc7, 0xfe, 0x7a, 0x00, 0x00, 0x00, | ||||||
|  |     0xcf, 0x00, 0x5c, 0xff, 0x40, 0x00, 0x00, 0x00, 0x6b, 0x00, 0xab, 0xff, 0x22, 0x00, 0x00, 0x00, 0x38, 0x00, 0xd3, | ||||||
|  |     0xff, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0xea, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xf3, 0xff, 0x06, 0x00, | ||||||
|  |     0x00, 0x00, 0x08, 0x00, 0xf8, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, | ||||||
|  |     0x00, 0xfd, 0xff, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, 0xff, | ||||||
|  |     0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, | ||||||
|  |     0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, | ||||||
|  |     0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, | ||||||
|  |     0x00, 0x00, 0x00, 0x82, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, | ||||||
|  |     0x92, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xff, 0xff, 0xff, 0x04, 0x00, | ||||||
|  |     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, | ||||||
|  |     0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | ||||||
|  |     0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x13, 0x00, 0x17, 0x00, | ||||||
|  |     0x1b, 0x00, 0x20, 0x00, 0x25, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x3c, 0x00, 0x42, 0x00, 0x49, 0x00, 0x51, | ||||||
|  |     0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8d, 0x00, 0x97, 0x00, 0xa1, 0x00, | ||||||
|  |     0xac, 0x00, 0xb7, 0x00, 0xc2, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xe5, 0x00, 0xf2, 0x00, 0xff, 0x00, 0x0c, 0x01, 0x19, | ||||||
|  |     0x01, 0x27, 0x01, 0x35, 0x01, 0x43, 0x01, 0x52, 0x01, 0x61, 0x01, 0x70, 0x01, 0x7f, 0x01, 0x8f, 0x01, 0x9f, 0x01, | ||||||
|  |     0xaf, 0x01, 0xc0, 0x01, 0xd1, 0x01, 0xe2, 0x01, 0xf3, 0x01, 0x05, 0x02, 0x17, 0x02, 0x29, 0x02, 0x3c, 0x02, 0x4e, | ||||||
|  |     0x02, 0x61, 0x02, 0x75, 0x02, 0x88, 0x02, 0x9c, 0x02, 0xb0, 0x02, 0xc4, 0x02, 0xd8, 0x02, 0xed, 0x02, 0x02, 0x03, | ||||||
|  |     0x17, 0x03, 0x2c, 0x03, 0x41, 0x03, 0x57, 0x03, 0x6d, 0x03, 0x83, 0x03, 0x99, 0x03, 0xb0, 0x03, 0xc7, 0x03, 0xdd, | ||||||
|  |     0x03, 0xf4, 0x03, 0x0c, 0x04, 0x23, 0x04, 0x3b, 0x04, 0x52, 0x04, 0x6a, 0x04, 0x82, 0x04, 0x9a, 0x04, 0xb3, 0x04, | ||||||
|  |     0xcb, 0x04, 0xe4, 0x04, 0xfd, 0x04, 0x16, 0x05, 0x2f, 0x05, 0x48, 0x05, 0x61, 0x05, 0x7a, 0x05, 0x94, 0x05, 0xad, | ||||||
|  |     0x05, 0xc7, 0x05, 0xe1, 0x05, 0xfb, 0x05, 0x15, 0x06, 0x2f, 0x06, 0x49, 0x06, 0x63, 0x06, 0x7e, 0x06, 0x98, 0x06, | ||||||
|  |     0xb2, 0x06, 0xcd, 0x06, 0xe7, 0x06, 0x02, 0x07, 0x1d, 0x07, 0x37, 0x07, 0x52, 0x07, 0x6d, 0x07, 0x87, 0x07, 0xa2, | ||||||
|  |     0x07, 0xbd, 0x07, 0xd8, 0x07, 0xf3, 0x07, 0x0d, 0x08, 0x28, 0x08, 0x43, 0x08, 0x5e, 0x08, 0x79, 0x08, 0x93, 0x08, | ||||||
|  |     0xae, 0x08, 0xc9, 0x08, 0xe3, 0x08, 0xfe, 0x08, 0x19, 0x09, 0x33, 0x09, 0x4e, 0x09, 0x68, 0x09, 0x82, 0x09, 0x9d, | ||||||
|  |     0x09, 0xb7, 0x09, 0xd1, 0x09, 0xeb, 0x09, 0x05, 0x0a, 0x1f, 0x0a, 0x39, 0x0a, 0x53, 0x0a, 0x6c, 0x0a, 0x86, 0x0a, | ||||||
|  |     0x9f, 0x0a, 0xb8, 0x0a, 0xd1, 0x0a, 0xea, 0x0a, 0x03, 0x0b, 0x1c, 0x0b, 0x35, 0x0b, 0x4d, 0x0b, 0x66, 0x0b, 0x7e, | ||||||
|  |     0x0b, 0x96, 0x0b, 0xae, 0x0b, 0xc5, 0x0b, 0xdd, 0x0b, 0xf4, 0x0b, 0x0c, 0x0c, 0x23, 0x0c, 0x39, 0x0c, 0x50, 0x0c, | ||||||
|  |     0x67, 0x0c, 0x7d, 0x0c, 0x93, 0x0c, 0xa9, 0x0c, 0xbf, 0x0c, 0xd4, 0x0c, 0xe9, 0x0c, 0xfe, 0x0c, 0x13, 0x0d, 0x28, | ||||||
|  |     0x0d, 0x3c, 0x0d, 0x50, 0x0d, 0x64, 0x0d, 0x78, 0x0d, 0x8b, 0x0d, 0x9f, 0x0d, 0xb2, 0x0d, 0xc4, 0x0d, 0xd7, 0x0d, | ||||||
|  |     0xe9, 0x0d, 0xfb, 0x0d, 0x0d, 0x0e, 0x1e, 0x0e, 0x2f, 0x0e, 0x40, 0x0e, 0x51, 0x0e, 0x61, 0x0e, 0x71, 0x0e, 0x81, | ||||||
|  |     0x0e, 0x90, 0x0e, 0x9f, 0x0e, 0xae, 0x0e, 0xbd, 0x0e, 0xcb, 0x0e, 0xd9, 0x0e, 0xe7, 0x0e, 0xf4, 0x0e, 0x01, 0x0f, | ||||||
|  |     0x0e, 0x0f, 0x1b, 0x0f, 0x27, 0x0f, 0x33, 0x0f, 0x3e, 0x0f, 0x49, 0x0f, 0x54, 0x0f, 0x5f, 0x0f, 0x69, 0x0f, 0x73, | ||||||
|  |     0x0f, 0x7d, 0x0f, 0x86, 0x0f, 0x8f, 0x0f, 0x98, 0x0f, 0xa0, 0x0f, 0xa8, 0x0f, 0xaf, 0x0f, 0xb7, 0x0f, 0xbe, 0x0f, | ||||||
|  |     0xc4, 0x0f, 0xcb, 0x0f, 0xd0, 0x0f, 0xd6, 0x0f, 0xdb, 0x0f, 0xe0, 0x0f, 0xe5, 0x0f, 0xe9, 0x0f, 0xed, 0x0f, 0xf0, | ||||||
|  |     0x0f, 0xf3, 0x0f, 0xf6, 0x0f, 0xf9, 0x0f, 0xfb, 0x0f, 0xfc, 0x0f, 0xfe, 0x0f, 0xff, 0x0f, 0x00, 0x10, 0x00, 0x10, | ||||||
|  |     0x00, 0x10, 0x00, 0x10, 0xff, 0x0f, 0xfe, 0x0f, 0xfc, 0x0f, 0xfb, 0x0f, 0xf9, 0x0f, 0xf6, 0x0f, 0xf3, 0x0f, 0xf0, | ||||||
|  |     0x0f, 0xed, 0x0f, 0xe9, 0x0f, 0xe5, 0x0f, 0xe0, 0x0f, 0xdb, 0x0f, 0xd6, 0x0f, 0xd0, 0x0f, 0xcb, 0x0f, 0xc4, 0x0f, | ||||||
|  |     0xbe, 0x0f, 0xb7, 0x0f, 0xaf, 0x0f, 0xa8, 0x0f, 0xa0, 0x0f, 0x98, 0x0f, 0x8f, 0x0f, 0x86, 0x0f, 0x7d, 0x0f, 0x73, | ||||||
|  |     0x0f, 0x69, 0x0f, 0x5f, 0x0f, 0x54, 0x0f, 0x49, 0x0f, 0x3e, 0x0f, 0x33, 0x0f, 0x27, 0x0f, 0x1b, 0x0f, 0x0e, 0x0f, | ||||||
|  |     0x01, 0x0f, 0xf4, 0x0e, 0xe7, 0x0e, 0xd9, 0x0e, 0xcb, 0x0e, 0xbd, 0x0e, 0xae, 0x0e, 0x9f, 0x0e, 0x90, 0x0e, 0x81, | ||||||
|  |     0x0e, 0x71, 0x0e, 0x61, 0x0e, 0x51, 0x0e, 0x40, 0x0e, 0x2f, 0x0e, 0x1e, 0x0e, 0x0d, 0x0e, 0xfb, 0x0d, 0xe9, 0x0d, | ||||||
|  |     0xd7, 0x0d, 0xc4, 0x0d, 0xb2, 0x0d, 0x9f, 0x0d, 0x8b, 0x0d, 0x78, 0x0d, 0x64, 0x0d, 0x50, 0x0d, 0x3c, 0x0d, 0x28, | ||||||
|  |     0x0d, 0x13, 0x0d, 0xfe, 0x0c, 0xe9, 0x0c, 0xd4, 0x0c, 0xbf, 0x0c, 0xa9, 0x0c, 0x93, 0x0c, 0x7d, 0x0c, 0x67, 0x0c, | ||||||
|  |     0x50, 0x0c, 0x39, 0x0c, 0x23, 0x0c, 0x0c, 0x0c, 0xf4, 0x0b, 0xdd, 0x0b, 0xc5, 0x0b, 0xae, 0x0b, 0x96, 0x0b, 0x7e, | ||||||
|  |     0x0b, 0x66, 0x0b, 0x4d, 0x0b, 0x35, 0x0b, 0x1c, 0x0b, 0x03, 0x0b, 0xea, 0x0a, 0xd1, 0x0a, 0xb8, 0x0a, 0x9f, 0x0a, | ||||||
|  |     0x86, 0x0a, 0x6c, 0x0a, 0x53, 0x0a, 0x39, 0x0a, 0x1f, 0x0a, 0x05, 0x0a, 0xeb, 0x09, 0xd1, 0x09, 0xb7, 0x09, 0x9d, | ||||||
|  |     0x09, 0x82, 0x09, 0x68, 0x09, 0x4e, 0x09, 0x33, 0x09, 0x19, 0x09, 0xfe, 0x08, 0xe3, 0x08, 0xc9, 0x08, 0xae, 0x08, | ||||||
|  |     0x93, 0x08, 0x79, 0x08, 0x5e, 0x08, 0x43, 0x08, 0x28, 0x08, 0x0d, 0x08, 0xf3, 0x07, 0xd8, 0x07, 0xbd, 0x07, 0xa2, | ||||||
|  |     0x07, 0x87, 0x07, 0x6d, 0x07, 0x52, 0x07, 0x37, 0x07, 0x1d, 0x07, 0x02, 0x07, 0xe7, 0x06, 0xcd, 0x06, 0xb2, 0x06, | ||||||
|  |     0x98, 0x06, 0x7e, 0x06, 0x63, 0x06, 0x49, 0x06, 0x2f, 0x06, 0x15, 0x06, 0xfb, 0x05, 0xe1, 0x05, 0xc7, 0x05, 0xad, | ||||||
|  |     0x05, 0x94, 0x05, 0x7a, 0x05, 0x61, 0x05, 0x48, 0x05, 0x2f, 0x05, 0x16, 0x05, 0xfd, 0x04, 0xe4, 0x04, 0xcb, 0x04, | ||||||
|  |     0xb3, 0x04, 0x9a, 0x04, 0x82, 0x04, 0x6a, 0x04, 0x52, 0x04, 0x3b, 0x04, 0x23, 0x04, 0x0c, 0x04, 0xf4, 0x03, 0xdd, | ||||||
|  |     0x03, 0xc7, 0x03, 0xb0, 0x03, 0x99, 0x03, 0x83, 0x03, 0x6d, 0x03, 0x57, 0x03, 0x41, 0x03, 0x2c, 0x03, 0x17, 0x03, | ||||||
|  |     0x02, 0x03, 0xed, 0x02, 0xd8, 0x02, 0xc4, 0x02, 0xb0, 0x02, 0x9c, 0x02, 0x88, 0x02, 0x75, 0x02, 0x61, 0x02, 0x4e, | ||||||
|  |     0x02, 0x3c, 0x02, 0x29, 0x02, 0x17, 0x02, 0x05, 0x02, 0xf3, 0x01, 0xe2, 0x01, 0xd1, 0x01, 0xc0, 0x01, 0xaf, 0x01, | ||||||
|  |     0x9f, 0x01, 0x8f, 0x01, 0x7f, 0x01, 0x70, 0x01, 0x61, 0x01, 0x52, 0x01, 0x43, 0x01, 0x35, 0x01, 0x27, 0x01, 0x19, | ||||||
|  |     0x01, 0x0c, 0x01, 0xff, 0x00, 0xf2, 0x00, 0xe5, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xac, 0x00, | ||||||
|  |     0xa1, 0x00, 0x97, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x68, 0x00, 0x60, 0x00, 0x58, 0x00, 0x51, | ||||||
|  |     0x00, 0x49, 0x00, 0x42, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2a, 0x00, 0x25, 0x00, 0x20, 0x00, 0x1b, 0x00, | ||||||
|  |     0x17, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0xee, 0xff, 0xff, 0x38, 0xee, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c, | ||||||
|  |     0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, | ||||||
|  |     0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xf4, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00, | ||||||
|  |     0x00, 0xfc, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, | ||||||
|  |     0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x68, 0x05, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, 0xc8, 0x04, 0x00, 0x00, 0x70, | ||||||
|  |     0x04, 0x00, 0x00, 0x4c, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, | ||||||
|  |     0x4c, 0x03, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x6c, 0x01, 0x00, | ||||||
|  |     0x00, 0x48, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x78, 0x00, | ||||||
|  |     0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf6, 0xfa, 0xff, 0xff, 0x0c, | ||||||
|  |     0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, | ||||||
|  |     0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x16, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, | ||||||
|  |     0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, | ||||||
|  |     0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3a, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||||||
|  |     0x0e, 0x00, 0x00, 0x00, 0xa6, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00, 0x00, | ||||||
|  |     0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x68, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, | ||||||
|  |     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xd6, 0xfc, 0xff, 0xff, 0x14, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||||||
|  |     0x98, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, | ||||||
|  |     0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0xfd, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00, | ||||||
|  |     0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xc8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x25, | ||||||
|  |     0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x36, 0xfd, 0xff, 0xff, | ||||||
|  |     0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, | ||||||
|  |     0x00, 0xf8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, | ||||||
|  |     0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||||||
|  |     0x84, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, | ||||||
|  |     0x00, 0x30, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x69, | ||||||
|  |     0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c, | ||||||
|  |     0x65, 0x00, 0x02, 0x24, 0x0f, 0x02, 0x01, 0x02, 0x03, 0x40, 0x04, 0x04, 0x04, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00, | ||||||
|  |     0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xdc, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, | ||||||
|  |     0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x73, 0x6e, | ||||||
|  |     0x72, 0x5f, 0x73, 0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x0b, 0x01, 0x01, 0x01, 0x06, 0x04, 0x02, 0x24, 0x01, 0x01, | ||||||
|  |     0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||||||
|  |     0x08, 0x00, 0x00, 0x00, 0x20, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, | ||||||
|  |     0x00, 0x0a, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f, | ||||||
|  |     0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, | ||||||
|  |     0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, | ||||||
|  |     0x67, 0x00, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, | ||||||
|  |     0x61, 0x6c, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, | ||||||
|  |     0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d, | ||||||
|  |     0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73, | ||||||
|  |     0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x73, 0x70, 0x65, 0x63, 0x74, | ||||||
|  |     0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, | ||||||
|  |     0x73, 0x00, 0x09, 0xa5, 0x88, 0x75, 0x6d, 0x59, 0x4d, 0x3a, 0x31, 0x23, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x29, | ||||||
|  |     0x3c, 0xd7, 0x03, 0x00, 0x00, 0x33, 0x03, 0x28, 0x00, 0x67, 0x3e, 0x99, 0x01, 0x0a, 0x00, 0x0e, 0x00, 0x05, 0x05, | ||||||
|  |     0x69, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1b, 0x25, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, | ||||||
|  |     0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0xfe, 0xff, 0xff, 0x10, 0x00, | ||||||
|  |     0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||||||
|  |     0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x54, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, | ||||||
|  |     0x00, 0x2c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, | ||||||
|  |     0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x01, 0x0e, 0x01, 0x01, 0x01, 0x28, 0x04, 0x02, 0x24, 0x01, 0x00, 0x01, | ||||||
|  |     0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||||||
|  |     0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x62, 0xfe, 0xff, | ||||||
|  |     0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, | ||||||
|  |     0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8c, 0xf2, 0xff, 0xff, | ||||||
|  |     0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, | ||||||
|  |     0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00, | ||||||
|  |     0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x14, | ||||||
|  |     0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0xf2, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | ||||||
|  |     0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, | ||||||
|  |     0x00, 0xfe, 0xfe, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, | ||||||
|  |     0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0xff, 0xff, 0xff, 0x10, | ||||||
|  |     0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | ||||||
|  |     0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, | ||||||
|  |     0x65, 0x78, 0x00, 0x02, 0x17, 0x0e, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0xf1, 0x00, 0x05, 0x00, 0x05, 0x05, | ||||||
|  |     0x06, 0x25, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, | ||||||
|  |     0x00, 0x00, 0x00, 0xb8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, | ||||||
|  |     0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x66, 0x66, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, | ||||||
|  |     0x68, 0x00, 0x02, 0x0e, 0x0d, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x02, 0x05, 0x05, 0x06, 0x25, | ||||||
|  |     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, | ||||||
|  |     0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, | ||||||
|  |     0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, | ||||||
|  |     0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, | ||||||
|  |     0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||||||
|  |     0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, | ||||||
|  |     0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, | ||||||
|  |     0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73, | ||||||
|  |     0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x07, 0x01, 0x01, 0x01, 0x0c, 0x04, 0x02, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00, | ||||||
|  |     0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, | ||||||
|  |     0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xc4, 0x0a, | ||||||
|  |     0x00, 0x00, 0x74, 0x0a, 0x00, 0x00, 0x3c, 0x0a, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x88, | ||||||
|  |     0x09, 0x00, 0x00, 0x40, 0x09, 0x00, 0x00, 0xfc, 0x08, 0x00, 0x00, 0xb8, 0x08, 0x00, 0x00, 0x6c, 0x08, 0x00, 0x00, | ||||||
|  |     0x20, 0x08, 0x00, 0x00, 0xd4, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x3c, 0x07, 0x00, 0x00, 0xf8, 0x06, 0x00, | ||||||
|  |     0x00, 0xb8, 0x06, 0x00, 0x00, 0x84, 0x06, 0x00, 0x00, 0x50, 0x06, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, 0xd8, 0x05, | ||||||
|  |     0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x14, 0x05, 0x00, 0x00, 0xd8, 0x04, 0x00, 0x00, 0x98, | ||||||
|  |     0x04, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00, | ||||||
|  |     0x6c, 0x03, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x2c, 0x02, 0x00, | ||||||
|  |     0x00, 0xe4, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x08, 0x01, | ||||||
|  |     0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xfe, | ||||||
|  |     0xf5, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x00, 0x44, 0xf5, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, | ||||||
|  |     0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, | ||||||
|  |     0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3e, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, | ||||||
|  |     0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x84, 0xf5, 0xff, 0xff, | ||||||
|  |     0x0d, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, | ||||||
|  |     0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7a, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, | ||||||
|  |     0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0xc0, | ||||||
|  |     0xf5, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, | ||||||
|  |     0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, | ||||||
|  |     0x00, 0xbe, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x28, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x04, 0xf6, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x61, | ||||||
|  |     0x64, 0x64, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x02, 0x18, 0x00, 0x00, 0x00, 0x38, 0xf6, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, | ||||||
|  |     0x74, 0x65, 0x44, 0x69, 0x76, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2a, 0xf7, 0xff, 0xff, 0x00, | ||||||
|  |     0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, | ||||||
|  |     0x10, 0x00, 0x00, 0x00, 0x70, 0xf6, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x00, 0x01, 0x00, 0x00, | ||||||
|  |     0x00, 0x28, 0x00, 0x00, 0x00, 0x5a, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, | ||||||
|  |     0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0xa0, 0xf6, 0xff, 0xff, 0x03, | ||||||
|  |     0x00, 0x00, 0x00, 0x6d, 0x75, 0x6c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x8a, 0xf7, 0xff, 0xff, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x02, 0x14, 0x00, 0x00, 0x00, 0xd0, 0xf6, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x32, | ||||||
|  |     0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xbe, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, | ||||||
|  |     0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00, | ||||||
|  |     0x04, 0xf7, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, | ||||||
|  |     0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, | ||||||
|  |     0x00, 0x00, 0x02, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x00, 0x48, 0xf7, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, | ||||||
|  |     0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, | ||||||
|  |     0x00, 0x3a, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x00, 0x00, 0x00, 0x80, 0xf7, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, 0x73, | ||||||
|  |     0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73, | ||||||
|  |     0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, | ||||||
|  |     0x31, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x92, 0xf8, 0xff, 0xff, 0x00, 0x00, | ||||||
|  |     0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x34, | ||||||
|  |     0x00, 0x00, 0x00, 0xd8, 0xf7, 0xff, 0xff, 0x27, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, | ||||||
|  |     0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c, | ||||||
|  |     0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, | ||||||
|  |     0x00, 0x00, 0xe6, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1f, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x2c, 0x00, 0x00, 0x00, 0x2c, 0xf8, 0xff, 0xff, 0x1e, 0x00, 0x00, 0x00, | ||||||
|  |     0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, | ||||||
|  |     0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, | ||||||
|  |     0x00, 0x00, 0x32, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1e, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x78, 0xf8, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, | ||||||
|  |     0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x00, | ||||||
|  |     0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x72, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, | ||||||
|  |     0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x00, 0xb8, | ||||||
|  |     0xf8, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||||||
|  |     0x01, 0x01, 0x00, 0x00, 0xa6, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, | ||||||
|  |     0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xec, 0xf8, 0xff, 0xff, 0x06, 0x00, | ||||||
|  |     0x00, 0x00, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0xda, | ||||||
|  |     0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x20, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, | ||||||
|  |     0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xec, 0x00, | ||||||
|  |     0x00, 0x00, 0x16, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1a, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xf9, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, | ||||||
|  |     0x43, 0x61, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x4a, 0xfa, 0xff, | ||||||
|  |     0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x0f, 0x1c, 0x00, 0x00, 0x00, 0x90, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, | ||||||
|  |     0x6c, 0x5f, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, | ||||||
|  |     0x86, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xf9, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69, | ||||||
|  |     0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x66, 0x66, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0xbe, | ||||||
|  |     0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x04, 0xfa, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, | ||||||
|  |     0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x31, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, | ||||||
|  |     0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00, 0x44, 0xfa, 0xff, 0xff, | ||||||
|  |     0x15, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f, | ||||||
|  |     0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x42, 0xfb, | ||||||
|  |     0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x88, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, | ||||||
|  |     0x61, 0x70, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x76, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, | ||||||
|  |     0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1c, 0x00, | ||||||
|  |     0x00, 0x00, 0xbc, 0xfa, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x77, 0x69, | ||||||
|  |     0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, | ||||||
|  |     0xb6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xfc, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43, 0x6f, | ||||||
|  |     0x6e, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, | ||||||
|  |     0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, | ||||||
|  |     0x2c, 0xfb, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x16, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xfb, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43, | ||||||
|  |     0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, | ||||||
|  |     0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, | ||||||
|  |     0x00, 0x8c, 0xfb, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, 0x68, | ||||||
|  |     0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82, 0xfc, 0xff, 0xff, 0x00, | ||||||
|  |     0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, | ||||||
|  |     0x24, 0x00, 0x00, 0x00, 0xc8, 0xfb, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, | ||||||
|  |     0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x2f, 0x79, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0xc2, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x08, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, | ||||||
|  |     0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, | ||||||
|  |     0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x0a, 0xfd, | ||||||
|  |     0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x50, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, | ||||||
|  |     0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, | ||||||
|  |     0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x52, 0xfd, 0xff, 0xff, 0x00, 0x00, | ||||||
|  |     0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, | ||||||
|  |     0x00, 0x00, 0x00, 0x98, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, | ||||||
|  |     0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00, | ||||||
|  |     0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x9a, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, | ||||||
|  |     0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0xe0, | ||||||
|  |     0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, | ||||||
|  |     0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x33, 0x00, 0x00, 0x01, 0x00, 0x00, | ||||||
|  |     0x00, 0x29, 0x00, 0x00, 0x00, 0xe2, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, | ||||||
|  |     0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x28, 0xfd, 0xff, 0xff, 0x1a, | ||||||
|  |     0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, | ||||||
|  |     0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, | ||||||
|  |     0x00, 0x2a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x00, 0x70, 0xfd, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x73, | ||||||
|  |     0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00, | ||||||
|  |     0x01, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x6a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, | ||||||
|  |     0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0xb0, 0xfd, | ||||||
|  |     0xff, 0xff, 0x13, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, | ||||||
|  |     0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xaa, 0xfe, 0xff, 0xff, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x02, 0x24, 0x00, 0x00, 0x00, 0xf0, 0xfd, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, | ||||||
|  |     0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01, | ||||||
|  |     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xee, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, | ||||||
|  |     0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x34, 0xfe, 0xff, | ||||||
|  |     0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, | ||||||
|  |     0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, | ||||||
|  |     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x78, 0xfe, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, | ||||||
|  |     0x74, 0x5f, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, | ||||||
|  |     0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xa8, | ||||||
|  |     0xfe, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||||||
|  |     0x05, 0x00, 0x00, 0x00, 0x96, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, | ||||||
|  |     0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xdc, 0xfe, 0xff, 0xff, 0x07, 0x00, | ||||||
|  |     0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x5f, 0x31, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xca, | ||||||
|  |     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, | ||||||
|  |     0x73, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x1c, 0x00, | ||||||
|  |     0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x16, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x07, 0x2c, 0x00, 0x00, 0x00, 0x5c, 0xff, 0xff, 0xff, 0x1d, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, | ||||||
|  |     0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, | ||||||
|  |     0x66, 0x72, 0x61, 0x6d, 0x65, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, | ||||||
|  |     0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, | ||||||
|  |     0xa4, 0x01, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, | ||||||
|  |     0x00, 0x10, 0x01, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x50, 0x00, | ||||||
|  |     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, | ||||||
|  |     0x00, 0x00, 0x00, 0x50, 0xfe, 0xff, 0xff, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x5c, 0xfe, 0xff, 0xff, | ||||||
|  |     0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x68, 0xfe, 0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x2a, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7c, 0xfe, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x12, 0x70, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x13, | ||||||
|  |     0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, | ||||||
|  |     0x4c, 0x6f, 0x67, 0x00, 0x98, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x20, 0x0a, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x50, 0x43, 0x41, 0x4e, 0x00, 0x00, 0xb8, 0xfe, | ||||||
|  |     0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x23, 0x00, 0x00, 0x00, 0x53, | ||||||
|  |     0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x70, 0x65, 0x63, | ||||||
|  |     0x74, 0x72, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0xf0, 0xfe, 0xff, | ||||||
|  |     0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1a, 0x00, 0x00, 0x00, 0x53, 0x69, | ||||||
|  |     0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x71, 0x75, 0x61, 0x72, | ||||||
|  |     0x65, 0x52, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, | ||||||
|  |     0x72, 0x42, 0x61, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x02, 0x6c, 0xff, 0xff, 0xff, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x0c, 0x00, 0x10, 0x00, 0x0f, | ||||||
|  |     0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x35, 0x7c, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0xa0, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0a, | ||||||
|  |     0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x66, 0x66, 0x74, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, | ||||||
|  |     0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, | ||||||
|  |     0x6e, 0x61, 0x6c, 0x46, 0x66, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x0c, 0x00, | ||||||
|  |     0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x16, 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||||||
|  |     0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, | ||||||
|  |     0x6e, 0x61, 0x6c, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x00}; | ||||||
|  |  | ||||||
|  | }  // namespace micro_wake_word | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP_IDF | ||||||
							
								
								
									
										503
									
								
								esphome/components/micro_wake_word/micro_wake_word.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								esphome/components/micro_wake_word/micro_wake_word.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,503 @@ | |||||||
|  | #include "micro_wake_word.h" | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This is a workaround until we can figure out a way to get | ||||||
|  |  * the tflite-micro idf component code available in CI | ||||||
|  |  * | ||||||
|  |  * */ | ||||||
|  | // | ||||||
|  | #ifndef CLANG_TIDY | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP_IDF | ||||||
|  |  | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | #include "audio_preprocessor_int8_model_data.h" | ||||||
|  |  | ||||||
|  | #include <tensorflow/lite/core/c/common.h> | ||||||
|  | #include <tensorflow/lite/micro/micro_interpreter.h> | ||||||
|  | #include <tensorflow/lite/micro/micro_mutable_op_resolver.h> | ||||||
|  |  | ||||||
|  | #include <cmath> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micro_wake_word { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "micro_wake_word"; | ||||||
|  |  | ||||||
|  | static const size_t SAMPLE_RATE_HZ = 16000;  // 16 kHz | ||||||
|  | static const size_t BUFFER_LENGTH = 500;     // 0.5 seconds | ||||||
|  | static const size_t BUFFER_SIZE = SAMPLE_RATE_HZ / 1000 * BUFFER_LENGTH; | ||||||
|  | static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000;  // 32ms * 16kHz / 1000ms | ||||||
|  |  | ||||||
|  | float MicroWakeWord::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } | ||||||
|  |  | ||||||
|  | static const LogString *micro_wake_word_state_to_string(State state) { | ||||||
|  |   switch (state) { | ||||||
|  |     case State::IDLE: | ||||||
|  |       return LOG_STR("IDLE"); | ||||||
|  |     case State::START_MICROPHONE: | ||||||
|  |       return LOG_STR("START_MICROPHONE"); | ||||||
|  |     case State::STARTING_MICROPHONE: | ||||||
|  |       return LOG_STR("STARTING_MICROPHONE"); | ||||||
|  |     case State::DETECTING_WAKE_WORD: | ||||||
|  |       return LOG_STR("DETECTING_WAKE_WORD"); | ||||||
|  |     case State::STOP_MICROPHONE: | ||||||
|  |       return LOG_STR("STOP_MICROPHONE"); | ||||||
|  |     case State::STOPPING_MICROPHONE: | ||||||
|  |       return LOG_STR("STOPPING_MICROPHONE"); | ||||||
|  |     default: | ||||||
|  |       return LOG_STR("UNKNOWN"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroWakeWord::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up Micro Wake Word..."); | ||||||
|  |  | ||||||
|  |   if (!this->initialize_models()) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to initialize models"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ExternalRAMAllocator<int16_t> allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE); | ||||||
|  |   this->input_buffer_ = allocator.allocate(NEW_SAMPLES_TO_GET); | ||||||
|  |   if (this->input_buffer_ == nullptr) { | ||||||
|  |     ESP_LOGW(TAG, "Could not allocate input buffer"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t)); | ||||||
|  |   if (this->ring_buffer_ == nullptr) { | ||||||
|  |     ESP_LOGW(TAG, "Could not allocate ring buffer"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGCONFIG(TAG, "Micro Wake Word initialized"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int MicroWakeWord::read_microphone_() { | ||||||
|  |   size_t bytes_read = this->microphone_->read(this->input_buffer_, NEW_SAMPLES_TO_GET * sizeof(int16_t)); | ||||||
|  |   if (bytes_read == 0) { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   size_t bytes_written = this->ring_buffer_->write((void *) this->input_buffer_, bytes_read); | ||||||
|  |   if (bytes_written != bytes_read) { | ||||||
|  |     ESP_LOGW(TAG, "Failed to write some data to ring buffer (written=%d, expected=%d)", bytes_written, bytes_read); | ||||||
|  |   } | ||||||
|  |   return bytes_written; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroWakeWord::loop() { | ||||||
|  |   switch (this->state_) { | ||||||
|  |     case State::IDLE: | ||||||
|  |       break; | ||||||
|  |     case State::START_MICROPHONE: | ||||||
|  |       ESP_LOGD(TAG, "Starting Microphone"); | ||||||
|  |       this->microphone_->start(); | ||||||
|  |       this->set_state_(State::STARTING_MICROPHONE); | ||||||
|  |       this->high_freq_.start(); | ||||||
|  |       break; | ||||||
|  |     case State::STARTING_MICROPHONE: | ||||||
|  |       if (this->microphone_->is_running()) { | ||||||
|  |         this->set_state_(State::DETECTING_WAKE_WORD); | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |     case State::DETECTING_WAKE_WORD: | ||||||
|  |       this->read_microphone_(); | ||||||
|  |       if (this->detect_wake_word_()) { | ||||||
|  |         ESP_LOGD(TAG, "Wake Word Detected"); | ||||||
|  |         this->detected_ = true; | ||||||
|  |         this->set_state_(State::STOP_MICROPHONE); | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |     case State::STOP_MICROPHONE: | ||||||
|  |       ESP_LOGD(TAG, "Stopping Microphone"); | ||||||
|  |       this->microphone_->stop(); | ||||||
|  |       this->set_state_(State::STOPPING_MICROPHONE); | ||||||
|  |       this->high_freq_.stop(); | ||||||
|  |       break; | ||||||
|  |     case State::STOPPING_MICROPHONE: | ||||||
|  |       if (this->microphone_->is_stopped()) { | ||||||
|  |         this->set_state_(State::IDLE); | ||||||
|  |         if (this->detected_) { | ||||||
|  |           this->detected_ = false; | ||||||
|  |           this->wake_word_detected_trigger_->trigger(""); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroWakeWord::start() { | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGW(TAG, "Wake word component is marked as failed. Please check setup logs"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (this->state_ != State::IDLE) { | ||||||
|  |     ESP_LOGW(TAG, "Wake word is already running"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   this->set_state_(State::START_MICROPHONE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroWakeWord::stop() { | ||||||
|  |   if (this->state_ == State::IDLE) { | ||||||
|  |     ESP_LOGW(TAG, "Wake word is already stopped"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (this->state_ == State::STOPPING_MICROPHONE) { | ||||||
|  |     ESP_LOGW(TAG, "Wake word is already stopping"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   this->set_state_(State::STOP_MICROPHONE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroWakeWord::set_state_(State state) { | ||||||
|  |   ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(micro_wake_word_state_to_string(this->state_)), | ||||||
|  |            LOG_STR_ARG(micro_wake_word_state_to_string(state))); | ||||||
|  |   this->state_ = state; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::initialize_models() { | ||||||
|  |   ExternalRAMAllocator<uint8_t> arena_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE); | ||||||
|  |   ExternalRAMAllocator<int8_t> features_allocator(ExternalRAMAllocator<int8_t>::ALLOW_FAILURE); | ||||||
|  |   ExternalRAMAllocator<int16_t> audio_samples_allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE); | ||||||
|  |  | ||||||
|  |   this->streaming_tensor_arena_ = arena_allocator.allocate(STREAMING_MODEL_ARENA_SIZE); | ||||||
|  |   if (this->streaming_tensor_arena_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "Could not allocate the streaming model's tensor arena."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->streaming_var_arena_ = arena_allocator.allocate(STREAMING_MODEL_VARIABLE_ARENA_SIZE); | ||||||
|  |   if (this->streaming_var_arena_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "Could not allocate the streaming model variable's tensor arena."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->preprocessor_tensor_arena_ = arena_allocator.allocate(PREPROCESSOR_ARENA_SIZE); | ||||||
|  |   if (this->preprocessor_tensor_arena_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "Could not allocate the audio preprocessor model's tensor arena."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->new_features_data_ = features_allocator.allocate(PREPROCESSOR_FEATURE_SIZE); | ||||||
|  |   if (this->new_features_data_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "Could not allocate the audio features buffer."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->preprocessor_audio_buffer_ = audio_samples_allocator.allocate(SAMPLE_DURATION_COUNT); | ||||||
|  |   if (this->preprocessor_audio_buffer_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "Could not allocate the audio preprocessor's buffer."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->preprocessor_stride_buffer_ = audio_samples_allocator.allocate(HISTORY_SAMPLES_TO_KEEP); | ||||||
|  |   if (this->preprocessor_stride_buffer_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "Could not allocate the audio preprocessor's stride buffer."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->preprocessor_model_ = tflite::GetModel(G_AUDIO_PREPROCESSOR_INT8_TFLITE); | ||||||
|  |   if (this->preprocessor_model_->version() != TFLITE_SCHEMA_VERSION) { | ||||||
|  |     ESP_LOGE(TAG, "Wake word's audio preprocessor model's schema is not supported"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->streaming_model_ = tflite::GetModel(this->model_start_); | ||||||
|  |   if (this->streaming_model_->version() != TFLITE_SCHEMA_VERSION) { | ||||||
|  |     ESP_LOGE(TAG, "Wake word's streaming model's schema is not supported"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static tflite::MicroMutableOpResolver<18> preprocessor_op_resolver; | ||||||
|  |   static tflite::MicroMutableOpResolver<14> streaming_op_resolver; | ||||||
|  |  | ||||||
|  |   if (!this->register_preprocessor_ops_(preprocessor_op_resolver)) | ||||||
|  |     return false; | ||||||
|  |   if (!this->register_streaming_ops_(streaming_op_resolver)) | ||||||
|  |     return false; | ||||||
|  |  | ||||||
|  |   tflite::MicroAllocator *ma = | ||||||
|  |       tflite::MicroAllocator::Create(this->streaming_var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE); | ||||||
|  |   this->mrv_ = tflite::MicroResourceVariables::Create(ma, 15); | ||||||
|  |  | ||||||
|  |   static tflite::MicroInterpreter static_preprocessor_interpreter( | ||||||
|  |       this->preprocessor_model_, preprocessor_op_resolver, this->preprocessor_tensor_arena_, PREPROCESSOR_ARENA_SIZE); | ||||||
|  |  | ||||||
|  |   static tflite::MicroInterpreter static_streaming_interpreter(this->streaming_model_, streaming_op_resolver, | ||||||
|  |                                                                this->streaming_tensor_arena_, | ||||||
|  |                                                                STREAMING_MODEL_ARENA_SIZE, this->mrv_); | ||||||
|  |  | ||||||
|  |   this->preprocessor_interperter_ = &static_preprocessor_interpreter; | ||||||
|  |   this->streaming_interpreter_ = &static_streaming_interpreter; | ||||||
|  |  | ||||||
|  |   // Allocate tensors for each models. | ||||||
|  |   if (this->preprocessor_interperter_->AllocateTensors() != kTfLiteOk) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to allocate tensors for the audio preprocessor"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   if (this->streaming_interpreter_->AllocateTensors() != kTfLiteOk) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to allocate tensors for the streaming model"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Verify input tensor matches expected values | ||||||
|  |   TfLiteTensor *input = this->streaming_interpreter_->input(0); | ||||||
|  |   if ((input->dims->size != 3) || (input->dims->data[0] != 1) || (input->dims->data[0] != 1) || | ||||||
|  |       (input->dims->data[1] != 1) || (input->dims->data[2] != PREPROCESSOR_FEATURE_SIZE)) { | ||||||
|  |     ESP_LOGE(TAG, "Wake word detection model tensor input dimensions is not 1x1x%u", input->dims->data[2]); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (input->type != kTfLiteInt8) { | ||||||
|  |     ESP_LOGE(TAG, "Wake word detection model tensor input is not int8."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Verify output tensor matches expected values | ||||||
|  |   TfLiteTensor *output = this->streaming_interpreter_->output(0); | ||||||
|  |   if ((output->dims->size != 2) || (output->dims->data[0] != 1) || (output->dims->data[1] != 1)) { | ||||||
|  |     ESP_LOGE(TAG, "Wake word detection model tensor output dimensions is not 1x1."); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (output->type != kTfLiteUInt8) { | ||||||
|  |     ESP_LOGE(TAG, "Wake word detection model tensor input is not uint8."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0); | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::update_features_() { | ||||||
|  |   // Verify we have enough samples for a feature slice | ||||||
|  |   if (!this->slice_available_()) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Retrieve strided audio samples | ||||||
|  |   int16_t *audio_samples = nullptr; | ||||||
|  |   if (!this->stride_audio_samples_(&audio_samples)) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Compute the features for the newest audio samples | ||||||
|  |   if (!this->generate_single_feature_(audio_samples, SAMPLE_DURATION_COUNT, this->new_features_data_)) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float MicroWakeWord::perform_streaming_inference_() { | ||||||
|  |   TfLiteTensor *input = this->streaming_interpreter_->input(0); | ||||||
|  |  | ||||||
|  |   size_t bytes_to_copy = input->bytes; | ||||||
|  |  | ||||||
|  |   memcpy((void *) (tflite::GetTensorData<int8_t>(input)), (const void *) (this->new_features_data_), bytes_to_copy); | ||||||
|  |  | ||||||
|  |   uint32_t prior_invoke = millis(); | ||||||
|  |  | ||||||
|  |   TfLiteStatus invoke_status = this->streaming_interpreter_->Invoke(); | ||||||
|  |   if (invoke_status != kTfLiteOk) { | ||||||
|  |     ESP_LOGW(TAG, "Streaming Interpreter Invoke failed"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "Streaming Inference Latency=%u ms", (millis() - prior_invoke)); | ||||||
|  |  | ||||||
|  |   TfLiteTensor *output = this->streaming_interpreter_->output(0); | ||||||
|  |  | ||||||
|  |   return static_cast<float>(output->data.uint8[0]) / 255.0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::detect_wake_word_() { | ||||||
|  |   // Preprocess the newest audio samples into features | ||||||
|  |   if (!this->update_features_()) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Perform inference | ||||||
|  |   uint32_t streaming_size = micros(); | ||||||
|  |   float streaming_prob = this->perform_streaming_inference_(); | ||||||
|  |  | ||||||
|  |   // Add the most recent probability to the sliding window | ||||||
|  |   this->recent_streaming_probabilities_[this->last_n_index_] = streaming_prob; | ||||||
|  |   ++this->last_n_index_; | ||||||
|  |   if (this->last_n_index_ == this->sliding_window_average_size_) | ||||||
|  |     this->last_n_index_ = 0; | ||||||
|  |  | ||||||
|  |   float sum = 0.0; | ||||||
|  |   for (auto &prob : this->recent_streaming_probabilities_) { | ||||||
|  |     sum += prob; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   float sliding_window_average = sum / static_cast<float>(this->sliding_window_average_size_); | ||||||
|  |  | ||||||
|  |   // Ensure we have enough samples since the last positive detection | ||||||
|  |   this->ignore_windows_ = std::min(this->ignore_windows_ + 1, 0); | ||||||
|  |   if (this->ignore_windows_ < 0) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Detect the wake word if the sliding window average is above the cutoff | ||||||
|  |   if (sliding_window_average > this->probability_cutoff_) { | ||||||
|  |     this->ignore_windows_ = -MIN_SLICES_BEFORE_DETECTION; | ||||||
|  |     for (auto &prob : this->recent_streaming_probabilities_) { | ||||||
|  |       prob = 0; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroWakeWord::set_sliding_window_average_size(size_t size) { | ||||||
|  |   this->sliding_window_average_size_ = size; | ||||||
|  |   this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::slice_available_() { | ||||||
|  |   size_t available = this->ring_buffer_->available(); | ||||||
|  |  | ||||||
|  |   return available > (NEW_SAMPLES_TO_GET * sizeof(int16_t)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) { | ||||||
|  |   // Copy 320 bytes (160 samples over 10 ms) into preprocessor_audio_buffer_ from history in | ||||||
|  |   // preprocessor_stride_buffer_ | ||||||
|  |   memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_stride_buffer_), | ||||||
|  |          HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t)); | ||||||
|  |  | ||||||
|  |   if (this->ring_buffer_->available() < NEW_SAMPLES_TO_GET * sizeof(int16_t)) { | ||||||
|  |     ESP_LOGD(TAG, "Audio Buffer not full enough"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Copy 640 bytes (320 samples over 20 ms) from the ring buffer | ||||||
|  |   // The first 320 bytes (160 samples over 10 ms) will be from history | ||||||
|  |   size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_ + HISTORY_SAMPLES_TO_KEEP), | ||||||
|  |                                                NEW_SAMPLES_TO_GET * sizeof(int16_t), pdMS_TO_TICKS(200)); | ||||||
|  |  | ||||||
|  |   if (bytes_read == 0) { | ||||||
|  |     ESP_LOGE(TAG, "Could not read data from Ring Buffer"); | ||||||
|  |   } else if (bytes_read < NEW_SAMPLES_TO_GET * sizeof(int16_t)) { | ||||||
|  |     ESP_LOGD(TAG, "Partial Read of Data by Model"); | ||||||
|  |     ESP_LOGD(TAG, "Could only read %d bytes when required %d bytes ", bytes_read, | ||||||
|  |              (int) (NEW_SAMPLES_TO_GET * sizeof(int16_t))); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer into history stride buffer for the next | ||||||
|  |   // iteration | ||||||
|  |   memcpy((void *) (this->preprocessor_stride_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET), | ||||||
|  |          HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t)); | ||||||
|  |  | ||||||
|  |   *audio_samples = this->preprocessor_audio_buffer_; | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::generate_single_feature_(const int16_t *audio_data, const int audio_data_size, | ||||||
|  |                                              int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]) { | ||||||
|  |   TfLiteTensor *input = this->preprocessor_interperter_->input(0); | ||||||
|  |   TfLiteTensor *output = this->preprocessor_interperter_->output(0); | ||||||
|  |   std::copy_n(audio_data, audio_data_size, tflite::GetTensorData<int16_t>(input)); | ||||||
|  |  | ||||||
|  |   if (this->preprocessor_interperter_->Invoke() != kTfLiteOk) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to preprocess audio for local wake word."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   std::memcpy(feature_output, tflite::GetTensorData<int8_t>(output), PREPROCESSOR_FEATURE_SIZE * sizeof(int8_t)); | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver) { | ||||||
|  |   if (op_resolver.AddReshape() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddCast() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddStridedSlice() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddConcatenation() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddMul() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddAdd() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddDiv() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddMinimum() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddMaximum() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddWindow() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddFftAutoScale() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddRfft() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddEnergy() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddFilterBank() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddFilterBankSquareRoot() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddFilterBankSpectralSubtraction() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddPCAN() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddFilterBankLog() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver) { | ||||||
|  |   if (op_resolver.AddCallOnce() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddVarHandle() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddReshape() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddReadVariable() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddStridedSlice() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddConcatenation() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddAssignVariable() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddConv2D() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddMul() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddAdd() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddMean() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddFullyConnected() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddLogistic() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |   if (op_resolver.AddQuantize() != kTfLiteOk) | ||||||
|  |     return false; | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace micro_wake_word | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP_IDF | ||||||
|  |  | ||||||
|  | #endif  // CLANG_TIDY | ||||||
							
								
								
									
										204
									
								
								esphome/components/micro_wake_word/micro_wake_word.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								esphome/components/micro_wake_word/micro_wake_word.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This is a workaround until we can figure out a way to get | ||||||
|  |  * the tflite-micro idf component code available in CI | ||||||
|  |  * | ||||||
|  |  * */ | ||||||
|  | // | ||||||
|  | #ifndef CLANG_TIDY | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP_IDF | ||||||
|  |  | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/ring_buffer.h" | ||||||
|  |  | ||||||
|  | #include "esphome/components/microphone/microphone.h" | ||||||
|  |  | ||||||
|  | #include <tensorflow/lite/core/c/common.h> | ||||||
|  | #include <tensorflow/lite/micro/micro_interpreter.h> | ||||||
|  | #include <tensorflow/lite/micro/micro_mutable_op_resolver.h> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micro_wake_word { | ||||||
|  |  | ||||||
|  | // The following are dictated by the preprocessor model | ||||||
|  | // | ||||||
|  | // The number of features the audio preprocessor generates per slice | ||||||
|  | static const uint8_t PREPROCESSOR_FEATURE_SIZE = 40; | ||||||
|  | // How frequently the preprocessor generates a new set of features | ||||||
|  | static const uint8_t FEATURE_STRIDE_MS = 20; | ||||||
|  | // Duration of each slice used as input into the preprocessor | ||||||
|  | static const uint8_t FEATURE_DURATION_MS = 30; | ||||||
|  | // Audio sample frequency in hertz | ||||||
|  | static const uint16_t AUDIO_SAMPLE_FREQUENCY = 16000; | ||||||
|  | // The number of old audio samples that are saved to be part of the next feature window | ||||||
|  | static const uint16_t HISTORY_SAMPLES_TO_KEEP = | ||||||
|  |     ((FEATURE_DURATION_MS - FEATURE_STRIDE_MS) * (AUDIO_SAMPLE_FREQUENCY / 1000)); | ||||||
|  | // The number of new audio samples to receive to be included with the next feature window | ||||||
|  | static const uint16_t NEW_SAMPLES_TO_GET = (FEATURE_STRIDE_MS * (AUDIO_SAMPLE_FREQUENCY / 1000)); | ||||||
|  | // The total number of audio samples included in the feature window | ||||||
|  | static const uint16_t SAMPLE_DURATION_COUNT = FEATURE_DURATION_MS * AUDIO_SAMPLE_FREQUENCY / 1000; | ||||||
|  | // Number of bytes in memory needed for the preprocessor arena | ||||||
|  | static const uint32_t PREPROCESSOR_ARENA_SIZE = 9528; | ||||||
|  |  | ||||||
|  | // The following configure the streaming wake word model | ||||||
|  | // | ||||||
|  | // The number of audio slices to process before accepting a positive detection | ||||||
|  | static const uint8_t MIN_SLICES_BEFORE_DETECTION = 74; | ||||||
|  |  | ||||||
|  | // Number of bytes in memory needed for the streaming wake word model | ||||||
|  | static const uint32_t STREAMING_MODEL_ARENA_SIZE = 64000; | ||||||
|  | static const uint32_t STREAMING_MODEL_VARIABLE_ARENA_SIZE = 1024; | ||||||
|  |  | ||||||
|  | enum State { | ||||||
|  |   IDLE, | ||||||
|  |   START_MICROPHONE, | ||||||
|  |   STARTING_MICROPHONE, | ||||||
|  |   DETECTING_WAKE_WORD, | ||||||
|  |   STOP_MICROPHONE, | ||||||
|  |   STOPPING_MICROPHONE, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class MicroWakeWord : public Component { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |   void loop() override; | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  |   void start(); | ||||||
|  |   void stop(); | ||||||
|  |  | ||||||
|  |   bool is_running() const { return this->state_ != State::IDLE; } | ||||||
|  |  | ||||||
|  |   bool initialize_models(); | ||||||
|  |  | ||||||
|  |   // Increasing either of these will reduce the rate of false acceptances while increasing the false rejection rate | ||||||
|  |   void set_probability_cutoff(float probability_cutoff) { this->probability_cutoff_ = probability_cutoff; } | ||||||
|  |   void set_sliding_window_average_size(size_t size); | ||||||
|  |  | ||||||
|  |   void set_microphone(microphone::Microphone *microphone) { this->microphone_ = microphone; } | ||||||
|  |  | ||||||
|  |   Trigger<std::string> *get_wake_word_detected_trigger() const { return this->wake_word_detected_trigger_; } | ||||||
|  |  | ||||||
|  |   void set_model_start(const uint8_t *model_start) { this->model_start_ = model_start; } | ||||||
|  |   void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void set_state_(State state); | ||||||
|  |   int read_microphone_(); | ||||||
|  |  | ||||||
|  |   const uint8_t *model_start_; | ||||||
|  |   std::string wake_word_; | ||||||
|  |  | ||||||
|  |   microphone::Microphone *microphone_{nullptr}; | ||||||
|  |   Trigger<std::string> *wake_word_detected_trigger_ = new Trigger<std::string>(); | ||||||
|  |   State state_{State::IDLE}; | ||||||
|  |   HighFrequencyLoopRequester high_freq_; | ||||||
|  |  | ||||||
|  |   std::unique_ptr<RingBuffer> ring_buffer_; | ||||||
|  |  | ||||||
|  |   int16_t *input_buffer_; | ||||||
|  |  | ||||||
|  |   const tflite::Model *preprocessor_model_{nullptr}; | ||||||
|  |   const tflite::Model *streaming_model_{nullptr}; | ||||||
|  |   tflite::MicroInterpreter *streaming_interpreter_{nullptr}; | ||||||
|  |   tflite::MicroInterpreter *preprocessor_interperter_{nullptr}; | ||||||
|  |  | ||||||
|  |   std::vector<float> recent_streaming_probabilities_; | ||||||
|  |   size_t last_n_index_{0}; | ||||||
|  |  | ||||||
|  |   float probability_cutoff_{0.5}; | ||||||
|  |   size_t sliding_window_average_size_{10}; | ||||||
|  |  | ||||||
|  |   // When the wake word detection first starts or after the word has been detected once, we ignore this many audio | ||||||
|  |   // feature slices before accepting a positive detection again | ||||||
|  |   int16_t ignore_windows_{-MIN_SLICES_BEFORE_DETECTION}; | ||||||
|  |  | ||||||
|  |   uint8_t *streaming_var_arena_{nullptr}; | ||||||
|  |   uint8_t *streaming_tensor_arena_{nullptr}; | ||||||
|  |   uint8_t *preprocessor_tensor_arena_{nullptr}; | ||||||
|  |   int8_t *new_features_data_{nullptr}; | ||||||
|  |  | ||||||
|  |   tflite::MicroResourceVariables *mrv_{nullptr}; | ||||||
|  |  | ||||||
|  |   // Stores audio fed into feature generator preprocessor | ||||||
|  |   int16_t *preprocessor_audio_buffer_; | ||||||
|  |   int16_t *preprocessor_stride_buffer_; | ||||||
|  |  | ||||||
|  |   bool detected_{false}; | ||||||
|  |  | ||||||
|  |   /** Detects if wake word has been said | ||||||
|  |    * | ||||||
|  |    * If enough audio samples are available, it will generate one slice of new features. | ||||||
|  |    * If the streaming model predicts the wake word, then the nonstreaming model confirms it. | ||||||
|  |    * @param ring_Buffer Ring buffer containing raw audio samples | ||||||
|  |    * @return True if the wake word is detected, false otherwise | ||||||
|  |    */ | ||||||
|  |   bool detect_wake_word_(); | ||||||
|  |  | ||||||
|  |   /// @brief Returns true if there are enough audio samples in the buffer to generate another slice of features | ||||||
|  |   bool slice_available_(); | ||||||
|  |  | ||||||
|  |   /** Shifts previous feature slices over by one and generates a new slice of features | ||||||
|  |    * | ||||||
|  |    * @param ring_buffer ring buffer containing raw audio samples | ||||||
|  |    * @return True if a new slice of features was generated, false otherwise | ||||||
|  |    */ | ||||||
|  |   bool update_features_(); | ||||||
|  |  | ||||||
|  |   /** Generates features from audio samples | ||||||
|  |    * | ||||||
|  |    * Adapted from TFLite micro speech example | ||||||
|  |    * @param audio_data Pointer to array with the audio samples | ||||||
|  |    * @param audio_data_size The number of samples to use as input to the preprocessor model | ||||||
|  |    * @param feature_output Array that will store the features | ||||||
|  |    * @return True if successful, false otherwise. | ||||||
|  |    */ | ||||||
|  |   bool generate_single_feature_(const int16_t *audio_data, int audio_data_size, | ||||||
|  |                                 int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]); | ||||||
|  |  | ||||||
|  |   /** Performs inference over the most recent feature slice with the streaming model | ||||||
|  |    * | ||||||
|  |    * @return Probability of the wake word between 0.0 and 1.0 | ||||||
|  |    */ | ||||||
|  |   float perform_streaming_inference_(); | ||||||
|  |  | ||||||
|  |   /** Strides the audio samples by keeping the last 10 ms of the previous slice | ||||||
|  |    * | ||||||
|  |    * Adapted from the TFLite micro speech example | ||||||
|  |    * @param ring_buffer Ring buffer containing raw audio samples | ||||||
|  |    * @param audio_samples Pointer to an array that will store the strided audio samples | ||||||
|  |    * @return True if successful, false otherwise | ||||||
|  |    */ | ||||||
|  |   bool stride_audio_samples_(int16_t **audio_samples); | ||||||
|  |  | ||||||
|  |   /// @brief Returns true if successfully registered the preprocessor's TensorFlow operations | ||||||
|  |   bool register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver); | ||||||
|  |  | ||||||
|  |   /// @brief Returns true if successfully registered the streaming model's TensorFlow operations | ||||||
|  |   bool register_streaming_ops_(tflite::MicroMutableOpResolver<14> &op_resolver); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<MicroWakeWord> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->start(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class StopAction : public Action<Ts...>, public Parented<MicroWakeWord> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->stop(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class IsRunningCondition : public Condition<Ts...>, public Parented<MicroWakeWord> { | ||||||
|  |  public: | ||||||
|  |   bool check(Ts... x) override { return this->parent_->is_running(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace micro_wake_word | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP_IDF | ||||||
|  |  | ||||||
|  | #endif  // CLANG_TIDY | ||||||
							
								
								
									
										15
									
								
								tests/components/micro_wake_word/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/components/micro_wake_word/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | i2s_audio: | ||||||
|  |   i2s_lrclk_pin: GPIO18 | ||||||
|  |   i2s_bclk_pin: GPIO19 | ||||||
|  |  | ||||||
|  | microphone: | ||||||
|  |   - platform: i2s_audio | ||||||
|  |     id: echo_microphone | ||||||
|  |     i2s_din_pin: GPIO17 | ||||||
|  |     adc_type: external | ||||||
|  |     pdm: true | ||||||
|  |  | ||||||
|  | micro_wake_word: | ||||||
|  |   model: hey_jarvis | ||||||
|  |   on_wake_word_detected: | ||||||
|  |     - logger.log: "Wake word detected" | ||||||
		Reference in New Issue
	
	Block a user