aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/lib/nrfutil
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
commit4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch)
tree65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/lib/nrfutil
parent0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff)
add circuitpython code
Diffstat (limited to 'circuitpython/lib/nrfutil')
-rw-r--r--circuitpython/lib/nrfutil/README.md75
-rw-r--r--circuitpython/lib/nrfutil/binaries/win32/nrfutil.exebin0 -> 11793224 bytes
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/__main__.py303
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/codec.py76
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/slip.py115
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/test_codec.py81
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/crc16.py44
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu.py234
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport.py204
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_ble.py327
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_serial.py340
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/init_packet.py131
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/__init__.py1286
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/compat.py57
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/manifest.py239
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/model.py46
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/nrfhex.py168
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/package.py369
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/signing.py149
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_dfu_transport_serial.py136
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_init_packet.py123
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_manifest.py201
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_nrfhex.py134
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_package.py164
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_signing.py155
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/util.py179
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/exceptions.py60
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/target_registry.py121
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/test_target_registry.py90
-rw-r--r--circuitpython/lib/nrfutil/build/lib/nordicsemi/version.py33
-rw-r--r--circuitpython/lib/nrfutil/dist/nrfutil-0.5.2-py2.7.eggbin0 -> 149932 bytes
-rw-r--r--circuitpython/lib/nrfutil/license.txt27
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/__init__.pycbin0 -> 250 bytes
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/__main__.py307
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/bluetooth/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/codec.py76
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/slip.py115
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/test_codec.py81
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/crc16.py44
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/dfu.py232
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport.py204
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_ble.py327
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_serial.py337
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/init_packet.py131
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/__init__.py1286
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/compat.py57
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py239
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/model.py46
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py168
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/package.py369
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/signing.py149
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar.hex828
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar_wanted.binbin0 -> 13192 bytes
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo.hex4835
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo_wanted.binbin0 -> 73152 bytes
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foobar_wanted.binbin0 -> 86344 bytes
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/pca10028_nrf51422_xxac_blinky.binbin0 -> 676 bytes
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s130_nrf51_mini.hex894
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s132_nrf52_mini.hex910
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/key.pem5
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_dfu_transport_serial.py136
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_init_packet.py123
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_manifest.py201
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_nrfhex.py134
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_package.py164
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_signing.py155
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/util.py179
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/exceptions.py60
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/utility/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/utility/target_registry.py121
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/utility/tests/__init__.py29
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_target_registry.py90
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_targets.json17
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/version.py33
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/version.pycbin0 -> 300 bytes
-rw-r--r--circuitpython/lib/nrfutil/nrfutil.egg-info/PKG-INFO11
-rw-r--r--circuitpython/lib/nrfutil/nrfutil.egg-info/SOURCES.txt43
-rw-r--r--circuitpython/lib/nrfutil/nrfutil.egg-info/dependency_links.txt1
-rw-r--r--circuitpython/lib/nrfutil/nrfutil.egg-info/entry_points.txt4
-rw-r--r--circuitpython/lib/nrfutil/nrfutil.egg-info/not-zip-safe1
-rw-r--r--circuitpython/lib/nrfutil/nrfutil.egg-info/top_level.txt1
-rw-r--r--circuitpython/lib/nrfutil/requirements.txt5
-rw-r--r--circuitpython/lib/nrfutil/setup.py133
-rw-r--r--circuitpython/lib/nrfutil/tests/bdd/environment.py37
-rw-r--r--circuitpython/lib/nrfutil/tests/bdd/genpkg_generate_dfu_package.feature673
-rw-r--r--circuitpython/lib/nrfutil/tests/bdd/genpkg_help_information.feature10
-rw-r--r--circuitpython/lib/nrfutil/tests/bdd/steps/common_steps.py84
-rw-r--r--circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_generate_dfu_package_steps.py250
-rw-r--r--circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_help_information_steps.py64
-rw-r--r--circuitpython/lib/nrfutil/tests/bdd/steps/util.py154
-rw-r--r--circuitpython/lib/nrfutil/tests/resources/blinky.binbin0 -> 676 bytes
-rw-r--r--circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s110.hex1229
-rw-r--r--circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s130.hex1287
-rw-r--r--circuitpython/lib/nrfutil/tests/resources/dfu_test_bootloader_b.hex8
-rw-r--r--circuitpython/lib/nrfutil/tests/resources/dfu_test_softdevice_b.hex3
-rw-r--r--circuitpython/lib/nrfutil/tests/resources/test.pem5
109 files changed, 23187 insertions, 0 deletions
diff --git a/circuitpython/lib/nrfutil/README.md b/circuitpython/lib/nrfutil/README.md
new file mode 100644
index 0000000..bd49ae9
--- /dev/null
+++ b/circuitpython/lib/nrfutil/README.md
@@ -0,0 +1,75 @@
+# nrfutil
+
+`nrfutil` is a Python package that includes the nrfutil command line utility
+and the nordicsemi library.
+
+This tool can be used used with the [Adafruit nRF52 Feather](https://www.adafruit.com/product/3406)
+to flash firmware images onto the device using the simple serial port.
+
+This library is written for Python 2.7.
+
+# Installation
+
+Run the following commands to make `nrfutil` available from the command line
+or to development platforms like the Arduino IDE or CircuitPython:
+
+**Notes** : Do **NOT** install nrfutil from the pip package (ex. `sudo pip
+install nrfutil`). The latest nrfutil does not support DFU via Serial, and you
+should install version 0.5.2 from a local copy of this repo via the methods
+detailed below:
+
+### OS X and Linux
+
+```
+$ sudo pip install -r requirements.txt
+$ sudo python setup.py install
+```
+
+### Windows
+
+#### Option 1: Pre-Built Binary
+
+A pre-built 32-bit version of nrfutil is included as part of this repo in the
+`binaries/win32` folder. You can use this pre-built binary by adding it to your
+systems `$PATH` variable.
+
+#### Option 2: Build nrfutil from Source
+
+- Make sure that you have **Python 2.7** available on your system.
+- Manually install **py2exe version 0.6.9** from this link (selecting
+ the 32-bit or 64-bit version depending on your Python installation):
+ [Download py2exe 0.6.9](https://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/).
+- VC compiler for Python (Windows only) (http://www.microsoft.com/en-us/download/confirmation.aspx?id=44266)
+- From the command prompt, install nrfutil via pip as follows:
+
+```
+pip install -r requirements.txt
+python setup.py install
+```
+
+To generate a self-contained Windows exe version of the utility (Windows only):
+
+```
+python setup.py py2exe
+```
+
+# Usage
+
+To get info on usage of nrfutil:
+
+```
+nrfutil --help
+```
+
+To convert an nRF52 .hex file into a DFU pkg file that the serial bootloader
+can make use of:
+
+```
+nrfutil dfu genpkg --dev-type 0x0052 --application firmware.hex dfu-package.zip
+```
+
+To flash a DFU pkg file over serial:
+
+```
+nrfutil dfu serial --package dfu-package.zip -p /dev/tty.SLAB_USBtoUART -b 115200
+```
diff --git a/circuitpython/lib/nrfutil/binaries/win32/nrfutil.exe b/circuitpython/lib/nrfutil/binaries/win32/nrfutil.exe
new file mode 100644
index 0000000..450bb47
--- /dev/null
+++ b/circuitpython/lib/nrfutil/binaries/win32/nrfutil.exe
Binary files differ
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/__main__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/__main__.py
new file mode 100644
index 0000000..688b59b
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/__main__.py
@@ -0,0 +1,303 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""nrfutil command line tool."""
+import logging
+import os
+import click
+
+from nordicsemi.dfu.dfu import Dfu
+from nordicsemi.dfu.dfu_transport import DfuEvent
+from nordicsemi.dfu.dfu_transport_serial import DfuTransportSerial
+from nordicsemi.dfu.package import Package
+from nordicsemi import version as nrfutil_version
+from nordicsemi.dfu.signing import Signing
+from nordicsemi.dfu.util import query_func
+
+
+class nRFException(Exception):
+ pass
+
+
+def int_as_text_to_int(value):
+ try:
+ if value[:2].lower() == '0x':
+ return int(value[2:], 16)
+ elif value[:1] == '0':
+ return int(value, 8)
+ return int(value, 10)
+ except ValueError:
+ raise nRFException('%s is not a valid integer' % value)
+
+
+class BasedIntOrNoneParamType(click.ParamType):
+ name = 'Int or None'
+
+ def convert(self, value, param, ctx):
+ try:
+ if value.lower() == 'none':
+ return 'none'
+ return int_as_text_to_int(value)
+ except nRFException:
+ self.fail('%s is not a valid integer' % value, param, ctx)
+
+BASED_INT_OR_NONE = BasedIntOrNoneParamType()
+
+
+class TextOrNoneParamType(click.ParamType):
+ name = 'Text or None'
+
+ def convert(self, value, param, ctx):
+ return value
+
+TEXT_OR_NONE = TextOrNoneParamType()
+
+
+@click.group()
+@click.option('--verbose',
+ help='Show verbose information',
+ is_flag=True)
+def cli(verbose):
+ if verbose:
+ logging.basicConfig(format='%(message)s', level=logging.INFO)
+ else:
+ logging.basicConfig(format='%(message)s')
+
+
+@cli.command()
+def version():
+ """Displays nrf utility version."""
+ click.echo("nrfutil version {}".format(nrfutil_version.NRFUTIL_VERSION))
+
+
+@cli.command(short_help='Generate keys for signing or generate public keys')
+@click.argument('key_file', required=True)
+@click.option('--gen-key',
+ help='generate signing key and store at given path (pem-file)',
+ type=click.BOOL,
+ is_flag=True)
+@click.option('--show-vk',
+ help='Show the verification keys for DFU Signing (hex|code|pem)',
+ type=click.STRING)
+def keys(key_file,
+ gen_key,
+ show_vk):
+ """
+ This set of commands support creation of signing key (private) and showing the verification key (public)
+ from a previously loaded signing key. Signing key is stored in PEM format
+ """
+ if not gen_key and show_vk is None:
+ raise nRFException("Use either gen-key or show-vk.")
+
+ signer = Signing()
+
+ if gen_key:
+ if os.path.exists(key_file):
+ if not query_func("File found at %s. Do you want to overwrite the file?" % key_file):
+ click.echo('Key generation aborted')
+ return
+
+ signer.gen_key(key_file)
+ click.echo("Generated key at: %s" % key_file)
+
+ elif show_vk:
+ if not os.path.isfile(key_file):
+ raise nRFException("No key file to load at: %s" % key_file)
+
+ signer.load_key(key_file)
+ click.echo(signer.get_vk(show_vk))
+
+
+@cli.group()
+def dfu():
+ """
+ This set of commands support Nordic DFU OTA package generation for distribution to
+ applications and serial DFU.
+ """
+ pass
+
+
+@dfu.command(short_help='Generate a package for distribution to Apps supporting Nordic DFU OTA')
+@click.argument('zipfile',
+ required=True,
+ type=click.Path())
+@click.option('--application',
+ help='The application firmware file',
+ type=click.STRING)
+@click.option('--application-version',
+ help='Application version, default: 0xFFFFFFFF',
+ type=BASED_INT_OR_NONE,
+ default=str(Package.DEFAULT_APP_VERSION))
+@click.option('--bootloader',
+ help='The bootloader firmware file',
+ type=click.STRING)
+@click.option('--dev-revision',
+ help='Device revision, default: 0xFFFF',
+ type=BASED_INT_OR_NONE,
+ default=str(Package.DEFAULT_DEV_REV))
+@click.option('--dev-type',
+ help='Device type, default: 0xFFFF',
+ type=BASED_INT_OR_NONE,
+ default=str(Package.DEFAULT_DEV_TYPE))
+@click.option('--dfu-ver',
+ help='DFU packet version to use, default: 0.5',
+ type=click.FLOAT,
+ default=Package.DEFAULT_DFU_VER)
+@click.option('--sd-req',
+ help='SoftDevice requirement. A list of SoftDevice versions (1 or more)'
+ 'of which one is required to be present on the target device.'
+ 'Example: --sd-req 0x4F,0x5A. Default: 0xFFFE.',
+ type=TEXT_OR_NONE,
+ default=str(Package.DEFAULT_SD_REQ[0]))
+@click.option('--softdevice',
+ help='The SoftDevice firmware file',
+ type=click.STRING)
+@click.option('--key-file',
+ help='Signing key (pem fomat)',
+ type=click.Path(exists=True, resolve_path=True, file_okay=True, dir_okay=False))
+def genpkg(zipfile,
+ application,
+ application_version,
+ bootloader,
+ dev_revision,
+ dev_type,
+ dfu_ver,
+ sd_req,
+ softdevice,
+ key_file):
+ """
+ Generate a zipfile package for distribution to Apps supporting Nordic DFU OTA.
+ The application, bootloader and softdevice files are converted to .bin if it is a .hex file.
+ For more information on the generated init packet see:
+ http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00065.html
+ """
+ zipfile_path = zipfile
+
+ if application_version == 'none':
+ application_version = None
+
+ if dev_revision == 'none':
+ dev_revision = None
+
+ if dev_type == 'none':
+ dev_type = None
+
+ sd_req_list = None
+
+ if sd_req.lower() == 'none':
+ sd_req_list = []
+ elif sd_req:
+ try:
+ # This will parse any string starting with 0x as base 16.
+ sd_req_list = sd_req.split(',')
+ sd_req_list = map(int_as_text_to_int, sd_req_list)
+ except ValueError:
+ raise nRFException("Could not parse value for --sd-req. "
+ "Hex values should be prefixed with 0x.")
+
+ if key_file and dfu_ver < 0.8:
+ click.echo("Key file was given, setting DFU version to 0.8")
+
+ package = Package(dev_type,
+ dev_revision,
+ application_version,
+ sd_req_list,
+ application,
+ bootloader,
+ softdevice,
+ dfu_ver,
+ key_file)
+
+ package.generate_package(zipfile_path)
+
+ log_message = "Zip created at {0}".format(zipfile_path)
+ click.echo(log_message)
+
+
+global_bar = None
+
+
+def update_progress(progress=0, done=False, log_message=""):
+ del done, log_message # Unused parameters
+ #global global_bar
+ #if global_bar is None:
+ # with click.progressbar(length=100) as bar:
+ # global_bar = bar
+ #global_bar.update(max(1, progress))
+ click.echo('#', nl=False)
+
+
+@dfu.command(short_help="Program a device with bootloader that support serial DFU")
+@click.option('-pkg', '--package',
+ help='DFU package filename',
+ type=click.Path(exists=True, resolve_path=True, file_okay=True, dir_okay=False),
+ required=True)
+@click.option('-p', '--port',
+ help='Serial port COM Port to which the device is connected',
+ type=click.STRING,
+ required=True)
+@click.option('-b', '--baudrate',
+ help='Desired baud rate 38400/96000/115200/230400/250000/460800/921600/1000000 (default: 38400). '
+ 'Note: Physical serial ports (e.g. COM1) typically do not support baud rates > 115200',
+ type=click.INT,
+ default=DfuTransportSerial.DEFAULT_BAUD_RATE)
+@click.option('-fc', '--flowcontrol',
+ help='Enable flow control, default: disabled',
+ type=click.BOOL,
+ is_flag=True)
+def serial(package, port, baudrate, flowcontrol):
+ """Program a device with bootloader that support serial DFU"""
+ serial_backend = DfuTransportSerial(port, baudrate, flowcontrol)
+ serial_backend.register_events_callback(DfuEvent.PROGRESS_EVENT, update_progress)
+ dfu = Dfu(package, dfu_transport=serial_backend)
+
+ click.echo("Upgrading target on {1} with DFU package {0}. Flow control is {2}."
+ .format(package, port, "enabled" if flowcontrol else "disabled"))
+
+ try:
+ dfu.dfu_send_images()
+
+ except Exception as e:
+ click.echo("")
+ click.echo("Failed to upgrade target. Error is: {0}".format(e.message))
+ click.echo("")
+ click.echo("Possible causes:")
+ click.echo("- Bootloader, SoftDevice or Application on target "
+ "does not match the requirements in the DFU package.")
+ click.echo("- Baud rate must be 115200, Flow control must be off.")
+ click.echo("- Target is not in DFU mode. Ground DFU pin and RESET and release both to enter DFU mode.")
+
+ return False
+
+ click.echo("Device programmed.")
+
+ return True
+
+
+if __name__ == '__main__':
+ cli()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/codec.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/codec.py
new file mode 100644
index 0000000..bebd790
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/codec.py
@@ -0,0 +1,76 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UART_HEADER_OCTET_COUNT = 4
+
+
+class ThreeWireUartPacket(object):
+ """
+ This class encapsulate a three wire uart packet according to Bluetooth specification
+ version 4.0 [Vol 4] part D.
+ """
+ def __init__(self):
+ self.ack = None # Acknowledgement number
+ self.seq = None # Sequence number
+ self.di = None # Data integrity present
+ self.rp = None # Reliable packet
+ self.type = None # Packet type
+ self.length = None # Payload Length
+ self.checksum = None # Header checksum
+ self.payload = None # Payload
+
+ @staticmethod
+ def decode(packet):
+ """
+ Decodes a packet from a str encoded array
+
+ :param packet_bytes: A str encoded array
+ :return: TheeWireUartPacket
+ """
+
+ decoded_packet = ThreeWireUartPacket()
+
+ packet_bytes = bytearray(packet)
+
+ decoded_packet.ack = (packet_bytes[0] & int('38', 16)) >> 3
+ decoded_packet.seq = (packet_bytes[0] & int('07', 16))
+ decoded_packet.di = (packet_bytes[0] & int('40', 16)) >> 6
+ decoded_packet.rp = (packet_bytes[0] & int('80', 16)) >> 7
+ decoded_packet.type = (packet_bytes[1] & int('0F', 16))
+ decoded_packet.length = ((packet_bytes[1] & int('F0', 16)) >> 4) + (packet_bytes[2] * 16)
+
+ checksum = packet_bytes[0]
+ checksum = checksum + packet_bytes[1]
+ checksum = checksum + packet_bytes[2]
+ checksum &= int('FF', 16)
+ decoded_packet.checksum = (~checksum + 1) & int('FF', 16)
+
+ if decoded_packet.length > 0:
+ decoded_packet.payload = packet_bytes[UART_HEADER_OCTET_COUNT:-1]
+
+ return decoded_packet
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/slip.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/slip.py
new file mode 100644
index 0000000..e2a525f
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/slip.py
@@ -0,0 +1,115 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class Slip(object):
+ def __init__(self):
+ self.SLIP_END = '\xc0'
+ self.SLIP_ESC = '\xdb'
+ self.SLIP_ESC_END = '\xdc'
+ self.SLIP_ESC_ESC = '\xdd'
+
+ self.started = False
+ self.escaped = False
+ self.stream = ''
+ self.packet = ''
+
+ def append(self, data):
+ """
+ Append a new
+ :param data: Append a new block of data to do decoding on when calling decode.
+ The developer may add more than one SLIP packet before calling decode.
+ :return:
+ """
+ self.stream += data
+
+ def decode(self):
+ """
+ Decodes a package according to http://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol
+ :return Slip: A list of decoded slip packets
+ """
+ packet_list = list()
+
+ for char in self.stream:
+ if char == self.SLIP_END:
+ if self.started:
+ if len(self.packet) > 0:
+ self.started = False
+ packet_list.append(self.packet)
+ self.packet = ''
+ else:
+ self.started = True
+ self.packet = ''
+ elif char == self.SLIP_ESC:
+ self.escaped = True
+ elif char == self.SLIP_ESC_END:
+ if self.escaped:
+ self.packet += self.SLIP_END
+ self.escaped = False
+ else:
+ self.packet += char
+ elif char == self.SLIP_ESC_ESC:
+ if self.escaped:
+ self.packet += self.SLIP_ESC
+ self.escaped = False
+ else:
+ self.packet += char
+ else:
+ if self.escaped:
+ logging.error("Error in SLIP packet, ignoring error.")
+ self.packet = ''
+ self.escaped = False
+ else:
+ self.packet += char
+
+ self.stream = ''
+
+ return packet_list
+
+ def encode(self, packet):
+ """
+ Encode a packet according to SLIP.
+ :param packet: A str array that represents the package
+ :return: str array with an encoded SLIP packet
+ """
+ encoded = self.SLIP_END
+
+ for char in packet:
+ if char == self.SLIP_END:
+ encoded += self.SLIP_ESC + self.SLIP_ESC_END
+ elif char == self.SLIP_ESC:
+ encoded += self.SLIP_ESC + self.SLIP_ESC_ESC
+ else:
+ encoded += char
+ encoded += self.SLIP_END
+
+ return encoded
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/test_codec.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/test_codec.py
new file mode 100644
index 0000000..c7d6f26
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/bluetooth/hci/tests/test_codec.py
@@ -0,0 +1,81 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json
+import unittest
+from nordicsemi.bluetooth.hci.slip import Slip
+from nordicsemi.bluetooth.hci import codec
+
+
+class TestInitPacket(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def test_decode_packet(self):
+ # TODO: extend this test, this tests only a small portion of the slip/hci decoding
+ # These are packets read from Device Monitoring Studio
+ # during communication between serializer application and firmware
+ read_packets = [
+ " C0 10 00 00 F0 C0 C0 D1 6E 00 C1 01 86 00 00 00 00 17 63 C0",
+ " C0 D2 DE 02 4E 02 1B 00 FF FF 01 17 FE B4 9A 9D E1 B0 F8 02"
+ " 01 06 11 07 1B C5 D5 A5 02 00 A9 B7 E2 11 A4 C6 00 FE E7 74"
+ " 09 09 49 44 54 57 32 31 38 48 5A BB C0",
+ " C0 D3 EE 00 3F 02 1B 00 FF FF 01 17 FE B4 9A 9D E1 AF 01 F1 62 C0",
+ " C0 D4 DE 02 4C 02 1B 00 FF FF 01 17 FE B4 9A 9D E1 B1 F8 02 01 06"
+ " 11 07 1B C5 D5 A5 02 00 A9 B7 E2 11 A4 C6 00 FE E7 74 09 09 49 44 54 57 32 31 38 48 6E C8 C0"
+ ]
+
+ slip = Slip()
+ output = list()
+
+ for uart_packet in read_packets:
+ hex_string = uart_packet.replace(" ", "")
+ hex_data = hex_string.decode("hex")
+ slip.append(hex_data)
+
+ packets = slip.decode()
+
+ for packet in packets:
+ output.append(codec.ThreeWireUartPacket.decode(packet))
+
+ self.assertEqual(len(output), 5)
+
+ packet_index = 0
+ self.assertEqual(output[packet_index].seq, 0)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 1)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 2)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 3)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 4)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/crc16.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/crc16.py
new file mode 100644
index 0000000..2db4af6
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/crc16.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+def calc_crc16(binary_data, crc=0xffff):
+ """
+ Calculates CRC16 on binary_data
+
+ :param int crc: CRC value to start calculation with
+ :param bytearray binary_data: Array with data to run CRC16 calculation on
+ :return int: Calculated CRC value of binary_data
+ """
+
+ for b in binary_data:
+ crc = (crc >> 8 & 0x00FF) | (crc << 8 & 0xFF00)
+ crc ^= ord(b)
+ crc ^= (crc & 0x00FF) >> 4
+ crc ^= (crc << 8) << 4
+ crc ^= ((crc & 0x00FF) << 4) << 1
+ return crc & 0xFFFF
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu.py
new file mode 100644
index 0000000..a839159
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu.py
@@ -0,0 +1,234 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python standard library
+import os
+import tempfile
+import shutil
+import logging
+from time import time, sleep
+from datetime import datetime, timedelta
+
+# Nordic libraries
+from nordicsemi.exceptions import *
+from nordicsemi.dfu.package import Package
+from nordicsemi.dfu.dfu_transport import DfuEvent
+from nordicsemi.dfu.model import HexType
+from nordicsemi.dfu.manifest import SoftdeviceBootloaderFirmware
+
+logger = logging.getLogger(__name__)
+
+
+class Dfu(object):
+ """ Class to handle upload of a new hex image to the device. """
+
+ def __init__(self, zip_file_path, dfu_transport):
+ """
+ Initializes the dfu upgrade, unpacks zip and registers callbacks.
+
+ @param zip_file_path: Path to the zip file with the firmware to upgrade
+ @type zip_file_path: str
+ @param dfu_transport: Transport backend to use to upgrade
+ @type dfu_transport: nordicsemi.dfu.dfu_transport.DfuTransport
+ @return
+ """
+ self.zip_file_path = zip_file_path
+ self.ready_to_send = True
+ self.response_opcode_received = None
+
+ self.temp_dir = tempfile.mkdtemp(prefix="nrf_dfu_")
+ self.unpacked_zip_path = os.path.join(self.temp_dir, 'unpacked_zip')
+ self.manifest = Package.unpack_package(self.zip_file_path, self.unpacked_zip_path)
+
+ if dfu_transport:
+ self.dfu_transport = dfu_transport
+
+ self.dfu_transport.register_events_callback(DfuEvent.TIMEOUT_EVENT, self.timeout_event_handler)
+ self.dfu_transport.register_events_callback(DfuEvent.ERROR_EVENT, self.error_event_handler)
+
+ def __del__(self):
+ """
+ Destructor removes the temporary directory for the unpacked zip
+ :return:
+ """
+ shutil.rmtree(self.temp_dir)
+
+ def error_event_handler(self, log_message=""):
+ """
+ Event handler for errors, closes the transport backend.
+ :param str log_message: The log message for the error.
+ :return:
+ """
+ if self.dfu_transport.is_open():
+ self.dfu_transport.close()
+
+ logger.error(log_message)
+
+ def timeout_event_handler(self, log_message):
+ """
+ Event handler for timeouts, closes the transport backend.
+ :param log_message: The log message for the timeout.
+ :return:
+ """
+ if self.dfu_transport.is_open():
+ self.dfu_transport.close()
+
+ logger.error(log_message)
+
+ @staticmethod
+ def _read_file(file_path):
+ """
+ Reads a file and returns the content as a string.
+
+ :param str file_path: The path to the file to read.
+ :return str: Content of the file.
+ """
+ buffer_size = 4096
+
+ file_content = ""
+
+ with open(file_path, 'rb') as binary_file:
+ while True:
+ data = binary_file.read(buffer_size)
+
+ if data:
+ file_content += data
+ else:
+ break
+
+ return file_content
+
+ def _wait_while_opening_transport(self):
+ timeout = 10
+ start_time = datetime.now()
+
+ while not self.dfu_transport.is_open():
+ timed_out = datetime.now() - start_time > timedelta(0, timeout)
+
+ if timed_out:
+ log_message = "Failed to open transport backend"
+ raise NordicSemiException(log_message)
+
+ sleep(0.1)
+
+
+ def _dfu_send_image(self, program_mode, firmware_manifest):
+ """
+ Does DFU for one image. Reads the firmware image and init file.
+ Opens the transport backend, calls setup, send and finalize and closes the backend again.
+ @param program_mode: What type of firmware the DFU is
+ @type program_mode: nordicsemi.dfu.model.HexType
+ @param firmware_manifest: The manifest for the firmware image
+ @type firmware_manifest: nordicsemi.dfu.manifest.Firmware
+ @return:
+ """
+
+ if firmware_manifest is None:
+ raise MissingArgumentException("firmware_manifest must be provided.")
+
+ if self.dfu_transport.is_open():
+ raise IllegalStateException("Transport is already open.")
+
+ self.dfu_transport.open()
+ self._wait_while_opening_transport()
+
+ softdevice_size = 0
+ bootloader_size = 0
+ application_size = 0
+
+ bin_file_path = os.path.join(self.unpacked_zip_path, firmware_manifest.bin_file)
+ firmware = self._read_file(bin_file_path)
+
+ dat_file_path = os.path.join(self.unpacked_zip_path, firmware_manifest.dat_file)
+ init_packet = self._read_file(dat_file_path)
+
+ if program_mode == HexType.SD_BL:
+ if not isinstance(firmware_manifest, SoftdeviceBootloaderFirmware):
+ raise NordicSemiException("Wrong type of manifest")
+ softdevice_size = firmware_manifest.sd_size
+ bootloader_size = firmware_manifest.bl_size
+ firmware_size = len(firmware)
+ if softdevice_size + bootloader_size != firmware_size:
+ raise NordicSemiException(
+ "Size of bootloader ({} bytes) and softdevice ({} bytes)"
+ " is not equal to firmware provided ({} bytes)".format(
+ bootloader_size, softdevice_size, firmware_size))
+
+ elif program_mode == HexType.SOFTDEVICE:
+ softdevice_size = len(firmware)
+
+ elif program_mode == HexType.BOOTLOADER:
+ bootloader_size = len(firmware)
+
+ elif program_mode == HexType.APPLICATION:
+ application_size = len(firmware)
+
+ start_time = time()
+ logger.info("Starting DFU upgrade of type %s, SoftDevice size: %s, bootloader size: %s, application size: %s",
+ program_mode,
+ softdevice_size,
+ bootloader_size,
+ application_size)
+
+ #logger.info("Sending DFU start packet, afterwards we wait for the flash on "
+ # "target to be initialized before continuing.")
+ logger.info("Sending DFU start packet")
+ self.dfu_transport.send_start_dfu(program_mode, softdevice_size, bootloader_size,
+ application_size)
+
+ logger.info("Sending DFU init packet")
+ self.dfu_transport.send_init_packet(init_packet)
+
+ logger.info("Sending firmware file")
+ self.dfu_transport.send_firmware(firmware)
+
+ self.dfu_transport.send_validate_firmware()
+
+ self.dfu_transport.send_activate_firmware()
+
+ end_time = time()
+ logger.info("\nDFU upgrade took {0}s".format(end_time - start_time))
+
+ self.dfu_transport.close()
+
+ def dfu_send_images(self):
+ """
+ Does DFU for all firmware images in the stored manifest.
+ :return:
+ """
+ if self.manifest.softdevice_bootloader:
+ self._dfu_send_image(HexType.SD_BL, self.manifest.softdevice_bootloader)
+
+ if self.manifest.softdevice:
+ self._dfu_send_image(HexType.SOFTDEVICE, self.manifest.softdevice)
+
+ if self.manifest.bootloader:
+ self._dfu_send_image(HexType.BOOTLOADER, self.manifest.bootloader)
+
+ if self.manifest.application:
+ self._dfu_send_image(HexType.APPLICATION, self.manifest.application)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport.py
new file mode 100644
index 0000000..67c4354
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport.py
@@ -0,0 +1,204 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python specific imports
+import abc
+import logging
+
+# Nordic Semiconductor imports
+from nordicsemi.dfu.util import int32_to_bytes
+
+logger = logging.getLogger(__name__)
+
+
+class DfuEvent:
+ PROGRESS_EVENT = 1
+ TIMEOUT_EVENT = 2
+ ERROR_EVENT = 3
+
+
+class DfuTransport(object):
+ """
+ This class as an abstract base class inherited from when implementing transports.
+
+ The class is generic in nature, the underlying implementation may have missing semantic
+ than this class describes. But the intent is that the implementer shall follow the semantic as
+ best as she can.
+ """
+ __metaclass__ = abc.ABCMeta
+
+ @staticmethod
+ def create_image_size_packet(softdevice_size=0, bootloader_size=0, app_size=0):
+ """
+ Creates an image size packet necessary for sending start dfu.
+
+ @param softdevice_size: Size of SoftDevice firmware
+ @type softdevice_size: int
+ @param bootloader_size: Size of bootloader firmware
+ @type softdevice_size: int
+ @param app_size: Size of application firmware
+ :return: The image size packet
+ :rtype: str
+ """
+ softdevice_size_packet = int32_to_bytes(softdevice_size)
+ bootloader_size_packet = int32_to_bytes(bootloader_size)
+ app_size_packet = int32_to_bytes(app_size)
+ image_size_packet = softdevice_size_packet + bootloader_size_packet + app_size_packet
+ return image_size_packet
+
+ @abc.abstractmethod
+ def __init__(self):
+ self.callbacks = {}
+
+ @abc.abstractmethod
+ def open(self):
+ """
+ Open a port if appropriate for the transport.
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def close(self):
+ """
+ Close a port if appropriate for the transport.
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def is_open(self):
+ """
+ Returns if transport is open.
+
+ :return bool: True if transport is open, False if not
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_start_dfu(self, program_mode, softdevice_size=0, bootloader_size=0, app_size=0):
+ """
+ Send packet to initiate DFU communication. Returns when packet is sent or timeout occurs.
+
+ This call will block until packet is sent.
+ If timeout or errors occurs exception is thrown.
+
+ :param nordicsemi.dfu.model.HexType program_mode: Type of firmware to upgrade
+ :param int softdevice_size: Size of softdevice firmware
+ :param int bootloader_size: Size of bootloader firmware
+ :param int app_size: Size of application firmware
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_init_packet(self, init_packet):
+ """
+ Send init_packet to device.
+
+ This call will block until init_packet is sent and transfer of packet is complete.
+ If timeout or errors occurs exception is thrown.
+
+ :param str init_packet: Init packet as a str.
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_firmware(self, firmware):
+ """
+ Start sending firmware to device.
+
+ This call will block until transfer of firmware is complete.
+ If timeout or errors occurs exception is thrown.
+
+ :param str firmware:
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_validate_firmware(self):
+ """
+ Send request to device to verify that firmware has been correctly transferred.
+
+ This call will block until validation is sent and validation is complete.
+ If timeout or errors occurs exception is thrown.
+
+ :return bool: True if firmware validated successfully.
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_activate_firmware(self):
+ """
+ Send command to device to activate new firmware and restart the device.
+ The device will start up with the new firmware.
+
+ Raises an nRFException if anything fails.
+
+ :return:
+ """
+ pass
+
+ def register_events_callback(self, event_type, callback):
+ """
+ Register a callback.
+
+ :param DfuEvent callback:
+ :return: None
+ """
+ if event_type not in self.callbacks:
+ self.callbacks[event_type] = []
+
+ self.callbacks[event_type].append(callback)
+
+ def unregister_events_callback(self, callback):
+ """
+ Unregister a callback.
+
+ :param callback: # TODO: add documentation for callback
+ :return: None
+ """
+ for event_type in self.callbacks.keys():
+ if callback in self.callbacks[event_type]:
+ self.callbacks[event_type].remove(callback)
+
+ def _send_event(self, event_type, **kwargs):
+ """
+ Method for sending events to registered callbacks.
+
+ If callbacks throws exceptions event propagation will stop and this method be part of the track trace.
+
+ :param DfuEvent event_type:
+ :param args: Arguments to callback function
+ :return:
+ """
+ if event_type in self.callbacks.keys():
+ for callback in self.callbacks[event_type]:
+ callback(**kwargs)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_ble.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_ble.py
new file mode 100644
index 0000000..ff56750
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_ble.py
@@ -0,0 +1,327 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python standard library
+from time import sleep
+from datetime import datetime, timedelta
+import abc
+import logging
+
+# Nordic libraries
+from nordicsemi.exceptions import NordicSemiException, IllegalStateException
+from nordicsemi.dfu.util import int16_to_bytes
+from nordicsemi.dfu.dfu_transport import DfuTransport, DfuEvent
+
+logger = logging.getLogger(__name__)
+
+
+# BLE DFU OpCodes :
+class DfuOpcodesBle(object):
+ """ DFU opcodes used during DFU communication with bootloader
+
+ See http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00949.html#gafa9a52a3e6c43ccf00cf680f944d67a3
+ for further information
+ """
+ INVALID_OPCODE = 0
+ START_DFU = 1
+ INITIALIZE_DFU = 2
+ RECEIVE_FIRMWARE_IMAGE = 3
+ VALIDATE_FIRMWARE_IMAGE = 4
+ ACTIVATE_FIRMWARE_AND_RESET = 5
+ SYSTEM_RESET = 6
+ REQ_PKT_RCPT_NOTIFICATION = 8
+ RESPONSE = 16
+ PKT_RCPT_NOTIF = 17
+
+
+class DfuErrorCodeBle(object):
+ """ DFU error code used during DFU communication with bootloader
+
+ See http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00949.html#gafa9a52a3e6c43ccf00cf680f944d67a3
+ for further information
+ """
+ SUCCESS = 1
+ INVALID_STATE = 2
+ NOT_SUPPORTED = 3
+ DATA_SIZE_EXCEEDS_LIMIT = 4
+ CRC_ERROR = 5
+ OPERATION_FAILED = 6
+
+ @staticmethod
+ def error_code_lookup(error_code):
+ """
+ Returns a description lookup table for error codes received from peer.
+
+ :param int error_code: Error code to parse
+ :return str: Textual description of the error code
+ """
+ code_lookup = {DfuErrorCodeBle.SUCCESS: "SUCCESS",
+ DfuErrorCodeBle.INVALID_STATE: "Invalid State",
+ DfuErrorCodeBle.NOT_SUPPORTED: "Not Supported",
+ DfuErrorCodeBle.DATA_SIZE_EXCEEDS_LIMIT: "Data Size Exceeds Limit",
+ DfuErrorCodeBle.CRC_ERROR: "CRC Error",
+ DfuErrorCodeBle.OPERATION_FAILED: "Operation Failed"}
+
+ return code_lookup.get(error_code, "UNKOWN ERROR CODE")
+
+# Service UUID. For further information, look at the nRF51 SDK documentation V7.2.0:
+# http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00071.html#ota_spec_number
+UUID_DFU_SERVICE = '000015301212EFDE1523785FEABCD123'
+# Characteristic UUID
+UUID_DFU_PACKET_CHARACTERISTIC = '000015321212EFDE1523785FEABCD123'
+UUID_DFU_CONTROL_STATE_CHARACTERISTIC = '000015311212EFDE1523785FEABCD123'
+# Descriptor UUID
+UUID_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR = 0x2902
+
+# NOTE: If packet receipt notification is enabled, a packet receipt
+# notification will be received for each 'num_of_packets_between_notif'
+# number of packets.
+#
+# Configuration tip: Increase this to get lesser notifications from the DFU
+# Target about packet receipts. Make it 0 to disable the packet receipt
+# notification
+
+NUM_OF_PACKETS_BETWEEN_NOTIF = 10
+DATA_PACKET_SIZE = 20
+
+
+class DfuTransportBle(DfuTransport):
+
+ def __init__(self):
+ super(DfuTransportBle, self).__init__()
+
+ def open(self):
+ super(DfuTransportBle, self).open()
+
+ def is_open(self):
+ return super(DfuTransportBle, self).is_open()
+
+ def close(self):
+ super(DfuTransportBle, self).close()
+
+ def _wait_for_condition(self, condition_function, expected_condition_value=True, timeout=10,
+ waiting_for="condition"):
+ """
+ Waits for condition_function to be true
+ Will timeout after 60 seconds
+
+ :param function condition_function: The function we are waiting for to return true
+ :param str timeout_message: Message that should be logged
+ :return:
+ """
+
+ start_time = datetime.now()
+
+ while condition_function() != expected_condition_value:
+ timeout_message = "Timeout while waiting for {0}.".format(waiting_for)
+ timed_out = datetime.now() - start_time > timedelta(0, timeout)
+ if timed_out:
+ self._send_event(DfuEvent.TIMEOUT_EVENT, log_message=timeout_message)
+ raise NordicSemiException(timeout_message)
+
+ if not self.is_open():
+ log_message = "Disconnected from device while waiting for {0}.".format(waiting_for)
+ raise IllegalStateException(log_message)
+
+ sleep(0.1)
+
+ if self.get_last_error() != DfuErrorCodeBle.SUCCESS:
+ error_message = "Error occoured while waiting for {0}. Error response {1}."
+ error_code = DfuErrorCodeBle.error_code_lookup(self.get_last_error())
+ error_message = error_message.format(waiting_for, error_code)
+ self._send_event(DfuEvent.ERROR_EVENT, log_message=error_message)
+ raise NordicSemiException(error_message)
+
+ @abc.abstractmethod
+ def send_packet_data(self, data):
+ """
+ Send data to the packet characteristic
+
+ :param str data: The data to be sent
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_control_data(self, opcode, data=""):
+ """
+ Send data to the control characteristic
+
+ :param int opcode: The opcode for the operation command sent to the control characteristic
+ :param str data: The data to be sent
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def get_received_response(self):
+ """
+ Returns True if the transport layer has received a response it expected
+
+ :return: bool
+ """
+ pass
+
+ def clear_received_response(self):
+ """
+ Clears the received response status, sets it to False.
+
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def is_waiting_for_notification(self):
+ """
+ Returns True if the transport layer is waiting for a notification
+
+ :return: bool
+ """
+ pass
+
+ def set_waiting_for_notification(self):
+ """
+ Notifies the transport layer that it should wait for notification
+
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def get_last_error(self):
+ """
+ Returns the last error code
+
+ :return: DfuErrorCodeBle
+ """
+ pass
+
+ def _start_dfu(self, program_mode, image_size_packet):
+ logger.debug("Sending 'START DFU' command")
+ self.send_control_data(DfuOpcodesBle.START_DFU, chr(program_mode))
+ logger.debug("Sending image size")
+ self.send_packet_data(image_size_packet)
+ self._wait_for_condition(self.get_received_response, waiting_for="response for START DFU")
+ self.clear_received_response()
+
+ def send_start_dfu(self, program_mode, softdevice_size=0, bootloader_size=0, app_size=0):
+ super(DfuTransportBle, self).send_start_dfu(program_mode, softdevice_size, bootloader_size, app_size)
+ image_size_packet = DfuTransport.create_image_size_packet(softdevice_size, bootloader_size, app_size)
+
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=0, log_message="Setting up transfer...")
+
+ try:
+ self._start_dfu(program_mode, image_size_packet)
+ except IllegalStateException:
+ # We got disconnected. Try to send Start DFU again in case of buttonless dfu.
+ self.close()
+ self.open()
+
+ if not self.is_open():
+ raise IllegalStateException("Failed to reopen transport backend.")
+
+ self._start_dfu(program_mode, image_size_packet)
+
+ def send_init_packet(self, init_packet):
+ super(DfuTransportBle, self).send_init_packet(init_packet)
+ init_packet_start = chr(0x00)
+ init_packet_end = chr(0x01)
+
+ logger.debug("Sending 'INIT DFU' command")
+ self.send_control_data(DfuOpcodesBle.INITIALIZE_DFU, init_packet_start)
+
+ logger.debug("Sending init data")
+ for i in range(0, len(init_packet), DATA_PACKET_SIZE):
+ data_to_send = init_packet[i:i + DATA_PACKET_SIZE]
+ self.send_packet_data(data_to_send)
+
+ logger.debug("Sending 'Init Packet Complete' command")
+ self.send_control_data(DfuOpcodesBle.INITIALIZE_DFU, init_packet_end)
+ self._wait_for_condition(self.get_received_response, timeout=60, waiting_for="response for INITIALIZE DFU")
+ self.clear_received_response()
+
+ if NUM_OF_PACKETS_BETWEEN_NOTIF:
+ packet = int16_to_bytes(NUM_OF_PACKETS_BETWEEN_NOTIF)
+ logger.debug("Send number of packets before device sends notification")
+ self.send_control_data(DfuOpcodesBle.REQ_PKT_RCPT_NOTIFICATION, packet)
+
+ def send_firmware(self, firmware):
+ def progress_percentage(part, complete):
+ """
+ Calculate progress percentage
+ :param int part: Part value
+ :param int complete: Completed value
+ :return: int: Percentage complete
+ """
+ return min(100, (part + DATA_PACKET_SIZE) * 100 / complete)
+
+ super(DfuTransportBle, self).send_firmware(firmware)
+ packets_sent = 0
+ last_progress_update = -1 # Last packet sequence number when an update was fired to the event system
+ bin_size = len(firmware)
+ logger.debug("Send 'RECEIVE FIRMWARE IMAGE' command")
+ self.send_control_data(DfuOpcodesBle.RECEIVE_FIRMWARE_IMAGE)
+
+ for i in range(0, bin_size, DATA_PACKET_SIZE):
+ progress = progress_percentage(i, bin_size)
+
+ if progress != last_progress_update:
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=progress, log_message="Uploading firmware")
+ last_progress_update = progress
+
+ self._wait_for_condition(self.is_waiting_for_notification, expected_condition_value=False,
+ waiting_for="notification from device")
+
+ data_to_send = firmware[i:i + DATA_PACKET_SIZE]
+
+ log_message = "Sending Firmware bytes [{0}, {1}]".format(i, i + len(data_to_send))
+ logger.debug(log_message)
+
+ packets_sent += 1
+
+ if NUM_OF_PACKETS_BETWEEN_NOTIF != 0:
+ if (packets_sent % NUM_OF_PACKETS_BETWEEN_NOTIF) == 0:
+ self.set_waiting_for_notification()
+
+ self.send_packet_data(data_to_send)
+
+ self._wait_for_condition(self.get_received_response, waiting_for="response for RECEIVE FIRMWARE IMAGE")
+ self.clear_received_response()
+
+ def send_validate_firmware(self):
+ super(DfuTransportBle, self).send_validate_firmware()
+ logger.debug("Sending 'VALIDATE FIRMWARE IMAGE' command")
+ self.send_control_data(DfuOpcodesBle.VALIDATE_FIRMWARE_IMAGE)
+ self._wait_for_condition(self.get_received_response, waiting_for="response for VALIDATE FIRMWARE IMAGE")
+ self.clear_received_response()
+ logger.info("Firmware validated OK.")
+
+ def send_activate_firmware(self):
+ super(DfuTransportBle, self).send_activate_firmware()
+ logger.debug("Sending 'ACTIVATE FIRMWARE AND RESET' command")
+ self.send_control_data(DfuOpcodesBle.ACTIVATE_FIRMWARE_AND_RESET)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_serial.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_serial.py
new file mode 100644
index 0000000..d94c700
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/dfu_transport_serial.py
@@ -0,0 +1,340 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python imports
+import time
+from datetime import datetime, timedelta
+import binascii
+import logging
+
+# Python 3rd party imports
+from serial import Serial
+
+# Nordic Semiconductor imports
+from nordicsemi.dfu.util import slip_parts_to_four_bytes, slip_encode_esc_chars, int16_to_bytes, int32_to_bytes
+from nordicsemi.dfu import crc16
+from nordicsemi.exceptions import NordicSemiException
+from nordicsemi.dfu.dfu_transport import DfuTransport, DfuEvent
+
+
+logger = logging.getLogger(__name__)
+
+
+class DfuTransportSerial(DfuTransport):
+
+ DEFAULT_BAUD_RATE = 115200
+ DEFAULT_FLOW_CONTROL = False
+ DEFAULT_SERIAL_PORT_TIMEOUT = 1.0 # Timeout time on serial port read
+ SERIAL_PORT_OPEN_WAIT_TIME = 0.1
+ NRF52_RESET_WAIT_TIME = 0.1
+ ACK_PACKET_TIMEOUT = 1.0 # Timeout time for for ACK packet received before reporting timeout through event system
+ SEND_INIT_PACKET_WAIT_TIME = 0.5 # 1.0 # Time to wait before communicating with bootloader after init packet is sent
+
+ # SEND_START_DFU_WAIT_TIME = 10.0 # Time to wait before communicating with bootloader after start DFU packet is sent
+ # ADADFRUIT:
+ # - After Start packet is sent, nrf5x will start to erase flash page, each page takes 2.05 - 89.7 ms
+ # nrfutil need to wait accordingly for the image size, but not less than this value (0.5) second
+ # - Afterwards, command to activate new firmware --> nrf52 erase bank0 and copy image from bank1 to bank 0
+ # nrfutil need to wait otherwise and re-open serial could cause flash corruption
+
+ SEND_START_DFU_MIN_WAIT_TIME = 0.5
+
+ FLASH_PAGE_ERASE_MAX_TIME = 0.09 # Worst time to erase a page 90 ms (89 ms)
+ FLASH_PAGE_ERASE_MIN_TIME = 0.00205 # Best time to erase a page 2.05 ms
+
+ FLASH_WORD_WRITE_MAX_TIME = 0.000338 # Worst time to write one word 338 us
+ FLASH_WORD_WRITE_MIN_TIME = 0.0000675 # Best time to write one word 67.5 us
+
+ FLASH_OP_WAIT_RATIO = 0.5 # Ratio in % for flash operation (erase, write) comparing to the MAX(worst) scenario
+
+ FLASH_PAGE_SIZE = 4096 # 4K for nrf52
+ DFU_PACKET_MAX_SIZE = 512 # The DFU packet max size
+
+ def __init__(self, com_port, baud_rate=DEFAULT_BAUD_RATE, flow_control=DEFAULT_FLOW_CONTROL, timeout=DEFAULT_SERIAL_PORT_TIMEOUT):
+ super(DfuTransportSerial, self).__init__()
+ self.com_port = com_port
+ self.baud_rate = baud_rate
+ self.flow_control = 1 if flow_control else 0
+ self.timeout = timeout
+ self.serial_port = None
+ self.total_size = 167936 # default is max application size
+ """:type: serial.Serial """
+
+ def open(self):
+ super(DfuTransportSerial, self).open()
+
+ try:
+ self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.timeout)
+ except Exception, e:
+ raise NordicSemiException("Serial port could not be opened on {0}. Reason: {1}".format(self.com_port, e.message))
+
+ # Wait for the system to reset
+ time.sleep(DfuTransportSerial.SERIAL_PORT_OPEN_WAIT_TIME)
+ def open(self):
+ super(DfuTransportSerial, self).open()
+
+ try:
+ self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.timeout)
+ except Exception, e:
+ raise NordicSemiException("Serial port could not be opened on {0}. Reason: {1}".format(self.com_port, e.message))
+
+ time.sleep(DfuTransportSerial.SERIAL_PORT_OPEN_WAIT_TIME)
+
+ # Toggle DTR to reset the board and enter DFU mode
+ # Note: This double reset may or may not be necessary depending on the
+ # CP21xx configuration, but we'll perform a second reset here to be
+ # sure
+ self.serial_port.setDTR(False)
+ time.sleep(0.05)
+ self.serial_port.setDTR(True)
+ time.sleep(0.05)
+ self.serial_port.setDTR(False)
+
+ # Delay to allow device to boot up
+ time.sleep(DfuTransportSerial.NRF52_RESET_WAIT_TIME)
+
+ def close(self):
+ super(DfuTransportSerial, self).close()
+ self.serial_port.close()
+
+ def is_open(self):
+ super(DfuTransportSerial, self).is_open()
+
+ if self.serial_port is None:
+ return False
+
+ return self.serial_port.isOpen()
+
+ def send_validate_firmware(self):
+ super(DfuTransportSerial, self).send_validate_firmware()
+ return True
+
+ def send_init_packet(self, init_packet):
+ super(DfuTransportSerial, self).send_init_packet(init_packet)
+
+ frame = int32_to_bytes(DFU_INIT_PACKET)
+ frame += init_packet
+ frame += int16_to_bytes(0x0000) # Padding required
+
+ packet = HciPacket(frame)
+ self.send_packet(packet)
+ time.sleep(DfuTransportSerial.SEND_INIT_PACKET_WAIT_TIME)
+
+ def get_erase_wait_time(self):
+ avg_flash_erase = (self.FLASH_PAGE_ERASE_MAX_TIME - self.FLASH_PAGE_ERASE_MIN_TIME) * self.FLASH_OP_WAIT_RATIO + self.FLASH_PAGE_ERASE_MIN_TIME
+ erase_wait_time = (((self.total_size)//self.FLASH_PAGE_SIZE)+1)*avg_flash_erase
+ erase_wait_time = max(erase_wait_time, self.SEND_START_DFU_MIN_WAIT_TIME)
+ return erase_wait_time
+
+ def get_activate_wait_time(self):
+ # Activate wait time including time to erase bank 0 and writing bank 0
+ avg_flash_write = (self.FLASH_WORD_WRITE_MAX_TIME - self.FLASH_WORD_WRITE_MIN_TIME) * self.FLASH_OP_WAIT_RATIO + self.FLASH_WORD_WRITE_MIN_TIME
+ write_wait_time = ((self.total_size // 4) + 1) * avg_flash_write
+ write_wait_time = max(write_wait_time, self.SEND_START_DFU_MIN_WAIT_TIME)
+ return self.get_erase_wait_time() + write_wait_time
+
+ def send_start_dfu(self, mode, softdevice_size=None, bootloader_size=None, app_size=None):
+ super(DfuTransportSerial, self).send_start_dfu(mode, softdevice_size, bootloader_size, app_size)
+
+ frame = int32_to_bytes(DFU_START_PACKET)
+ frame += int32_to_bytes(mode)
+ frame += DfuTransport.create_image_size_packet(softdevice_size, bootloader_size, app_size)
+
+ packet = HciPacket(frame)
+ self.send_packet(packet)
+
+ self.total_size = softdevice_size+bootloader_size+app_size
+ #logger.info("Wait after Init Packet %s second", self.get_erase_wait_time())
+ time.sleep( self.get_erase_wait_time() )
+
+ def send_activate_firmware(self):
+ super(DfuTransportSerial, self).send_activate_firmware()
+ # nrf52 will erase the bank 0 up to Application size & Transfer App size from bank1 to bank0
+ # There must a enough delay before finished to prevent Arduino IDE reopen Serial Monitor
+
+ logger.info("\nActivating new firmware")
+ #logger.info("Wait after activating %s second", self.get_activate_wait_time())
+ time.sleep( self.get_activate_wait_time() )
+
+ def send_firmware(self, firmware):
+ super(DfuTransportSerial, self).send_firmware(firmware)
+
+ def progress_percentage(part, whole):
+ return int(100 * float(part)/float(whole))
+
+ frames = []
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=0, done=False, log_message="")
+
+ for i in range(0, len(firmware), DfuTransportSerial.DFU_PACKET_MAX_SIZE):
+ data_packet = HciPacket(int32_to_bytes(DFU_DATA_PACKET) + firmware[i:i + DfuTransportSerial.DFU_PACKET_MAX_SIZE])
+ frames.append(data_packet)
+
+ frames_count = len(frames)
+
+ # Send firmware packets
+ for count, pkt in enumerate(frames):
+ self.send_packet(pkt)
+ self._send_event(DfuEvent.PROGRESS_EVENT,
+ log_message="",
+ progress=progress_percentage(count, frames_count),
+ done=False)
+
+ # Send data stop packet
+ frame = int32_to_bytes(DFU_STOP_DATA_PACKET)
+ packet = HciPacket(frame)
+ self.send_packet(packet)
+
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=100, done=False, log_message="")
+
+ def send_packet(self, pkt):
+ attempts = 0
+ last_ack = None
+ packet_sent = False
+
+ logger.debug("PC -> target: {0}".format(pkt))
+
+ while not packet_sent:
+ self.serial_port.write(pkt.data)
+ attempts += 1
+ ack = self.get_ack_nr()
+
+ if last_ack is None:
+ break
+
+ if ack == (last_ack + 1) % 8:
+ last_ack = ack
+ packet_sent = True
+
+ if attempts > 3:
+ raise Exception("Three failed tx attempts encountered on packet {0}".format(pkt.sequence_number))
+
+ def get_ack_nr(self):
+ def is_timeout(start_time, timeout_sec):
+ return not (datetime.now() - start_time <= timedelta(0, timeout_sec))
+
+ uart_buffer = ''
+ start = datetime.now()
+
+ while uart_buffer.count('\xC0') < 2:
+ # Disregard first of the two C0
+ temp = self.serial_port.read(6)
+
+ if temp:
+ uart_buffer += temp
+
+ if is_timeout(start, DfuTransportSerial.ACK_PACKET_TIMEOUT):
+ # reset HciPacket numbering back to 0
+ HciPacket.sequence_number = 0
+ self._send_event(DfuEvent.TIMEOUT_EVENT,
+ log_message="Timed out waiting for acknowledgement from device.")
+
+ # quit loop
+ break
+
+ # read until you get a new C0
+ # RESUME_WORK
+
+ if len(uart_buffer) < 2:
+ raise NordicSemiException("No data received on serial port. Not able to proceed.")
+
+ logger.debug("PC <- target: {0}".format(binascii.hexlify(uart_buffer)))
+ data = self.decode_esc_chars(uart_buffer)
+
+ # Remove 0xC0 at start and beginning
+ data = data[1:-1]
+
+ # Extract ACK number from header
+ return (data[0] >> 3) & 0x07
+
+ @staticmethod
+ def decode_esc_chars(data):
+ """Replace 0xDBDC with 0xCO and 0xDBDD with 0xDB"""
+ result = []
+
+ data = bytearray(data)
+
+ while len(data):
+ char = data.pop(0)
+
+ if char == 0xDB:
+ char2 = data.pop(0)
+
+ if char2 == 0xDC:
+ result.append(0xC0)
+ elif char2 == 0xDD:
+ result.append(0xDB)
+ else:
+ raise Exception('Char 0xDB NOT followed by 0xDC or 0xDD')
+ else:
+ result.append(char)
+
+ return result
+
+DATA_INTEGRITY_CHECK_PRESENT = 1
+RELIABLE_PACKET = 1
+HCI_PACKET_TYPE = 14
+
+DFU_INIT_PACKET = 1
+DFU_START_PACKET = 3
+DFU_DATA_PACKET = 4
+DFU_STOP_DATA_PACKET = 5
+
+DFU_UPDATE_MODE_NONE = 0
+DFU_UPDATE_MODE_SD = 1
+DFU_UPDATE_MODE_BL = 2
+DFU_UPDATE_MODE_APP = 4
+
+
+class HciPacket(object):
+ """Class representing a single HCI packet"""
+
+ sequence_number = 0
+
+ def __init__(self, data=''):
+ HciPacket.sequence_number = (HciPacket.sequence_number + 1) % 8
+ self.temp_data = ''
+ self.temp_data += slip_parts_to_four_bytes(HciPacket.sequence_number,
+ DATA_INTEGRITY_CHECK_PRESENT,
+ RELIABLE_PACKET,
+ HCI_PACKET_TYPE,
+ len(data))
+ self.temp_data += data
+ # Add escape characters
+ crc = crc16.calc_crc16(self.temp_data, crc=0xffff)
+
+ self.temp_data += chr(crc & 0xFF)
+ self.temp_data += chr((crc & 0xFF00) >> 8)
+
+ self.temp_data = slip_encode_esc_chars(self.temp_data)
+
+ self.data = chr(0xc0)
+ self.data += self.temp_data
+ self.data += chr(0xc0)
+
+ def __str__(self):
+ return binascii.hexlify(self.data)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/init_packet.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/init_packet.py
new file mode 100644
index 0000000..ccf8c34
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/init_packet.py
@@ -0,0 +1,131 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from enum import Enum
+import struct
+
+
+INIT_PACKET_USES_CRC16 = 0
+INIT_PACKET_USES_HASH = 1
+INIT_PACKET_EXT_USES_ECDS = 2
+
+
+class PacketField(Enum):
+ DEVICE_TYPE = 1
+ DEVICE_REVISION = 2
+ APP_VERSION = 3
+ REQUIRED_SOFTDEVICES_ARRAY = 4
+ OPT_DATA = 5
+ NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID = 6
+ NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH = 7
+ NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH = 8
+ NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16 = 9
+ NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS = 10
+
+
+class Packet(object):
+ """
+ Class that implements the INIT packet format.
+ http://developer.nordicsemi.com/nRF51_SDK/doc/7.1.0/s110/html/a00065.html
+ """
+
+ UNSIGNED_SHORT = "H"
+ UNSIGNED_INT = "I"
+ UNSIGNED_CHAR = "B"
+ CHAR_ARRAY = "s"
+
+ def __init__(self, init_packet_fields):
+ """
+
+ :param init_packet_fields: Dictionary with packet fields
+ """
+ self.init_packet_fields = init_packet_fields
+
+ def generate_packet(self):
+ """
+ Generates a binary packet from provided init_packet_fields provided in constructor.
+ This version includes the extended data
+
+ :return str: Returns a string representing the init_packet (in binary)
+
+ """
+ # Create struct format string based on keys that are
+ # present in self.init_packet_fields
+ format_string = self.__generate_struct_format_string()
+ args = []
+
+ # If you got error message AttributeError: 'int' object has no attribute 'value'.
+ # Uncomment line 84 and comment out line 85 and run 'python setup.py install'
+ #for key in sorted(self.init_packet_fields.keys(), key=lambda x: x):
+ for key in sorted(self.init_packet_fields.keys(), key=lambda x: x.value):
+ # Add length to fields that required that
+ if key in [PacketField.REQUIRED_SOFTDEVICES_ARRAY,
+ PacketField.OPT_DATA]:
+ args.append(len(self.init_packet_fields[key]))
+ args.extend(self.init_packet_fields[key])
+ else:
+ args.append(self.init_packet_fields[key])
+
+ return struct.pack(format_string, *args)
+
+ def __generate_struct_format_string(self):
+ format_string = "<" # Use little endian format with standard sizes for python,
+ # see https://docs.python.org/2/library/struct.html
+
+ # If you got error message AttributeError: 'int' object has no attribute 'value'.
+ # Uncomment line 102 and comment out line 103 and run 'python setup.py install'
+ #for key in sorted(self.init_packet_fields.keys(), key=lambda x: x):
+ for key in sorted(self.init_packet_fields.keys(), key=lambda x: x.value):
+ if key in [PacketField.DEVICE_TYPE,
+ PacketField.DEVICE_REVISION,
+ ]:
+ format_string += Packet.UNSIGNED_SHORT
+
+ elif key in [PacketField.APP_VERSION]:
+ format_string += Packet.UNSIGNED_INT
+ elif key in [PacketField.REQUIRED_SOFTDEVICES_ARRAY]:
+ array_elements = self.init_packet_fields[key]
+ format_string += Packet.UNSIGNED_SHORT # Add length field to format packet
+
+ for _ in range(len(array_elements)):
+ format_string += Packet.UNSIGNED_SHORT
+ elif key in [PacketField.OPT_DATA]:
+ format_string += Packet.UNSIGNED_SHORT # Add length field to optional data
+ format_string += "{0}{1}".format(len(self.init_packet_fields[key]), Packet.CHAR_ARRAY)
+ elif key in [PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID]:
+ format_string += Packet.UNSIGNED_INT # Add the extended packet id field
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH:
+ format_string += Packet.UNSIGNED_INT # Add the firmware length field
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ format_string += "32{0}".format(Packet.CHAR_ARRAY) # SHA-256 requires 32 bytes
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16:
+ format_string += Packet.UNSIGNED_SHORT
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ format_string += "64{0}".format(Packet.CHAR_ARRAY) # ECDS based on P-256 using SHA-256 requires 64 bytes
+
+ return format_string
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/__init__.py
new file mode 100644
index 0000000..068036d
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/__init__.py
@@ -0,0 +1,1286 @@
+# Copyright (c) 2005-2013, Alexander Belchenko
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms,
+# with or without modification, are permitted provided
+# that the following conditions are met:
+#
+# * Redistributions of source code must retain
+# the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce
+# the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the author nor the names
+# of its contributors may be used to endorse
+# or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+'''Intel HEX file format reader and converter.
+
+@author Alexander Belchenko (alexander dot belchenko at gmail dot com)
+@version 1.5
+'''
+
+
+__docformat__ = "javadoc"
+
+
+from array import array
+from binascii import hexlify, unhexlify
+from bisect import bisect_right
+import os
+import sys
+
+from compat import asbytes, asstr
+
+
+class _DeprecatedParam(object):
+ pass
+
+_DEPRECATED = _DeprecatedParam()
+
+
+class IntelHex(object):
+ ''' Intel HEX file reader. '''
+
+ def __init__(self, source=None):
+ ''' Constructor. If source specified, object will be initialized
+ with the contents of source. Otherwise the object will be empty.
+
+ @param source source for initialization
+ (file name of HEX file, file object, addr dict or
+ other IntelHex object)
+ '''
+ # public members
+ self.padding = 0x0FF
+ # Start Address
+ self.start_addr = None
+
+ # private members
+ self._buf = {}
+ self._offset = 0
+
+ if source is not None:
+ if isinstance(source, basestring) or getattr(source, "read", None):
+ # load hex file
+ self.loadhex(source)
+ elif isinstance(source, dict):
+ self.fromdict(source)
+ elif isinstance(source, IntelHex):
+ self.padding = source.padding
+ if source.start_addr:
+ self.start_addr = source.start_addr.copy()
+ self._buf = source._buf.copy()
+ else:
+ raise ValueError("source: bad initializer type")
+
+ def _decode_record(self, s, line=0):
+ '''Decode one record of HEX file.
+
+ @param s line with HEX record.
+ @param line line number (for error messages).
+
+ @raise EndOfFile if EOF record encountered.
+ '''
+ s = s.rstrip('\r\n')
+ if not s:
+ return # empty line
+
+ if s[0] == ':':
+ try:
+ bin = array('B', unhexlify(asbytes(s[1:])))
+ except (TypeError, ValueError):
+ # this might be raised by unhexlify when odd hexascii digits
+ raise HexRecordError(line=line)
+ length = len(bin)
+ if length < 5:
+ raise HexRecordError(line=line)
+ else:
+ raise HexRecordError(line=line)
+
+ record_length = bin[0]
+ if length != (5 + record_length):
+ raise RecordLengthError(line=line)
+
+ addr = bin[1]*256 + bin[2]
+
+ record_type = bin[3]
+ if not (0 <= record_type <= 5):
+ raise RecordTypeError(line=line)
+
+ crc = sum(bin)
+ crc &= 0x0FF
+ if crc != 0:
+ raise RecordChecksumError(line=line)
+
+ if record_type == 0:
+ # data record
+ addr += self._offset
+ for i in xrange(4, 4+record_length):
+ if not self._buf.get(addr, None) is None:
+ raise AddressOverlapError(address=addr, line=line)
+ self._buf[addr] = bin[i]
+ addr += 1 # FIXME: addr should be wrapped
+ # BUT after 02 record (at 64K boundary)
+ # and after 04 record (at 4G boundary)
+
+ elif record_type == 1:
+ # end of file record
+ if record_length != 0:
+ raise EOFRecordError(line=line)
+ raise _EndOfFile
+
+ elif record_type == 2:
+ # Extended 8086 Segment Record
+ if record_length != 2 or addr != 0:
+ raise ExtendedSegmentAddressRecordError(line=line)
+ self._offset = (bin[4]*256 + bin[5]) * 16
+
+ elif record_type == 4:
+ # Extended Linear Address Record
+ if record_length != 2 or addr != 0:
+ raise ExtendedLinearAddressRecordError(line=line)
+ self._offset = (bin[4]*256 + bin[5]) * 65536
+
+ elif record_type == 3:
+ # Start Segment Address Record
+ if record_length != 4 or addr != 0:
+ raise StartSegmentAddressRecordError(line=line)
+ if self.start_addr:
+ raise DuplicateStartAddressRecordError(line=line)
+ self.start_addr = {'CS': bin[4]*256 + bin[5],
+ 'IP': bin[6]*256 + bin[7],
+ }
+
+ elif record_type == 5:
+ # Start Linear Address Record
+ if record_length != 4 or addr != 0:
+ raise StartLinearAddressRecordError(line=line)
+ if self.start_addr:
+ raise DuplicateStartAddressRecordError(line=line)
+ self.start_addr = {'EIP': (bin[4]*16777216 +
+ bin[5]*65536 +
+ bin[6]*256 +
+ bin[7]),
+ }
+
+ def loadhex(self, fobj):
+ """Load hex file into internal buffer. This is not necessary
+ if object was initialized with source set. This will overwrite
+ addresses if object was already initialized.
+
+ @param fobj file name or file-like object
+ """
+ if getattr(fobj, "read", None) is None:
+ fobj = open(fobj, "r")
+ fclose = fobj.close
+ else:
+ fclose = None
+
+ self._offset = 0
+ line = 0
+
+ try:
+ decode = self._decode_record
+ try:
+ for s in fobj:
+ line += 1
+ decode(s, line)
+ except _EndOfFile:
+ pass
+ finally:
+ if fclose:
+ fclose()
+
+ def loadbin(self, fobj, offset=0):
+ """Load bin file into internal buffer. Not needed if source set in
+ constructor. This will overwrite addresses without warning
+ if object was already initialized.
+
+ @param fobj file name or file-like object
+ @param offset starting address offset
+ """
+ fread = getattr(fobj, "read", None)
+ if fread is None:
+ f = open(fobj, "rb")
+ fread = f.read
+ fclose = f.close
+ else:
+ fclose = None
+
+ try:
+ self.frombytes(array('B', asbytes(fread())), offset=offset)
+ finally:
+ if fclose:
+ fclose()
+
+ def loadfile(self, fobj, format):
+ """Load data file into internal buffer. Preferred wrapper over
+ loadbin or loadhex.
+
+ @param fobj file name or file-like object
+ @param format file format ("hex" or "bin")
+ """
+ if format == "hex":
+ self.loadhex(fobj)
+ elif format == "bin":
+ self.loadbin(fobj)
+ else:
+ raise ValueError('format should be either "hex" or "bin";'
+ ' got %r instead' % format)
+
+ # alias (to be consistent with method tofile)
+ fromfile = loadfile
+
+ def fromdict(self, dikt):
+ """Load data from dictionary. Dictionary should contain int keys
+ representing addresses. Values should be the data to be stored in
+ those addresses in unsigned char form (i.e. not strings).
+ The dictionary may contain the key, ``start_addr``
+ to indicate the starting address of the data as described in README.
+
+ The contents of the dict will be merged with this object and will
+ overwrite any conflicts. This function is not necessary if the
+ object was initialized with source specified.
+ """
+ s = dikt.copy()
+ start_addr = s.get('start_addr')
+ if start_addr is not None:
+ del s['start_addr']
+ for k in s.keys():
+ if type(k) not in (int, long) or k < 0:
+ raise ValueError('Source dictionary should have only int keys')
+ self._buf.update(s)
+ if start_addr is not None:
+ self.start_addr = start_addr
+
+ def frombytes(self, bytes, offset=0):
+ """Load data from array or list of bytes.
+ Similar to loadbin() method but works directly with iterable bytes.
+ """
+ for b in bytes:
+ self._buf[offset] = b
+ offset += 1
+
+ def _get_start_end(self, start=None, end=None, size=None):
+ """Return default values for start and end if they are None.
+ If this IntelHex object is empty then it's error to
+ invoke this method with both start and end as None.
+ """
+ if (start,end) == (None,None) and self._buf == {}:
+ raise EmptyIntelHexError
+ if size is not None:
+ if None not in (start, end):
+ raise ValueError("tobinarray: you can't use start,end and size"
+ " arguments in the same time")
+ if (start, end) == (None, None):
+ start = self.minaddr()
+ if start is not None:
+ end = start + size - 1
+ else:
+ start = end - size + 1
+ if start < 0:
+ raise ValueError("tobinarray: invalid size (%d) "
+ "for given end address (%d)" % (size,end))
+ else:
+ if start is None:
+ start = self.minaddr()
+ if end is None:
+ end = self.maxaddr()
+ if start > end:
+ start, end = end, start
+ return start, end
+
+ def tobinarray(self, start=None, end=None, pad=_DEPRECATED, size=None):
+ ''' Convert this object to binary form as array. If start and end
+ unspecified, they will be inferred from the data.
+ @param start start address of output bytes.
+ @param end end address of output bytes (inclusive).
+ @param pad [DEPRECATED PARAMETER, please use self.padding instead]
+ fill empty spaces with this value
+ (if pad is None then this method uses self.padding).
+ @param size size of the block, used with start or end parameter.
+ @return array of unsigned char data.
+ '''
+ if not isinstance(pad, _DeprecatedParam):
+ print "IntelHex.tobinarray: 'pad' parameter is deprecated."
+ if pad is not None:
+ print "Please, use IntelHex.padding attribute instead."
+ else:
+ print "Please, don't pass it explicitly."
+ print "Use syntax like this: ih.tobinarray(start=xxx, end=yyy, size=zzz)"
+ else:
+ pad = None
+ return self._tobinarray_really(start, end, pad, size)
+
+ def _tobinarray_really(self, start, end, pad, size):
+ if pad is None:
+ pad = self.padding
+
+ bin = array('B')
+
+ if self._buf == {} and None in (start, end):
+ return bin
+
+ if size is not None and size <= 0:
+ raise ValueError("tobinarray: wrong value for size")
+
+ start, end = self._get_start_end(start, end, size)
+
+ for i in xrange(start, end+1):
+ bin.append(self._buf.get(i, pad))
+
+ return bin
+
+ def tobinstr(self, start=None, end=None, pad=_DEPRECATED, size=None):
+ ''' Convert to binary form and return as a string.
+ @param start start address of output bytes.
+ @param end end address of output bytes (inclusive).
+ @param pad [DEPRECATED PARAMETER, please use self.padding instead]
+ fill empty spaces with this value
+ (if pad is None then this method uses self.padding).
+ @param size size of the block, used with start or end parameter.
+ @return string of binary data.
+ '''
+ if not isinstance(pad, _DeprecatedParam):
+ print "IntelHex.tobinstr: 'pad' parameter is deprecated."
+ if pad is not None:
+ print "Please, use IntelHex.padding attribute instead."
+ else:
+ print "Please, don't pass it explicitly."
+ print "Use syntax like this: ih.tobinstr(start=xxx, end=yyy, size=zzz)"
+ else:
+ pad = None
+ return self._tobinstr_really(start, end, pad, size)
+
+ def _tobinstr_really(self, start, end, pad, size):
+ return asstr(self._tobinarray_really(start, end, pad, size).tostring())
+
+ def tobinfile(self, fobj, start=None, end=None, pad=_DEPRECATED, size=None):
+ '''Convert to binary and write to file.
+
+ @param fobj file name or file object for writing output bytes.
+ @param start start address of output bytes.
+ @param end end address of output bytes (inclusive).
+ @param pad [DEPRECATED PARAMETER, please use self.padding instead]
+ fill empty spaces with this value
+ (if pad is None then this method uses self.padding).
+ @param size size of the block, used with start or end parameter.
+ '''
+ if not isinstance(pad, _DeprecatedParam):
+ print "IntelHex.tobinfile: 'pad' parameter is deprecated."
+ if pad is not None:
+ print "Please, use IntelHex.padding attribute instead."
+ else:
+ print "Please, don't pass it explicitly."
+ print "Use syntax like this: ih.tobinfile(start=xxx, end=yyy, size=zzz)"
+ else:
+ pad = None
+ if getattr(fobj, "write", None) is None:
+ fobj = open(fobj, "wb")
+ close_fd = True
+ else:
+ close_fd = False
+
+ fobj.write(self._tobinstr_really(start, end, pad, size))
+
+ if close_fd:
+ fobj.close()
+
+ def todict(self):
+ '''Convert to python dictionary.
+
+ @return dict suitable for initializing another IntelHex object.
+ '''
+ r = {}
+ r.update(self._buf)
+ if self.start_addr:
+ r['start_addr'] = self.start_addr
+ return r
+
+ def addresses(self):
+ '''Returns all used addresses in sorted order.
+ @return list of occupied data addresses in sorted order.
+ '''
+ aa = self._buf.keys()
+ aa.sort()
+ return aa
+
+ def minaddr(self):
+ '''Get minimal address of HEX content.
+ @return minimal address or None if no data
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return None
+ else:
+ return min(aa)
+
+ def maxaddr(self):
+ '''Get maximal address of HEX content.
+ @return maximal address or None if no data
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return None
+ else:
+ return max(aa)
+
+ def __getitem__(self, addr):
+ ''' Get requested byte from address.
+ @param addr address of byte.
+ @return byte if address exists in HEX file, or self.padding
+ if no data found.
+ '''
+ t = type(addr)
+ if t in (int, long):
+ if addr < 0:
+ raise TypeError('Address should be >= 0.')
+ return self._buf.get(addr, self.padding)
+ elif t == slice:
+ addresses = self._buf.keys()
+ ih = IntelHex()
+ if addresses:
+ addresses.sort()
+ start = addr.start or addresses[0]
+ stop = addr.stop or (addresses[-1]+1)
+ step = addr.step or 1
+ for i in xrange(start, stop, step):
+ x = self._buf.get(i)
+ if x is not None:
+ ih[i] = x
+ return ih
+ else:
+ raise TypeError('Address has unsupported type: %s' % t)
+
+ def __setitem__(self, addr, byte):
+ """Set byte at address."""
+ t = type(addr)
+ if t in (int, long):
+ if addr < 0:
+ raise TypeError('Address should be >= 0.')
+ self._buf[addr] = byte
+ elif t == slice:
+ if not isinstance(byte, (list, tuple)):
+ raise ValueError('Slice operation expects sequence of bytes')
+ start = addr.start
+ stop = addr.stop
+ step = addr.step or 1
+ if None not in (start, stop):
+ ra = range(start, stop, step)
+ if len(ra) != len(byte):
+ raise ValueError('Length of bytes sequence does not match '
+ 'address range')
+ elif (start, stop) == (None, None):
+ raise TypeError('Unsupported address range')
+ elif start is None:
+ start = stop - len(byte)
+ elif stop is None:
+ stop = start + len(byte)
+ if start < 0:
+ raise TypeError('start address cannot be negative')
+ if stop < 0:
+ raise TypeError('stop address cannot be negative')
+ j = 0
+ for i in xrange(start, stop, step):
+ self._buf[i] = byte[j]
+ j += 1
+ else:
+ raise TypeError('Address has unsupported type: %s' % t)
+
+ def __delitem__(self, addr):
+ """Delete byte at address."""
+ t = type(addr)
+ if t in (int, long):
+ if addr < 0:
+ raise TypeError('Address should be >= 0.')
+ del self._buf[addr]
+ elif t == slice:
+ addresses = self._buf.keys()
+ if addresses:
+ addresses.sort()
+ start = addr.start or addresses[0]
+ stop = addr.stop or (addresses[-1]+1)
+ step = addr.step or 1
+ for i in xrange(start, stop, step):
+ x = self._buf.get(i)
+ if x is not None:
+ del self._buf[i]
+ else:
+ raise TypeError('Address has unsupported type: %s' % t)
+
+ def __len__(self):
+ """Return count of bytes with real values."""
+ return len(self._buf.keys())
+
+ def write_hex_file(self, f, write_start_addr=True):
+ """Write data to file f in HEX format.
+
+ @param f filename or file-like object for writing
+ @param write_start_addr enable or disable writing start address
+ record to file (enabled by default).
+ If there is no start address in obj, nothing
+ will be written regardless of this setting.
+ """
+ fwrite = getattr(f, "write", None)
+ if fwrite:
+ fobj = f
+ fclose = None
+ else:
+ fobj = open(f, 'w')
+ fwrite = fobj.write
+ fclose = fobj.close
+
+ # Translation table for uppercasing hex ascii string.
+ # timeit shows that using hexstr.translate(table)
+ # is faster than hexstr.upper():
+ # 0.452ms vs. 0.652ms (translate vs. upper)
+ if sys.version_info[0] >= 3:
+ table = bytes(range(256)).upper()
+ else:
+ table = ''.join(chr(i).upper() for i in range(256))
+
+
+
+ # start address record if any
+ if self.start_addr and write_start_addr:
+ keys = self.start_addr.keys()
+ keys.sort()
+ bin = array('B', asbytes('\0'*9))
+ if keys == ['CS','IP']:
+ # Start Segment Address Record
+ bin[0] = 4 # reclen
+ bin[1] = 0 # offset msb
+ bin[2] = 0 # offset lsb
+ bin[3] = 3 # rectyp
+ cs = self.start_addr['CS']
+ bin[4] = (cs >> 8) & 0x0FF
+ bin[5] = cs & 0x0FF
+ ip = self.start_addr['IP']
+ bin[6] = (ip >> 8) & 0x0FF
+ bin[7] = ip & 0x0FF
+ bin[8] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+ elif keys == ['EIP']:
+ # Start Linear Address Record
+ bin[0] = 4 # reclen
+ bin[1] = 0 # offset msb
+ bin[2] = 0 # offset lsb
+ bin[3] = 5 # rectyp
+ eip = self.start_addr['EIP']
+ bin[4] = (eip >> 24) & 0x0FF
+ bin[5] = (eip >> 16) & 0x0FF
+ bin[6] = (eip >> 8) & 0x0FF
+ bin[7] = eip & 0x0FF
+ bin[8] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+ else:
+ if fclose:
+ fclose()
+ raise InvalidStartAddressValueError(start_addr=self.start_addr)
+
+ # data
+ addresses = self._buf.keys()
+ addresses.sort()
+ addr_len = len(addresses)
+ if addr_len:
+ minaddr = addresses[0]
+ maxaddr = addresses[-1]
+
+ if maxaddr > 65535:
+ need_offset_record = True
+ else:
+ need_offset_record = False
+ high_ofs = 0
+
+ cur_addr = minaddr
+ cur_ix = 0
+
+ while cur_addr <= maxaddr:
+ if need_offset_record:
+ bin = array('B', asbytes('\0'*7))
+ bin[0] = 2 # reclen
+ bin[1] = 0 # offset msb
+ bin[2] = 0 # offset lsb
+ bin[3] = 4 # rectyp
+ high_ofs = int(cur_addr>>16)
+ b = divmod(high_ofs, 256)
+ bin[4] = b[0] # msb of high_ofs
+ bin[5] = b[1] # lsb of high_ofs
+ bin[6] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+
+ while True:
+ # produce one record
+ low_addr = cur_addr & 0x0FFFF
+ # chain_len off by 1
+ chain_len = min(15, 65535-low_addr, maxaddr-cur_addr)
+
+ # search continuous chain
+ stop_addr = cur_addr + chain_len
+ if chain_len:
+ ix = bisect_right(addresses, stop_addr,
+ cur_ix,
+ min(cur_ix+chain_len+1, addr_len))
+ chain_len = ix - cur_ix # real chain_len
+ # there could be small holes in the chain
+ # but we will catch them by try-except later
+ # so for big continuous files we will work
+ # at maximum possible speed
+ else:
+ chain_len = 1 # real chain_len
+
+ bin = array('B', asbytes('\0'*(5+chain_len)))
+ b = divmod(low_addr, 256)
+ bin[1] = b[0] # msb of low_addr
+ bin[2] = b[1] # lsb of low_addr
+ bin[3] = 0 # rectype
+ try: # if there is small holes we'll catch them
+ for i in range(chain_len):
+ bin[4+i] = self._buf[cur_addr+i]
+ except KeyError:
+ # we catch a hole so we should shrink the chain
+ chain_len = i
+ bin = bin[:5+i]
+ bin[0] = chain_len
+ bin[4+chain_len] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+
+ # adjust cur_addr/cur_ix
+ cur_ix += chain_len
+ if cur_ix < addr_len:
+ cur_addr = addresses[cur_ix]
+ else:
+ cur_addr = maxaddr + 1
+ break
+ high_addr = int(cur_addr>>16)
+ if high_addr > high_ofs:
+ break
+
+ # end-of-file record
+ fwrite(":00000001FF\n")
+ if fclose:
+ fclose()
+
+ def tofile(self, fobj, format):
+ """Write data to hex or bin file. Preferred method over tobin or tohex.
+
+ @param fobj file name or file-like object
+ @param format file format ("hex" or "bin")
+ """
+ if format == 'hex':
+ self.write_hex_file(fobj)
+ elif format == 'bin':
+ self.tobinfile(fobj)
+ else:
+ raise ValueError('format should be either "hex" or "bin";'
+ ' got %r instead' % format)
+
+ def gets(self, addr, length):
+ """Get string of bytes from given address. If any entries are blank
+ from addr through addr+length, a NotEnoughDataError exception will
+ be raised. Padding is not used."""
+ a = array('B', asbytes('\0'*length))
+ try:
+ for i in xrange(length):
+ a[i] = self._buf[addr+i]
+ except KeyError:
+ raise NotEnoughDataError(address=addr, length=length)
+ return asstr(a.tostring())
+
+ def puts(self, addr, s):
+ """Put string of bytes at given address. Will overwrite any previous
+ entries.
+ """
+ a = array('B', asbytes(s))
+ for i in xrange(len(a)):
+ self._buf[addr+i] = a[i]
+
+ def getsz(self, addr):
+ """Get zero-terminated string from given address. Will raise
+ NotEnoughDataError exception if a hole is encountered before a 0.
+ """
+ i = 0
+ try:
+ while True:
+ if self._buf[addr+i] == 0:
+ break
+ i += 1
+ except KeyError:
+ raise NotEnoughDataError(msg=('Bad access at 0x%X: '
+ 'not enough data to read zero-terminated string') % addr)
+ return self.gets(addr, i)
+
+ def putsz(self, addr, s):
+ """Put string in object at addr and append terminating zero at end."""
+ self.puts(addr, s)
+ self._buf[addr+len(s)] = 0
+
+ def dump(self, tofile=None):
+ """Dump object content to specified file object or to stdout if None.
+ Format is a hexdump with some header information at the beginning,
+ addresses on the left, and data on right.
+
+ @param tofile file-like object to dump to
+ """
+
+ if tofile is None:
+ tofile = sys.stdout
+ # start addr possibly
+ if self.start_addr is not None:
+ cs = self.start_addr.get('CS')
+ ip = self.start_addr.get('IP')
+ eip = self.start_addr.get('EIP')
+ if eip is not None and cs is None and ip is None:
+ tofile.write('EIP = 0x%08X\n' % eip)
+ elif eip is None and cs is not None and ip is not None:
+ tofile.write('CS = 0x%04X, IP = 0x%04X\n' % (cs, ip))
+ else:
+ tofile.write('start_addr = %r\n' % start_addr)
+ # actual data
+ addresses = self._buf.keys()
+ if addresses:
+ addresses.sort()
+ minaddr = addresses[0]
+ maxaddr = addresses[-1]
+ startaddr = int(minaddr>>4)*16
+ endaddr = int((maxaddr>>4)+1)*16
+ maxdigits = max(len(str(endaddr)), 4)
+ templa = '%%0%dX' % maxdigits
+ range16 = range(16)
+ for i in xrange(startaddr, endaddr, 16):
+ tofile.write(templa % i)
+ tofile.write(' ')
+ s = []
+ for j in range16:
+ x = self._buf.get(i+j)
+ if x is not None:
+ tofile.write(' %02X' % x)
+ if 32 <= x < 127: # GNU less does not like 0x7F (128 decimal) so we'd better show it as dot
+ s.append(chr(x))
+ else:
+ s.append('.')
+ else:
+ tofile.write(' --')
+ s.append(' ')
+ tofile.write(' |' + ''.join(s) + '|\n')
+
+ def merge(self, other, overlap='error'):
+ """Merge content of other IntelHex object into current object (self).
+ @param other other IntelHex object.
+ @param overlap action on overlap of data or starting addr:
+ - error: raising OverlapError;
+ - ignore: ignore other data and keep current data
+ in overlapping region;
+ - replace: replace data with other data
+ in overlapping region.
+
+ @raise TypeError if other is not instance of IntelHex
+ @raise ValueError if other is the same object as self
+ (it can't merge itself)
+ @raise ValueError if overlap argument has incorrect value
+ @raise AddressOverlapError on overlapped data
+ """
+ # check args
+ if not isinstance(other, IntelHex):
+ raise TypeError('other should be IntelHex object')
+ if other is self:
+ raise ValueError("Can't merge itself")
+ if overlap not in ('error', 'ignore', 'replace'):
+ raise ValueError("overlap argument should be either "
+ "'error', 'ignore' or 'replace'")
+ # merge data
+ this_buf = self._buf
+ other_buf = other._buf
+ for i in other_buf:
+ if i in this_buf:
+ if overlap == 'error':
+ raise AddressOverlapError(
+ 'Data overlapped at address 0x%X' % i)
+ elif overlap == 'ignore':
+ continue
+ this_buf[i] = other_buf[i]
+ # merge start_addr
+ if self.start_addr != other.start_addr:
+ if self.start_addr is None: # set start addr from other
+ self.start_addr = other.start_addr
+ elif other.start_addr is None: # keep existing start addr
+ pass
+ else: # conflict
+ if overlap == 'error':
+ raise AddressOverlapError(
+ 'Starting addresses are different')
+ elif overlap == 'replace':
+ self.start_addr = other.start_addr
+#/IntelHex
+
+
+class IntelHex16bit(IntelHex):
+ """Access to data as 16-bit words. Intended to use with Microchip HEX files."""
+
+ def __init__(self, source=None):
+ """Construct class from HEX file
+ or from instance of ordinary IntelHex class. If IntelHex object
+ is passed as source, the original IntelHex object should not be used
+ again because this class will alter it. This class leaves padding
+ alone unless it was precisely 0xFF. In that instance it is sign
+ extended to 0xFFFF.
+
+ @param source file name of HEX file or file object
+ or instance of ordinary IntelHex class.
+ Will also accept dictionary from todict method.
+ """
+ if isinstance(source, IntelHex):
+ # from ihex8
+ self.padding = source.padding
+ self.start_addr = source.start_addr
+ # private members
+ self._buf = source._buf
+ self._offset = source._offset
+ elif isinstance(source, dict):
+ raise IntelHexError("IntelHex16bit does not support initialization from dictionary yet.\n"
+ "Patches are welcome.")
+ else:
+ IntelHex.__init__(self, source)
+
+ if self.padding == 0x0FF:
+ self.padding = 0x0FFFF
+
+ def __getitem__(self, addr16):
+ """Get 16-bit word from address.
+ Raise error if only one byte from the pair is set.
+ We assume a Little Endian interpretation of the hex file.
+
+ @param addr16 address of word (addr8 = 2 * addr16).
+ @return word if bytes exists in HEX file, or self.padding
+ if no data found.
+ """
+ addr1 = addr16 * 2
+ addr2 = addr1 + 1
+ byte1 = self._buf.get(addr1, None)
+ byte2 = self._buf.get(addr2, None)
+
+ if byte1 != None and byte2 != None:
+ return byte1 | (byte2 << 8) # low endian
+
+ if byte1 == None and byte2 == None:
+ return self.padding
+
+ raise BadAccess16bit(address=addr16)
+
+ def __setitem__(self, addr16, word):
+ """Sets the address at addr16 to word assuming Little Endian mode.
+ """
+ addr_byte = addr16 * 2
+ b = divmod(word, 256)
+ self._buf[addr_byte] = b[1]
+ self._buf[addr_byte+1] = b[0]
+
+ def minaddr(self):
+ '''Get minimal address of HEX content in 16-bit mode.
+
+ @return minimal address used in this object
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return 0
+ else:
+ return min(aa)>>1
+
+ def maxaddr(self):
+ '''Get maximal address of HEX content in 16-bit mode.
+
+ @return maximal address used in this object
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return 0
+ else:
+ return max(aa)>>1
+
+ def tobinarray(self, start=None, end=None, size=None):
+ '''Convert this object to binary form as array (of 2-bytes word data).
+ If start and end unspecified, they will be inferred from the data.
+ @param start start address of output data.
+ @param end end address of output data (inclusive).
+ @param size size of the block (number of words),
+ used with start or end parameter.
+ @return array of unsigned short (uint16_t) data.
+ '''
+ bin = array('H')
+
+ if self._buf == {} and None in (start, end):
+ return bin
+
+ if size is not None and size <= 0:
+ raise ValueError("tobinarray: wrong value for size")
+
+ start, end = self._get_start_end(start, end, size)
+
+ for addr in xrange(start, end+1):
+ bin.append(self[addr])
+
+ return bin
+
+
+#/class IntelHex16bit
+
+
+def hex2bin(fin, fout, start=None, end=None, size=None, pad=None):
+ """Hex-to-Bin convertor engine.
+ @return 0 if all OK
+
+ @param fin input hex file (filename or file-like object)
+ @param fout output bin file (filename or file-like object)
+ @param start start of address range (optional)
+ @param end end of address range (inclusive; optional)
+ @param size size of resulting file (in bytes) (optional)
+ @param pad padding byte (optional)
+ """
+ try:
+ h = IntelHex(fin)
+ except HexReaderError, e:
+ txt = "ERROR: bad HEX file: %s" % str(e)
+ print(txt)
+ return 1
+
+ # start, end, size
+ if size != None and size != 0:
+ if end == None:
+ if start == None:
+ start = h.minaddr()
+ end = start + size - 1
+ else:
+ if (end+1) >= size:
+ start = end + 1 - size
+ else:
+ start = 0
+
+ try:
+ if pad is not None:
+ # using .padding attribute rather than pad argument to function call
+ h.padding = pad
+ h.tobinfile(fout, start, end)
+ except IOError, e:
+ txt = "ERROR: Could not write to file: %s: %s" % (fout, str(e))
+ print(txt)
+ return 1
+
+ return 0
+#/def hex2bin
+
+
+def bin2hex(fin, fout, offset=0):
+ """Simple bin-to-hex convertor.
+ @return 0 if all OK
+
+ @param fin input bin file (filename or file-like object)
+ @param fout output hex file (filename or file-like object)
+ @param offset starting address offset for loading bin
+ """
+ h = IntelHex()
+ try:
+ h.loadbin(fin, offset)
+ except IOError, e:
+ txt = 'ERROR: unable to load bin file:', str(e)
+ print(txt)
+ return 1
+
+ try:
+ h.tofile(fout, format='hex')
+ except IOError, e:
+ txt = "ERROR: Could not write to file: %s: %s" % (fout, str(e))
+ print(txt)
+ return 1
+
+ return 0
+#/def bin2hex
+
+
+def diff_dumps(ih1, ih2, tofile=None, name1="a", name2="b", n_context=3):
+ """Diff 2 IntelHex objects and produce unified diff output for their
+ hex dumps.
+
+ @param ih1 first IntelHex object to compare
+ @param ih2 second IntelHex object to compare
+ @param tofile file-like object to write output
+ @param name1 name of the first hex file to show in the diff header
+ @param name2 name of the first hex file to show in the diff header
+ @param n_context number of context lines in the unidiff output
+ """
+ def prepare_lines(ih):
+ from cStringIO import StringIO
+ sio = StringIO()
+ ih.dump(sio)
+ dump = sio.getvalue()
+ lines = dump.splitlines()
+ return lines
+ a = prepare_lines(ih1)
+ b = prepare_lines(ih2)
+ import difflib
+ result = list(difflib.unified_diff(a, b, fromfile=name1, tofile=name2, n=n_context, lineterm=''))
+ if tofile is None:
+ tofile = sys.stdout
+ output = '\n'.join(result)+'\n'
+ tofile.write(output)
+
+
+class Record(object):
+ """Helper methods to build valid ihex records."""
+
+ def _from_bytes(bytes):
+ """Takes a list of bytes, computes the checksum, and outputs the entire
+ record as a string. bytes should be the hex record without the colon
+ or final checksum.
+
+ @param bytes list of byte values so far to pack into record.
+ @return String representation of one HEX record
+ """
+ assert len(bytes) >= 4
+ # calculate checksum
+ s = (-sum(bytes)) & 0x0FF
+ bin = array('B', bytes + [s])
+ return ':' + asstr(hexlify(bin.tostring())).upper()
+ _from_bytes = staticmethod(_from_bytes)
+
+ def data(offset, bytes):
+ """Return Data record. This constructs the full record, including
+ the length information, the record type (0x00), the
+ checksum, and the offset.
+
+ @param offset load offset of first byte.
+ @param bytes list of byte values to pack into record.
+
+ @return String representation of one HEX record
+ """
+ assert 0 <= offset < 65536
+ assert 0 < len(bytes) < 256
+ b = [len(bytes), (offset>>8)&0x0FF, offset&0x0FF, 0x00] + bytes
+ return Record._from_bytes(b)
+ data = staticmethod(data)
+
+ def eof():
+ """Return End of File record as a string.
+ @return String representation of Intel Hex EOF record
+ """
+ return ':00000001FF'
+ eof = staticmethod(eof)
+
+ def extended_segment_address(usba):
+ """Return Extended Segment Address Record.
+ @param usba Upper Segment Base Address.
+
+ @return String representation of Intel Hex USBA record.
+ """
+ b = [2, 0, 0, 0x02, (usba>>8)&0x0FF, usba&0x0FF]
+ return Record._from_bytes(b)
+ extended_segment_address = staticmethod(extended_segment_address)
+
+ def start_segment_address(cs, ip):
+ """Return Start Segment Address Record.
+ @param cs 16-bit value for CS register.
+ @param ip 16-bit value for IP register.
+
+ @return String representation of Intel Hex SSA record.
+ """
+ b = [4, 0, 0, 0x03, (cs>>8)&0x0FF, cs&0x0FF,
+ (ip>>8)&0x0FF, ip&0x0FF]
+ return Record._from_bytes(b)
+ start_segment_address = staticmethod(start_segment_address)
+
+ def extended_linear_address(ulba):
+ """Return Extended Linear Address Record.
+ @param ulba Upper Linear Base Address.
+
+ @return String representation of Intel Hex ELA record.
+ """
+ b = [2, 0, 0, 0x04, (ulba>>8)&0x0FF, ulba&0x0FF]
+ return Record._from_bytes(b)
+ extended_linear_address = staticmethod(extended_linear_address)
+
+ def start_linear_address(eip):
+ """Return Start Linear Address Record.
+ @param eip 32-bit linear address for the EIP register.
+
+ @return String representation of Intel Hex SLA record.
+ """
+ b = [4, 0, 0, 0x05, (eip>>24)&0x0FF, (eip>>16)&0x0FF,
+ (eip>>8)&0x0FF, eip&0x0FF]
+ return Record._from_bytes(b)
+ start_linear_address = staticmethod(start_linear_address)
+
+
+class _BadFileNotation(Exception):
+ """Special error class to use with _get_file_and_addr_range."""
+ pass
+
+def _get_file_and_addr_range(s, _support_drive_letter=None):
+ """Special method for hexmerge.py script to split file notation
+ into 3 parts: (filename, start, end)
+
+ @raise _BadFileNotation when string cannot be safely split.
+ """
+ if _support_drive_letter is None:
+ _support_drive_letter = (os.name == 'nt')
+ drive = ''
+ if _support_drive_letter:
+ if s[1:2] == ':' and s[0].upper() in ''.join([chr(i) for i in range(ord('A'), ord('Z')+1)]):
+ drive = s[:2]
+ s = s[2:]
+ parts = s.split(':')
+ n = len(parts)
+ if n == 1:
+ fname = parts[0]
+ fstart = None
+ fend = None
+ elif n != 3:
+ raise _BadFileNotation
+ else:
+ fname = parts[0]
+ def ascii_hex_to_int(ascii):
+ if ascii is not None:
+ try:
+ return int(ascii, 16)
+ except ValueError:
+ raise _BadFileNotation
+ return ascii
+ fstart = ascii_hex_to_int(parts[1] or None)
+ fend = ascii_hex_to_int(parts[2] or None)
+ return drive+fname, fstart, fend
+
+
+##
+# IntelHex Errors Hierarchy:
+#
+# IntelHexError - basic error
+# HexReaderError - general hex reader error
+# AddressOverlapError - data for the same address overlap
+# HexRecordError - hex record decoder base error
+# RecordLengthError - record has invalid length
+# RecordTypeError - record has invalid type (RECTYP)
+# RecordChecksumError - record checksum mismatch
+# EOFRecordError - invalid EOF record (type 01)
+# ExtendedAddressRecordError - extended address record base error
+# ExtendedSegmentAddressRecordError - invalid extended segment address record (type 02)
+# ExtendedLinearAddressRecordError - invalid extended linear address record (type 04)
+# StartAddressRecordError - start address record base error
+# StartSegmentAddressRecordError - invalid start segment address record (type 03)
+# StartLinearAddressRecordError - invalid start linear address record (type 05)
+# DuplicateStartAddressRecordError - start address record appears twice
+# InvalidStartAddressValueError - invalid value of start addr record
+# _EndOfFile - it's not real error, used internally by hex reader as signal that EOF record found
+# BadAccess16bit - not enough data to read 16 bit value (deprecated, see NotEnoughDataError)
+# NotEnoughDataError - not enough data to read N contiguous bytes
+# EmptyIntelHexError - requested operation cannot be performed with empty object
+
+class IntelHexError(Exception):
+ '''Base Exception class for IntelHex module'''
+
+ _fmt = 'IntelHex base error' #: format string
+
+ def __init__(self, msg=None, **kw):
+ """Initialize the Exception with the given message.
+ """
+ self.msg = msg
+ for key, value in kw.items():
+ setattr(self, key, value)
+
+ def __str__(self):
+ """Return the message in this Exception."""
+ if self.msg:
+ return self.msg
+ try:
+ return self._fmt % self.__dict__
+ except (NameError, ValueError, KeyError), e:
+ return 'Unprintable exception %s: %s' \
+ % (repr(e), str(e))
+
+class _EndOfFile(IntelHexError):
+ """Used for internal needs only."""
+ _fmt = 'EOF record reached -- signal to stop read file'
+
+class HexReaderError(IntelHexError):
+ _fmt = 'Hex reader base error'
+
+class AddressOverlapError(HexReaderError):
+ _fmt = 'Hex file has data overlap at address 0x%(address)X on line %(line)d'
+
+# class NotAHexFileError was removed in trunk.revno.54 because it's not used
+
+
+class HexRecordError(HexReaderError):
+ _fmt = 'Hex file contains invalid record at line %(line)d'
+
+
+class RecordLengthError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid length'
+
+class RecordTypeError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid record type'
+
+class RecordChecksumError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid checksum'
+
+class EOFRecordError(HexRecordError):
+ _fmt = 'File has invalid End-of-File record'
+
+
+class ExtendedAddressRecordError(HexRecordError):
+ _fmt = 'Base class for extended address exceptions'
+
+class ExtendedSegmentAddressRecordError(ExtendedAddressRecordError):
+ _fmt = 'Invalid Extended Segment Address Record at line %(line)d'
+
+class ExtendedLinearAddressRecordError(ExtendedAddressRecordError):
+ _fmt = 'Invalid Extended Linear Address Record at line %(line)d'
+
+
+class StartAddressRecordError(HexRecordError):
+ _fmt = 'Base class for start address exceptions'
+
+class StartSegmentAddressRecordError(StartAddressRecordError):
+ _fmt = 'Invalid Start Segment Address Record at line %(line)d'
+
+class StartLinearAddressRecordError(StartAddressRecordError):
+ _fmt = 'Invalid Start Linear Address Record at line %(line)d'
+
+class DuplicateStartAddressRecordError(StartAddressRecordError):
+ _fmt = 'Start Address Record appears twice at line %(line)d'
+
+class InvalidStartAddressValueError(StartAddressRecordError):
+ _fmt = 'Invalid start address value: %(start_addr)s'
+
+
+class NotEnoughDataError(IntelHexError):
+ _fmt = ('Bad access at 0x%(address)X: '
+ 'not enough data to read %(length)d contiguous bytes')
+
+class BadAccess16bit(NotEnoughDataError):
+ _fmt = 'Bad access at 0x%(address)X: not enough data to read 16 bit value'
+
+class EmptyIntelHexError(IntelHexError):
+ _fmt = "Requested operation cannot be executed with empty object"
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/compat.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/compat.py
new file mode 100644
index 0000000..3f48350
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/intelhex/compat.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2011, Bernhard Leiner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms,
+# with or without modification, are permitted provided
+# that the following conditions are met:
+#
+# * Redistributions of source code must retain
+# the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce
+# the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the author nor the names
+# of its contributors may be used to endorse
+# or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+'''Compatibility functions for python 2 and 3.
+
+@author Bernhard Leiner (bleiner AT gmail com)
+@version 1.0
+'''
+
+__docformat__ = "javadoc"
+
+
+import sys
+
+if sys.version_info[0] >= 3:
+ def asbytes(s):
+ if isinstance(s, bytes):
+ return s
+ return s.encode('latin1')
+ def asstr(s):
+ if isinstance(s, str):
+ return s
+ return s.decode('latin1')
+else:
+ asbytes = str
+ asstr = str
+
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/manifest.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/manifest.py
new file mode 100644
index 0000000..c65e7dd
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/manifest.py
@@ -0,0 +1,239 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python libraries
+import json
+import binascii
+import os
+
+# Nordic libraries
+from nordicsemi.exceptions import NotImplementedException
+from nordicsemi.dfu.init_packet import PacketField
+from nordicsemi.dfu.model import HexType, FirmwareKeys
+
+
+class ManifestGenerator(object):
+ def __init__(self, dfu_version, firmwares_data):
+ """
+ The Manifest Generator constructor. Needs a data structure to generate a manifest from.
+
+ :type float dfu_version: The dfu version number to state in manifest
+ :type dict firmwares_data: The firmwares data structure describing the Nordic DFU package
+ """
+ self.dfu_version = dfu_version
+ self.firmwares_data = firmwares_data
+ self.manifest = None
+
+ def generate_manifest(self):
+ self.manifest = Manifest()
+ self.manifest.dfu_version = self.dfu_version
+
+ for key in self.firmwares_data:
+ firmware_dict = self.firmwares_data[key]
+
+ if key == HexType.SD_BL:
+ _firmware = SoftdeviceBootloaderFirmware()
+ _firmware.bl_size = firmware_dict[FirmwareKeys.BL_SIZE]
+ _firmware.sd_size = firmware_dict[FirmwareKeys.SD_SIZE]
+ else:
+ _firmware = Firmware()
+
+ # Strip path, add only filename
+ _firmware.bin_file = os.path.basename(firmware_dict[FirmwareKeys.BIN_FILENAME])
+ _firmware.dat_file = os.path.basename(firmware_dict[FirmwareKeys.DAT_FILENAME])
+
+ init_packet_data = InitPacketData()
+
+ for init_packet_data_key in firmware_dict[FirmwareKeys.INIT_PACKET_DATA]:
+ field = firmware_dict[FirmwareKeys.INIT_PACKET_DATA][init_packet_data_key]
+
+ if init_packet_data_key == PacketField.APP_VERSION:
+ init_packet_data.application_version = field
+ elif init_packet_data_key == PacketField.DEVICE_TYPE:
+ init_packet_data.device_type = field
+ elif init_packet_data_key == PacketField.DEVICE_REVISION:
+ init_packet_data.device_revision = field
+ elif init_packet_data_key == PacketField.REQUIRED_SOFTDEVICES_ARRAY:
+ init_packet_data.softdevice_req = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID:
+ init_packet_data.ext_packet_id = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH:
+ init_packet_data.firmware_length = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ init_packet_data.firmware_hash = binascii.hexlify(field)
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16:
+ init_packet_data.firmware_crc16 = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ init_packet_data.init_packet_ecds = binascii.hexlify(field)
+ else:
+ raise NotImplementedException(
+ "Support for init packet data type {0} not implemented yet.".format(init_packet_data_key))
+
+ _firmware.init_packet_data = init_packet_data
+
+ if key == HexType.APPLICATION:
+ self.manifest.application = _firmware
+ elif key == HexType.BOOTLOADER:
+ self.manifest.bootloader = _firmware
+ elif key == HexType.SOFTDEVICE:
+ self.manifest.softdevice = _firmware
+ elif key == HexType.SD_BL:
+ self.manifest.softdevice_bootloader = _firmware
+ else:
+ raise NotImplementedException("Support for firmware type {0} not implemented yet.".format(key))
+
+ return self.to_json()
+
+ def to_json(self):
+ def remove_none_entries(d):
+ if not isinstance(d, dict):
+ return d
+
+ return dict((k, remove_none_entries(v)) for k, v in d.iteritems() if v is not None)
+
+ return json.dumps({'manifest': self.manifest},
+ default=lambda o: remove_none_entries(o.__dict__),
+ sort_keys=True, indent=4,
+ separators=(',', ': '))
+
+
+class InitPacketData(object):
+ def __init__(self,
+ device_type=None,
+ device_revision=None,
+ application_version=None,
+ softdevice_req=None,
+ ext_packet_id=None,
+ firmware_length=None,
+ firmware_hash=None,
+ firmware_crc16=None,
+ init_packet_ecds=None
+ ):
+ """
+ The InitPacketData data model.
+
+ :param int device_type: device type
+ :param int device_revision: device revision
+ :param int application_version: application version
+ :param list softdevice_req: softdevice requirements
+ :param int ext_packet_id: packet extension id
+ :param int firmware_length: firmware length
+ :param str firmware_hash: firmware hash
+ :param int firmware_crc16: firmware CRC-16 calculated value
+ :param str init_packet_ecds: Init packet signature
+ :return: InitPacketData
+ """
+ self.device_type = device_type
+ self.device_revision = device_revision
+ self.application_version = application_version
+ self.softdevice_req = softdevice_req
+ self.ext_packet_id = ext_packet_id
+ self.firmware_length = firmware_length
+ self.firmware_hash = firmware_hash
+ self.firmware_crc16 = firmware_crc16
+ self.init_packet_ecds = init_packet_ecds
+
+
+class Firmware(object):
+ def __init__(self,
+ bin_file=None,
+ dat_file=None,
+ init_packet_data=None):
+ """
+ The firmware datamodel
+
+ :param str bin_file: Firmware binary file
+ :param str dat_file: Firmware .dat file (init packet for Nordic DFU)
+ :param dict init_packet_data: Initial packet data
+ :return:
+ """
+ self.dat_file = dat_file
+ self.bin_file = bin_file
+
+ if init_packet_data:
+ self.init_packet_data = InitPacketData(**init_packet_data)
+
+
+class SoftdeviceBootloaderFirmware(Firmware):
+ def __init__(self,
+ bin_file=None,
+ dat_file=None,
+ init_packet_data=None,
+ sd_size=None,
+ bl_size=None):
+ """
+ The SoftdeviceBootloaderFirmware data model
+
+ :param str bin_file: Firmware binary file
+ :param str dat_file: Firmware .dat file (init packet for Nordic DFU)
+ :param int sd_size: The softdevice size
+ :param int bl_size: The bootloader size
+ :return: SoftdeviceBootloaderFirmware
+ """
+ super(SoftdeviceBootloaderFirmware, self).__init__(
+ bin_file,
+ dat_file,
+ init_packet_data)
+ self.sd_size = sd_size
+ self.bl_size = bl_size
+
+
+class Manifest:
+ def __init__(self,
+ application=None,
+ bootloader=None,
+ softdevice=None,
+ softdevice_bootloader=None,
+ dfu_version=None):
+ """
+ The Manifest data model.
+
+ :param dict application: Application firmware in package
+ :param dict bootloader: Bootloader firmware in package
+ :param dict softdevice: Softdevice firmware in package
+ :param dict softdevice_bootloader: Combined softdevice and bootloader firmware in package
+ :return: Manifest
+ """
+ self.softdevice_bootloader = \
+ SoftdeviceBootloaderFirmware(**softdevice_bootloader) if softdevice_bootloader else None
+
+ self.softdevice = Firmware(**softdevice) if softdevice else None
+ self.bootloader = Firmware(**bootloader) if bootloader else None
+ self.application = Firmware(**application) if application else None
+ self.dfu_version = dfu_version
+
+ @staticmethod
+ def from_json(data):
+ """
+ Parses a manifest according to Nordic DFU package specification.
+
+ :param str data: The manifest in string format
+ :return: Manifest
+ """
+ kwargs = json.loads(data)
+ return Manifest(**kwargs['manifest'])
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/model.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/model.py
new file mode 100644
index 0000000..a5c3426
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/model.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from enum import Enum
+
+
+class HexType(object):
+ SOFTDEVICE = 1
+ BOOTLOADER = 2
+ SD_BL = 3
+ APPLICATION = 4
+
+
+class FirmwareKeys(Enum):
+ ENCRYPT = 1
+ FIRMWARE_FILENAME = 2
+ BIN_FILENAME = 3
+ DAT_FILENAME = 4
+ INIT_PACKET_DATA = 5
+ SD_SIZE = 6
+ BL_SIZE = 7
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/nrfhex.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/nrfhex.py
new file mode 100644
index 0000000..67a5d5c
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/nrfhex.py
@@ -0,0 +1,168 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from nordicsemi.dfu import intelhex
+from struct import unpack
+
+
+class nRFHex(intelhex.IntelHex):
+ """
+ Converts and merges .hex and .bin files into one .bin file.
+ """
+
+ info_struct_address_base = 0x00003000
+ info_struct_address_offset = 0x1000
+
+ info_struct_magic_number = 0x51B1E5DB
+ info_struct_magic_number_offset = 0x004
+
+ s1x0_mbr_end_address = 0x1000
+ s132_mbr_end_address = 0x3000
+
+ def __init__(self, source, bootloader=None):
+ """
+ Constructor that requires a firmware file path.
+ Softdevices can take an optional bootloader file path as parameter.
+
+ :param str source: The file path for the firmware
+ :param str bootloader: Optional file path to bootloader firmware
+ :return: None
+ """
+ super(nRFHex, self).__init__()
+
+ self.file_format = 'hex'
+
+ if source.endswith('.bin'):
+ self.file_format = 'bin'
+
+ self.loadfile(source, self.file_format)
+
+ self._removeuicr()
+
+ self.bootloaderhex = None
+
+ if bootloader is not None:
+ self.bootloaderhex = nRFHex(bootloader)
+
+ def _removeuicr(self):
+ uicr_start_address = 0x10000000
+ maxaddress = self.maxaddr()
+ if maxaddress >= uicr_start_address:
+ for i in range(uicr_start_address, maxaddress + 1):
+ self._buf.pop(i, 0)
+
+ def address_has_magic_number(self, address):
+ try:
+ potential_magic_number = self.gets(address, 4)
+ potential_magic_number = unpack('I', potential_magic_number)[0]
+ return nRFHex.info_struct_magic_number == potential_magic_number
+ except Exception:
+ return False
+
+ def get_softdevice_variant(self):
+ potential_magic_number_address = nRFHex.info_struct_address_base + nRFHex.info_struct_magic_number_offset
+
+ if self.address_has_magic_number(potential_magic_number_address):
+ return "s1x0"
+
+ for i in xrange(4):
+ potential_magic_number_address += nRFHex.info_struct_address_offset
+
+ if self.address_has_magic_number(potential_magic_number_address):
+ return "s132"
+
+ return "unknown"
+
+ def get_mbr_end_address(self):
+ softdevice_variant = self.get_softdevice_variant()
+
+ if softdevice_variant == "s132":
+ return nRFHex.s132_mbr_end_address
+ else:
+ return nRFHex.s1x0_mbr_end_address
+
+ def minaddr(self):
+ min_address = super(nRFHex, self).minaddr()
+
+ # Lower addresses are reserved for master boot record
+ if self.file_format != 'bin':
+ min_address = max(self.get_mbr_end_address(), min_address)
+
+ return min_address
+
+ def size(self):
+ """
+ Returns the size of the source.
+ :return: int
+ """
+ min_address = self.minaddr()
+ max_address = self.maxaddr()
+
+ size = max_address - min_address + 1
+
+ # Round up to nearest word
+ word_size = 4
+ number_of_words = (size + (word_size - 1)) / word_size
+ size = number_of_words * word_size
+
+ return size
+
+ def bootloadersize(self):
+ """
+ Returns the size of the bootloader.
+ :return: int
+ """
+ if self.bootloaderhex is None:
+ return 0
+
+ return self.bootloaderhex.size()
+
+ def tobinfile(self, fobj, start=None, end=None, pad=None, size=None):
+ """
+ Writes a binary version of source and bootloader respectivly to fobj which could be a
+ file object or a file path.
+
+ :param str fobj: File path or object the function writes to
+ :return: None
+ """
+ # If there is a bootloader this will make the recursion call use the samme file object.
+ if getattr(fobj, "write", None) is None:
+ fobj = open(fobj, "wb")
+ close_fd = True
+ else:
+ close_fd = False
+
+ start_address = self.minaddr()
+ size = self.size()
+ super(nRFHex, self).tobinfile(fobj, start=start_address, size=size)
+
+ if self.bootloaderhex is not None:
+ self.bootloaderhex.tobinfile(fobj)
+
+ if close_fd:
+ fobj.close()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/package.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/package.py
new file mode 100644
index 0000000..68c1d80
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/package.py
@@ -0,0 +1,369 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python standard library
+import os
+import tempfile
+import shutil
+
+# 3rd party libraries
+from zipfile import ZipFile
+import hashlib
+
+
+# Nordic libraries
+from nordicsemi.exceptions import NordicSemiException
+from nordicsemi.dfu.nrfhex import *
+from nordicsemi.dfu.init_packet import *
+from nordicsemi.dfu.manifest import ManifestGenerator, Manifest
+from nordicsemi.dfu.model import HexType, FirmwareKeys
+from nordicsemi.dfu.crc16 import *
+
+from signing import Signing
+
+
+class Package(object):
+ """
+ Packages and unpacks Nordic DFU packages. Nordic DFU packages are zip files that contains firmware and meta-information
+ necessary for utilities to perform a DFU on nRF5X devices.
+
+ The internal data model used in Package is a dictionary. The dictionary is expressed like this in
+ json format:
+
+ {
+ "manifest": {
+ "bootloader": {
+ "bin_file": "asdf.bin",
+ "dat_file": "asdf.dat",
+ "init_packet_data": {
+ "application_version": null,
+ "device_revision": null,
+ "device_type": 5,
+ "firmware_hash": "asdfasdkfjhasdkfjashfkjasfhaskjfhkjsdfhasjkhf",
+ "softdevice_req": [
+ 17,
+ 18
+ ]
+ }
+ }
+ }
+
+ Attributes application, bootloader, softdevice, softdevice_bootloader shall not be put into the manifest if they are null
+
+ """
+
+ DEFAULT_DEV_TYPE = 0xFFFF
+ DEFAULT_DEV_REV = 0xFFFF
+ DEFAULT_APP_VERSION = 0xFFFFFFFF
+ DEFAULT_SD_REQ = [0xFFFE]
+ DEFAULT_DFU_VER = 0.5
+ MANIFEST_FILENAME = "manifest.json"
+
+ def __init__(self,
+ dev_type=DEFAULT_DEV_TYPE,
+ dev_rev=DEFAULT_DEV_REV,
+ app_version=DEFAULT_APP_VERSION,
+ sd_req=DEFAULT_SD_REQ,
+ app_fw=None,
+ bootloader_fw=None,
+ softdevice_fw=None,
+ dfu_ver=DEFAULT_DFU_VER,
+ key_file=None):
+ """
+ Constructor that requires values used for generating a Nordic DFU package.
+
+ :param int dev_type: Device type init-packet field
+ :param int dev_rev: Device revision init-packet field
+ :param int app_version: App version init-packet field
+ :param list sd_req: Softdevice Requirement init-packet field
+ :param str app_fw: Path to application firmware file
+ :param str bootloader_fw: Path to bootloader firmware file
+ :param str softdevice_fw: Path to softdevice firmware file
+ :param float dfu_ver: DFU version to use when generating init-packet
+ :param str key_file: Path to Signing key file (PEM)
+ :return: None
+ """
+ self.dfu_ver = dfu_ver
+
+ init_packet_vars = {}
+
+ if dev_type is not None:
+ init_packet_vars[PacketField.DEVICE_TYPE] = dev_type
+
+ if dev_rev is not None:
+ init_packet_vars[PacketField.DEVICE_REVISION] = dev_rev
+
+ if app_version is not None:
+ init_packet_vars[PacketField.APP_VERSION] = app_version
+
+ if sd_req is not None:
+ init_packet_vars[PacketField.REQUIRED_SOFTDEVICES_ARRAY] = sd_req
+
+ self.firmwares_data = {}
+
+ if app_fw:
+ self.__add_firmware_info(HexType.APPLICATION,
+ app_fw,
+ init_packet_vars)
+
+ if bootloader_fw:
+ self.__add_firmware_info(HexType.BOOTLOADER,
+ bootloader_fw,
+ init_packet_vars)
+
+ if softdevice_fw:
+ self.__add_firmware_info(HexType.SOFTDEVICE,
+ softdevice_fw,
+ init_packet_vars)
+
+ if key_file:
+ self.dfu_ver = 0.8
+ self.key_file = key_file
+
+ def generate_package(self, filename, preserve_work_directory=False):
+ """
+ Generates a Nordic DFU package. The package is a zip file containing firmware(s) and metadata required
+ for Nordic DFU applications to perform DFU onn nRF5X devices.
+
+ :param str filename: Filename for generated package.
+ :param bool preserve_work_directory: True to preserve the temporary working directory.
+ Useful for debugging of a package, and if the user wants to look at the generated package without having to
+ unzip it.
+ :return: None
+ """
+ work_directory = self.__create_temp_workspace()
+
+ if Package._is_bootloader_softdevice_combination(self.firmwares_data):
+ # Removing softdevice and bootloader data from dictionary and adding the combined later
+ softdevice_fw_data = self.firmwares_data.pop(HexType.SOFTDEVICE)
+ bootloader_fw_data = self.firmwares_data.pop(HexType.BOOTLOADER)
+
+ softdevice_fw_name = softdevice_fw_data[FirmwareKeys.FIRMWARE_FILENAME]
+ bootloader_fw_name = bootloader_fw_data[FirmwareKeys.FIRMWARE_FILENAME]
+
+ new_filename = "sd_bl.bin"
+ sd_bl_file_path = os.path.join(work_directory, new_filename)
+
+ nrf_hex = nRFHex(softdevice_fw_name, bootloader_fw_name)
+ nrf_hex.tobinfile(sd_bl_file_path)
+
+ softdevice_size = nrf_hex.size()
+ bootloader_size = nrf_hex.bootloadersize()
+
+ self.__add_firmware_info(HexType.SD_BL,
+ sd_bl_file_path,
+ softdevice_fw_data[FirmwareKeys.INIT_PACKET_DATA],
+ softdevice_size,
+ bootloader_size)
+
+ for key in self.firmwares_data:
+ firmware = self.firmwares_data[key]
+
+ # Normalize the firmware file and store it in the work directory
+ firmware[FirmwareKeys.BIN_FILENAME] = \
+ Package.normalize_firmware_to_bin(work_directory, firmware[FirmwareKeys.FIRMWARE_FILENAME])
+
+ # Calculate the hash for the .bin file located in the work directory
+ bin_file_path = os.path.join(work_directory, firmware[FirmwareKeys.BIN_FILENAME])
+
+ init_packet_data = firmware[FirmwareKeys.INIT_PACKET_DATA]
+
+ if self.dfu_ver <= 0.5:
+ firmware_hash = Package.calculate_crc16(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16] = firmware_hash
+ elif self.dfu_ver == 0.6:
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID] = INIT_PACKET_USES_CRC16
+ firmware_hash = Package.calculate_crc16(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16] = firmware_hash
+ elif self.dfu_ver == 0.7:
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID] = INIT_PACKET_USES_HASH
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH] = int(Package.calculate_file_size(bin_file_path))
+ firmware_hash = Package.calculate_sha256_hash(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH] = firmware_hash
+ elif self.dfu_ver == 0.8:
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID] = INIT_PACKET_EXT_USES_ECDS
+ firmware_hash = Package.calculate_sha256_hash(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH] = int(Package.calculate_file_size(bin_file_path))
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH] = firmware_hash
+ temp_packet = self._create_init_packet(firmware)
+ signer = Signing()
+ signer.load_key(self.key_file)
+ signature = signer.sign(temp_packet)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS] = signature
+
+ # Store the .dat file in the work directory
+ init_packet = self._create_init_packet(firmware)
+ init_packet_filename = firmware[FirmwareKeys.BIN_FILENAME].replace(".bin", ".dat")
+
+ with open(os.path.join(work_directory, init_packet_filename), 'wb') as init_packet_file:
+ init_packet_file.write(init_packet)
+
+ firmware[FirmwareKeys.DAT_FILENAME] = \
+ init_packet_filename
+
+ # Store the manifest to manifest.json
+ manifest = self.create_manifest()
+
+ with open(os.path.join(work_directory, Package.MANIFEST_FILENAME), "w") as manifest_file:
+ manifest_file.write(manifest)
+
+ # Package the work_directory to a zip file
+ Package.create_zip_package(work_directory, filename)
+
+ # Delete the temporary directory
+ if not preserve_work_directory:
+ shutil.rmtree(work_directory)
+
+ @staticmethod
+ def __create_temp_workspace():
+ return tempfile.mkdtemp(prefix="nrf_dfu_")
+
+ @staticmethod
+ def create_zip_package(work_directory, filename):
+ files = os.listdir(work_directory)
+
+ with ZipFile(filename, 'w') as package:
+ for _file in files:
+ file_path = os.path.join(work_directory, _file)
+ package.write(file_path, _file)
+
+ @staticmethod
+ def calculate_file_size(firmware_filename):
+ b = os.path.getsize(firmware_filename)
+ return b
+
+ @staticmethod
+ def calculate_sha256_hash(firmware_filename):
+ read_buffer = 4096
+
+ digest = hashlib.sha256()
+
+ with open(firmware_filename, 'rb') as firmware_file:
+ while True:
+ data = firmware_file.read(read_buffer)
+
+ if data:
+ digest.update(data)
+ else:
+ break
+
+ return digest.digest()
+
+ @staticmethod
+ def calculate_crc16(firmware_filename):
+ """
+ Calculates CRC16 has on provided firmware filename
+
+ :type str firmware_filename:
+ """
+ data_buffer = b''
+ read_size = 4096
+
+ with open(firmware_filename, 'rb') as firmware_file:
+ while True:
+ data = firmware_file.read(read_size)
+
+ if data:
+ data_buffer += data
+ else:
+ break
+
+ return calc_crc16(data_buffer, 0xffff)
+
+ def create_manifest(self):
+ manifest = ManifestGenerator(self.dfu_ver, self.firmwares_data)
+ return manifest.generate_manifest()
+
+ @staticmethod
+ def _is_bootloader_softdevice_combination(firmwares):
+ return (HexType.BOOTLOADER in firmwares) and (HexType.SOFTDEVICE in firmwares)
+
+ def __add_firmware_info(self, firmware_type, filename, init_packet_data, sd_size=None, bl_size=None):
+ self.firmwares_data[firmware_type] = {
+ FirmwareKeys.FIRMWARE_FILENAME: filename,
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data.copy(),
+ # Copying init packet to avoid using the same for all firmware
+ }
+
+ if firmware_type == HexType.SD_BL:
+ self.firmwares_data[firmware_type][FirmwareKeys.SD_SIZE] = sd_size
+ self.firmwares_data[firmware_type][FirmwareKeys.BL_SIZE] = bl_size
+
+ @staticmethod
+ def _create_init_packet(firmware_data):
+ p = Packet(firmware_data[FirmwareKeys.INIT_PACKET_DATA])
+ return p.generate_packet()
+
+ @staticmethod
+ def normalize_firmware_to_bin(work_directory, firmware_path):
+ firmware_filename = os.path.basename(firmware_path)
+ new_filename = firmware_filename.replace(".hex", ".bin")
+ new_filepath = os.path.join(work_directory, new_filename)
+
+ if not os.path.exists(new_filepath):
+ temp = nRFHex(firmware_path)
+ temp.tobinfile(new_filepath)
+
+ return new_filepath
+
+ @staticmethod
+ def unpack_package(package_path, target_dir):
+ """
+ Unpacks a Nordic DFU package.
+
+ :param str package_path: Path to the package
+ :param str target_dir: Target directory to unpack the package to
+ :return: Manifest Manifest: Returns a manifest back to the user. The manifest is a parse datamodel
+ of the manifest found in the Nordic DFU package.
+ """
+
+ if not os.path.isfile(package_path):
+ raise NordicSemiException("Package {0} not found.".format(package_path))
+
+ target_dir = os.path.abspath(target_dir)
+ target_base_path = os.path.dirname(target_dir)
+
+ if not os.path.exists(target_base_path):
+ raise NordicSemiException("Base path to target directory {0} does not exist.".format(target_base_path))
+
+ if not os.path.isdir(target_base_path):
+ raise NordicSemiException("Base path to target directory {0} is not a directory.".format(target_base_path))
+
+ if os.path.exists(target_dir):
+ raise NordicSemiException(
+ "Target directory {0} exists, not able to unpack to that directory.",
+ target_dir)
+
+ with ZipFile(package_path, 'r') as pkg:
+ pkg.extractall(target_dir)
+
+ with open(os.path.join(target_dir, Package.MANIFEST_FILENAME), 'r') as f:
+ _json = f.read()
+ """:type :str """
+
+ return Manifest.from_json(_json)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/signing.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/signing.py
new file mode 100644
index 0000000..ca98eb1
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/signing.py
@@ -0,0 +1,149 @@
+# Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
+#
+# The information contained herein is property of Nordic Semiconductor ASA.
+# Terms and conditions of usage are described in detail in NORDIC
+# SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+#
+# Licensees are granted free, non-transferable use of the information. NO
+# WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+# the file.
+
+import hashlib
+import binascii
+
+try:
+ from ecdsa import SigningKey
+ from ecdsa.curves import NIST256p
+ from ecdsa.keys import sigencode_string
+except Exception:
+ print "Failed to import ecdsa, cannot do signing"
+
+from nordicsemi.exceptions import InvalidArgumentException, IllegalStateException
+
+
+class Signing(object):
+ """
+ Class for singing of hex-files
+ """
+ def gen_key(self, filename):
+ """
+ Generate a new Signing key using NIST P-256 curve
+ """
+ self.sk = SigningKey.generate(curve=NIST256p)
+
+ with open(filename, "w") as sk_file:
+ sk_file.write(self.sk.to_pem())
+
+ def load_key(self, filename):
+ """
+ Load signing key (from pem file)
+ """
+ with open(filename, "r") as sk_file:
+ sk_pem = sk_file.read()
+
+ self.sk = SigningKey.from_pem(sk_pem)
+
+ sk_hex = "".join(c.encode('hex') for c in self.sk.to_string())
+
+ def sign(self, init_packet_data):
+ """
+ Create signature for init package using P-256 curve and SHA-256 as hashing algorithm
+ Returns R and S keys combined in a 64 byte array
+ """
+ # Add assertion of init_packet
+ if self.sk is None:
+ raise IllegalStateException("Can't save key. No key created/loaded")
+
+ # Sign the init-packet
+ signature = self.sk.sign(init_packet_data, hashfunc=hashlib.sha256, sigencode=sigencode_string)
+ return signature
+
+ def verify(self, init_packet, signature):
+ """
+ Verify init packet
+ """
+ # Add assertion of init_packet
+ if self.sk is None:
+ raise IllegalStateException("Can't save key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+
+ # Verify init packet
+ try:
+ vk.verify(signature, init_packet, hashfunc=hashlib.sha256)
+ except:
+ return False
+
+ return True
+
+ def get_vk(self, output_type):
+ """
+ Get verification key (as hex, code or pem)
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ if output_type is None:
+ raise InvalidArgumentException("Invalid output type for signature.")
+ elif output_type == 'hex':
+ return self.get_vk_hex()
+ elif output_type == 'code':
+ return self.get_vk_code()
+ elif output_type == 'pem':
+ return self.get_vk_pem()
+ else:
+ raise InvalidArgumentException("Invalid argument. Can't get key")
+
+ def get_vk_hex(self):
+ """
+ Get the verification key as hex
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+ vk_hexlify = binascii.hexlify(vk.to_string())
+
+ vk_hex = "Verification key Qx: {0}\n".format(vk_hexlify[0:64])
+ vk_hex += "Verification key Qy: {0}".format(vk_hexlify[64:128])
+
+ return vk_hex
+
+ def get_vk_code(self):
+ """
+ Get the verification key as code
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+ vk_hex = binascii.hexlify(vk.to_string())
+
+ vk_x_separated = ""
+ vk_x_str = vk_hex[0:64]
+ for i in xrange(0, len(vk_x_str), 2):
+ vk_x_separated += "0x" + vk_x_str[i:i+2] + ", "
+ vk_x_separated = vk_x_separated[:-2]
+
+ vk_y_separated = ""
+ vk_y_str = vk_hex[64:128]
+ for i in xrange(0, len(vk_y_str), 2):
+ vk_y_separated += "0x" + vk_y_str[i:i+2] + ", "
+ vk_y_separated = vk_y_separated[:-2]
+
+ vk_code = "static uint8_t Qx[] = {{ {0} }};\n".format(vk_x_separated)
+ vk_code += "static uint8_t Qy[] = {{ {0} }};".format(vk_y_separated)
+
+ return vk_code
+
+ def get_vk_pem(self):
+ """
+ Get the verification key as PEM
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+ vk_pem = vk.to_pem()
+
+ return vk_pem
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_dfu_transport_serial.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_dfu_transport_serial.py
new file mode 100644
index 0000000..2f9c4e8
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_dfu_transport_serial.py
@@ -0,0 +1,136 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import os
+import unittest
+
+# Nordic Semiconductor imports
+import sys
+from nordicsemi.dfu.dfu_transport import DfuEvent
+from nordicsemi.dfu import crc16
+from nordicsemi.dfu.init_packet import PacketField, Packet
+from nordicsemi.dfu.model import HexType
+from nordicsemi.dfu.dfu_transport_serial import DfuTransportSerial
+
+
+def setup_logging():
+ root = logging.getLogger()
+ root.setLevel(logging.DEBUG)
+
+ ch = logging.StreamHandler(sys.stdout)
+ ch.setLevel(logging.DEBUG)
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ ch.setFormatter(formatter)
+ root.addHandler(ch)
+
+
+@unittest.skip('Ignoring these tests since they take too much time to run.')
+class TestDfuTransportSerial(unittest.TestCase):
+ DEVKEY_PORT = "NORDICSEMI_PCA10028_1_PORT"
+
+ def setUp(self):
+ setup_logging()
+
+ # Assert that environment variables are setUp before starting tests.
+ # TODO: create generic functionality for fetching environment variables that map
+ # TODO: communication ports to PCA versions
+ # TODO: setup target nRF5X device to a given state (bootloader+sd+application)
+ if self.DEVKEY_PORT not in os.environ:
+ self.fail("Environment variable {0} not found. "
+ "Must specify serial port with development kit connected."
+ .format(self.DEVKEY_PORT))
+
+ self.transport = DfuTransportSerial(os.environ[self.DEVKEY_PORT],
+ baud_rate=38400,
+ flow_control=True)
+
+ def tearDown(self):
+ if self.transport and self.transport.is_open():
+ self.transport.close()
+
+ def test_open_close(self):
+ self.transport.open()
+ self.assertTrue(self.transport.is_open())
+ self.transport.close()
+ self.assertFalse(self.transport.is_open())
+
+ def test_dfu_methods(self):
+ def timeout_callback(log_message):
+ logging.debug("timeout_callback. Message: %s", log_message)
+
+ def progress_callback(progress, log_message, done):
+ logging.debug("Log message: %s, Progress: %d, done: %s", log_message, progress, done)
+
+ def error_callback(log_message=""):
+ logging.error("Log message: %s", log_message)
+
+ self.transport.register_events_callback(DfuEvent.TIMEOUT_EVENT, timeout_callback)
+ self.transport.register_events_callback(DfuEvent.PROGRESS_EVENT, progress_callback)
+ self.transport.register_events_callback(DfuEvent.ERROR_EVENT, error_callback())
+
+ firmware = ''
+ test_firmware_path = os.path.join("firmwares", "pca10028_nrf51422_xxac_blinky.bin")
+
+ with open(test_firmware_path, 'rb') as f:
+ while True:
+ data = f.read()
+
+ if data:
+ firmware += data
+ else:
+ break
+
+ crc = crc16.calc_crc16(firmware, 0xffff)
+
+ self.transport.open()
+
+ # Sending start DFU command to target
+ self.transport.send_start_dfu(HexType.APPLICATION,
+ app_size=len(firmware),
+ softdevice_size=0,
+ bootloader_size=0)
+
+ # Sending DFU init packet to target
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 0xfffa,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [0x005a],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: crc
+ }
+ pkt = Packet(init_packet_vars)
+ self.transport.send_init_packet(pkt.generate_packet())
+
+ # Sending firmware to target
+ self.transport.send_firmware(firmware)
+
+ # Validating firmware
+ self.transport.send_validate_firmware()
+ self.transport.send_activate_firmware()
+ self.transport.close()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_init_packet.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_init_packet.py
new file mode 100644
index 0000000..eaef3ec
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_init_packet.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+from nordicsemi.dfu.init_packet import *
+
+
+class TestInitPacket(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def test_generate_packet_a(self):
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 3,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [1111, 2222, 3333, 4444],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 2,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e",
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ '1\xd7B8\x129\xaa\xc3\xe6\x8b\xe2\x01\xd11\x17\x01\x00\xae\x1e\x04\xf9~q\xcd\xbfv"\xdan\xc0f2\xd49' +
+ '\xdc\xc7\xf8\xae\x16VV\x17\x90\xa3\x96\xadxPa\x0bs\xfe\xbdi]\xb2\x95\x81\x99\xe4\xb0\xcf\xe9\xda'
+ }
+
+ ip = Packet(init_packet_vars)
+ data = ip.generate_packet()
+ self.assertEqual(data, ("\x01\x00" # Device type
+ "\x02\x00" # Device revision
+ "\x03\x00\x00\x00" # App version
+ "\x04\x00" # Softdevice array length
+ "\x57\x04" # Softdevice entry #1
+ "\xae\x08" # Softdevice entry #2
+ "\x05\x0d" # Softdevice entry #3
+ "\x5c\x11" # Softdevice entry #4
+ "\x02\x00\x00\x00" # ext packet id
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12" # Firmware hash, part one
+ "\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e" # Firmware hash, part two
+ '1\xd7B8\x129\xaa\xc3\xe6\x8b\xe2\x01\xd11\x17\x01' # Init packet ECDS, part 1
+ '\x00\xae\x1e\x04\xf9~q\xcd\xbfv"\xdan\xc0f2\xd49' # Init packet ECDS, part 2
+ '\xdc\xc7\xf8\xae\x16VV\x17\x90\xa3\x96\xadxPa\x0b' # Init packet ECDS, part 3
+ 's\xfe\xbdi]\xb2\x95\x81\x99\xe4\xb0\xcf\xe9\xda' # Init packet ECDS, part 4
+ )
+ )
+
+ def test_generate_packet_b(self):
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 0xffeeffee,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [1111, 2222, 3333],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 1,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e"
+ }
+
+ ip = Packet(init_packet_vars)
+ data = ip.generate_packet()
+ self.assertEqual(data, ("\x01\x00" # Device type
+ "\x02\x00" # Device revision
+ "\xee\xff\xee\xff" # App version
+ "\x03\x00" # Softdevice array length
+ "\x57\x04" # Softdevice entry #1
+ "\xae\x08" # Softdevice entry #2
+ "\x05\x0d" # Softdevice entry #3
+ "\x01\x00\x00\x00" # ext packet id
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12" # Firmware hash, part one
+ "\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e" # Firmware hash, part two
+ )
+ )
+
+ def test_generate_packet_c(self):
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 0xffeeffee,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [1111, 2222, 3333],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 0,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: 0xfaae
+ }
+
+ ip = Packet(init_packet_vars)
+ data = ip.generate_packet()
+ self.assertEqual(data, ("\x01\x00" # Device type
+ "\x02\x00" # Device revision
+ "\xee\xff\xee\xff" # App version
+ "\x03\x00" # Softdevice array length
+ "\x57\x04" # Softdevice entry #1
+ "\xae\x08" # Softdevice entry #2
+ "\x05\x0d" # Softdevice entry #3
+ "\x00\x00\x00\x00" # ext packet id
+ "\xae\xfa" # CRC-16 checksum for firmware
+ )
+ )
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_manifest.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_manifest.py
new file mode 100644
index 0000000..f2755fe
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_manifest.py
@@ -0,0 +1,201 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import copy
+import json
+import unittest
+
+from nordicsemi.dfu.init_packet import PacketField
+from nordicsemi.dfu.manifest import ManifestGenerator, Manifest
+from nordicsemi.dfu.model import HexType
+from nordicsemi.dfu.package import FirmwareKeys
+
+
+class TestManifest(unittest.TestCase):
+ def setUp(self):
+ self.firmwares_data_a = {}
+
+ init_packet_data_a = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 1000,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [22, 11],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 2,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH: 1234,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ '\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e',
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ '1\xd7B8\x129\xaa\xc3\xe6\x8b\xe2\x01\xd11\x17\x01\x00\xae\x1e\x04\xf9~q\xcd\xbfv"\xdan\xc0f2\xd49' +
+ '\xdc\xc7\xf8\xae\x16VV\x17\x90\xa3\x96\xadxPa\x0bs\xfe\xbdi]\xb2\x95\x81\x99\xe4\xb0\xcf\xe9\xda'
+ }
+
+ self.firmwares_data_a[HexType.APPLICATION] = {
+ FirmwareKeys.BIN_FILENAME: "app_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "app_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data_a,
+ FirmwareKeys.ENCRYPT: False}
+
+ self.firmwares_data_a[HexType.SD_BL] = {
+ FirmwareKeys.BIN_FILENAME: "sd_bl_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "sd_bl_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: copy.copy(init_packet_data_a), # Fake the hash
+ FirmwareKeys.BL_SIZE: 50,
+ FirmwareKeys.SD_SIZE: 90
+ }
+
+ self.firmwares_data_b = {}
+
+ init_packet_data_b = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 1000,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [22, 11],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: 0xfaae
+ }
+
+ self.firmwares_data_b[HexType.APPLICATION] = {
+ FirmwareKeys.BIN_FILENAME: "app_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "app_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data_b
+ }
+
+ self.firmwares_data_b[HexType.BOOTLOADER] = {
+ FirmwareKeys.BIN_FILENAME: "bootloader_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "bootloader_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: copy.copy(init_packet_data_b), # Fake the hash
+ }
+
+ self.firmwares_data_c = {}
+
+ init_packet_data_c = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 1000,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [22, 11],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: 0xfaae
+ }
+
+ self.firmwares_data_c[HexType.SOFTDEVICE] = {
+ FirmwareKeys.BIN_FILENAME: "softdevice_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "softdevice_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data_c
+ }
+
+ def test_generate_manifest(self):
+ r = ManifestGenerator(0.5, self.firmwares_data_a)
+
+ _json = json.loads(r.generate_manifest())
+
+ # Test for presence of attributes in document
+ self.assertIn('manifest', _json)
+
+ manifest = _json['manifest']
+ self.assertIn('application', manifest)
+
+ application = manifest['application']
+ self.assertIn('init_packet_data', application)
+ self.assertIn('dat_file', application)
+ self.assertIn('bin_file', application)
+
+ init_packet_data = application['init_packet_data']
+ self.assertIn('firmware_hash', init_packet_data)
+ self.assertIn('softdevice_req', init_packet_data)
+ self.assertIn('device_revision', init_packet_data)
+ self.assertIn('device_type', init_packet_data)
+ self.assertIn('application_version', init_packet_data)
+
+ # Test for values in document
+ self.assertEqual("app_fw.bin", application['bin_file'])
+ self.assertEqual("app_fw.dat", application['dat_file'])
+
+ self.assertEqual(2, init_packet_data['ext_packet_id'])
+ self.assertEqual(1234, init_packet_data['firmware_length'])
+ self.assertEqual('c9d3bf69f21e88a0311e0dd242536112f842579bef265a24bd0255fd443f759e',
+ init_packet_data['firmware_hash'])
+ self.assertEqual('31d742381239aac3e68be201d131170100ae1e04f97e71cdbf7622da6ec06632d439dcc7f8ae1656561790a396ad7850610b73febd695db2958199e4b0cfe9da',
+ init_packet_data['init_packet_ecds'])
+ self.assertEqual(1000, init_packet_data['application_version'])
+ self.assertEqual(1, init_packet_data['device_type'])
+ self.assertEqual(2, init_packet_data['device_revision'])
+ self.assertEqual([22, 11], init_packet_data['softdevice_req'])
+
+ # Test softdevice_bootloader
+ bl_sd = manifest['softdevice_bootloader']
+ self.assertIsNotNone(bl_sd)
+ self.assertEqual(90, bl_sd['sd_size'])
+ self.assertEqual(50, bl_sd['bl_size'])
+
+ # Test for values in document
+ self.assertEqual("sd_bl_fw.bin", bl_sd['bin_file'])
+ self.assertEqual("sd_bl_fw.dat", bl_sd['dat_file'])
+
+ def test_manifest_a(self):
+ r = ManifestGenerator(0.5, self.firmwares_data_a)
+ m = Manifest.from_json(r.generate_manifest())
+ self.assertIsNotNone(m)
+ self.assertIsNotNone(m.application)
+ self.assertEqual("app_fw.bin", m.application.bin_file)
+ self.assertEqual("app_fw.dat", m.application.dat_file)
+ self.assertIsNone(m.bootloader)
+ self.assertIsNone(m.softdevice)
+ self.assertIsNotNone(m.softdevice_bootloader)
+ self.assertEqual(90, m.softdevice_bootloader.sd_size)
+ self.assertEqual(50, m.softdevice_bootloader.bl_size)
+ self.assertEqual("sd_bl_fw.bin", m.softdevice_bootloader.bin_file)
+ self.assertEqual("sd_bl_fw.dat", m.softdevice_bootloader.dat_file)
+
+ def test_manifest_b(self):
+ r = ManifestGenerator("0.5", self.firmwares_data_b)
+ m = Manifest.from_json(r.generate_manifest())
+ self.assertIsNotNone(m)
+ self.assertIsNotNone(m.application)
+ self.assertEqual("app_fw.bin", m.application.bin_file)
+ self.assertEqual("app_fw.dat", m.application.dat_file)
+ self.assertIsNotNone(m.bootloader)
+ self.assertEqual("bootloader_fw.bin", m.bootloader.bin_file)
+ self.assertEqual("bootloader_fw.dat", m.bootloader.dat_file)
+ self.assertIsNone(m.softdevice)
+ self.assertIsNone(m.softdevice_bootloader)
+ self.assertEqual(0xfaae, m.application.init_packet_data.firmware_crc16)
+ self.assertEqual(0xfaae, m.bootloader.init_packet_data.firmware_crc16)
+
+
+ def test_manifest_c(self):
+ r = ManifestGenerator("0.5", self.firmwares_data_c)
+ m = Manifest.from_json(r.generate_manifest())
+ self.assertIsNotNone(m)
+ self.assertIsNone(m.application)
+ self.assertIsNone(m.bootloader)
+ self.assertIsNotNone(m.softdevice)
+ self.assertEqual('softdevice_fw.bin', m.softdevice.bin_file)
+ self.assertEqual('softdevice_fw.dat', m.softdevice.dat_file)
+ self.assertIsNone(m.softdevice_bootloader)
+ self.assertEqual(0xfaae, m.softdevice.init_packet_data.firmware_crc16)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_nrfhex.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_nrfhex.py
new file mode 100644
index 0000000..e2f2f2d
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_nrfhex.py
@@ -0,0 +1,134 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+
+import unittest
+import nordicsemi.dfu.nrfhex as nrfhex
+import nordicsemi.dfu.intelhex as intelhex
+
+
+class TestnRFHex(unittest.TestCase):
+ def setUp(self):
+ script_abspath = os.path.abspath(__file__)
+ script_dirname = os.path.dirname(script_abspath)
+ os.chdir(script_dirname)
+
+ def comparefiles(self, actual, wanted):
+ actualfile = intelhex.IntelHex()
+ actualfile.loadfile(actual, format="bin")
+
+ wantedfile = intelhex.IntelHex()
+ wantedfile.loadfile(wanted, format="bin")
+
+ self.assertEqual(actualfile.minaddr(), wantedfile.minaddr())
+ self.assertEqual(actualfile.maxaddr(), wantedfile.maxaddr())
+
+ minaddress = actualfile.minaddr()
+ maxaddress = actualfile.maxaddr()
+
+ length = maxaddress - minaddress
+
+ actualfile_data = actualfile.gets(minaddress, length)
+ wantedfile_data = wantedfile.gets(minaddress, length)
+
+ self.assertEqual(actualfile_data, wantedfile_data)
+
+ def test_tobinfile_single_file_without_uicr_content(self):
+ nrf = nrfhex.nRFHex("firmwares/bar.hex")
+ nrf.tobinfile("firmwares/bar.bin")
+
+ self.comparefiles("firmwares/bar.bin", "firmwares/bar_wanted.bin")
+
+ def test_tobinfile_single_file_with_uicr_content(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex")
+ nrf.tobinfile("firmwares/foo.bin")
+
+ self.comparefiles("firmwares/foo.bin", "firmwares/foo_wanted.bin")
+
+ def test_tobinfile_single_bin_file(self):
+ nrf = nrfhex.nRFHex("firmwares/bar_wanted.bin")
+ nrf.tobinfile("firmwares/bar.bin")
+
+ self.comparefiles("firmwares/bar.bin", "firmwares/bar_wanted.bin")
+
+ def test_tobinfile_two_hex_files(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar.hex")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_tobinfile_one_hex_one_bin(self):
+ nrf = nrfhex.nRFHex("firmwares/foo_wanted.bin", "firmwares/bar.hex")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_tobinfile_one_bin_one_hex(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar_wanted.bin")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_tobinfile_two_bin(self):
+ nrf = nrfhex.nRFHex("firmwares/foo_wanted.bin", "firmwares/bar_wanted.bin")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_sizes(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar.hex")
+
+ self.assertEqual(nrf.get_mbr_end_address(), 0x1000)
+ self.assertEqual(nrf.minaddr(), 0x1000)
+ self.assertEqual(nrf.size(), 73152)
+ self.assertEqual(nrf.bootloadersize(), 13192)
+
+ nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex")
+
+ self.assertEqual(nrf.get_mbr_end_address(), 0x3000)
+ self.assertEqual(nrf.minaddr(), 0x3000)
+ self.assertEqual(nrf.size(), 12288)
+ self.assertEqual(nrf.bootloadersize(), 0)
+
+ def test_get_softdevice_variant(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex")
+
+ self.assertEqual(nrf.get_softdevice_variant(), "unknown")
+
+ nrf = nrfhex.nRFHex("firmwares/s130_nrf51_mini.hex")
+
+ self.assertEqual(nrf.get_softdevice_variant(), "s1x0")
+
+ nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex")
+
+ self.assertEqual(nrf.get_softdevice_variant(), "s132")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_package.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_package.py
new file mode 100644
index 0000000..36dbda0
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_package.py
@@ -0,0 +1,164 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json
+import os
+import tempfile
+import unittest
+from zipfile import ZipFile
+import shutil
+
+from nordicsemi.dfu.package import Package
+
+
+class TestPackage(unittest.TestCase):
+ def setUp(self):
+ self.work_directory = tempfile.mkdtemp(prefix="nrf_dfu_tests_")
+
+ def tearDown(self):
+ shutil.rmtree(self.work_directory, ignore_errors=True)
+
+ def test_generate_package_application(self):
+ self.p = Package(
+ dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xfffe],
+ app_fw="firmwares/bar.hex"
+ )
+
+ pkg_name = "mypackage.zip"
+
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+ expected_zip_content = ["manifest.json", "bar.bin", "bar.dat"]
+
+ with ZipFile(pkg_name, 'r') as pkg:
+ infolist = pkg.infolist()
+
+ for file_information in infolist:
+ self.assertTrue(file_information.filename in expected_zip_content)
+ self.assertGreater(file_information.file_size, 0)
+
+ # Extract all and load json document to see if it is correct regarding to paths
+ pkg.extractall(self.work_directory)
+
+ with open(os.path.join(self.work_directory, 'manifest.json'), 'r') as f:
+ _json = json.load(f)
+ self.assertEqual(u'bar.bin', _json['manifest']['application']['bin_file'])
+ self.assertEqual(u'bar.dat', _json['manifest']['application']['dat_file'])
+ self.assertTrue(u'softdevice' not in _json['manifest'])
+ self.assertTrue(u'softdevice_bootloader' not in _json['manifest'])
+ self.assertTrue(u'bootloader' not in _json['manifest'])
+
+ def test_generate_package_sd_bl(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xfffe],
+ softdevice_fw="firmwares/foo.hex",
+ bootloader_fw="firmwares/bar.hex")
+
+ pkg_name = "mypackage.zip"
+
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ expected_zip_content = ["manifest.json", "sd_bl.bin", "sd_bl.dat"]
+
+ with ZipFile(pkg_name, 'r') as pkg:
+ infolist = pkg.infolist()
+
+ for file_information in infolist:
+ self.assertTrue(file_information.filename in expected_zip_content)
+ self.assertGreater(file_information.file_size, 0)
+
+ # Extract all and load json document to see if it is correct regarding to paths
+ pkg.extractall(self.work_directory)
+
+ with open(os.path.join(self.work_directory, 'manifest.json'), 'r') as f:
+ _json = json.load(f)
+ self.assertEqual(u'sd_bl.bin', _json['manifest']['softdevice_bootloader']['bin_file'])
+ self.assertEqual(u'sd_bl.dat', _json['manifest']['softdevice_bootloader']['dat_file'])
+
+ def test_unpack_package_a(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xffff],
+ softdevice_fw="firmwares/bar.hex",
+ dfu_ver=0.6)
+ pkg_name = os.path.join(self.work_directory, "mypackage.zip")
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ unpacked_dir = os.path.join(self.work_directory, "unpacked")
+ manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir)
+ self.assertIsNotNone(manifest)
+ self.assertEqual(u'bar.bin', manifest.softdevice.bin_file)
+ self.assertEqual(0, manifest.softdevice.init_packet_data.ext_packet_id)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.firmware_crc16)
+
+ def test_unpack_package_b(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xffff],
+ softdevice_fw="firmwares/bar.hex",
+ dfu_ver=0.7)
+ pkg_name = os.path.join(self.work_directory, "mypackage.zip")
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ unpacked_dir = os.path.join(self.work_directory, "unpacked")
+ manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir)
+ self.assertIsNotNone(manifest)
+ self.assertEqual(u'bar.bin', manifest.softdevice.bin_file)
+ self.assertEqual(1, manifest.softdevice.init_packet_data.ext_packet_id)
+ self.assertIsNone(manifest.softdevice.init_packet_data.firmware_crc16)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.firmware_hash)
+
+ def test_unpack_package_c(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xffff],
+ softdevice_fw="firmwares/bar.hex",
+ key_file="key.pem")
+ pkg_name = os.path.join(self.work_directory, "mypackage.zip")
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ unpacked_dir = os.path.join(self.work_directory, "unpacked")
+ manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir)
+ self.assertIsNotNone(manifest)
+ self.assertEqual(u'bar.bin', manifest.softdevice.bin_file)
+ self.assertEqual(2, manifest.softdevice.init_packet_data.ext_packet_id)
+ self.assertIsNone(manifest.softdevice.init_packet_data.firmware_crc16)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.firmware_hash)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.init_packet_ecds)
+ self.assertEqual(manifest.dfu_version, 0.8)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_signing.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_signing.py
new file mode 100644
index 0000000..3b19fb0
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/tests/test_signing.py
@@ -0,0 +1,155 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import binascii
+import os
+import shutil
+import tempfile
+import unittest
+
+from nordicsemi.dfu.signing import Signing
+from nordicsemi.dfu.init_packet import Packet, PacketField
+
+
+class TestSinging(unittest.TestCase):
+ def setUp(self):
+ script_abspath = os.path.abspath(__file__)
+ script_dirname = os.path.dirname(script_abspath)
+ os.chdir(script_dirname)
+
+ def test_gen_key(self):
+ self.work_directory = tempfile.mkdtemp(prefix="nrf_signing_tests_")
+
+ key_file_name = 'key.pem'
+ key_file_path = os.path.join(self.work_directory, key_file_name)
+
+ signing = Signing()
+ signing.gen_key(key_file_path)
+
+ self.assertTrue(os.path.exists(key_file_path))
+
+ shutil.rmtree(self.work_directory, ignore_errors=True)
+
+ def test_load_key(self):
+ key_file_name = 'key.pem'
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ self.assertEqual(64, len(binascii.hexlify(signing.sk.to_string())))
+
+ def test_sign_and_verify(self):
+ key_file_name = 'key.pem'
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ init_packet_fields = {
+ PacketField.DEVICE_TYPE: 0xFFFF,
+ PacketField.DEVICE_REVISION: 0xFFFF,
+ PacketField.APP_VERSION: 0xFFFFFFFF,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [0xFFFE],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 2,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH: 1234,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ '\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e',
+ }
+ init_packet = Packet(init_packet_fields)
+ init_packet_data = init_packet.generate_packet()
+
+ signature = signing.sign(init_packet_data)
+
+ self.assertTrue(signing.verify(init_packet_data, signature))
+
+ init_packet_fields[PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS] = signature
+
+ init_packet = Packet(init_packet_fields)
+ init_packet_data = init_packet.generate_packet()
+
+ self.assertFalse(signing.verify(init_packet_data, signature))
+
+ def test_get_vk(self):
+ key_file_name = 'key.pem'
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_str = signing.get_vk('hex')
+ vk_hex = signing.get_vk_hex()
+ self.assertEqual(vk_hex, vk_str)
+
+ vk_str = signing.get_vk('code')
+ vk_code = signing.get_vk_code()
+ self.assertEqual(vk_code, vk_str)
+
+ vk_str = signing.get_vk('pem')
+ vk_pem = signing.get_vk_pem()
+ self.assertEqual(vk_pem, vk_str)
+
+ def test_get_vk_hex(self):
+ key_file_name = 'key.pem'
+ expected_vk_hex = "Verification key Qx: 658da2eddb981f697dae7220d68217abed3fb87005ec8a05b9b56bbbaa17f460\n" \
+ "Verification key Qy: 909baecdad7226c204b612b662ff4fccbd1b0c90841090d83a59cdad6c981d4c"
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_hex = signing.get_vk_hex()
+
+ self.assertEqual(expected_vk_hex, vk_hex)
+
+ def test_get_vk_code(self):
+ key_file_name = 'key.pem'
+
+ expected_vk_code = "static uint8_t Qx[] = { 0x65, 0x8d, 0xa2, 0xed, 0xdb, 0x98, 0x1f, 0x69, 0x7d, " \
+ "0xae, 0x72, 0x20, 0xd6, 0x82, 0x17, 0xab, 0xed, 0x3f, 0xb8, 0x70, 0x05, 0xec, " \
+ "0x8a, 0x05, 0xb9, 0xb5, 0x6b, 0xbb, 0xaa, 0x17, 0xf4, 0x60 };\n" \
+ "static uint8_t Qy[] = { 0x90, 0x9b, 0xae, 0xcd, 0xad, 0x72, 0x26, 0xc2, 0x04, " \
+ "0xb6, 0x12, 0xb6, 0x62, 0xff, 0x4f, 0xcc, 0xbd, 0x1b, 0x0c, 0x90, 0x84, 0x10, " \
+ "0x90, 0xd8, 0x3a, 0x59, 0xcd, 0xad, 0x6c, 0x98, 0x1d, 0x4c };"
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_code = signing.get_vk_code()
+
+ self.assertEqual(expected_vk_code, vk_code)
+
+ def test_get_vk_pem(self):
+ key_file_name = 'key.pem'
+ expected_vk_pem = "-----BEGIN PUBLIC KEY-----\n" \
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF\n" \
+ "7IoFubVru6oX9GCQm67NrXImwgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA==\n" \
+ "-----END PUBLIC KEY-----\n"
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_pem = signing.get_vk_pem()
+
+ self.assertEqual(expected_vk_pem, vk_pem)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/util.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/util.py
new file mode 100644
index 0000000..a7040fb
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/dfu/util.py
@@ -0,0 +1,179 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Nordic libraries
+from nordicsemi.exceptions import NordicSemiException
+
+
+# TODO: Create query function that maps query-result strings with functions
+def query_func(question, default=False):
+ """
+ Ask a string question
+ No input defaults to "no" which results in False
+ """
+ valid = {"yes": True, "y": True, "no": False, "n": False}
+ if default is True:
+ prompt = " [Y/n]"
+ else:
+ prompt = " [y/N]"
+
+ while True:
+ print "%s %s" % (question, prompt)
+ choice = raw_input().lower()
+ if choice == '':
+ return default
+ elif choice in valid:
+ return valid[choice]
+ else:
+ print "Please respond with y/n"
+
+
+def convert_uint16_to_array(value):
+ """
+ Converts a int to an array of 2 bytes (little endian)
+
+ :param int value: int value to convert to list
+ :return list[int]: list with 2 bytes
+ """
+ byte0 = value & 0xFF
+ byte1 = (value >> 8) & 0xFF
+ return [byte0, byte1]
+
+
+def convert_uint32_to_array(value):
+ """
+ Converts a int to an array of 4 bytes (little endian)
+
+ :param int value: int value to convert to list
+ :return list[int]: list with 4 bytes
+ """
+ byte0 = value & 0xFF
+ byte1 = (value >> 8) & 0xFF
+ byte2 = (value >> 16) & 0xFF
+ byte3 = (value >> 24) & 0xFF
+ return [byte0, byte1, byte2, byte3]
+
+
+def slip_parts_to_four_bytes(seq, dip, rp, pkt_type, pkt_len):
+ """
+ Creates a SLIP header.
+
+ For a description of the SLIP header go to:
+ http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00093.html
+
+ :param int seq: Packet sequence number
+ :param int dip: Data integrity check
+ :param int rp: Reliable packet
+ :param pkt_type: Payload packet
+ :param pkt_len: Packet length
+ :return: str with SLIP header
+ """
+ ints = [0, 0, 0, 0]
+ ints[0] = seq | (((seq + 1) % 8) << 3) | (dip << 6) | (rp << 7)
+ ints[1] = pkt_type | ((pkt_len & 0x000F) << 4)
+ ints[2] = (pkt_len & 0x0FF0) >> 4
+ ints[3] = (~(sum(ints[0:3])) + 1) & 0xFF
+
+ return ''.join(chr(b) for b in ints)
+
+
+def int32_to_bytes(value):
+ """
+ Converts a int to a str with 4 bytes
+
+ :param value: int value to convert
+ :return: str with 4 bytes
+ """
+ ints = [0, 0, 0, 0]
+ ints[0] = (value & 0x000000FF)
+ ints[1] = (value & 0x0000FF00) >> 8
+ ints[2] = (value & 0x00FF0000) >> 16
+ ints[3] = (value & 0xFF000000) >> 24
+ return ''.join(chr(b) for b in ints)
+
+
+def int16_to_bytes(value):
+ """
+ Converts a int to a str with 4 bytes
+
+ :param value: int value to convert
+ :return: str with 4 bytes
+ """
+
+ ints = [0, 0]
+ ints[0] = (value & 0x00FF)
+ ints[1] = (value & 0xFF00) >> 8
+ return ''.join(chr(b) for b in ints)
+
+
+def slip_decode_esc_chars(data):
+ """Decode esc characters in a SLIP package.
+
+ Replaces 0xDBDC with 0xCO and 0xDBDD with 0xDB.
+
+ :return: str decoded data
+ :type str data: data to decode
+ """
+ result = []
+ while len(data):
+ char = data.pop(0)
+ if char == 0xDB:
+ char2 = data.pop(0)
+ if char2 == 0xDC:
+ result.append(0xC0)
+ elif char2 == 0xDD:
+ result.append(0xDB)
+ else:
+ raise NordicSemiException('Char 0xDB NOT followed by 0xDC or 0xDD')
+ else:
+ result.append(char)
+ return result
+
+
+def slip_encode_esc_chars(data_in):
+ """Encode esc characters in a SLIP package.
+
+ Replace 0xCO with 0xDBDC and 0xDB with 0xDBDD.
+
+ :type str data_in: str to encode
+ :return: str with encoded packet
+ """
+ result = []
+ data = []
+ for i in data_in:
+ data.append(ord(i))
+
+ while len(data):
+ char = data.pop(0)
+ if char == 0xC0:
+ result.extend([0xDB, 0xDC])
+ elif char == 0xDB:
+ result.extend([0xDB, 0xDD])
+ else:
+ result.append(char)
+ return ''.join(chr(i) for i in result)
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/exceptions.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/exceptions.py
new file mode 100644
index 0000000..d2ad206
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/exceptions.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+class NordicSemiException(Exception):
+ """
+ Exception used as based exception for other exceptions defined in this package.
+ """
+ pass
+
+
+class NotImplementedException(NordicSemiException):
+ """
+ Exception used when functionality has not been implemented yet.
+ """
+ pass
+
+
+class InvalidArgumentException(NordicSemiException):
+ """"
+ Exception used when a argument is of wrong type
+ """
+ pass
+
+class MissingArgumentException(NordicSemiException):
+ """"
+ Exception used when a argument is missing
+ """
+ pass
+
+
+class IllegalStateException(NordicSemiException):
+ """"
+ Exception used when program is in an illegal state
+ """
+ pass
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/__init__.py
new file mode 100644
index 0000000..58c0272
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.s
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/target_registry.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/target_registry.py
new file mode 100644
index 0000000..f87e006
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/target_registry.py
@@ -0,0 +1,121 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import re
+import os
+import json
+from abc import ABCMeta, abstractmethod
+
+
+class TargetDatabase(object):
+ __metaclass__ = ABCMeta
+
+ @abstractmethod
+ def get_targets(self):
+ pass
+
+ @abstractmethod
+ def get_target(self, target_id):
+ pass
+
+ @abstractmethod
+ def refresh(self):
+ pass
+
+ @staticmethod
+ def find_target(targets, target_id):
+ for target in targets:
+ if target["id"] == target_id:
+ return target
+
+ return None
+
+
+class EnvTargetDatabase(TargetDatabase):
+ def __init__(self):
+ self.targets = None
+
+ def get_targets(self):
+ if self.targets is None:
+ self.targets = []
+
+ for key, value in os.environ.iteritems():
+ match = re.match("NORDICSEMI_TARGET_(?P<target>\d+)_(?P<key>[a-zA-Z_]+)", key)
+
+ if match:
+ key_value = match.groupdict()
+ if "key" in key_value and "target" in key_value:
+ target_id = int(key_value["target"])
+
+ target = self.find_target(self.targets, target_id)
+
+ if target is None:
+ target = {"id": int(target_id)}
+ self.targets.append(target)
+
+ target[key_value["key"].lower()] = value
+
+ return self.targets
+
+ def refresh(self):
+ self.targets = None
+
+ def get_target(self, target_id):
+ return self.find_target(self.get_targets(), target_id)
+
+
+class FileTargetDatabase(TargetDatabase):
+ def __init__(self, filename):
+ self.filename = filename
+ self.targets = None
+
+ def get_targets(self):
+ if not self.targets:
+ self.targets = json.load(open(self.filename, "r"))["targets"]
+
+ return self.targets
+
+ def get_target(self, target_id):
+ return self.find_target(self.get_targets(), target_id)
+
+ def refresh(self):
+ self.targets = None
+
+
+class TargetRegistry(object):
+ def __init__(self, target_db=EnvTargetDatabase()):
+ self.target_db = target_db
+
+ def find_one(self, target_id=None):
+ if target_id:
+ return self.target_db.get_target(target_id)
+ else:
+ return None
+
+ def get_all(self):
+ return self.target_db.get_targets()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/__init__.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/test_target_registry.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/test_target_registry.py
new file mode 100644
index 0000000..1d6df65
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/utility/tests/test_target_registry.py
@@ -0,0 +1,90 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import unittest
+from nordicsemi.utility.target_registry import TargetRegistry, EnvTargetDatabase
+from nordicsemi.utility.target_registry import FileTargetDatabase
+
+
+class TestTargetRegistry(unittest.TestCase):
+ def setUp(self):
+ script_abspath = os.path.abspath(__file__)
+ script_dirname = os.path.dirname(script_abspath)
+ os.chdir(script_dirname)
+
+ # Setup the environment variables
+ os.environ["NORDICSEMI_TARGET_1_SERIAL_PORT"] = "COM1"
+ os.environ["NORDICSEMI_TARGET_1_PCA"] = "PCA10028"
+ os.environ["NORDICSEMI_TARGET_1_DRIVE"] = "D:\\"
+ os.environ["NORDICSEMI_TARGET_1_SEGGER_SN"] = "1231233333"
+
+ os.environ["NORDICSEMI_TARGET_2_SERIAL_PORT"] = "COM2"
+ os.environ["NORDICSEMI_TARGET_2_PCA"] = "PCA10028"
+ os.environ["NORDICSEMI_TARGET_2_DRIVE"] = "E:\\"
+ os.environ["NORDICSEMI_TARGET_2_SEGGER_SN"] = "3332222111"
+
+ def test_get_targets_from_file(self):
+ target_database = FileTargetDatabase("test_targets.json")
+ target_repository = TargetRegistry(target_db=target_database)
+
+ target = target_repository.find_one(target_id=1)
+ assert target is not None
+ assert target["drive"] == "d:\\"
+ assert target["serial_port"] == "COM7"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "123123123123"
+
+ target = target_repository.find_one(target_id=2)
+ assert target is not None
+ assert target["drive"] == "e:\\"
+ assert target["serial_port"] == "COM8"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "321321321312"
+
+ def test_get_targets_from_environment(self):
+ target_database = EnvTargetDatabase()
+ target_repository = TargetRegistry(target_db=target_database)
+
+ target = target_repository.find_one(target_id=1)
+ assert target is not None
+ assert target["drive"] == "D:\\"
+ assert target["serial_port"] == "COM1"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "1231233333"
+
+ target = target_repository.find_one(target_id=2)
+ assert target is not None
+ assert target["drive"] == "E:\\"
+ assert target["serial_port"] == "COM2"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "3332222111"
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/build/lib/nordicsemi/version.py b/circuitpython/lib/nrfutil/build/lib/nordicsemi/version.py
new file mode 100644
index 0000000..ca01d46
--- /dev/null
+++ b/circuitpython/lib/nrfutil/build/lib/nordicsemi/version.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+""" Version definition for nrfutil. """
+
+NRFUTIL_VERSION = "0.5.2"
diff --git a/circuitpython/lib/nrfutil/dist/nrfutil-0.5.2-py2.7.egg b/circuitpython/lib/nrfutil/dist/nrfutil-0.5.2-py2.7.egg
new file mode 100644
index 0000000..3b67d78
--- /dev/null
+++ b/circuitpython/lib/nrfutil/dist/nrfutil-0.5.2-py2.7.egg
Binary files differ
diff --git a/circuitpython/lib/nrfutil/license.txt b/circuitpython/lib/nrfutil/license.txt
new file mode 100644
index 0000000..545df43
--- /dev/null
+++ b/circuitpython/lib/nrfutil/license.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2015, Nordic Semiconductor
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of Nordic Semiconductor ASA nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/circuitpython/lib/nrfutil/nordicsemi/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/__init__.pyc b/circuitpython/lib/nrfutil/nordicsemi/__init__.pyc
new file mode 100644
index 0000000..45965ef
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/__init__.pyc
Binary files differ
diff --git a/circuitpython/lib/nrfutil/nordicsemi/__main__.py b/circuitpython/lib/nrfutil/nordicsemi/__main__.py
new file mode 100644
index 0000000..02bb049
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/__main__.py
@@ -0,0 +1,307 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""nrfutil command line tool."""
+import logging
+import os
+import click
+
+from nordicsemi.dfu.dfu import Dfu
+from nordicsemi.dfu.dfu_transport import DfuEvent
+from nordicsemi.dfu.dfu_transport_serial import DfuTransportSerial
+from nordicsemi.dfu.package import Package
+from nordicsemi import version as nrfutil_version
+from nordicsemi.dfu.signing import Signing
+from nordicsemi.dfu.util import query_func
+
+
+class nRFException(Exception):
+ pass
+
+
+def int_as_text_to_int(value):
+ try:
+ if value[:2].lower() == '0x':
+ return int(value[2:], 16)
+ elif value[:1] == '0':
+ return int(value, 8)
+ return int(value, 10)
+ except ValueError:
+ raise nRFException('%s is not a valid integer' % value)
+
+
+class BasedIntOrNoneParamType(click.ParamType):
+ name = 'Int or None'
+
+ def convert(self, value, param, ctx):
+ try:
+ if value.lower() == 'none':
+ return 'none'
+ return int_as_text_to_int(value)
+ except nRFException:
+ self.fail('%s is not a valid integer' % value, param, ctx)
+
+BASED_INT_OR_NONE = BasedIntOrNoneParamType()
+
+
+class TextOrNoneParamType(click.ParamType):
+ name = 'Text or None'
+
+ def convert(self, value, param, ctx):
+ return value
+
+TEXT_OR_NONE = TextOrNoneParamType()
+
+
+@click.group()
+@click.option('--verbose',
+ help='Show verbose information',
+ is_flag=True)
+def cli(verbose):
+ if verbose:
+ logging.basicConfig(format='%(message)s', level=logging.INFO)
+ else:
+ logging.basicConfig(format='%(message)s')
+
+
+@cli.command()
+def version():
+ """Displays nrf utility version."""
+ click.echo("nrfutil version {}".format(nrfutil_version.NRFUTIL_VERSION))
+
+
+@cli.command(short_help='Generate keys for signing or generate public keys')
+@click.argument('key_file', required=True)
+@click.option('--gen-key',
+ help='generate signing key and store at given path (pem-file)',
+ type=click.BOOL,
+ is_flag=True)
+@click.option('--show-vk',
+ help='Show the verification keys for DFU Signing (hex|code|pem)',
+ type=click.STRING)
+def keys(key_file,
+ gen_key,
+ show_vk):
+ """
+ This set of commands support creation of signing key (private) and showing the verification key (public)
+ from a previously loaded signing key. Signing key is stored in PEM format
+ """
+ if not gen_key and show_vk is None:
+ raise nRFException("Use either gen-key or show-vk.")
+
+ signer = Signing()
+
+ if gen_key:
+ if os.path.exists(key_file):
+ if not query_func("File found at %s. Do you want to overwrite the file?" % key_file):
+ click.echo('Key generation aborted')
+ return
+
+ signer.gen_key(key_file)
+ click.echo("Generated key at: %s" % key_file)
+
+ elif show_vk:
+ if not os.path.isfile(key_file):
+ raise nRFException("No key file to load at: %s" % key_file)
+
+ signer.load_key(key_file)
+ click.echo(signer.get_vk(show_vk))
+
+
+@cli.group()
+def dfu():
+ """
+ This set of commands support Nordic DFU OTA package generation for distribution to
+ applications and serial DFU.
+ """
+ pass
+
+
+@dfu.command(short_help='Generate a package for distribution to Apps supporting Nordic DFU OTA')
+@click.argument('zipfile',
+ required=True,
+ type=click.Path())
+@click.option('--application',
+ help='The application firmware file',
+ type=click.STRING)
+@click.option('--application-version',
+ help='Application version, default: 0xFFFFFFFF',
+ type=BASED_INT_OR_NONE,
+ default=str(Package.DEFAULT_APP_VERSION))
+@click.option('--bootloader',
+ help='The bootloader firmware file',
+ type=click.STRING)
+@click.option('--dev-revision',
+ help='Device revision, default: 0xFFFF',
+ type=BASED_INT_OR_NONE,
+ default=str(Package.DEFAULT_DEV_REV))
+@click.option('--dev-type',
+ help='Device type, default: 0xFFFF',
+ type=BASED_INT_OR_NONE,
+ default=str(Package.DEFAULT_DEV_TYPE))
+@click.option('--dfu-ver',
+ help='DFU packet version to use, default: 0.5',
+ type=click.FLOAT,
+ default=Package.DEFAULT_DFU_VER)
+@click.option('--sd-req',
+ help='SoftDevice requirement. A list of SoftDevice versions (1 or more)'
+ 'of which one is required to be present on the target device.'
+ 'Example: --sd-req 0x4F,0x5A. Default: 0xFFFE.',
+ type=TEXT_OR_NONE,
+ default=str(Package.DEFAULT_SD_REQ[0]))
+@click.option('--softdevice',
+ help='The SoftDevice firmware file',
+ type=click.STRING)
+@click.option('--key-file',
+ help='Signing key (pem fomat)',
+ type=click.Path(exists=True, resolve_path=True, file_okay=True, dir_okay=False))
+def genpkg(zipfile,
+ application,
+ application_version,
+ bootloader,
+ dev_revision,
+ dev_type,
+ dfu_ver,
+ sd_req,
+ softdevice,
+ key_file):
+ """
+ Generate a zipfile package for distribution to Apps supporting Nordic DFU OTA.
+ The application, bootloader and softdevice files are converted to .bin if it is a .hex file.
+ For more information on the generated init packet see:
+ http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00065.html
+ """
+ zipfile_path = zipfile
+
+ if application_version == 'none':
+ application_version = None
+
+ if dev_revision == 'none':
+ dev_revision = None
+
+ if dev_type == 'none':
+ dev_type = None
+
+ sd_req_list = None
+
+ if sd_req.lower() == 'none':
+ sd_req_list = []
+ elif sd_req:
+ try:
+ # This will parse any string starting with 0x as base 16.
+ sd_req_list = sd_req.split(',')
+ sd_req_list = map(int_as_text_to_int, sd_req_list)
+ except ValueError:
+ raise nRFException("Could not parse value for --sd-req. "
+ "Hex values should be prefixed with 0x.")
+
+ if key_file and dfu_ver < 0.8:
+ click.echo("Key file was given, setting DFU version to 0.8")
+
+ package = Package(dev_type,
+ dev_revision,
+ application_version,
+ sd_req_list,
+ application,
+ bootloader,
+ softdevice,
+ dfu_ver,
+ key_file)
+
+ package.generate_package(zipfile_path)
+
+ log_message = "Zip created at {0}".format(zipfile_path)
+ click.echo(log_message)
+
+
+global_bar = None
+
+
+def update_progress(progress=0, done=False, log_message=""):
+ del done, log_message # Unused parameters
+ #global global_bar
+ #if global_bar is None:
+ # with click.progressbar(length=100) as bar:
+ # global_bar = bar
+ #global_bar.update(max(1, progress))
+ click.echo('#', nl=False)
+
+
+@dfu.command(short_help="Program a device with bootloader that support serial DFU")
+@click.option('-pkg', '--package',
+ help='DFU package filename',
+ type=click.Path(exists=True, resolve_path=True, file_okay=True, dir_okay=False),
+ required=True)
+@click.option('-p', '--port',
+ help='Serial port COM Port to which the device is connected',
+ type=click.STRING,
+ required=True)
+@click.option('-b', '--baudrate',
+ help='Desired baud rate 38400/96000/115200/230400/250000/460800/921600/1000000 (default: 38400). '
+ 'Note: Physical serial ports (e.g. COM1) typically do not support baud rates > 115200',
+ type=click.INT,
+ default=DfuTransportSerial.DEFAULT_BAUD_RATE)
+@click.option('-fc', '--flowcontrol',
+ help='Enable flow control, default: disabled',
+ type=click.BOOL,
+ is_flag=True)
+@click.option('-sb', '--singlebank',
+ help='Single band bootloader to skip firmware activating delay, default: Dual bank',
+ type=click.BOOL,
+ is_flag=True)
+def serial(package, port, baudrate, flowcontrol, singlebank):
+ """Program a device with bootloader that support serial DFU"""
+ serial_backend = DfuTransportSerial(port, baudrate, flowcontrol, singlebank)
+ serial_backend.register_events_callback(DfuEvent.PROGRESS_EVENT, update_progress)
+ dfu = Dfu(package, dfu_transport=serial_backend)
+
+ click.echo("Upgrading target on {1} with DFU package {0}. Flow control is {2}, {3} bank mode"
+ .format(package, port, "enabled" if flowcontrol else "disabled", "Single" if singlebank else "Dual"))
+
+ try:
+ dfu.dfu_send_images()
+
+ except Exception as e:
+ click.echo("")
+ click.echo("Failed to upgrade target. Error is: {0}".format(e.message))
+ click.echo("")
+ click.echo("Possible causes:")
+ click.echo("- Selected Bootloader version does not match the one on Bluefruit device.")
+ click.echo(" Please upgrade the Bootloader or select correct version in Tools->Bootloader.")
+ click.echo("- Baud rate must be 115200, Flow control must be off.")
+ click.echo("- Target is not in DFU mode. Ground DFU pin and RESET and release both to enter DFU mode.")
+
+ return False
+
+ click.echo("Device programmed.")
+
+ return True
+
+
+if __name__ == '__main__':
+ cli()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/bluetooth/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/codec.py b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/codec.py
new file mode 100644
index 0000000..bebd790
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/codec.py
@@ -0,0 +1,76 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+UART_HEADER_OCTET_COUNT = 4
+
+
+class ThreeWireUartPacket(object):
+ """
+ This class encapsulate a three wire uart packet according to Bluetooth specification
+ version 4.0 [Vol 4] part D.
+ """
+ def __init__(self):
+ self.ack = None # Acknowledgement number
+ self.seq = None # Sequence number
+ self.di = None # Data integrity present
+ self.rp = None # Reliable packet
+ self.type = None # Packet type
+ self.length = None # Payload Length
+ self.checksum = None # Header checksum
+ self.payload = None # Payload
+
+ @staticmethod
+ def decode(packet):
+ """
+ Decodes a packet from a str encoded array
+
+ :param packet_bytes: A str encoded array
+ :return: TheeWireUartPacket
+ """
+
+ decoded_packet = ThreeWireUartPacket()
+
+ packet_bytes = bytearray(packet)
+
+ decoded_packet.ack = (packet_bytes[0] & int('38', 16)) >> 3
+ decoded_packet.seq = (packet_bytes[0] & int('07', 16))
+ decoded_packet.di = (packet_bytes[0] & int('40', 16)) >> 6
+ decoded_packet.rp = (packet_bytes[0] & int('80', 16)) >> 7
+ decoded_packet.type = (packet_bytes[1] & int('0F', 16))
+ decoded_packet.length = ((packet_bytes[1] & int('F0', 16)) >> 4) + (packet_bytes[2] * 16)
+
+ checksum = packet_bytes[0]
+ checksum = checksum + packet_bytes[1]
+ checksum = checksum + packet_bytes[2]
+ checksum &= int('FF', 16)
+ decoded_packet.checksum = (~checksum + 1) & int('FF', 16)
+
+ if decoded_packet.length > 0:
+ decoded_packet.payload = packet_bytes[UART_HEADER_OCTET_COUNT:-1]
+
+ return decoded_packet
diff --git a/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/slip.py b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/slip.py
new file mode 100644
index 0000000..e2a525f
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/slip.py
@@ -0,0 +1,115 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class Slip(object):
+ def __init__(self):
+ self.SLIP_END = '\xc0'
+ self.SLIP_ESC = '\xdb'
+ self.SLIP_ESC_END = '\xdc'
+ self.SLIP_ESC_ESC = '\xdd'
+
+ self.started = False
+ self.escaped = False
+ self.stream = ''
+ self.packet = ''
+
+ def append(self, data):
+ """
+ Append a new
+ :param data: Append a new block of data to do decoding on when calling decode.
+ The developer may add more than one SLIP packet before calling decode.
+ :return:
+ """
+ self.stream += data
+
+ def decode(self):
+ """
+ Decodes a package according to http://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol
+ :return Slip: A list of decoded slip packets
+ """
+ packet_list = list()
+
+ for char in self.stream:
+ if char == self.SLIP_END:
+ if self.started:
+ if len(self.packet) > 0:
+ self.started = False
+ packet_list.append(self.packet)
+ self.packet = ''
+ else:
+ self.started = True
+ self.packet = ''
+ elif char == self.SLIP_ESC:
+ self.escaped = True
+ elif char == self.SLIP_ESC_END:
+ if self.escaped:
+ self.packet += self.SLIP_END
+ self.escaped = False
+ else:
+ self.packet += char
+ elif char == self.SLIP_ESC_ESC:
+ if self.escaped:
+ self.packet += self.SLIP_ESC
+ self.escaped = False
+ else:
+ self.packet += char
+ else:
+ if self.escaped:
+ logging.error("Error in SLIP packet, ignoring error.")
+ self.packet = ''
+ self.escaped = False
+ else:
+ self.packet += char
+
+ self.stream = ''
+
+ return packet_list
+
+ def encode(self, packet):
+ """
+ Encode a packet according to SLIP.
+ :param packet: A str array that represents the package
+ :return: str array with an encoded SLIP packet
+ """
+ encoded = self.SLIP_END
+
+ for char in packet:
+ if char == self.SLIP_END:
+ encoded += self.SLIP_ESC + self.SLIP_ESC_END
+ elif char == self.SLIP_ESC:
+ encoded += self.SLIP_ESC + self.SLIP_ESC_ESC
+ else:
+ encoded += char
+ encoded += self.SLIP_END
+
+ return encoded
diff --git a/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/test_codec.py b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/test_codec.py
new file mode 100644
index 0000000..c7d6f26
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/bluetooth/hci/tests/test_codec.py
@@ -0,0 +1,81 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json
+import unittest
+from nordicsemi.bluetooth.hci.slip import Slip
+from nordicsemi.bluetooth.hci import codec
+
+
+class TestInitPacket(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def test_decode_packet(self):
+ # TODO: extend this test, this tests only a small portion of the slip/hci decoding
+ # These are packets read from Device Monitoring Studio
+ # during communication between serializer application and firmware
+ read_packets = [
+ " C0 10 00 00 F0 C0 C0 D1 6E 00 C1 01 86 00 00 00 00 17 63 C0",
+ " C0 D2 DE 02 4E 02 1B 00 FF FF 01 17 FE B4 9A 9D E1 B0 F8 02"
+ " 01 06 11 07 1B C5 D5 A5 02 00 A9 B7 E2 11 A4 C6 00 FE E7 74"
+ " 09 09 49 44 54 57 32 31 38 48 5A BB C0",
+ " C0 D3 EE 00 3F 02 1B 00 FF FF 01 17 FE B4 9A 9D E1 AF 01 F1 62 C0",
+ " C0 D4 DE 02 4C 02 1B 00 FF FF 01 17 FE B4 9A 9D E1 B1 F8 02 01 06"
+ " 11 07 1B C5 D5 A5 02 00 A9 B7 E2 11 A4 C6 00 FE E7 74 09 09 49 44 54 57 32 31 38 48 6E C8 C0"
+ ]
+
+ slip = Slip()
+ output = list()
+
+ for uart_packet in read_packets:
+ hex_string = uart_packet.replace(" ", "")
+ hex_data = hex_string.decode("hex")
+ slip.append(hex_data)
+
+ packets = slip.decode()
+
+ for packet in packets:
+ output.append(codec.ThreeWireUartPacket.decode(packet))
+
+ self.assertEqual(len(output), 5)
+
+ packet_index = 0
+ self.assertEqual(output[packet_index].seq, 0)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 1)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 2)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 3)
+
+ packet_index += 1
+ self.assertEqual(output[packet_index].seq, 4)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/crc16.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/crc16.py
new file mode 100644
index 0000000..2db4af6
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/crc16.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+def calc_crc16(binary_data, crc=0xffff):
+ """
+ Calculates CRC16 on binary_data
+
+ :param int crc: CRC value to start calculation with
+ :param bytearray binary_data: Array with data to run CRC16 calculation on
+ :return int: Calculated CRC value of binary_data
+ """
+
+ for b in binary_data:
+ crc = (crc >> 8 & 0x00FF) | (crc << 8 & 0xFF00)
+ crc ^= ord(b)
+ crc ^= (crc & 0x00FF) >> 4
+ crc ^= (crc << 8) << 4
+ crc ^= ((crc & 0x00FF) << 4) << 1
+ return crc & 0xFFFF
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu.py
new file mode 100644
index 0000000..a018cbe
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu.py
@@ -0,0 +1,232 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python standard library
+import os
+import tempfile
+import shutil
+import logging
+from time import time, sleep
+from datetime import datetime, timedelta
+
+# Nordic libraries
+from nordicsemi.exceptions import *
+from nordicsemi.dfu.package import Package
+from nordicsemi.dfu.dfu_transport import DfuEvent
+from nordicsemi.dfu.model import HexType
+from nordicsemi.dfu.manifest import SoftdeviceBootloaderFirmware
+
+logger = logging.getLogger(__name__)
+
+
+class Dfu(object):
+ """ Class to handle upload of a new hex image to the device. """
+
+ def __init__(self, zip_file_path, dfu_transport):
+ """
+ Initializes the dfu upgrade, unpacks zip and registers callbacks.
+
+ @param zip_file_path: Path to the zip file with the firmware to upgrade
+ @type zip_file_path: str
+ @param dfu_transport: Transport backend to use to upgrade
+ @type dfu_transport: nordicsemi.dfu.dfu_transport.DfuTransport
+ @return
+ """
+ self.zip_file_path = zip_file_path
+ self.ready_to_send = True
+ self.response_opcode_received = None
+
+ self.temp_dir = tempfile.mkdtemp(prefix="nrf_dfu_")
+ self.unpacked_zip_path = os.path.join(self.temp_dir, 'unpacked_zip')
+ self.manifest = Package.unpack_package(self.zip_file_path, self.unpacked_zip_path)
+
+ if dfu_transport:
+ self.dfu_transport = dfu_transport
+
+ self.dfu_transport.register_events_callback(DfuEvent.TIMEOUT_EVENT, self.timeout_event_handler)
+ self.dfu_transport.register_events_callback(DfuEvent.ERROR_EVENT, self.error_event_handler)
+
+ def __del__(self):
+ """
+ Destructor removes the temporary directory for the unpacked zip
+ :return:
+ """
+ shutil.rmtree(self.temp_dir)
+
+ def error_event_handler(self, log_message=""):
+ """
+ Event handler for errors, closes the transport backend.
+ :param str log_message: The log message for the error.
+ :return:
+ """
+ if self.dfu_transport.is_open():
+ self.dfu_transport.close()
+
+ logger.error(log_message)
+
+ def timeout_event_handler(self, log_message):
+ """
+ Event handler for timeouts, closes the transport backend.
+ :param log_message: The log message for the timeout.
+ :return:
+ """
+ if self.dfu_transport.is_open():
+ self.dfu_transport.close()
+
+ logger.error(log_message)
+
+ @staticmethod
+ def _read_file(file_path):
+ """
+ Reads a file and returns the content as a string.
+
+ :param str file_path: The path to the file to read.
+ :return str: Content of the file.
+ """
+ buffer_size = 4096
+
+ file_content = ""
+
+ with open(file_path, 'rb') as binary_file:
+ while True:
+ data = binary_file.read(buffer_size)
+
+ if data:
+ file_content += data
+ else:
+ break
+
+ return file_content
+
+ def _wait_while_opening_transport(self):
+ timeout = 10
+ start_time = datetime.now()
+
+ while not self.dfu_transport.is_open():
+ timed_out = datetime.now() - start_time > timedelta(0, timeout)
+
+ if timed_out:
+ log_message = "Failed to open transport backend"
+ raise NordicSemiException(log_message)
+
+ sleep(0.1)
+
+
+ def _dfu_send_image(self, program_mode, firmware_manifest):
+ """
+ Does DFU for one image. Reads the firmware image and init file.
+ Opens the transport backend, calls setup, send and finalize and closes the backend again.
+ @param program_mode: What type of firmware the DFU is
+ @type program_mode: nordicsemi.dfu.model.HexType
+ @param firmware_manifest: The manifest for the firmware image
+ @type firmware_manifest: nordicsemi.dfu.manifest.Firmware
+ @return:
+ """
+
+ if firmware_manifest is None:
+ raise MissingArgumentException("firmware_manifest must be provided.")
+
+ if self.dfu_transport.is_open():
+ raise IllegalStateException("Transport is already open.")
+
+ self.dfu_transport.open()
+ self._wait_while_opening_transport()
+
+ softdevice_size = 0
+ bootloader_size = 0
+ application_size = 0
+
+ bin_file_path = os.path.join(self.unpacked_zip_path, firmware_manifest.bin_file)
+ firmware = self._read_file(bin_file_path)
+
+ dat_file_path = os.path.join(self.unpacked_zip_path, firmware_manifest.dat_file)
+ init_packet = self._read_file(dat_file_path)
+
+ if program_mode == HexType.SD_BL:
+ if not isinstance(firmware_manifest, SoftdeviceBootloaderFirmware):
+ raise NordicSemiException("Wrong type of manifest")
+ softdevice_size = firmware_manifest.sd_size
+ bootloader_size = firmware_manifest.bl_size
+ firmware_size = len(firmware)
+ if softdevice_size + bootloader_size != firmware_size:
+ raise NordicSemiException(
+ "Size of bootloader ({} bytes) and softdevice ({} bytes)"
+ " is not equal to firmware provided ({} bytes)".format(
+ bootloader_size, softdevice_size, firmware_size))
+
+ elif program_mode == HexType.SOFTDEVICE:
+ softdevice_size = len(firmware)
+
+ elif program_mode == HexType.BOOTLOADER:
+ bootloader_size = len(firmware)
+
+ elif program_mode == HexType.APPLICATION:
+ application_size = len(firmware)
+
+ start_time = time()
+ logger.info("Starting DFU upgrade of type %s, SoftDevice size: %s, bootloader size: %s, application size: %s",
+ program_mode,
+ softdevice_size,
+ bootloader_size,
+ application_size)
+
+ logger.info("Sending DFU start packet")
+ self.dfu_transport.send_start_dfu(program_mode, softdevice_size, bootloader_size,
+ application_size)
+
+ logger.info("Sending DFU init packet")
+ self.dfu_transport.send_init_packet(init_packet)
+
+ logger.info("Sending firmware file")
+ self.dfu_transport.send_firmware(firmware)
+
+ self.dfu_transport.send_validate_firmware()
+
+ self.dfu_transport.send_activate_firmware()
+
+ end_time = time()
+ logger.info("\nDFU upgrade took {0}s".format(end_time - start_time))
+
+ self.dfu_transport.close()
+
+ def dfu_send_images(self):
+ """
+ Does DFU for all firmware images in the stored manifest.
+ :return:
+ """
+ if self.manifest.softdevice_bootloader:
+ self._dfu_send_image(HexType.SD_BL, self.manifest.softdevice_bootloader)
+
+ if self.manifest.softdevice:
+ self._dfu_send_image(HexType.SOFTDEVICE, self.manifest.softdevice)
+
+ if self.manifest.bootloader:
+ self._dfu_send_image(HexType.BOOTLOADER, self.manifest.bootloader)
+
+ if self.manifest.application:
+ self._dfu_send_image(HexType.APPLICATION, self.manifest.application)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport.py
new file mode 100644
index 0000000..67c4354
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport.py
@@ -0,0 +1,204 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python specific imports
+import abc
+import logging
+
+# Nordic Semiconductor imports
+from nordicsemi.dfu.util import int32_to_bytes
+
+logger = logging.getLogger(__name__)
+
+
+class DfuEvent:
+ PROGRESS_EVENT = 1
+ TIMEOUT_EVENT = 2
+ ERROR_EVENT = 3
+
+
+class DfuTransport(object):
+ """
+ This class as an abstract base class inherited from when implementing transports.
+
+ The class is generic in nature, the underlying implementation may have missing semantic
+ than this class describes. But the intent is that the implementer shall follow the semantic as
+ best as she can.
+ """
+ __metaclass__ = abc.ABCMeta
+
+ @staticmethod
+ def create_image_size_packet(softdevice_size=0, bootloader_size=0, app_size=0):
+ """
+ Creates an image size packet necessary for sending start dfu.
+
+ @param softdevice_size: Size of SoftDevice firmware
+ @type softdevice_size: int
+ @param bootloader_size: Size of bootloader firmware
+ @type softdevice_size: int
+ @param app_size: Size of application firmware
+ :return: The image size packet
+ :rtype: str
+ """
+ softdevice_size_packet = int32_to_bytes(softdevice_size)
+ bootloader_size_packet = int32_to_bytes(bootloader_size)
+ app_size_packet = int32_to_bytes(app_size)
+ image_size_packet = softdevice_size_packet + bootloader_size_packet + app_size_packet
+ return image_size_packet
+
+ @abc.abstractmethod
+ def __init__(self):
+ self.callbacks = {}
+
+ @abc.abstractmethod
+ def open(self):
+ """
+ Open a port if appropriate for the transport.
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def close(self):
+ """
+ Close a port if appropriate for the transport.
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def is_open(self):
+ """
+ Returns if transport is open.
+
+ :return bool: True if transport is open, False if not
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_start_dfu(self, program_mode, softdevice_size=0, bootloader_size=0, app_size=0):
+ """
+ Send packet to initiate DFU communication. Returns when packet is sent or timeout occurs.
+
+ This call will block until packet is sent.
+ If timeout or errors occurs exception is thrown.
+
+ :param nordicsemi.dfu.model.HexType program_mode: Type of firmware to upgrade
+ :param int softdevice_size: Size of softdevice firmware
+ :param int bootloader_size: Size of bootloader firmware
+ :param int app_size: Size of application firmware
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_init_packet(self, init_packet):
+ """
+ Send init_packet to device.
+
+ This call will block until init_packet is sent and transfer of packet is complete.
+ If timeout or errors occurs exception is thrown.
+
+ :param str init_packet: Init packet as a str.
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_firmware(self, firmware):
+ """
+ Start sending firmware to device.
+
+ This call will block until transfer of firmware is complete.
+ If timeout or errors occurs exception is thrown.
+
+ :param str firmware:
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_validate_firmware(self):
+ """
+ Send request to device to verify that firmware has been correctly transferred.
+
+ This call will block until validation is sent and validation is complete.
+ If timeout or errors occurs exception is thrown.
+
+ :return bool: True if firmware validated successfully.
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_activate_firmware(self):
+ """
+ Send command to device to activate new firmware and restart the device.
+ The device will start up with the new firmware.
+
+ Raises an nRFException if anything fails.
+
+ :return:
+ """
+ pass
+
+ def register_events_callback(self, event_type, callback):
+ """
+ Register a callback.
+
+ :param DfuEvent callback:
+ :return: None
+ """
+ if event_type not in self.callbacks:
+ self.callbacks[event_type] = []
+
+ self.callbacks[event_type].append(callback)
+
+ def unregister_events_callback(self, callback):
+ """
+ Unregister a callback.
+
+ :param callback: # TODO: add documentation for callback
+ :return: None
+ """
+ for event_type in self.callbacks.keys():
+ if callback in self.callbacks[event_type]:
+ self.callbacks[event_type].remove(callback)
+
+ def _send_event(self, event_type, **kwargs):
+ """
+ Method for sending events to registered callbacks.
+
+ If callbacks throws exceptions event propagation will stop and this method be part of the track trace.
+
+ :param DfuEvent event_type:
+ :param args: Arguments to callback function
+ :return:
+ """
+ if event_type in self.callbacks.keys():
+ for callback in self.callbacks[event_type]:
+ callback(**kwargs)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_ble.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_ble.py
new file mode 100644
index 0000000..ff56750
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_ble.py
@@ -0,0 +1,327 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python standard library
+from time import sleep
+from datetime import datetime, timedelta
+import abc
+import logging
+
+# Nordic libraries
+from nordicsemi.exceptions import NordicSemiException, IllegalStateException
+from nordicsemi.dfu.util import int16_to_bytes
+from nordicsemi.dfu.dfu_transport import DfuTransport, DfuEvent
+
+logger = logging.getLogger(__name__)
+
+
+# BLE DFU OpCodes :
+class DfuOpcodesBle(object):
+ """ DFU opcodes used during DFU communication with bootloader
+
+ See http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00949.html#gafa9a52a3e6c43ccf00cf680f944d67a3
+ for further information
+ """
+ INVALID_OPCODE = 0
+ START_DFU = 1
+ INITIALIZE_DFU = 2
+ RECEIVE_FIRMWARE_IMAGE = 3
+ VALIDATE_FIRMWARE_IMAGE = 4
+ ACTIVATE_FIRMWARE_AND_RESET = 5
+ SYSTEM_RESET = 6
+ REQ_PKT_RCPT_NOTIFICATION = 8
+ RESPONSE = 16
+ PKT_RCPT_NOTIF = 17
+
+
+class DfuErrorCodeBle(object):
+ """ DFU error code used during DFU communication with bootloader
+
+ See http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00949.html#gafa9a52a3e6c43ccf00cf680f944d67a3
+ for further information
+ """
+ SUCCESS = 1
+ INVALID_STATE = 2
+ NOT_SUPPORTED = 3
+ DATA_SIZE_EXCEEDS_LIMIT = 4
+ CRC_ERROR = 5
+ OPERATION_FAILED = 6
+
+ @staticmethod
+ def error_code_lookup(error_code):
+ """
+ Returns a description lookup table for error codes received from peer.
+
+ :param int error_code: Error code to parse
+ :return str: Textual description of the error code
+ """
+ code_lookup = {DfuErrorCodeBle.SUCCESS: "SUCCESS",
+ DfuErrorCodeBle.INVALID_STATE: "Invalid State",
+ DfuErrorCodeBle.NOT_SUPPORTED: "Not Supported",
+ DfuErrorCodeBle.DATA_SIZE_EXCEEDS_LIMIT: "Data Size Exceeds Limit",
+ DfuErrorCodeBle.CRC_ERROR: "CRC Error",
+ DfuErrorCodeBle.OPERATION_FAILED: "Operation Failed"}
+
+ return code_lookup.get(error_code, "UNKOWN ERROR CODE")
+
+# Service UUID. For further information, look at the nRF51 SDK documentation V7.2.0:
+# http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00071.html#ota_spec_number
+UUID_DFU_SERVICE = '000015301212EFDE1523785FEABCD123'
+# Characteristic UUID
+UUID_DFU_PACKET_CHARACTERISTIC = '000015321212EFDE1523785FEABCD123'
+UUID_DFU_CONTROL_STATE_CHARACTERISTIC = '000015311212EFDE1523785FEABCD123'
+# Descriptor UUID
+UUID_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR = 0x2902
+
+# NOTE: If packet receipt notification is enabled, a packet receipt
+# notification will be received for each 'num_of_packets_between_notif'
+# number of packets.
+#
+# Configuration tip: Increase this to get lesser notifications from the DFU
+# Target about packet receipts. Make it 0 to disable the packet receipt
+# notification
+
+NUM_OF_PACKETS_BETWEEN_NOTIF = 10
+DATA_PACKET_SIZE = 20
+
+
+class DfuTransportBle(DfuTransport):
+
+ def __init__(self):
+ super(DfuTransportBle, self).__init__()
+
+ def open(self):
+ super(DfuTransportBle, self).open()
+
+ def is_open(self):
+ return super(DfuTransportBle, self).is_open()
+
+ def close(self):
+ super(DfuTransportBle, self).close()
+
+ def _wait_for_condition(self, condition_function, expected_condition_value=True, timeout=10,
+ waiting_for="condition"):
+ """
+ Waits for condition_function to be true
+ Will timeout after 60 seconds
+
+ :param function condition_function: The function we are waiting for to return true
+ :param str timeout_message: Message that should be logged
+ :return:
+ """
+
+ start_time = datetime.now()
+
+ while condition_function() != expected_condition_value:
+ timeout_message = "Timeout while waiting for {0}.".format(waiting_for)
+ timed_out = datetime.now() - start_time > timedelta(0, timeout)
+ if timed_out:
+ self._send_event(DfuEvent.TIMEOUT_EVENT, log_message=timeout_message)
+ raise NordicSemiException(timeout_message)
+
+ if not self.is_open():
+ log_message = "Disconnected from device while waiting for {0}.".format(waiting_for)
+ raise IllegalStateException(log_message)
+
+ sleep(0.1)
+
+ if self.get_last_error() != DfuErrorCodeBle.SUCCESS:
+ error_message = "Error occoured while waiting for {0}. Error response {1}."
+ error_code = DfuErrorCodeBle.error_code_lookup(self.get_last_error())
+ error_message = error_message.format(waiting_for, error_code)
+ self._send_event(DfuEvent.ERROR_EVENT, log_message=error_message)
+ raise NordicSemiException(error_message)
+
+ @abc.abstractmethod
+ def send_packet_data(self, data):
+ """
+ Send data to the packet characteristic
+
+ :param str data: The data to be sent
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def send_control_data(self, opcode, data=""):
+ """
+ Send data to the control characteristic
+
+ :param int opcode: The opcode for the operation command sent to the control characteristic
+ :param str data: The data to be sent
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def get_received_response(self):
+ """
+ Returns True if the transport layer has received a response it expected
+
+ :return: bool
+ """
+ pass
+
+ def clear_received_response(self):
+ """
+ Clears the received response status, sets it to False.
+
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def is_waiting_for_notification(self):
+ """
+ Returns True if the transport layer is waiting for a notification
+
+ :return: bool
+ """
+ pass
+
+ def set_waiting_for_notification(self):
+ """
+ Notifies the transport layer that it should wait for notification
+
+ :return:
+ """
+ pass
+
+ @abc.abstractmethod
+ def get_last_error(self):
+ """
+ Returns the last error code
+
+ :return: DfuErrorCodeBle
+ """
+ pass
+
+ def _start_dfu(self, program_mode, image_size_packet):
+ logger.debug("Sending 'START DFU' command")
+ self.send_control_data(DfuOpcodesBle.START_DFU, chr(program_mode))
+ logger.debug("Sending image size")
+ self.send_packet_data(image_size_packet)
+ self._wait_for_condition(self.get_received_response, waiting_for="response for START DFU")
+ self.clear_received_response()
+
+ def send_start_dfu(self, program_mode, softdevice_size=0, bootloader_size=0, app_size=0):
+ super(DfuTransportBle, self).send_start_dfu(program_mode, softdevice_size, bootloader_size, app_size)
+ image_size_packet = DfuTransport.create_image_size_packet(softdevice_size, bootloader_size, app_size)
+
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=0, log_message="Setting up transfer...")
+
+ try:
+ self._start_dfu(program_mode, image_size_packet)
+ except IllegalStateException:
+ # We got disconnected. Try to send Start DFU again in case of buttonless dfu.
+ self.close()
+ self.open()
+
+ if not self.is_open():
+ raise IllegalStateException("Failed to reopen transport backend.")
+
+ self._start_dfu(program_mode, image_size_packet)
+
+ def send_init_packet(self, init_packet):
+ super(DfuTransportBle, self).send_init_packet(init_packet)
+ init_packet_start = chr(0x00)
+ init_packet_end = chr(0x01)
+
+ logger.debug("Sending 'INIT DFU' command")
+ self.send_control_data(DfuOpcodesBle.INITIALIZE_DFU, init_packet_start)
+
+ logger.debug("Sending init data")
+ for i in range(0, len(init_packet), DATA_PACKET_SIZE):
+ data_to_send = init_packet[i:i + DATA_PACKET_SIZE]
+ self.send_packet_data(data_to_send)
+
+ logger.debug("Sending 'Init Packet Complete' command")
+ self.send_control_data(DfuOpcodesBle.INITIALIZE_DFU, init_packet_end)
+ self._wait_for_condition(self.get_received_response, timeout=60, waiting_for="response for INITIALIZE DFU")
+ self.clear_received_response()
+
+ if NUM_OF_PACKETS_BETWEEN_NOTIF:
+ packet = int16_to_bytes(NUM_OF_PACKETS_BETWEEN_NOTIF)
+ logger.debug("Send number of packets before device sends notification")
+ self.send_control_data(DfuOpcodesBle.REQ_PKT_RCPT_NOTIFICATION, packet)
+
+ def send_firmware(self, firmware):
+ def progress_percentage(part, complete):
+ """
+ Calculate progress percentage
+ :param int part: Part value
+ :param int complete: Completed value
+ :return: int: Percentage complete
+ """
+ return min(100, (part + DATA_PACKET_SIZE) * 100 / complete)
+
+ super(DfuTransportBle, self).send_firmware(firmware)
+ packets_sent = 0
+ last_progress_update = -1 # Last packet sequence number when an update was fired to the event system
+ bin_size = len(firmware)
+ logger.debug("Send 'RECEIVE FIRMWARE IMAGE' command")
+ self.send_control_data(DfuOpcodesBle.RECEIVE_FIRMWARE_IMAGE)
+
+ for i in range(0, bin_size, DATA_PACKET_SIZE):
+ progress = progress_percentage(i, bin_size)
+
+ if progress != last_progress_update:
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=progress, log_message="Uploading firmware")
+ last_progress_update = progress
+
+ self._wait_for_condition(self.is_waiting_for_notification, expected_condition_value=False,
+ waiting_for="notification from device")
+
+ data_to_send = firmware[i:i + DATA_PACKET_SIZE]
+
+ log_message = "Sending Firmware bytes [{0}, {1}]".format(i, i + len(data_to_send))
+ logger.debug(log_message)
+
+ packets_sent += 1
+
+ if NUM_OF_PACKETS_BETWEEN_NOTIF != 0:
+ if (packets_sent % NUM_OF_PACKETS_BETWEEN_NOTIF) == 0:
+ self.set_waiting_for_notification()
+
+ self.send_packet_data(data_to_send)
+
+ self._wait_for_condition(self.get_received_response, waiting_for="response for RECEIVE FIRMWARE IMAGE")
+ self.clear_received_response()
+
+ def send_validate_firmware(self):
+ super(DfuTransportBle, self).send_validate_firmware()
+ logger.debug("Sending 'VALIDATE FIRMWARE IMAGE' command")
+ self.send_control_data(DfuOpcodesBle.VALIDATE_FIRMWARE_IMAGE)
+ self._wait_for_condition(self.get_received_response, waiting_for="response for VALIDATE FIRMWARE IMAGE")
+ self.clear_received_response()
+ logger.info("Firmware validated OK.")
+
+ def send_activate_firmware(self):
+ super(DfuTransportBle, self).send_activate_firmware()
+ logger.debug("Sending 'ACTIVATE FIRMWARE AND RESET' command")
+ self.send_control_data(DfuOpcodesBle.ACTIVATE_FIRMWARE_AND_RESET)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_serial.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_serial.py
new file mode 100644
index 0000000..0036c90
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/dfu_transport_serial.py
@@ -0,0 +1,337 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python imports
+import time
+from datetime import datetime, timedelta
+import binascii
+import logging
+import click
+
+# Python 3rd party imports
+from serial import Serial
+
+# Nordic Semiconductor imports
+from nordicsemi.dfu.util import slip_parts_to_four_bytes, slip_encode_esc_chars, int16_to_bytes, int32_to_bytes
+from nordicsemi.dfu import crc16
+from nordicsemi.exceptions import NordicSemiException
+from nordicsemi.dfu.dfu_transport import DfuTransport, DfuEvent
+
+
+logger = logging.getLogger(__name__)
+
+
+class DfuTransportSerial(DfuTransport):
+
+ DEFAULT_BAUD_RATE = 115200
+ DEFAULT_FLOW_CONTROL = False
+ DEFAULT_SERIAL_PORT_TIMEOUT = 1.0 # Timeout time on serial port read
+ SERIAL_PORT_OPEN_WAIT_TIME = 0.1
+ NRF52_RESET_WAIT_TIME = 0.1
+ ACK_PACKET_TIMEOUT = 1.0 # Timeout time for for ACK packet received before reporting timeout through event system
+ SEND_INIT_PACKET_WAIT_TIME = 0.5 # 1.0 # Time to wait before communicating with bootloader after init packet is sent
+
+ # SEND_START_DFU_WAIT_TIME = 10.0 # Time to wait before communicating with bootloader after start DFU packet is sent
+ # ADADFRUIT:
+ # - After Start packet is sent, nrf5x will start to erase flash page, each page takes 2.05 - 89.7 ms
+ # nrfutil need to wait accordingly for the image size
+ # - After sending all data -> send command to activate new firmware --> nrf52 erase bank0 and copy image
+ # from bank1 to bank0 (if dual bank) nrfutil need to wait otherwise and re-open serial could cause flash corruption
+
+ # T erase page for nrf52832 is (2.05 to 89.7 ms), nrf52840 is ~85 ms max
+ FLASH_PAGE_ERASE_MAX_TIME = 0.085
+
+ # T write word for nrf52832 is (6.7 to 338 us), nrf52840 is ~41 us max
+ FLASH_WORD_WRITE_AVG_TIME = 0.000041
+
+ FLASH_PAGE_SIZE = 4096 # 4K for nrf52
+ DFU_PACKET_MAX_SIZE = 512 # The DFU packet max size
+
+ def __init__(self, com_port, baud_rate=DEFAULT_BAUD_RATE, flow_control=DEFAULT_FLOW_CONTROL, single_bank=False, timeout=DEFAULT_SERIAL_PORT_TIMEOUT):
+ super(DfuTransportSerial, self).__init__()
+ self.com_port = com_port
+ self.baud_rate = baud_rate
+ self.flow_control = 1 if flow_control else 0
+ self.single_bank = single_bank
+ self.timeout = timeout
+ self.serial_port = None
+ self.total_size = 167936 # default is max application size
+ self.sd_size = 0
+ """:type: serial.Serial """
+
+ def open(self):
+ super(DfuTransportSerial, self).open()
+
+ try:
+ self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.timeout)
+ except Exception, e:
+ raise NordicSemiException("Serial port could not be opened on {0}. Reason: {1}".format(self.com_port, e.message))
+
+ # Wait for the system to reset
+ time.sleep(DfuTransportSerial.SERIAL_PORT_OPEN_WAIT_TIME)
+ def open(self):
+ super(DfuTransportSerial, self).open()
+
+ try:
+ self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.timeout)
+ except Exception, e:
+ raise NordicSemiException("Serial port could not be opened on {0}. Reason: {1}".format(self.com_port, e.message))
+
+ time.sleep(DfuTransportSerial.SERIAL_PORT_OPEN_WAIT_TIME)
+
+ # Toggle DTR to reset the board and enter DFU mode
+ self.serial_port.setDTR(False)
+ time.sleep(0.05)
+ self.serial_port.setDTR(True)
+
+ # Delay to allow device to boot up
+ time.sleep(DfuTransportSerial.NRF52_RESET_WAIT_TIME)
+
+ def close(self):
+ super(DfuTransportSerial, self).close()
+ self.serial_port.close()
+
+ def is_open(self):
+ super(DfuTransportSerial, self).is_open()
+
+ if self.serial_port is None:
+ return False
+
+ return self.serial_port.isOpen()
+
+ def send_validate_firmware(self):
+ super(DfuTransportSerial, self).send_validate_firmware()
+ return True
+
+ def send_init_packet(self, init_packet):
+ super(DfuTransportSerial, self).send_init_packet(init_packet)
+
+ frame = int32_to_bytes(DFU_INIT_PACKET)
+ frame += init_packet
+ frame += int16_to_bytes(0x0000) # Padding required
+
+ packet = HciPacket(frame)
+ self.send_packet(packet)
+ time.sleep(DfuTransportSerial.SEND_INIT_PACKET_WAIT_TIME)
+
+ def get_erase_wait_time(self):
+ return (((self.total_size)//self.FLASH_PAGE_SIZE)+1)*self.FLASH_PAGE_ERASE_MAX_TIME
+
+ def get_activate_wait_time(self):
+ if (self.single_bank and (self.sd_size == 0)):
+ # Single bank and not updating SD+Bootloader, we can skip bank1 -> bank0 delay
+ # but still need to delay bootloader setting save (1 flash page)
+ return self.FLASH_PAGE_ERASE_MAX_TIME;
+ else:
+ # Activate wait time including time to erase bank0 and transfer bank1 -> bank0
+ write_wait_time = ((self.total_size // 4) + 1) * self.FLASH_WORD_WRITE_AVG_TIME
+ return self.get_erase_wait_time() + write_wait_time
+
+ def send_start_dfu(self, mode, softdevice_size=None, bootloader_size=None, app_size=None):
+ super(DfuTransportSerial, self).send_start_dfu(mode, softdevice_size, bootloader_size, app_size)
+
+ frame = int32_to_bytes(DFU_START_PACKET)
+ frame += int32_to_bytes(mode)
+ frame += DfuTransport.create_image_size_packet(softdevice_size, bootloader_size, app_size)
+
+ packet = HciPacket(frame)
+ self.send_packet(packet)
+
+ self.sd_size = softdevice_size
+ self.total_size = softdevice_size+bootloader_size+app_size
+ #logger.info("Wait after Init Packet %s second", self.get_erase_wait_time())
+ time.sleep( self.get_erase_wait_time() )
+
+ def send_activate_firmware(self):
+ super(DfuTransportSerial, self).send_activate_firmware()
+
+ # Dual bank bootloader will erase the bank 0 with Application size & Transfer App size from bank1 to bank0
+ # There must a enough delay before finished to prevent Arduino IDE reopen Serial Monitor which cause pin reset
+ # Single bank bootloader could skip this delay if package contains only application firmware
+ click.echo("\nActivating new firmware")
+
+ # logger.info("Wait after activating %s second", self.get_activate_wait_time())
+ time.sleep( self.get_activate_wait_time() )
+
+ def send_firmware(self, firmware):
+ super(DfuTransportSerial, self).send_firmware(firmware)
+
+ def progress_percentage(part, whole):
+ return int(100 * float(part)/float(whole))
+
+ frames = []
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=0, done=False, log_message="")
+
+ for i in range(0, len(firmware), DfuTransportSerial.DFU_PACKET_MAX_SIZE):
+ data_packet = HciPacket(int32_to_bytes(DFU_DATA_PACKET) + firmware[i:i + DfuTransportSerial.DFU_PACKET_MAX_SIZE])
+ frames.append(data_packet)
+
+ frames_count = len(frames)
+
+ # Send firmware packets
+ for count, pkt in enumerate(frames):
+ self.send_packet(pkt)
+ self._send_event(DfuEvent.PROGRESS_EVENT,
+ log_message="",
+ progress=progress_percentage(count, frames_count),
+ done=False)
+
+ # Send data stop packet
+ frame = int32_to_bytes(DFU_STOP_DATA_PACKET)
+ packet = HciPacket(frame)
+ self.send_packet(packet)
+
+ self._send_event(DfuEvent.PROGRESS_EVENT, progress=100, done=False, log_message="")
+
+ def send_packet(self, pkt):
+ attempts = 0
+ last_ack = None
+ packet_sent = False
+
+ logger.debug("PC -> target: {0}".format(pkt))
+
+ while not packet_sent:
+ self.serial_port.write(pkt.data)
+ attempts += 1
+ ack = self.get_ack_nr()
+
+ if last_ack is None:
+ break
+
+ if ack == (last_ack + 1) % 8:
+ last_ack = ack
+ packet_sent = True
+
+ if attempts > 3:
+ raise Exception("Three failed tx attempts encountered on packet {0}".format(pkt.sequence_number))
+
+ def get_ack_nr(self):
+ def is_timeout(start_time, timeout_sec):
+ return not (datetime.now() - start_time <= timedelta(0, timeout_sec))
+
+ uart_buffer = ''
+ start = datetime.now()
+
+ while uart_buffer.count('\xC0') < 2:
+ # Disregard first of the two C0
+ temp = self.serial_port.read(6)
+
+ if temp:
+ uart_buffer += temp
+
+ if is_timeout(start, DfuTransportSerial.ACK_PACKET_TIMEOUT):
+ # reset HciPacket numbering back to 0
+ HciPacket.sequence_number = 0
+ self._send_event(DfuEvent.TIMEOUT_EVENT,
+ log_message="Timed out waiting for acknowledgement from device.")
+
+ # quit loop
+ break
+
+ # read until you get a new C0
+ # RESUME_WORK
+
+ if len(uart_buffer) < 2:
+ raise NordicSemiException("No data received on serial port. Not able to proceed.")
+
+ logger.debug("PC <- target: {0}".format(binascii.hexlify(uart_buffer)))
+ data = self.decode_esc_chars(uart_buffer)
+
+ # Remove 0xC0 at start and beginning
+ data = data[1:-1]
+
+ # Extract ACK number from header
+ return (data[0] >> 3) & 0x07
+
+ @staticmethod
+ def decode_esc_chars(data):
+ """Replace 0xDBDC with 0xCO and 0xDBDD with 0xDB"""
+ result = []
+
+ data = bytearray(data)
+
+ while len(data):
+ char = data.pop(0)
+
+ if char == 0xDB:
+ char2 = data.pop(0)
+
+ if char2 == 0xDC:
+ result.append(0xC0)
+ elif char2 == 0xDD:
+ result.append(0xDB)
+ else:
+ raise Exception('Char 0xDB NOT followed by 0xDC or 0xDD')
+ else:
+ result.append(char)
+
+ return result
+
+DATA_INTEGRITY_CHECK_PRESENT = 1
+RELIABLE_PACKET = 1
+HCI_PACKET_TYPE = 14
+
+DFU_INIT_PACKET = 1
+DFU_START_PACKET = 3
+DFU_DATA_PACKET = 4
+DFU_STOP_DATA_PACKET = 5
+
+DFU_UPDATE_MODE_NONE = 0
+DFU_UPDATE_MODE_SD = 1
+DFU_UPDATE_MODE_BL = 2
+DFU_UPDATE_MODE_APP = 4
+
+
+class HciPacket(object):
+ """Class representing a single HCI packet"""
+
+ sequence_number = 0
+
+ def __init__(self, data=''):
+ HciPacket.sequence_number = (HciPacket.sequence_number + 1) % 8
+ self.temp_data = ''
+ self.temp_data += slip_parts_to_four_bytes(HciPacket.sequence_number,
+ DATA_INTEGRITY_CHECK_PRESENT,
+ RELIABLE_PACKET,
+ HCI_PACKET_TYPE,
+ len(data))
+ self.temp_data += data
+ # Add escape characters
+ crc = crc16.calc_crc16(self.temp_data, crc=0xffff)
+
+ self.temp_data += chr(crc & 0xFF)
+ self.temp_data += chr((crc & 0xFF00) >> 8)
+
+ self.temp_data = slip_encode_esc_chars(self.temp_data)
+
+ self.data = chr(0xc0)
+ self.data += self.temp_data
+ self.data += chr(0xc0)
+
+ def __str__(self):
+ return binascii.hexlify(self.data)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/init_packet.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/init_packet.py
new file mode 100644
index 0000000..ccf8c34
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/init_packet.py
@@ -0,0 +1,131 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from enum import Enum
+import struct
+
+
+INIT_PACKET_USES_CRC16 = 0
+INIT_PACKET_USES_HASH = 1
+INIT_PACKET_EXT_USES_ECDS = 2
+
+
+class PacketField(Enum):
+ DEVICE_TYPE = 1
+ DEVICE_REVISION = 2
+ APP_VERSION = 3
+ REQUIRED_SOFTDEVICES_ARRAY = 4
+ OPT_DATA = 5
+ NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID = 6
+ NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH = 7
+ NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH = 8
+ NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16 = 9
+ NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS = 10
+
+
+class Packet(object):
+ """
+ Class that implements the INIT packet format.
+ http://developer.nordicsemi.com/nRF51_SDK/doc/7.1.0/s110/html/a00065.html
+ """
+
+ UNSIGNED_SHORT = "H"
+ UNSIGNED_INT = "I"
+ UNSIGNED_CHAR = "B"
+ CHAR_ARRAY = "s"
+
+ def __init__(self, init_packet_fields):
+ """
+
+ :param init_packet_fields: Dictionary with packet fields
+ """
+ self.init_packet_fields = init_packet_fields
+
+ def generate_packet(self):
+ """
+ Generates a binary packet from provided init_packet_fields provided in constructor.
+ This version includes the extended data
+
+ :return str: Returns a string representing the init_packet (in binary)
+
+ """
+ # Create struct format string based on keys that are
+ # present in self.init_packet_fields
+ format_string = self.__generate_struct_format_string()
+ args = []
+
+ # If you got error message AttributeError: 'int' object has no attribute 'value'.
+ # Uncomment line 84 and comment out line 85 and run 'python setup.py install'
+ #for key in sorted(self.init_packet_fields.keys(), key=lambda x: x):
+ for key in sorted(self.init_packet_fields.keys(), key=lambda x: x.value):
+ # Add length to fields that required that
+ if key in [PacketField.REQUIRED_SOFTDEVICES_ARRAY,
+ PacketField.OPT_DATA]:
+ args.append(len(self.init_packet_fields[key]))
+ args.extend(self.init_packet_fields[key])
+ else:
+ args.append(self.init_packet_fields[key])
+
+ return struct.pack(format_string, *args)
+
+ def __generate_struct_format_string(self):
+ format_string = "<" # Use little endian format with standard sizes for python,
+ # see https://docs.python.org/2/library/struct.html
+
+ # If you got error message AttributeError: 'int' object has no attribute 'value'.
+ # Uncomment line 102 and comment out line 103 and run 'python setup.py install'
+ #for key in sorted(self.init_packet_fields.keys(), key=lambda x: x):
+ for key in sorted(self.init_packet_fields.keys(), key=lambda x: x.value):
+ if key in [PacketField.DEVICE_TYPE,
+ PacketField.DEVICE_REVISION,
+ ]:
+ format_string += Packet.UNSIGNED_SHORT
+
+ elif key in [PacketField.APP_VERSION]:
+ format_string += Packet.UNSIGNED_INT
+ elif key in [PacketField.REQUIRED_SOFTDEVICES_ARRAY]:
+ array_elements = self.init_packet_fields[key]
+ format_string += Packet.UNSIGNED_SHORT # Add length field to format packet
+
+ for _ in range(len(array_elements)):
+ format_string += Packet.UNSIGNED_SHORT
+ elif key in [PacketField.OPT_DATA]:
+ format_string += Packet.UNSIGNED_SHORT # Add length field to optional data
+ format_string += "{0}{1}".format(len(self.init_packet_fields[key]), Packet.CHAR_ARRAY)
+ elif key in [PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID]:
+ format_string += Packet.UNSIGNED_INT # Add the extended packet id field
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH:
+ format_string += Packet.UNSIGNED_INT # Add the firmware length field
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ format_string += "32{0}".format(Packet.CHAR_ARRAY) # SHA-256 requires 32 bytes
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16:
+ format_string += Packet.UNSIGNED_SHORT
+ elif key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ format_string += "64{0}".format(Packet.CHAR_ARRAY) # ECDS based on P-256 using SHA-256 requires 64 bytes
+
+ return format_string
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/__init__.py
new file mode 100644
index 0000000..068036d
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/__init__.py
@@ -0,0 +1,1286 @@
+# Copyright (c) 2005-2013, Alexander Belchenko
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms,
+# with or without modification, are permitted provided
+# that the following conditions are met:
+#
+# * Redistributions of source code must retain
+# the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce
+# the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the author nor the names
+# of its contributors may be used to endorse
+# or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+'''Intel HEX file format reader and converter.
+
+@author Alexander Belchenko (alexander dot belchenko at gmail dot com)
+@version 1.5
+'''
+
+
+__docformat__ = "javadoc"
+
+
+from array import array
+from binascii import hexlify, unhexlify
+from bisect import bisect_right
+import os
+import sys
+
+from compat import asbytes, asstr
+
+
+class _DeprecatedParam(object):
+ pass
+
+_DEPRECATED = _DeprecatedParam()
+
+
+class IntelHex(object):
+ ''' Intel HEX file reader. '''
+
+ def __init__(self, source=None):
+ ''' Constructor. If source specified, object will be initialized
+ with the contents of source. Otherwise the object will be empty.
+
+ @param source source for initialization
+ (file name of HEX file, file object, addr dict or
+ other IntelHex object)
+ '''
+ # public members
+ self.padding = 0x0FF
+ # Start Address
+ self.start_addr = None
+
+ # private members
+ self._buf = {}
+ self._offset = 0
+
+ if source is not None:
+ if isinstance(source, basestring) or getattr(source, "read", None):
+ # load hex file
+ self.loadhex(source)
+ elif isinstance(source, dict):
+ self.fromdict(source)
+ elif isinstance(source, IntelHex):
+ self.padding = source.padding
+ if source.start_addr:
+ self.start_addr = source.start_addr.copy()
+ self._buf = source._buf.copy()
+ else:
+ raise ValueError("source: bad initializer type")
+
+ def _decode_record(self, s, line=0):
+ '''Decode one record of HEX file.
+
+ @param s line with HEX record.
+ @param line line number (for error messages).
+
+ @raise EndOfFile if EOF record encountered.
+ '''
+ s = s.rstrip('\r\n')
+ if not s:
+ return # empty line
+
+ if s[0] == ':':
+ try:
+ bin = array('B', unhexlify(asbytes(s[1:])))
+ except (TypeError, ValueError):
+ # this might be raised by unhexlify when odd hexascii digits
+ raise HexRecordError(line=line)
+ length = len(bin)
+ if length < 5:
+ raise HexRecordError(line=line)
+ else:
+ raise HexRecordError(line=line)
+
+ record_length = bin[0]
+ if length != (5 + record_length):
+ raise RecordLengthError(line=line)
+
+ addr = bin[1]*256 + bin[2]
+
+ record_type = bin[3]
+ if not (0 <= record_type <= 5):
+ raise RecordTypeError(line=line)
+
+ crc = sum(bin)
+ crc &= 0x0FF
+ if crc != 0:
+ raise RecordChecksumError(line=line)
+
+ if record_type == 0:
+ # data record
+ addr += self._offset
+ for i in xrange(4, 4+record_length):
+ if not self._buf.get(addr, None) is None:
+ raise AddressOverlapError(address=addr, line=line)
+ self._buf[addr] = bin[i]
+ addr += 1 # FIXME: addr should be wrapped
+ # BUT after 02 record (at 64K boundary)
+ # and after 04 record (at 4G boundary)
+
+ elif record_type == 1:
+ # end of file record
+ if record_length != 0:
+ raise EOFRecordError(line=line)
+ raise _EndOfFile
+
+ elif record_type == 2:
+ # Extended 8086 Segment Record
+ if record_length != 2 or addr != 0:
+ raise ExtendedSegmentAddressRecordError(line=line)
+ self._offset = (bin[4]*256 + bin[5]) * 16
+
+ elif record_type == 4:
+ # Extended Linear Address Record
+ if record_length != 2 or addr != 0:
+ raise ExtendedLinearAddressRecordError(line=line)
+ self._offset = (bin[4]*256 + bin[5]) * 65536
+
+ elif record_type == 3:
+ # Start Segment Address Record
+ if record_length != 4 or addr != 0:
+ raise StartSegmentAddressRecordError(line=line)
+ if self.start_addr:
+ raise DuplicateStartAddressRecordError(line=line)
+ self.start_addr = {'CS': bin[4]*256 + bin[5],
+ 'IP': bin[6]*256 + bin[7],
+ }
+
+ elif record_type == 5:
+ # Start Linear Address Record
+ if record_length != 4 or addr != 0:
+ raise StartLinearAddressRecordError(line=line)
+ if self.start_addr:
+ raise DuplicateStartAddressRecordError(line=line)
+ self.start_addr = {'EIP': (bin[4]*16777216 +
+ bin[5]*65536 +
+ bin[6]*256 +
+ bin[7]),
+ }
+
+ def loadhex(self, fobj):
+ """Load hex file into internal buffer. This is not necessary
+ if object was initialized with source set. This will overwrite
+ addresses if object was already initialized.
+
+ @param fobj file name or file-like object
+ """
+ if getattr(fobj, "read", None) is None:
+ fobj = open(fobj, "r")
+ fclose = fobj.close
+ else:
+ fclose = None
+
+ self._offset = 0
+ line = 0
+
+ try:
+ decode = self._decode_record
+ try:
+ for s in fobj:
+ line += 1
+ decode(s, line)
+ except _EndOfFile:
+ pass
+ finally:
+ if fclose:
+ fclose()
+
+ def loadbin(self, fobj, offset=0):
+ """Load bin file into internal buffer. Not needed if source set in
+ constructor. This will overwrite addresses without warning
+ if object was already initialized.
+
+ @param fobj file name or file-like object
+ @param offset starting address offset
+ """
+ fread = getattr(fobj, "read", None)
+ if fread is None:
+ f = open(fobj, "rb")
+ fread = f.read
+ fclose = f.close
+ else:
+ fclose = None
+
+ try:
+ self.frombytes(array('B', asbytes(fread())), offset=offset)
+ finally:
+ if fclose:
+ fclose()
+
+ def loadfile(self, fobj, format):
+ """Load data file into internal buffer. Preferred wrapper over
+ loadbin or loadhex.
+
+ @param fobj file name or file-like object
+ @param format file format ("hex" or "bin")
+ """
+ if format == "hex":
+ self.loadhex(fobj)
+ elif format == "bin":
+ self.loadbin(fobj)
+ else:
+ raise ValueError('format should be either "hex" or "bin";'
+ ' got %r instead' % format)
+
+ # alias (to be consistent with method tofile)
+ fromfile = loadfile
+
+ def fromdict(self, dikt):
+ """Load data from dictionary. Dictionary should contain int keys
+ representing addresses. Values should be the data to be stored in
+ those addresses in unsigned char form (i.e. not strings).
+ The dictionary may contain the key, ``start_addr``
+ to indicate the starting address of the data as described in README.
+
+ The contents of the dict will be merged with this object and will
+ overwrite any conflicts. This function is not necessary if the
+ object was initialized with source specified.
+ """
+ s = dikt.copy()
+ start_addr = s.get('start_addr')
+ if start_addr is not None:
+ del s['start_addr']
+ for k in s.keys():
+ if type(k) not in (int, long) or k < 0:
+ raise ValueError('Source dictionary should have only int keys')
+ self._buf.update(s)
+ if start_addr is not None:
+ self.start_addr = start_addr
+
+ def frombytes(self, bytes, offset=0):
+ """Load data from array or list of bytes.
+ Similar to loadbin() method but works directly with iterable bytes.
+ """
+ for b in bytes:
+ self._buf[offset] = b
+ offset += 1
+
+ def _get_start_end(self, start=None, end=None, size=None):
+ """Return default values for start and end if they are None.
+ If this IntelHex object is empty then it's error to
+ invoke this method with both start and end as None.
+ """
+ if (start,end) == (None,None) and self._buf == {}:
+ raise EmptyIntelHexError
+ if size is not None:
+ if None not in (start, end):
+ raise ValueError("tobinarray: you can't use start,end and size"
+ " arguments in the same time")
+ if (start, end) == (None, None):
+ start = self.minaddr()
+ if start is not None:
+ end = start + size - 1
+ else:
+ start = end - size + 1
+ if start < 0:
+ raise ValueError("tobinarray: invalid size (%d) "
+ "for given end address (%d)" % (size,end))
+ else:
+ if start is None:
+ start = self.minaddr()
+ if end is None:
+ end = self.maxaddr()
+ if start > end:
+ start, end = end, start
+ return start, end
+
+ def tobinarray(self, start=None, end=None, pad=_DEPRECATED, size=None):
+ ''' Convert this object to binary form as array. If start and end
+ unspecified, they will be inferred from the data.
+ @param start start address of output bytes.
+ @param end end address of output bytes (inclusive).
+ @param pad [DEPRECATED PARAMETER, please use self.padding instead]
+ fill empty spaces with this value
+ (if pad is None then this method uses self.padding).
+ @param size size of the block, used with start or end parameter.
+ @return array of unsigned char data.
+ '''
+ if not isinstance(pad, _DeprecatedParam):
+ print "IntelHex.tobinarray: 'pad' parameter is deprecated."
+ if pad is not None:
+ print "Please, use IntelHex.padding attribute instead."
+ else:
+ print "Please, don't pass it explicitly."
+ print "Use syntax like this: ih.tobinarray(start=xxx, end=yyy, size=zzz)"
+ else:
+ pad = None
+ return self._tobinarray_really(start, end, pad, size)
+
+ def _tobinarray_really(self, start, end, pad, size):
+ if pad is None:
+ pad = self.padding
+
+ bin = array('B')
+
+ if self._buf == {} and None in (start, end):
+ return bin
+
+ if size is not None and size <= 0:
+ raise ValueError("tobinarray: wrong value for size")
+
+ start, end = self._get_start_end(start, end, size)
+
+ for i in xrange(start, end+1):
+ bin.append(self._buf.get(i, pad))
+
+ return bin
+
+ def tobinstr(self, start=None, end=None, pad=_DEPRECATED, size=None):
+ ''' Convert to binary form and return as a string.
+ @param start start address of output bytes.
+ @param end end address of output bytes (inclusive).
+ @param pad [DEPRECATED PARAMETER, please use self.padding instead]
+ fill empty spaces with this value
+ (if pad is None then this method uses self.padding).
+ @param size size of the block, used with start or end parameter.
+ @return string of binary data.
+ '''
+ if not isinstance(pad, _DeprecatedParam):
+ print "IntelHex.tobinstr: 'pad' parameter is deprecated."
+ if pad is not None:
+ print "Please, use IntelHex.padding attribute instead."
+ else:
+ print "Please, don't pass it explicitly."
+ print "Use syntax like this: ih.tobinstr(start=xxx, end=yyy, size=zzz)"
+ else:
+ pad = None
+ return self._tobinstr_really(start, end, pad, size)
+
+ def _tobinstr_really(self, start, end, pad, size):
+ return asstr(self._tobinarray_really(start, end, pad, size).tostring())
+
+ def tobinfile(self, fobj, start=None, end=None, pad=_DEPRECATED, size=None):
+ '''Convert to binary and write to file.
+
+ @param fobj file name or file object for writing output bytes.
+ @param start start address of output bytes.
+ @param end end address of output bytes (inclusive).
+ @param pad [DEPRECATED PARAMETER, please use self.padding instead]
+ fill empty spaces with this value
+ (if pad is None then this method uses self.padding).
+ @param size size of the block, used with start or end parameter.
+ '''
+ if not isinstance(pad, _DeprecatedParam):
+ print "IntelHex.tobinfile: 'pad' parameter is deprecated."
+ if pad is not None:
+ print "Please, use IntelHex.padding attribute instead."
+ else:
+ print "Please, don't pass it explicitly."
+ print "Use syntax like this: ih.tobinfile(start=xxx, end=yyy, size=zzz)"
+ else:
+ pad = None
+ if getattr(fobj, "write", None) is None:
+ fobj = open(fobj, "wb")
+ close_fd = True
+ else:
+ close_fd = False
+
+ fobj.write(self._tobinstr_really(start, end, pad, size))
+
+ if close_fd:
+ fobj.close()
+
+ def todict(self):
+ '''Convert to python dictionary.
+
+ @return dict suitable for initializing another IntelHex object.
+ '''
+ r = {}
+ r.update(self._buf)
+ if self.start_addr:
+ r['start_addr'] = self.start_addr
+ return r
+
+ def addresses(self):
+ '''Returns all used addresses in sorted order.
+ @return list of occupied data addresses in sorted order.
+ '''
+ aa = self._buf.keys()
+ aa.sort()
+ return aa
+
+ def minaddr(self):
+ '''Get minimal address of HEX content.
+ @return minimal address or None if no data
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return None
+ else:
+ return min(aa)
+
+ def maxaddr(self):
+ '''Get maximal address of HEX content.
+ @return maximal address or None if no data
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return None
+ else:
+ return max(aa)
+
+ def __getitem__(self, addr):
+ ''' Get requested byte from address.
+ @param addr address of byte.
+ @return byte if address exists in HEX file, or self.padding
+ if no data found.
+ '''
+ t = type(addr)
+ if t in (int, long):
+ if addr < 0:
+ raise TypeError('Address should be >= 0.')
+ return self._buf.get(addr, self.padding)
+ elif t == slice:
+ addresses = self._buf.keys()
+ ih = IntelHex()
+ if addresses:
+ addresses.sort()
+ start = addr.start or addresses[0]
+ stop = addr.stop or (addresses[-1]+1)
+ step = addr.step or 1
+ for i in xrange(start, stop, step):
+ x = self._buf.get(i)
+ if x is not None:
+ ih[i] = x
+ return ih
+ else:
+ raise TypeError('Address has unsupported type: %s' % t)
+
+ def __setitem__(self, addr, byte):
+ """Set byte at address."""
+ t = type(addr)
+ if t in (int, long):
+ if addr < 0:
+ raise TypeError('Address should be >= 0.')
+ self._buf[addr] = byte
+ elif t == slice:
+ if not isinstance(byte, (list, tuple)):
+ raise ValueError('Slice operation expects sequence of bytes')
+ start = addr.start
+ stop = addr.stop
+ step = addr.step or 1
+ if None not in (start, stop):
+ ra = range(start, stop, step)
+ if len(ra) != len(byte):
+ raise ValueError('Length of bytes sequence does not match '
+ 'address range')
+ elif (start, stop) == (None, None):
+ raise TypeError('Unsupported address range')
+ elif start is None:
+ start = stop - len(byte)
+ elif stop is None:
+ stop = start + len(byte)
+ if start < 0:
+ raise TypeError('start address cannot be negative')
+ if stop < 0:
+ raise TypeError('stop address cannot be negative')
+ j = 0
+ for i in xrange(start, stop, step):
+ self._buf[i] = byte[j]
+ j += 1
+ else:
+ raise TypeError('Address has unsupported type: %s' % t)
+
+ def __delitem__(self, addr):
+ """Delete byte at address."""
+ t = type(addr)
+ if t in (int, long):
+ if addr < 0:
+ raise TypeError('Address should be >= 0.')
+ del self._buf[addr]
+ elif t == slice:
+ addresses = self._buf.keys()
+ if addresses:
+ addresses.sort()
+ start = addr.start or addresses[0]
+ stop = addr.stop or (addresses[-1]+1)
+ step = addr.step or 1
+ for i in xrange(start, stop, step):
+ x = self._buf.get(i)
+ if x is not None:
+ del self._buf[i]
+ else:
+ raise TypeError('Address has unsupported type: %s' % t)
+
+ def __len__(self):
+ """Return count of bytes with real values."""
+ return len(self._buf.keys())
+
+ def write_hex_file(self, f, write_start_addr=True):
+ """Write data to file f in HEX format.
+
+ @param f filename or file-like object for writing
+ @param write_start_addr enable or disable writing start address
+ record to file (enabled by default).
+ If there is no start address in obj, nothing
+ will be written regardless of this setting.
+ """
+ fwrite = getattr(f, "write", None)
+ if fwrite:
+ fobj = f
+ fclose = None
+ else:
+ fobj = open(f, 'w')
+ fwrite = fobj.write
+ fclose = fobj.close
+
+ # Translation table for uppercasing hex ascii string.
+ # timeit shows that using hexstr.translate(table)
+ # is faster than hexstr.upper():
+ # 0.452ms vs. 0.652ms (translate vs. upper)
+ if sys.version_info[0] >= 3:
+ table = bytes(range(256)).upper()
+ else:
+ table = ''.join(chr(i).upper() for i in range(256))
+
+
+
+ # start address record if any
+ if self.start_addr and write_start_addr:
+ keys = self.start_addr.keys()
+ keys.sort()
+ bin = array('B', asbytes('\0'*9))
+ if keys == ['CS','IP']:
+ # Start Segment Address Record
+ bin[0] = 4 # reclen
+ bin[1] = 0 # offset msb
+ bin[2] = 0 # offset lsb
+ bin[3] = 3 # rectyp
+ cs = self.start_addr['CS']
+ bin[4] = (cs >> 8) & 0x0FF
+ bin[5] = cs & 0x0FF
+ ip = self.start_addr['IP']
+ bin[6] = (ip >> 8) & 0x0FF
+ bin[7] = ip & 0x0FF
+ bin[8] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+ elif keys == ['EIP']:
+ # Start Linear Address Record
+ bin[0] = 4 # reclen
+ bin[1] = 0 # offset msb
+ bin[2] = 0 # offset lsb
+ bin[3] = 5 # rectyp
+ eip = self.start_addr['EIP']
+ bin[4] = (eip >> 24) & 0x0FF
+ bin[5] = (eip >> 16) & 0x0FF
+ bin[6] = (eip >> 8) & 0x0FF
+ bin[7] = eip & 0x0FF
+ bin[8] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+ else:
+ if fclose:
+ fclose()
+ raise InvalidStartAddressValueError(start_addr=self.start_addr)
+
+ # data
+ addresses = self._buf.keys()
+ addresses.sort()
+ addr_len = len(addresses)
+ if addr_len:
+ minaddr = addresses[0]
+ maxaddr = addresses[-1]
+
+ if maxaddr > 65535:
+ need_offset_record = True
+ else:
+ need_offset_record = False
+ high_ofs = 0
+
+ cur_addr = minaddr
+ cur_ix = 0
+
+ while cur_addr <= maxaddr:
+ if need_offset_record:
+ bin = array('B', asbytes('\0'*7))
+ bin[0] = 2 # reclen
+ bin[1] = 0 # offset msb
+ bin[2] = 0 # offset lsb
+ bin[3] = 4 # rectyp
+ high_ofs = int(cur_addr>>16)
+ b = divmod(high_ofs, 256)
+ bin[4] = b[0] # msb of high_ofs
+ bin[5] = b[1] # lsb of high_ofs
+ bin[6] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+
+ while True:
+ # produce one record
+ low_addr = cur_addr & 0x0FFFF
+ # chain_len off by 1
+ chain_len = min(15, 65535-low_addr, maxaddr-cur_addr)
+
+ # search continuous chain
+ stop_addr = cur_addr + chain_len
+ if chain_len:
+ ix = bisect_right(addresses, stop_addr,
+ cur_ix,
+ min(cur_ix+chain_len+1, addr_len))
+ chain_len = ix - cur_ix # real chain_len
+ # there could be small holes in the chain
+ # but we will catch them by try-except later
+ # so for big continuous files we will work
+ # at maximum possible speed
+ else:
+ chain_len = 1 # real chain_len
+
+ bin = array('B', asbytes('\0'*(5+chain_len)))
+ b = divmod(low_addr, 256)
+ bin[1] = b[0] # msb of low_addr
+ bin[2] = b[1] # lsb of low_addr
+ bin[3] = 0 # rectype
+ try: # if there is small holes we'll catch them
+ for i in range(chain_len):
+ bin[4+i] = self._buf[cur_addr+i]
+ except KeyError:
+ # we catch a hole so we should shrink the chain
+ chain_len = i
+ bin = bin[:5+i]
+ bin[0] = chain_len
+ bin[4+chain_len] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ asstr(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+
+ # adjust cur_addr/cur_ix
+ cur_ix += chain_len
+ if cur_ix < addr_len:
+ cur_addr = addresses[cur_ix]
+ else:
+ cur_addr = maxaddr + 1
+ break
+ high_addr = int(cur_addr>>16)
+ if high_addr > high_ofs:
+ break
+
+ # end-of-file record
+ fwrite(":00000001FF\n")
+ if fclose:
+ fclose()
+
+ def tofile(self, fobj, format):
+ """Write data to hex or bin file. Preferred method over tobin or tohex.
+
+ @param fobj file name or file-like object
+ @param format file format ("hex" or "bin")
+ """
+ if format == 'hex':
+ self.write_hex_file(fobj)
+ elif format == 'bin':
+ self.tobinfile(fobj)
+ else:
+ raise ValueError('format should be either "hex" or "bin";'
+ ' got %r instead' % format)
+
+ def gets(self, addr, length):
+ """Get string of bytes from given address. If any entries are blank
+ from addr through addr+length, a NotEnoughDataError exception will
+ be raised. Padding is not used."""
+ a = array('B', asbytes('\0'*length))
+ try:
+ for i in xrange(length):
+ a[i] = self._buf[addr+i]
+ except KeyError:
+ raise NotEnoughDataError(address=addr, length=length)
+ return asstr(a.tostring())
+
+ def puts(self, addr, s):
+ """Put string of bytes at given address. Will overwrite any previous
+ entries.
+ """
+ a = array('B', asbytes(s))
+ for i in xrange(len(a)):
+ self._buf[addr+i] = a[i]
+
+ def getsz(self, addr):
+ """Get zero-terminated string from given address. Will raise
+ NotEnoughDataError exception if a hole is encountered before a 0.
+ """
+ i = 0
+ try:
+ while True:
+ if self._buf[addr+i] == 0:
+ break
+ i += 1
+ except KeyError:
+ raise NotEnoughDataError(msg=('Bad access at 0x%X: '
+ 'not enough data to read zero-terminated string') % addr)
+ return self.gets(addr, i)
+
+ def putsz(self, addr, s):
+ """Put string in object at addr and append terminating zero at end."""
+ self.puts(addr, s)
+ self._buf[addr+len(s)] = 0
+
+ def dump(self, tofile=None):
+ """Dump object content to specified file object or to stdout if None.
+ Format is a hexdump with some header information at the beginning,
+ addresses on the left, and data on right.
+
+ @param tofile file-like object to dump to
+ """
+
+ if tofile is None:
+ tofile = sys.stdout
+ # start addr possibly
+ if self.start_addr is not None:
+ cs = self.start_addr.get('CS')
+ ip = self.start_addr.get('IP')
+ eip = self.start_addr.get('EIP')
+ if eip is not None and cs is None and ip is None:
+ tofile.write('EIP = 0x%08X\n' % eip)
+ elif eip is None and cs is not None and ip is not None:
+ tofile.write('CS = 0x%04X, IP = 0x%04X\n' % (cs, ip))
+ else:
+ tofile.write('start_addr = %r\n' % start_addr)
+ # actual data
+ addresses = self._buf.keys()
+ if addresses:
+ addresses.sort()
+ minaddr = addresses[0]
+ maxaddr = addresses[-1]
+ startaddr = int(minaddr>>4)*16
+ endaddr = int((maxaddr>>4)+1)*16
+ maxdigits = max(len(str(endaddr)), 4)
+ templa = '%%0%dX' % maxdigits
+ range16 = range(16)
+ for i in xrange(startaddr, endaddr, 16):
+ tofile.write(templa % i)
+ tofile.write(' ')
+ s = []
+ for j in range16:
+ x = self._buf.get(i+j)
+ if x is not None:
+ tofile.write(' %02X' % x)
+ if 32 <= x < 127: # GNU less does not like 0x7F (128 decimal) so we'd better show it as dot
+ s.append(chr(x))
+ else:
+ s.append('.')
+ else:
+ tofile.write(' --')
+ s.append(' ')
+ tofile.write(' |' + ''.join(s) + '|\n')
+
+ def merge(self, other, overlap='error'):
+ """Merge content of other IntelHex object into current object (self).
+ @param other other IntelHex object.
+ @param overlap action on overlap of data or starting addr:
+ - error: raising OverlapError;
+ - ignore: ignore other data and keep current data
+ in overlapping region;
+ - replace: replace data with other data
+ in overlapping region.
+
+ @raise TypeError if other is not instance of IntelHex
+ @raise ValueError if other is the same object as self
+ (it can't merge itself)
+ @raise ValueError if overlap argument has incorrect value
+ @raise AddressOverlapError on overlapped data
+ """
+ # check args
+ if not isinstance(other, IntelHex):
+ raise TypeError('other should be IntelHex object')
+ if other is self:
+ raise ValueError("Can't merge itself")
+ if overlap not in ('error', 'ignore', 'replace'):
+ raise ValueError("overlap argument should be either "
+ "'error', 'ignore' or 'replace'")
+ # merge data
+ this_buf = self._buf
+ other_buf = other._buf
+ for i in other_buf:
+ if i in this_buf:
+ if overlap == 'error':
+ raise AddressOverlapError(
+ 'Data overlapped at address 0x%X' % i)
+ elif overlap == 'ignore':
+ continue
+ this_buf[i] = other_buf[i]
+ # merge start_addr
+ if self.start_addr != other.start_addr:
+ if self.start_addr is None: # set start addr from other
+ self.start_addr = other.start_addr
+ elif other.start_addr is None: # keep existing start addr
+ pass
+ else: # conflict
+ if overlap == 'error':
+ raise AddressOverlapError(
+ 'Starting addresses are different')
+ elif overlap == 'replace':
+ self.start_addr = other.start_addr
+#/IntelHex
+
+
+class IntelHex16bit(IntelHex):
+ """Access to data as 16-bit words. Intended to use with Microchip HEX files."""
+
+ def __init__(self, source=None):
+ """Construct class from HEX file
+ or from instance of ordinary IntelHex class. If IntelHex object
+ is passed as source, the original IntelHex object should not be used
+ again because this class will alter it. This class leaves padding
+ alone unless it was precisely 0xFF. In that instance it is sign
+ extended to 0xFFFF.
+
+ @param source file name of HEX file or file object
+ or instance of ordinary IntelHex class.
+ Will also accept dictionary from todict method.
+ """
+ if isinstance(source, IntelHex):
+ # from ihex8
+ self.padding = source.padding
+ self.start_addr = source.start_addr
+ # private members
+ self._buf = source._buf
+ self._offset = source._offset
+ elif isinstance(source, dict):
+ raise IntelHexError("IntelHex16bit does not support initialization from dictionary yet.\n"
+ "Patches are welcome.")
+ else:
+ IntelHex.__init__(self, source)
+
+ if self.padding == 0x0FF:
+ self.padding = 0x0FFFF
+
+ def __getitem__(self, addr16):
+ """Get 16-bit word from address.
+ Raise error if only one byte from the pair is set.
+ We assume a Little Endian interpretation of the hex file.
+
+ @param addr16 address of word (addr8 = 2 * addr16).
+ @return word if bytes exists in HEX file, or self.padding
+ if no data found.
+ """
+ addr1 = addr16 * 2
+ addr2 = addr1 + 1
+ byte1 = self._buf.get(addr1, None)
+ byte2 = self._buf.get(addr2, None)
+
+ if byte1 != None and byte2 != None:
+ return byte1 | (byte2 << 8) # low endian
+
+ if byte1 == None and byte2 == None:
+ return self.padding
+
+ raise BadAccess16bit(address=addr16)
+
+ def __setitem__(self, addr16, word):
+ """Sets the address at addr16 to word assuming Little Endian mode.
+ """
+ addr_byte = addr16 * 2
+ b = divmod(word, 256)
+ self._buf[addr_byte] = b[1]
+ self._buf[addr_byte+1] = b[0]
+
+ def minaddr(self):
+ '''Get minimal address of HEX content in 16-bit mode.
+
+ @return minimal address used in this object
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return 0
+ else:
+ return min(aa)>>1
+
+ def maxaddr(self):
+ '''Get maximal address of HEX content in 16-bit mode.
+
+ @return maximal address used in this object
+ '''
+ aa = self._buf.keys()
+ if aa == []:
+ return 0
+ else:
+ return max(aa)>>1
+
+ def tobinarray(self, start=None, end=None, size=None):
+ '''Convert this object to binary form as array (of 2-bytes word data).
+ If start and end unspecified, they will be inferred from the data.
+ @param start start address of output data.
+ @param end end address of output data (inclusive).
+ @param size size of the block (number of words),
+ used with start or end parameter.
+ @return array of unsigned short (uint16_t) data.
+ '''
+ bin = array('H')
+
+ if self._buf == {} and None in (start, end):
+ return bin
+
+ if size is not None and size <= 0:
+ raise ValueError("tobinarray: wrong value for size")
+
+ start, end = self._get_start_end(start, end, size)
+
+ for addr in xrange(start, end+1):
+ bin.append(self[addr])
+
+ return bin
+
+
+#/class IntelHex16bit
+
+
+def hex2bin(fin, fout, start=None, end=None, size=None, pad=None):
+ """Hex-to-Bin convertor engine.
+ @return 0 if all OK
+
+ @param fin input hex file (filename or file-like object)
+ @param fout output bin file (filename or file-like object)
+ @param start start of address range (optional)
+ @param end end of address range (inclusive; optional)
+ @param size size of resulting file (in bytes) (optional)
+ @param pad padding byte (optional)
+ """
+ try:
+ h = IntelHex(fin)
+ except HexReaderError, e:
+ txt = "ERROR: bad HEX file: %s" % str(e)
+ print(txt)
+ return 1
+
+ # start, end, size
+ if size != None and size != 0:
+ if end == None:
+ if start == None:
+ start = h.minaddr()
+ end = start + size - 1
+ else:
+ if (end+1) >= size:
+ start = end + 1 - size
+ else:
+ start = 0
+
+ try:
+ if pad is not None:
+ # using .padding attribute rather than pad argument to function call
+ h.padding = pad
+ h.tobinfile(fout, start, end)
+ except IOError, e:
+ txt = "ERROR: Could not write to file: %s: %s" % (fout, str(e))
+ print(txt)
+ return 1
+
+ return 0
+#/def hex2bin
+
+
+def bin2hex(fin, fout, offset=0):
+ """Simple bin-to-hex convertor.
+ @return 0 if all OK
+
+ @param fin input bin file (filename or file-like object)
+ @param fout output hex file (filename or file-like object)
+ @param offset starting address offset for loading bin
+ """
+ h = IntelHex()
+ try:
+ h.loadbin(fin, offset)
+ except IOError, e:
+ txt = 'ERROR: unable to load bin file:', str(e)
+ print(txt)
+ return 1
+
+ try:
+ h.tofile(fout, format='hex')
+ except IOError, e:
+ txt = "ERROR: Could not write to file: %s: %s" % (fout, str(e))
+ print(txt)
+ return 1
+
+ return 0
+#/def bin2hex
+
+
+def diff_dumps(ih1, ih2, tofile=None, name1="a", name2="b", n_context=3):
+ """Diff 2 IntelHex objects and produce unified diff output for their
+ hex dumps.
+
+ @param ih1 first IntelHex object to compare
+ @param ih2 second IntelHex object to compare
+ @param tofile file-like object to write output
+ @param name1 name of the first hex file to show in the diff header
+ @param name2 name of the first hex file to show in the diff header
+ @param n_context number of context lines in the unidiff output
+ """
+ def prepare_lines(ih):
+ from cStringIO import StringIO
+ sio = StringIO()
+ ih.dump(sio)
+ dump = sio.getvalue()
+ lines = dump.splitlines()
+ return lines
+ a = prepare_lines(ih1)
+ b = prepare_lines(ih2)
+ import difflib
+ result = list(difflib.unified_diff(a, b, fromfile=name1, tofile=name2, n=n_context, lineterm=''))
+ if tofile is None:
+ tofile = sys.stdout
+ output = '\n'.join(result)+'\n'
+ tofile.write(output)
+
+
+class Record(object):
+ """Helper methods to build valid ihex records."""
+
+ def _from_bytes(bytes):
+ """Takes a list of bytes, computes the checksum, and outputs the entire
+ record as a string. bytes should be the hex record without the colon
+ or final checksum.
+
+ @param bytes list of byte values so far to pack into record.
+ @return String representation of one HEX record
+ """
+ assert len(bytes) >= 4
+ # calculate checksum
+ s = (-sum(bytes)) & 0x0FF
+ bin = array('B', bytes + [s])
+ return ':' + asstr(hexlify(bin.tostring())).upper()
+ _from_bytes = staticmethod(_from_bytes)
+
+ def data(offset, bytes):
+ """Return Data record. This constructs the full record, including
+ the length information, the record type (0x00), the
+ checksum, and the offset.
+
+ @param offset load offset of first byte.
+ @param bytes list of byte values to pack into record.
+
+ @return String representation of one HEX record
+ """
+ assert 0 <= offset < 65536
+ assert 0 < len(bytes) < 256
+ b = [len(bytes), (offset>>8)&0x0FF, offset&0x0FF, 0x00] + bytes
+ return Record._from_bytes(b)
+ data = staticmethod(data)
+
+ def eof():
+ """Return End of File record as a string.
+ @return String representation of Intel Hex EOF record
+ """
+ return ':00000001FF'
+ eof = staticmethod(eof)
+
+ def extended_segment_address(usba):
+ """Return Extended Segment Address Record.
+ @param usba Upper Segment Base Address.
+
+ @return String representation of Intel Hex USBA record.
+ """
+ b = [2, 0, 0, 0x02, (usba>>8)&0x0FF, usba&0x0FF]
+ return Record._from_bytes(b)
+ extended_segment_address = staticmethod(extended_segment_address)
+
+ def start_segment_address(cs, ip):
+ """Return Start Segment Address Record.
+ @param cs 16-bit value for CS register.
+ @param ip 16-bit value for IP register.
+
+ @return String representation of Intel Hex SSA record.
+ """
+ b = [4, 0, 0, 0x03, (cs>>8)&0x0FF, cs&0x0FF,
+ (ip>>8)&0x0FF, ip&0x0FF]
+ return Record._from_bytes(b)
+ start_segment_address = staticmethod(start_segment_address)
+
+ def extended_linear_address(ulba):
+ """Return Extended Linear Address Record.
+ @param ulba Upper Linear Base Address.
+
+ @return String representation of Intel Hex ELA record.
+ """
+ b = [2, 0, 0, 0x04, (ulba>>8)&0x0FF, ulba&0x0FF]
+ return Record._from_bytes(b)
+ extended_linear_address = staticmethod(extended_linear_address)
+
+ def start_linear_address(eip):
+ """Return Start Linear Address Record.
+ @param eip 32-bit linear address for the EIP register.
+
+ @return String representation of Intel Hex SLA record.
+ """
+ b = [4, 0, 0, 0x05, (eip>>24)&0x0FF, (eip>>16)&0x0FF,
+ (eip>>8)&0x0FF, eip&0x0FF]
+ return Record._from_bytes(b)
+ start_linear_address = staticmethod(start_linear_address)
+
+
+class _BadFileNotation(Exception):
+ """Special error class to use with _get_file_and_addr_range."""
+ pass
+
+def _get_file_and_addr_range(s, _support_drive_letter=None):
+ """Special method for hexmerge.py script to split file notation
+ into 3 parts: (filename, start, end)
+
+ @raise _BadFileNotation when string cannot be safely split.
+ """
+ if _support_drive_letter is None:
+ _support_drive_letter = (os.name == 'nt')
+ drive = ''
+ if _support_drive_letter:
+ if s[1:2] == ':' and s[0].upper() in ''.join([chr(i) for i in range(ord('A'), ord('Z')+1)]):
+ drive = s[:2]
+ s = s[2:]
+ parts = s.split(':')
+ n = len(parts)
+ if n == 1:
+ fname = parts[0]
+ fstart = None
+ fend = None
+ elif n != 3:
+ raise _BadFileNotation
+ else:
+ fname = parts[0]
+ def ascii_hex_to_int(ascii):
+ if ascii is not None:
+ try:
+ return int(ascii, 16)
+ except ValueError:
+ raise _BadFileNotation
+ return ascii
+ fstart = ascii_hex_to_int(parts[1] or None)
+ fend = ascii_hex_to_int(parts[2] or None)
+ return drive+fname, fstart, fend
+
+
+##
+# IntelHex Errors Hierarchy:
+#
+# IntelHexError - basic error
+# HexReaderError - general hex reader error
+# AddressOverlapError - data for the same address overlap
+# HexRecordError - hex record decoder base error
+# RecordLengthError - record has invalid length
+# RecordTypeError - record has invalid type (RECTYP)
+# RecordChecksumError - record checksum mismatch
+# EOFRecordError - invalid EOF record (type 01)
+# ExtendedAddressRecordError - extended address record base error
+# ExtendedSegmentAddressRecordError - invalid extended segment address record (type 02)
+# ExtendedLinearAddressRecordError - invalid extended linear address record (type 04)
+# StartAddressRecordError - start address record base error
+# StartSegmentAddressRecordError - invalid start segment address record (type 03)
+# StartLinearAddressRecordError - invalid start linear address record (type 05)
+# DuplicateStartAddressRecordError - start address record appears twice
+# InvalidStartAddressValueError - invalid value of start addr record
+# _EndOfFile - it's not real error, used internally by hex reader as signal that EOF record found
+# BadAccess16bit - not enough data to read 16 bit value (deprecated, see NotEnoughDataError)
+# NotEnoughDataError - not enough data to read N contiguous bytes
+# EmptyIntelHexError - requested operation cannot be performed with empty object
+
+class IntelHexError(Exception):
+ '''Base Exception class for IntelHex module'''
+
+ _fmt = 'IntelHex base error' #: format string
+
+ def __init__(self, msg=None, **kw):
+ """Initialize the Exception with the given message.
+ """
+ self.msg = msg
+ for key, value in kw.items():
+ setattr(self, key, value)
+
+ def __str__(self):
+ """Return the message in this Exception."""
+ if self.msg:
+ return self.msg
+ try:
+ return self._fmt % self.__dict__
+ except (NameError, ValueError, KeyError), e:
+ return 'Unprintable exception %s: %s' \
+ % (repr(e), str(e))
+
+class _EndOfFile(IntelHexError):
+ """Used for internal needs only."""
+ _fmt = 'EOF record reached -- signal to stop read file'
+
+class HexReaderError(IntelHexError):
+ _fmt = 'Hex reader base error'
+
+class AddressOverlapError(HexReaderError):
+ _fmt = 'Hex file has data overlap at address 0x%(address)X on line %(line)d'
+
+# class NotAHexFileError was removed in trunk.revno.54 because it's not used
+
+
+class HexRecordError(HexReaderError):
+ _fmt = 'Hex file contains invalid record at line %(line)d'
+
+
+class RecordLengthError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid length'
+
+class RecordTypeError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid record type'
+
+class RecordChecksumError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid checksum'
+
+class EOFRecordError(HexRecordError):
+ _fmt = 'File has invalid End-of-File record'
+
+
+class ExtendedAddressRecordError(HexRecordError):
+ _fmt = 'Base class for extended address exceptions'
+
+class ExtendedSegmentAddressRecordError(ExtendedAddressRecordError):
+ _fmt = 'Invalid Extended Segment Address Record at line %(line)d'
+
+class ExtendedLinearAddressRecordError(ExtendedAddressRecordError):
+ _fmt = 'Invalid Extended Linear Address Record at line %(line)d'
+
+
+class StartAddressRecordError(HexRecordError):
+ _fmt = 'Base class for start address exceptions'
+
+class StartSegmentAddressRecordError(StartAddressRecordError):
+ _fmt = 'Invalid Start Segment Address Record at line %(line)d'
+
+class StartLinearAddressRecordError(StartAddressRecordError):
+ _fmt = 'Invalid Start Linear Address Record at line %(line)d'
+
+class DuplicateStartAddressRecordError(StartAddressRecordError):
+ _fmt = 'Start Address Record appears twice at line %(line)d'
+
+class InvalidStartAddressValueError(StartAddressRecordError):
+ _fmt = 'Invalid start address value: %(start_addr)s'
+
+
+class NotEnoughDataError(IntelHexError):
+ _fmt = ('Bad access at 0x%(address)X: '
+ 'not enough data to read %(length)d contiguous bytes')
+
+class BadAccess16bit(NotEnoughDataError):
+ _fmt = 'Bad access at 0x%(address)X: not enough data to read 16 bit value'
+
+class EmptyIntelHexError(IntelHexError):
+ _fmt = "Requested operation cannot be executed with empty object"
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/compat.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/compat.py
new file mode 100644
index 0000000..3f48350
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/intelhex/compat.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2011, Bernhard Leiner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms,
+# with or without modification, are permitted provided
+# that the following conditions are met:
+#
+# * Redistributions of source code must retain
+# the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce
+# the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the author nor the names
+# of its contributors may be used to endorse
+# or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+'''Compatibility functions for python 2 and 3.
+
+@author Bernhard Leiner (bleiner AT gmail com)
+@version 1.0
+'''
+
+__docformat__ = "javadoc"
+
+
+import sys
+
+if sys.version_info[0] >= 3:
+ def asbytes(s):
+ if isinstance(s, bytes):
+ return s
+ return s.encode('latin1')
+ def asstr(s):
+ if isinstance(s, str):
+ return s
+ return s.decode('latin1')
+else:
+ asbytes = str
+ asstr = str
+
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py
new file mode 100644
index 0000000..c65e7dd
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/manifest.py
@@ -0,0 +1,239 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python libraries
+import json
+import binascii
+import os
+
+# Nordic libraries
+from nordicsemi.exceptions import NotImplementedException
+from nordicsemi.dfu.init_packet import PacketField
+from nordicsemi.dfu.model import HexType, FirmwareKeys
+
+
+class ManifestGenerator(object):
+ def __init__(self, dfu_version, firmwares_data):
+ """
+ The Manifest Generator constructor. Needs a data structure to generate a manifest from.
+
+ :type float dfu_version: The dfu version number to state in manifest
+ :type dict firmwares_data: The firmwares data structure describing the Nordic DFU package
+ """
+ self.dfu_version = dfu_version
+ self.firmwares_data = firmwares_data
+ self.manifest = None
+
+ def generate_manifest(self):
+ self.manifest = Manifest()
+ self.manifest.dfu_version = self.dfu_version
+
+ for key in self.firmwares_data:
+ firmware_dict = self.firmwares_data[key]
+
+ if key == HexType.SD_BL:
+ _firmware = SoftdeviceBootloaderFirmware()
+ _firmware.bl_size = firmware_dict[FirmwareKeys.BL_SIZE]
+ _firmware.sd_size = firmware_dict[FirmwareKeys.SD_SIZE]
+ else:
+ _firmware = Firmware()
+
+ # Strip path, add only filename
+ _firmware.bin_file = os.path.basename(firmware_dict[FirmwareKeys.BIN_FILENAME])
+ _firmware.dat_file = os.path.basename(firmware_dict[FirmwareKeys.DAT_FILENAME])
+
+ init_packet_data = InitPacketData()
+
+ for init_packet_data_key in firmware_dict[FirmwareKeys.INIT_PACKET_DATA]:
+ field = firmware_dict[FirmwareKeys.INIT_PACKET_DATA][init_packet_data_key]
+
+ if init_packet_data_key == PacketField.APP_VERSION:
+ init_packet_data.application_version = field
+ elif init_packet_data_key == PacketField.DEVICE_TYPE:
+ init_packet_data.device_type = field
+ elif init_packet_data_key == PacketField.DEVICE_REVISION:
+ init_packet_data.device_revision = field
+ elif init_packet_data_key == PacketField.REQUIRED_SOFTDEVICES_ARRAY:
+ init_packet_data.softdevice_req = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID:
+ init_packet_data.ext_packet_id = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH:
+ init_packet_data.firmware_length = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ init_packet_data.firmware_hash = binascii.hexlify(field)
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16:
+ init_packet_data.firmware_crc16 = field
+ elif init_packet_data_key == PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ init_packet_data.init_packet_ecds = binascii.hexlify(field)
+ else:
+ raise NotImplementedException(
+ "Support for init packet data type {0} not implemented yet.".format(init_packet_data_key))
+
+ _firmware.init_packet_data = init_packet_data
+
+ if key == HexType.APPLICATION:
+ self.manifest.application = _firmware
+ elif key == HexType.BOOTLOADER:
+ self.manifest.bootloader = _firmware
+ elif key == HexType.SOFTDEVICE:
+ self.manifest.softdevice = _firmware
+ elif key == HexType.SD_BL:
+ self.manifest.softdevice_bootloader = _firmware
+ else:
+ raise NotImplementedException("Support for firmware type {0} not implemented yet.".format(key))
+
+ return self.to_json()
+
+ def to_json(self):
+ def remove_none_entries(d):
+ if not isinstance(d, dict):
+ return d
+
+ return dict((k, remove_none_entries(v)) for k, v in d.iteritems() if v is not None)
+
+ return json.dumps({'manifest': self.manifest},
+ default=lambda o: remove_none_entries(o.__dict__),
+ sort_keys=True, indent=4,
+ separators=(',', ': '))
+
+
+class InitPacketData(object):
+ def __init__(self,
+ device_type=None,
+ device_revision=None,
+ application_version=None,
+ softdevice_req=None,
+ ext_packet_id=None,
+ firmware_length=None,
+ firmware_hash=None,
+ firmware_crc16=None,
+ init_packet_ecds=None
+ ):
+ """
+ The InitPacketData data model.
+
+ :param int device_type: device type
+ :param int device_revision: device revision
+ :param int application_version: application version
+ :param list softdevice_req: softdevice requirements
+ :param int ext_packet_id: packet extension id
+ :param int firmware_length: firmware length
+ :param str firmware_hash: firmware hash
+ :param int firmware_crc16: firmware CRC-16 calculated value
+ :param str init_packet_ecds: Init packet signature
+ :return: InitPacketData
+ """
+ self.device_type = device_type
+ self.device_revision = device_revision
+ self.application_version = application_version
+ self.softdevice_req = softdevice_req
+ self.ext_packet_id = ext_packet_id
+ self.firmware_length = firmware_length
+ self.firmware_hash = firmware_hash
+ self.firmware_crc16 = firmware_crc16
+ self.init_packet_ecds = init_packet_ecds
+
+
+class Firmware(object):
+ def __init__(self,
+ bin_file=None,
+ dat_file=None,
+ init_packet_data=None):
+ """
+ The firmware datamodel
+
+ :param str bin_file: Firmware binary file
+ :param str dat_file: Firmware .dat file (init packet for Nordic DFU)
+ :param dict init_packet_data: Initial packet data
+ :return:
+ """
+ self.dat_file = dat_file
+ self.bin_file = bin_file
+
+ if init_packet_data:
+ self.init_packet_data = InitPacketData(**init_packet_data)
+
+
+class SoftdeviceBootloaderFirmware(Firmware):
+ def __init__(self,
+ bin_file=None,
+ dat_file=None,
+ init_packet_data=None,
+ sd_size=None,
+ bl_size=None):
+ """
+ The SoftdeviceBootloaderFirmware data model
+
+ :param str bin_file: Firmware binary file
+ :param str dat_file: Firmware .dat file (init packet for Nordic DFU)
+ :param int sd_size: The softdevice size
+ :param int bl_size: The bootloader size
+ :return: SoftdeviceBootloaderFirmware
+ """
+ super(SoftdeviceBootloaderFirmware, self).__init__(
+ bin_file,
+ dat_file,
+ init_packet_data)
+ self.sd_size = sd_size
+ self.bl_size = bl_size
+
+
+class Manifest:
+ def __init__(self,
+ application=None,
+ bootloader=None,
+ softdevice=None,
+ softdevice_bootloader=None,
+ dfu_version=None):
+ """
+ The Manifest data model.
+
+ :param dict application: Application firmware in package
+ :param dict bootloader: Bootloader firmware in package
+ :param dict softdevice: Softdevice firmware in package
+ :param dict softdevice_bootloader: Combined softdevice and bootloader firmware in package
+ :return: Manifest
+ """
+ self.softdevice_bootloader = \
+ SoftdeviceBootloaderFirmware(**softdevice_bootloader) if softdevice_bootloader else None
+
+ self.softdevice = Firmware(**softdevice) if softdevice else None
+ self.bootloader = Firmware(**bootloader) if bootloader else None
+ self.application = Firmware(**application) if application else None
+ self.dfu_version = dfu_version
+
+ @staticmethod
+ def from_json(data):
+ """
+ Parses a manifest according to Nordic DFU package specification.
+
+ :param str data: The manifest in string format
+ :return: Manifest
+ """
+ kwargs = json.loads(data)
+ return Manifest(**kwargs['manifest'])
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/model.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/model.py
new file mode 100644
index 0000000..a5c3426
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/model.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from enum import Enum
+
+
+class HexType(object):
+ SOFTDEVICE = 1
+ BOOTLOADER = 2
+ SD_BL = 3
+ APPLICATION = 4
+
+
+class FirmwareKeys(Enum):
+ ENCRYPT = 1
+ FIRMWARE_FILENAME = 2
+ BIN_FILENAME = 3
+ DAT_FILENAME = 4
+ INIT_PACKET_DATA = 5
+ SD_SIZE = 6
+ BL_SIZE = 7
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py
new file mode 100644
index 0000000..67a5d5c
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py
@@ -0,0 +1,168 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from nordicsemi.dfu import intelhex
+from struct import unpack
+
+
+class nRFHex(intelhex.IntelHex):
+ """
+ Converts and merges .hex and .bin files into one .bin file.
+ """
+
+ info_struct_address_base = 0x00003000
+ info_struct_address_offset = 0x1000
+
+ info_struct_magic_number = 0x51B1E5DB
+ info_struct_magic_number_offset = 0x004
+
+ s1x0_mbr_end_address = 0x1000
+ s132_mbr_end_address = 0x3000
+
+ def __init__(self, source, bootloader=None):
+ """
+ Constructor that requires a firmware file path.
+ Softdevices can take an optional bootloader file path as parameter.
+
+ :param str source: The file path for the firmware
+ :param str bootloader: Optional file path to bootloader firmware
+ :return: None
+ """
+ super(nRFHex, self).__init__()
+
+ self.file_format = 'hex'
+
+ if source.endswith('.bin'):
+ self.file_format = 'bin'
+
+ self.loadfile(source, self.file_format)
+
+ self._removeuicr()
+
+ self.bootloaderhex = None
+
+ if bootloader is not None:
+ self.bootloaderhex = nRFHex(bootloader)
+
+ def _removeuicr(self):
+ uicr_start_address = 0x10000000
+ maxaddress = self.maxaddr()
+ if maxaddress >= uicr_start_address:
+ for i in range(uicr_start_address, maxaddress + 1):
+ self._buf.pop(i, 0)
+
+ def address_has_magic_number(self, address):
+ try:
+ potential_magic_number = self.gets(address, 4)
+ potential_magic_number = unpack('I', potential_magic_number)[0]
+ return nRFHex.info_struct_magic_number == potential_magic_number
+ except Exception:
+ return False
+
+ def get_softdevice_variant(self):
+ potential_magic_number_address = nRFHex.info_struct_address_base + nRFHex.info_struct_magic_number_offset
+
+ if self.address_has_magic_number(potential_magic_number_address):
+ return "s1x0"
+
+ for i in xrange(4):
+ potential_magic_number_address += nRFHex.info_struct_address_offset
+
+ if self.address_has_magic_number(potential_magic_number_address):
+ return "s132"
+
+ return "unknown"
+
+ def get_mbr_end_address(self):
+ softdevice_variant = self.get_softdevice_variant()
+
+ if softdevice_variant == "s132":
+ return nRFHex.s132_mbr_end_address
+ else:
+ return nRFHex.s1x0_mbr_end_address
+
+ def minaddr(self):
+ min_address = super(nRFHex, self).minaddr()
+
+ # Lower addresses are reserved for master boot record
+ if self.file_format != 'bin':
+ min_address = max(self.get_mbr_end_address(), min_address)
+
+ return min_address
+
+ def size(self):
+ """
+ Returns the size of the source.
+ :return: int
+ """
+ min_address = self.minaddr()
+ max_address = self.maxaddr()
+
+ size = max_address - min_address + 1
+
+ # Round up to nearest word
+ word_size = 4
+ number_of_words = (size + (word_size - 1)) / word_size
+ size = number_of_words * word_size
+
+ return size
+
+ def bootloadersize(self):
+ """
+ Returns the size of the bootloader.
+ :return: int
+ """
+ if self.bootloaderhex is None:
+ return 0
+
+ return self.bootloaderhex.size()
+
+ def tobinfile(self, fobj, start=None, end=None, pad=None, size=None):
+ """
+ Writes a binary version of source and bootloader respectivly to fobj which could be a
+ file object or a file path.
+
+ :param str fobj: File path or object the function writes to
+ :return: None
+ """
+ # If there is a bootloader this will make the recursion call use the samme file object.
+ if getattr(fobj, "write", None) is None:
+ fobj = open(fobj, "wb")
+ close_fd = True
+ else:
+ close_fd = False
+
+ start_address = self.minaddr()
+ size = self.size()
+ super(nRFHex, self).tobinfile(fobj, start=start_address, size=size)
+
+ if self.bootloaderhex is not None:
+ self.bootloaderhex.tobinfile(fobj)
+
+ if close_fd:
+ fobj.close()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/package.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/package.py
new file mode 100644
index 0000000..68c1d80
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/package.py
@@ -0,0 +1,369 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Python standard library
+import os
+import tempfile
+import shutil
+
+# 3rd party libraries
+from zipfile import ZipFile
+import hashlib
+
+
+# Nordic libraries
+from nordicsemi.exceptions import NordicSemiException
+from nordicsemi.dfu.nrfhex import *
+from nordicsemi.dfu.init_packet import *
+from nordicsemi.dfu.manifest import ManifestGenerator, Manifest
+from nordicsemi.dfu.model import HexType, FirmwareKeys
+from nordicsemi.dfu.crc16 import *
+
+from signing import Signing
+
+
+class Package(object):
+ """
+ Packages and unpacks Nordic DFU packages. Nordic DFU packages are zip files that contains firmware and meta-information
+ necessary for utilities to perform a DFU on nRF5X devices.
+
+ The internal data model used in Package is a dictionary. The dictionary is expressed like this in
+ json format:
+
+ {
+ "manifest": {
+ "bootloader": {
+ "bin_file": "asdf.bin",
+ "dat_file": "asdf.dat",
+ "init_packet_data": {
+ "application_version": null,
+ "device_revision": null,
+ "device_type": 5,
+ "firmware_hash": "asdfasdkfjhasdkfjashfkjasfhaskjfhkjsdfhasjkhf",
+ "softdevice_req": [
+ 17,
+ 18
+ ]
+ }
+ }
+ }
+
+ Attributes application, bootloader, softdevice, softdevice_bootloader shall not be put into the manifest if they are null
+
+ """
+
+ DEFAULT_DEV_TYPE = 0xFFFF
+ DEFAULT_DEV_REV = 0xFFFF
+ DEFAULT_APP_VERSION = 0xFFFFFFFF
+ DEFAULT_SD_REQ = [0xFFFE]
+ DEFAULT_DFU_VER = 0.5
+ MANIFEST_FILENAME = "manifest.json"
+
+ def __init__(self,
+ dev_type=DEFAULT_DEV_TYPE,
+ dev_rev=DEFAULT_DEV_REV,
+ app_version=DEFAULT_APP_VERSION,
+ sd_req=DEFAULT_SD_REQ,
+ app_fw=None,
+ bootloader_fw=None,
+ softdevice_fw=None,
+ dfu_ver=DEFAULT_DFU_VER,
+ key_file=None):
+ """
+ Constructor that requires values used for generating a Nordic DFU package.
+
+ :param int dev_type: Device type init-packet field
+ :param int dev_rev: Device revision init-packet field
+ :param int app_version: App version init-packet field
+ :param list sd_req: Softdevice Requirement init-packet field
+ :param str app_fw: Path to application firmware file
+ :param str bootloader_fw: Path to bootloader firmware file
+ :param str softdevice_fw: Path to softdevice firmware file
+ :param float dfu_ver: DFU version to use when generating init-packet
+ :param str key_file: Path to Signing key file (PEM)
+ :return: None
+ """
+ self.dfu_ver = dfu_ver
+
+ init_packet_vars = {}
+
+ if dev_type is not None:
+ init_packet_vars[PacketField.DEVICE_TYPE] = dev_type
+
+ if dev_rev is not None:
+ init_packet_vars[PacketField.DEVICE_REVISION] = dev_rev
+
+ if app_version is not None:
+ init_packet_vars[PacketField.APP_VERSION] = app_version
+
+ if sd_req is not None:
+ init_packet_vars[PacketField.REQUIRED_SOFTDEVICES_ARRAY] = sd_req
+
+ self.firmwares_data = {}
+
+ if app_fw:
+ self.__add_firmware_info(HexType.APPLICATION,
+ app_fw,
+ init_packet_vars)
+
+ if bootloader_fw:
+ self.__add_firmware_info(HexType.BOOTLOADER,
+ bootloader_fw,
+ init_packet_vars)
+
+ if softdevice_fw:
+ self.__add_firmware_info(HexType.SOFTDEVICE,
+ softdevice_fw,
+ init_packet_vars)
+
+ if key_file:
+ self.dfu_ver = 0.8
+ self.key_file = key_file
+
+ def generate_package(self, filename, preserve_work_directory=False):
+ """
+ Generates a Nordic DFU package. The package is a zip file containing firmware(s) and metadata required
+ for Nordic DFU applications to perform DFU onn nRF5X devices.
+
+ :param str filename: Filename for generated package.
+ :param bool preserve_work_directory: True to preserve the temporary working directory.
+ Useful for debugging of a package, and if the user wants to look at the generated package without having to
+ unzip it.
+ :return: None
+ """
+ work_directory = self.__create_temp_workspace()
+
+ if Package._is_bootloader_softdevice_combination(self.firmwares_data):
+ # Removing softdevice and bootloader data from dictionary and adding the combined later
+ softdevice_fw_data = self.firmwares_data.pop(HexType.SOFTDEVICE)
+ bootloader_fw_data = self.firmwares_data.pop(HexType.BOOTLOADER)
+
+ softdevice_fw_name = softdevice_fw_data[FirmwareKeys.FIRMWARE_FILENAME]
+ bootloader_fw_name = bootloader_fw_data[FirmwareKeys.FIRMWARE_FILENAME]
+
+ new_filename = "sd_bl.bin"
+ sd_bl_file_path = os.path.join(work_directory, new_filename)
+
+ nrf_hex = nRFHex(softdevice_fw_name, bootloader_fw_name)
+ nrf_hex.tobinfile(sd_bl_file_path)
+
+ softdevice_size = nrf_hex.size()
+ bootloader_size = nrf_hex.bootloadersize()
+
+ self.__add_firmware_info(HexType.SD_BL,
+ sd_bl_file_path,
+ softdevice_fw_data[FirmwareKeys.INIT_PACKET_DATA],
+ softdevice_size,
+ bootloader_size)
+
+ for key in self.firmwares_data:
+ firmware = self.firmwares_data[key]
+
+ # Normalize the firmware file and store it in the work directory
+ firmware[FirmwareKeys.BIN_FILENAME] = \
+ Package.normalize_firmware_to_bin(work_directory, firmware[FirmwareKeys.FIRMWARE_FILENAME])
+
+ # Calculate the hash for the .bin file located in the work directory
+ bin_file_path = os.path.join(work_directory, firmware[FirmwareKeys.BIN_FILENAME])
+
+ init_packet_data = firmware[FirmwareKeys.INIT_PACKET_DATA]
+
+ if self.dfu_ver <= 0.5:
+ firmware_hash = Package.calculate_crc16(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16] = firmware_hash
+ elif self.dfu_ver == 0.6:
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID] = INIT_PACKET_USES_CRC16
+ firmware_hash = Package.calculate_crc16(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16] = firmware_hash
+ elif self.dfu_ver == 0.7:
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID] = INIT_PACKET_USES_HASH
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH] = int(Package.calculate_file_size(bin_file_path))
+ firmware_hash = Package.calculate_sha256_hash(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH] = firmware_hash
+ elif self.dfu_ver == 0.8:
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID] = INIT_PACKET_EXT_USES_ECDS
+ firmware_hash = Package.calculate_sha256_hash(bin_file_path)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH] = int(Package.calculate_file_size(bin_file_path))
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH] = firmware_hash
+ temp_packet = self._create_init_packet(firmware)
+ signer = Signing()
+ signer.load_key(self.key_file)
+ signature = signer.sign(temp_packet)
+ init_packet_data[PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS] = signature
+
+ # Store the .dat file in the work directory
+ init_packet = self._create_init_packet(firmware)
+ init_packet_filename = firmware[FirmwareKeys.BIN_FILENAME].replace(".bin", ".dat")
+
+ with open(os.path.join(work_directory, init_packet_filename), 'wb') as init_packet_file:
+ init_packet_file.write(init_packet)
+
+ firmware[FirmwareKeys.DAT_FILENAME] = \
+ init_packet_filename
+
+ # Store the manifest to manifest.json
+ manifest = self.create_manifest()
+
+ with open(os.path.join(work_directory, Package.MANIFEST_FILENAME), "w") as manifest_file:
+ manifest_file.write(manifest)
+
+ # Package the work_directory to a zip file
+ Package.create_zip_package(work_directory, filename)
+
+ # Delete the temporary directory
+ if not preserve_work_directory:
+ shutil.rmtree(work_directory)
+
+ @staticmethod
+ def __create_temp_workspace():
+ return tempfile.mkdtemp(prefix="nrf_dfu_")
+
+ @staticmethod
+ def create_zip_package(work_directory, filename):
+ files = os.listdir(work_directory)
+
+ with ZipFile(filename, 'w') as package:
+ for _file in files:
+ file_path = os.path.join(work_directory, _file)
+ package.write(file_path, _file)
+
+ @staticmethod
+ def calculate_file_size(firmware_filename):
+ b = os.path.getsize(firmware_filename)
+ return b
+
+ @staticmethod
+ def calculate_sha256_hash(firmware_filename):
+ read_buffer = 4096
+
+ digest = hashlib.sha256()
+
+ with open(firmware_filename, 'rb') as firmware_file:
+ while True:
+ data = firmware_file.read(read_buffer)
+
+ if data:
+ digest.update(data)
+ else:
+ break
+
+ return digest.digest()
+
+ @staticmethod
+ def calculate_crc16(firmware_filename):
+ """
+ Calculates CRC16 has on provided firmware filename
+
+ :type str firmware_filename:
+ """
+ data_buffer = b''
+ read_size = 4096
+
+ with open(firmware_filename, 'rb') as firmware_file:
+ while True:
+ data = firmware_file.read(read_size)
+
+ if data:
+ data_buffer += data
+ else:
+ break
+
+ return calc_crc16(data_buffer, 0xffff)
+
+ def create_manifest(self):
+ manifest = ManifestGenerator(self.dfu_ver, self.firmwares_data)
+ return manifest.generate_manifest()
+
+ @staticmethod
+ def _is_bootloader_softdevice_combination(firmwares):
+ return (HexType.BOOTLOADER in firmwares) and (HexType.SOFTDEVICE in firmwares)
+
+ def __add_firmware_info(self, firmware_type, filename, init_packet_data, sd_size=None, bl_size=None):
+ self.firmwares_data[firmware_type] = {
+ FirmwareKeys.FIRMWARE_FILENAME: filename,
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data.copy(),
+ # Copying init packet to avoid using the same for all firmware
+ }
+
+ if firmware_type == HexType.SD_BL:
+ self.firmwares_data[firmware_type][FirmwareKeys.SD_SIZE] = sd_size
+ self.firmwares_data[firmware_type][FirmwareKeys.BL_SIZE] = bl_size
+
+ @staticmethod
+ def _create_init_packet(firmware_data):
+ p = Packet(firmware_data[FirmwareKeys.INIT_PACKET_DATA])
+ return p.generate_packet()
+
+ @staticmethod
+ def normalize_firmware_to_bin(work_directory, firmware_path):
+ firmware_filename = os.path.basename(firmware_path)
+ new_filename = firmware_filename.replace(".hex", ".bin")
+ new_filepath = os.path.join(work_directory, new_filename)
+
+ if not os.path.exists(new_filepath):
+ temp = nRFHex(firmware_path)
+ temp.tobinfile(new_filepath)
+
+ return new_filepath
+
+ @staticmethod
+ def unpack_package(package_path, target_dir):
+ """
+ Unpacks a Nordic DFU package.
+
+ :param str package_path: Path to the package
+ :param str target_dir: Target directory to unpack the package to
+ :return: Manifest Manifest: Returns a manifest back to the user. The manifest is a parse datamodel
+ of the manifest found in the Nordic DFU package.
+ """
+
+ if not os.path.isfile(package_path):
+ raise NordicSemiException("Package {0} not found.".format(package_path))
+
+ target_dir = os.path.abspath(target_dir)
+ target_base_path = os.path.dirname(target_dir)
+
+ if not os.path.exists(target_base_path):
+ raise NordicSemiException("Base path to target directory {0} does not exist.".format(target_base_path))
+
+ if not os.path.isdir(target_base_path):
+ raise NordicSemiException("Base path to target directory {0} is not a directory.".format(target_base_path))
+
+ if os.path.exists(target_dir):
+ raise NordicSemiException(
+ "Target directory {0} exists, not able to unpack to that directory.",
+ target_dir)
+
+ with ZipFile(package_path, 'r') as pkg:
+ pkg.extractall(target_dir)
+
+ with open(os.path.join(target_dir, Package.MANIFEST_FILENAME), 'r') as f:
+ _json = f.read()
+ """:type :str """
+
+ return Manifest.from_json(_json)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/signing.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/signing.py
new file mode 100644
index 0000000..ca98eb1
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/signing.py
@@ -0,0 +1,149 @@
+# Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
+#
+# The information contained herein is property of Nordic Semiconductor ASA.
+# Terms and conditions of usage are described in detail in NORDIC
+# SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+#
+# Licensees are granted free, non-transferable use of the information. NO
+# WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+# the file.
+
+import hashlib
+import binascii
+
+try:
+ from ecdsa import SigningKey
+ from ecdsa.curves import NIST256p
+ from ecdsa.keys import sigencode_string
+except Exception:
+ print "Failed to import ecdsa, cannot do signing"
+
+from nordicsemi.exceptions import InvalidArgumentException, IllegalStateException
+
+
+class Signing(object):
+ """
+ Class for singing of hex-files
+ """
+ def gen_key(self, filename):
+ """
+ Generate a new Signing key using NIST P-256 curve
+ """
+ self.sk = SigningKey.generate(curve=NIST256p)
+
+ with open(filename, "w") as sk_file:
+ sk_file.write(self.sk.to_pem())
+
+ def load_key(self, filename):
+ """
+ Load signing key (from pem file)
+ """
+ with open(filename, "r") as sk_file:
+ sk_pem = sk_file.read()
+
+ self.sk = SigningKey.from_pem(sk_pem)
+
+ sk_hex = "".join(c.encode('hex') for c in self.sk.to_string())
+
+ def sign(self, init_packet_data):
+ """
+ Create signature for init package using P-256 curve and SHA-256 as hashing algorithm
+ Returns R and S keys combined in a 64 byte array
+ """
+ # Add assertion of init_packet
+ if self.sk is None:
+ raise IllegalStateException("Can't save key. No key created/loaded")
+
+ # Sign the init-packet
+ signature = self.sk.sign(init_packet_data, hashfunc=hashlib.sha256, sigencode=sigencode_string)
+ return signature
+
+ def verify(self, init_packet, signature):
+ """
+ Verify init packet
+ """
+ # Add assertion of init_packet
+ if self.sk is None:
+ raise IllegalStateException("Can't save key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+
+ # Verify init packet
+ try:
+ vk.verify(signature, init_packet, hashfunc=hashlib.sha256)
+ except:
+ return False
+
+ return True
+
+ def get_vk(self, output_type):
+ """
+ Get verification key (as hex, code or pem)
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ if output_type is None:
+ raise InvalidArgumentException("Invalid output type for signature.")
+ elif output_type == 'hex':
+ return self.get_vk_hex()
+ elif output_type == 'code':
+ return self.get_vk_code()
+ elif output_type == 'pem':
+ return self.get_vk_pem()
+ else:
+ raise InvalidArgumentException("Invalid argument. Can't get key")
+
+ def get_vk_hex(self):
+ """
+ Get the verification key as hex
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+ vk_hexlify = binascii.hexlify(vk.to_string())
+
+ vk_hex = "Verification key Qx: {0}\n".format(vk_hexlify[0:64])
+ vk_hex += "Verification key Qy: {0}".format(vk_hexlify[64:128])
+
+ return vk_hex
+
+ def get_vk_code(self):
+ """
+ Get the verification key as code
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+ vk_hex = binascii.hexlify(vk.to_string())
+
+ vk_x_separated = ""
+ vk_x_str = vk_hex[0:64]
+ for i in xrange(0, len(vk_x_str), 2):
+ vk_x_separated += "0x" + vk_x_str[i:i+2] + ", "
+ vk_x_separated = vk_x_separated[:-2]
+
+ vk_y_separated = ""
+ vk_y_str = vk_hex[64:128]
+ for i in xrange(0, len(vk_y_str), 2):
+ vk_y_separated += "0x" + vk_y_str[i:i+2] + ", "
+ vk_y_separated = vk_y_separated[:-2]
+
+ vk_code = "static uint8_t Qx[] = {{ {0} }};\n".format(vk_x_separated)
+ vk_code += "static uint8_t Qy[] = {{ {0} }};".format(vk_y_separated)
+
+ return vk_code
+
+ def get_vk_pem(self):
+ """
+ Get the verification key as PEM
+ """
+ if self.sk is None:
+ raise IllegalStateException("Can't get key. No key created/loaded")
+
+ vk = self.sk.get_verifying_key()
+ vk_pem = vk.to_pem()
+
+ return vk_pem
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar.hex b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar.hex
new file mode 100644
index 0000000..d3bf4c9
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar.hex
@@ -0,0 +1,828 @@
+:020000040003F7
+:10C800007834002065CA030077CA030079CA0300A0
+:10C810000000000000000000000000000000000018
+:10C820000000000000000000000000007BCA0300C0
+:10C8300000000000000000007DCA03007FCA030062
+:10C8400081CA030081CA030081CA030081CA0300B0
+:10C8500081CA030000000000ADDF030081CA0300AD
+:10C8600081CA030081CA030081CA030081CA030090
+:10C8700081CA030081CA030081CA030081CA030080
+:10C8800081CA0300E9D8030081CA030081CA0300FA
+:10C89000FFD8030081CA0300D5E4030081CA030066
+:10C8A00081CA030081CA03000000000000000000EC
+:10C8B0000000000000000000000000000000000078
+:10C8C00000F002F800F040F80CA030C80838241836
+:10C8D0002D18A246671EAB4654465D46AC4201D1B8
+:10C8E00000F032F87E460F3E0FCCB64601263342AA
+:10C8F00000D0FB1AA246AB4633431847583100001C
+:10C9000078310000103A02D378C878C1FAD85207BB
+:10C9100001D330C830C101D504680C6070470000F5
+:10C920000023002400250026103A01D378C1FBD84B
+:10C93000520700D330C100D50B6070471FB5C04609
+:10C94000C0461FBD10B510BD03F03EF81146FFF7FD
+:10C95000F5FF00F0BEF803F056F803B4FFF7F2FF5E
+:10C9600003BC03F05BF80000026882F308884368A8
+:10C9700018470000401E00BF00BF00BF00BF00BF3F
+:10C9800000BF00BF00BF00BF00BF00BF00BFF1D1AC
+:10C990007047000070B505460C46164602E00FCC05
+:10C9A0000FC5103E102EFAD2082E02D303CC03C5B9
+:10C9B000083E042E07D301CC01C5361F03E02178C1
+:10C9C0002970641C6D1C761EF9D270BD10B500F084
+:10C9D0001DF8002805D01F491D484860C8131E498E
+:10C9E00088611E48018CC9B201290ED1818C0907CA
+:10C9F0000BD1018D0906090F042906D1808D00068F
+:10CA0000000F02D116490120886010BD1348018C27
+:10CA1000C9B2012917D1818C090714D1018D0906EA
+:10CA20000A0F03D1828D1206120F0ED0090F0129B1
+:10CA300003D1828D1206120F07D0032903D1808DF6
+:10CA40000006000F01D00020704701207047000051
+:10CA5000DFFF07C000050040006C0040C00F00F081
+:10CA6000000600400A4802680F210A430260094894
+:10CA7000804709480047FEE7FEE7FEE7FEE7FEE7DE
+:10CA8000FEE7000005480649064A074B70470000CC
+:10CA900024050040CDC90300C1C803007828002048
+:10CAA00078340020782C0020782C0020964800292B
+:10CAB000016005D1012095490004C86000F0D8F854
+:10CAC00070470A4601469248F0E710B501F0CEFDE6
+:10CAD00010BD1CB50020694608718E490120086010
+:10CAE0008C49103908608B49091F0860102000F03C
+:10CAF000C7F80C2000F0C4F80F2000F0C1F8864DF4
+:10CB000028680524A403A04204D084A2F2210020B6
+:10CB1000FFF7CCFF79216869C902884204D07FA25F
+:10CB2000F4210020FFF7C2FF012000070069012166
+:10CB30008902884204D079A2F5210020FFF7B6FFD0
+:10CB400079480090794B05220321002000F0FAFE7D
+:10CB5000002803D071A2A421FFF7A8FF7349022087
+:10CB6000283901F089FA002803D06CA29921FFF737
+:10CB70009DFF65486E4B6F4A0121001D01F08DFB42
+:10CB8000002803D065A2B421FFF790FF6A4B502222
+:10CB90006A49082001F07AFC002803D05FA2D62160
+:10CBA000FFF784FF664801F08DFC002803D05BA2EC
+:10CBB000D921FFF77BFF614A14215032082001F090
+:10CBC0001BF9002803D055A2E121FFF76FFF01F008
+:10CBD000A3FB002803D051A2FF21FFF767FF01A9A3
+:10CBE000082001F0B4FB002804D0FF214BA2033140
+:10CBF000FFF75CFF01F09BFB002804D0FF2147A258
+:10CC00000631FFF753FF68460079002804D120461B
+:10CC100000F077FA00280FD101203C490003C860DA
+:10CC200000F0EFFA002804D0FF213CA20E31FFF7FC
+:10CC30003DFF0C2000F024F8204600F062FA0028A6
+:10CC40000BD0102000F01CF80C2000F019F80F2079
+:10CC500000F016F8204600F000FB102000F010F85D
+:10CC60000C2000F00DF80F2000F00AF800F000F89A
+:10CC7000BFF34F8F34493348C860BFF34F8FFEE78F
+:10CC8000012181402148816070471CB501910090CD
+:10CC90002E4A0821684601F0C3F81CBD1CB500905F
+:10CCA000684601712A4A082101F0BAF81CBD10B586
+:10CCB0000021284A084601F0B3F810BD10B504461B
+:10CCC000082905D0FF2124A214310020FFF7EEFE31
+:10CCD00021686068884710BD10B50446082904D053
+:10CCE00029A29B210020FFF7E1FE216820798847D7
+:10CCF00010BD10B5002904D02FA298210020FFF705
+:10CD0000D5FE01F085FB10BD042000200005005079
+:10CD1000EFBEADDE40070050001000102E2E5C6DFF
+:10CD200061696E2E630000008BCC03003C21002063
+:10CD30009DCC030066060000AFCC03007C230020DE
+:10CD4000CBCA03000400FA0500ED00E0BDCC0300EF
+:10CD5000D9CC0300F3CC03002E2E5C2E2E5C2E2E9D
+:10CD60005C2E2E5C2E2E5C496E636C7564655C6176
+:10CD700070705F636F6D6D6F6E5C6170705F746912
+:10CD80006D65722E680000002E2E5C2E2E5C2E2EFD
+:10CD90005C2E2E5C2E2E5C496E636C7564655C6146
+:10CDA00070705F636F6D6D6F6E5C6170705F6275E8
+:10CDB00074746F6E2E6800002E2E5C2E2E5C2E2E4C
+:10CDC0005C2E2E5C2E2E5C496E636C7564655C7304
+:10CDD000645F636F6D6D6F6E5C736F6674646576B0
+:10CDE0006963655F68616E646C65722E680000003F
+:10CDF00010460A4610B5B2494C68042C03D1022AE9
+:10CE000001D1002806D0002803D0AEA24E21FFF7A2
+:10CE10004DFE10BD8A69002AFBD01946904710BD0F
+:10CE200010B5A74B01201870032000F0A3F910BD26
+:10CE300010B5A34C2078002801D0082010BD6069EF
+:10CE400000F056FE002803D09EA27121FFF72EFEAF
+:10CE50000F2100224904606900F00DFE040003D098
+:10CE600098A27421FFF722FE204610BDF0B59B4921
+:10CE700087B09948924D08600024A1276C7029461C
+:10CE8000BF026C802431954801F039FD00281CD187
+:10CE90000520294680032431486028460146496A16
+:10CEA000C1611C3051264760B60202A800F0FEF9AD
+:10CEB0000498FE2802D13868401C0ED080483146C4
+:10CEC0001C3001F06DFD002802D06C6007B0F0BD91
+:10CED0000220019A009900F04DF97948804A00211A
+:10CEE000143000F081FD002803D076A2A521FFF7C1
+:10CEF000DDFD0F2100224904686900F0BCFD002817
+:10CF000003D070A2A921FFF7D1FDEE6001202C61B2
+:10CF100068600020DAE76A498861704770B5684C3C
+:10CF20000546E068854201D90C2070BDA80701D0F4
+:10CF3000062070BD6068012801D0082070BDFFF791
+:10CF400077FF0028FAD10221A560616070BD70B53D
+:10CF5000050004D0287A800703D0102070BD0E2071
+:10CF600070BD574C6068022805D0032803D0042800
+:10CF700003D0082070BD042060606868A168860046
+:10CF800020698019884204D90020C04320610C2008
+:10CF900070BDFFF74DFF0028FAD14948A968324615
+:10CFA0001C30236901F0CCFC0028F1D121698919DA
+:10CFB0002161A2689142EBD0092070BDF8B5404CC8
+:10CFC00005466068022802D0032805D101E003204D
+:10CFD00060602069002801D00820F8BDFFF728FF15
+:10CFE0000028FAD13D4B0021403B08E0AA688E00A2
+:10CFF000965962789700521CDE516270491C6A682B
+:10D000008A42F3D8F8BD70B52D4C6068042805D16C
+:10D0100005206060A1682069884201D0082516E0DB
+:10D02000FFF706FF050012D1A12000228002A168AF
+:10D0300001F0CAF929496080403962780988002ADC
+:10D0400003D0884201D00B2070BD062060602846C6
+:10D0500070BD3EB51A4C6068062802D008252846E7
+:10D060003EBD606900F044FD002804D0FF2115A2F8
+:10D070009631FFF71BFD1248A168243001F090FCA7
+:10D08000002804D0FF210FA29A31FFF70FFD0C48B2
+:10D0900000231C3041680830A26801F051FC0500F3
+:10D0A000DDD1009061886A469180A2680292019960
+:10D0B00000F060F8D3E710B5042000F05BF810BD75
+:10D0C000142000202E2E5C6466755F6475616C5FB1
+:10D0D00062616E6B2E630000F1CD03005C250020C1
+:10D0E00021CE030010B57B480368012B02D1022931
+:10D0F00000D10160100003D077A23421FFF7D6FCE5
+:10D1000010BD38B505250024AD03401B15D1684678
+:10D1100000F0F4F80098016801290ED181880029F7
+:10D1200008D0C1680022284601F04EF9009989888C
+:10D13000814201D1012400E00024204638BD10B511
+:10D14000044664481021001D01F0B2FB002803D002
+:10D1500061A28521FFF7AAFC5E4800231022214628
+:10D16000001D01F027FB002803D05BA28B21FFF7F5
+:10D170009DFC10BD17B581B0684600F0BFF801995D
+:10D180005948544C002913D003291CD0FE220129F0
+:10D1900023D002292CD0042909D101F0BAFD00289E
+:10D1A00003D04DA2BE21FFF781FC042020601FBDEB
+:10D1B0006946098981800399C1600121FF2282604B
+:10D1C0000160216010E001F0A4FD002803D042A21C
+:10D1D000A421FFF76BFC0320E8E7002181800260B7
+:10D1E000C1600099896881603F48FFF7A8FF1FBDB3
+:10D1F00000990B6803608B888380C9688260C16076
+:10D20000F2E73EB5394800901020019001200290CD
+:10D2100001F051FA00281FD12E496846091D01F07E
+:10D2200071FA002818D1FFF721FE002814D101F06F
+:10D230005FFE0546274C3DDF002803D026A246218D
+:10D24000FFF734FC00F062FE2068022803D00328B8
+:10D2500001D00428EFD128463EBD70B511DF00286B
+:10D2600004D0FF211CA20A31FFF720FC2049002036
+:10D270000B681F4C012180340A4682401A4204D0B8
+:10D28000C506ED0E0A46AA402260401CC0B2202806
+:10D29000F2D313DF002804D0FF210FA20F31FFF7D4
+:10D2A00005FC0520800300F025F870BD1FB5094975
+:10D2B000044600231022091D684601F0BAFA0098BE
+:10D2C000206068468088A0800398E0600298A06093
+:10D2D0001FBD0000402000202E2E5C626F6F746C1A
+:10D2E0006F616465722E630068250020E5D003003D
+:10D2F00000E100E010B5FFF737FB10BD0149016008
+:10D300007047000000FC030030B585B0002822D033
+:10D310000388F64CA34220D0F54B1B78002B1CD081
+:10D32000F34B10255B1C1D705970002401259A7069
+:10D33000032269460A820094019402940394C289EC
+:10D340000A808D708C8004A902910393008869463D
+:10D35000A6DF05B030BD0E20FBE70820F9E7F0B5E9
+:10D3600089B004460227684607730D468783608AA2
+:10D3700008AB07AA0021A5DF0026002804D0616AB7
+:10D38000002917D0884715E06846008CC007C00FF9
+:10D3900010D068460682208803A9A8DF002810D193
+:10D3A000A97E0B0002F041FB093A0F11191B1D1F4A
+:10D3B00038223A00FF20FE3069460882208803A9FF
+:10D3C000A8DF09B0F0BD009601E001200CE0226A60
+:10D3D0006946204690470020F3E70097F7E70320CF
+:10D3E00002E0042000E005200090F0E7288B0328ED
+:10D3F00005D2032208212046FFF786FFE1E7287FB8
+:10D40000E97E000208436946888003D00620009028
+:10D41000226ADEE70720FAE70920E5E70322EAE7C8
+:10D4200030B585B00D46040032D0002D30D02868CC
+:10D4300000282DD00020C043AE4B20800FCB04939A
+:10D4400001AB07C3AC4869460880891C01A862DFAC
+:10D4500000281CD1A21C69460120A0DF002816D19B
+:10D46000684680782071204600F0C0F800280ED170
+:10D47000204600F0F9F8002809D128682062686881
+:10D48000002800D060629A4901200870002060E7FF
+:10D490000E205EE73EB5002820D000291ED0026A8B
+:10D4A000002A1BD00A88102A19D0112A28D0502A05
+:10D4B00017D0512A12D10446891D087802280DD1AF
+:10D4C0004888E289904209D1891C2046FFF747FF2E
+:10D4D000002803D0616A002900D088473EBD8988B2
+:10D4E00010E0CA88C3889A42F8D1082200928A7F45
+:10D4F0006B461A7120310291026A694690473EBD1F
+:10D500000021C94301803EBDF0B585B00A46050043
+:10D510002DD02888754988422BD07548007800287E
+:10D5200027D0734C1020641C2070072060700127E6
+:10D53000A7700321684601820026E11C104600F016
+:10D540004CF801466846008A091868460182009630
+:10D55000019602960396E98901808770868004A867
+:10D560000394029028886946A6DF05B0F0BD0E201E
+:10D57000FBE70820F9E7F0B585B00A46050028D09A
+:10D5800028885A49884226D059480078002822D055
+:10D59000574C1120641C2070012768460782002622
+:10D5A000611C104600F019F801466846008A091807
+:10D5B000684601820096019602960396E9890180E9
+:10D5C0008770868004A80394029028886946A6DFA5
+:10D5D000CBE70E20C9E70820C7E70870020A4A70A7
+:10D5E000020C8A70000EC8700420704730B58FB0EE
+:10D5F00005461C21684602F024F969460878042192
+:10D600000843694608700024019403940494059427
+:10D610000694287908A9887037486946801C0884D0
+:10D62000601C00070794000F0C77103048778A7F42
+:10D63000F9200240921CE7200240012002438A7731
+:10D64000142109A802F0FDF808A8099007A80A907B
+:10D6500069468C851420CC8508860D946888AB1D9E
+:10D6600009AAA2DF0FB030BD30B58FB005461C212E
+:10D67000684602F0E6F86946087808210843102257
+:10D68000104369460870002401940394049405949F
+:10D690000694287908A9887017486946401C0884B0
+:10D6A000601C00070794000F0C7710304877887FC4
+:10D6B000F9210840801CF72108401043012108434C
+:10D6C00069468877142109A802F0BBF808A80990D8
+:10D6D00007A80A9069468C851720CC8508860D948A
+:10D6E0002B4668880E3309AAA2DFBBE7FFFF0000C4
+:10D6F0004C20002044FA0300301500008307FF226D
+:10D70000DB0E9A408907090E994000280BDA0007C2
+:10D71000000F08388308FC489B001B18D869904309
+:10D720000843D86170478308F8489B001B181868A5
+:10D730009043084318607047F0B5F54F28217C6886
+:10D7400041430D19F9684A1C09D028224A43161989
+:10D75000AB68B268934204D8D21AB2606962F860CA
+:10D76000F0BD0A4602E00A46796A9B1B4E1C0BD0AC
+:10D7700028264E433719BE689E42F4D328264E43CE
+:10D780003619B768FF1AB760AB60696228214A434F
+:10D7900011194862F0BDF8B5DD4CE568681C36D05B
+:10D7A000DC48002640682169401A07023F0A1AE057
+:10D7B0002820454360682A189068B84215D86369E4
+:10D7C0003F1A8619556A002B0AD0116AD06998470A
+:10D7D000002808D0FF21D0A25531FFF767F902E0F9
+:10D7E000D169106A8847681CE2D1A178E07881424B
+:10D7F00006D1401CC0B2E070022801D10020E070C8
+:10D80000C3490006800D18310E5000F0D3F9F8BD61
+:10D81000F8B50446BE48C1680091467856E0BC4859
+:10D82000F10082688D184BE0601C07D0B84A2821AF
+:10D8300052686143204689184C6A20E028781821F4
+:10D8400041436A68401CC0B252182870A9788842C7
+:10D8500001D100202870AE4B506828215B684143FD
+:10D86000C9181368012B2DD10B7E002B2AD1936888
+:10D87000CB60D3680B6113694B6152690A62A44A99
+:10D88000CF681369BC46FA1A1202AF4F120ABA42A5
+:10D8900002D20B69D21809E062469A1A12020B6989
+:10D8A000120A934201D99A1A00E000228A600022EB
+:10D8B000CA600A6101220A76921E4A62FFF73CFFA3
+:10D8C000601CB1D1287869788842ADD13046761E87
+:10D8D000F6B20028A3D18E48C1680098814201D0D9
+:10D8E0000120F8BD0020F8BD98490020086048607C
+:10D8F0008860C86095494039086048604BE7F0B5DA
+:10D90000002087B0C043029081480669C568684618
+:10D9100000F056F9074600F070F90446002F05D0D4
+:10D9200002AA3146009800F0B0F901240298FFF7EE
+:10D930006FFF002801D1002C02D0284600F0CEF95C
+:10D9400007B0F0BDFFB59807002481B00F4615461B
+:10D950001E4600280BD1002E09D000F01AF96C49A0
+:10D960000A9848610F70324600204E6008E0072098
+:10D9700005B0F0BD28234343D4509B181C76401CAF
+:10D98000B842F7DB28204743BB19032048700F46F5
+:10D9900018468B6019461830002218232E465E4325
+:10D9A000D3005B181C705C709D7058603018521C5E
+:10D9B000032AF5DB0020C043F860BC70FC70012432
+:10D9C00063482405046003211420FFF797FE614893
+:10D9D0000460504C0198A06003211120FFF78EFED7
+:10D9E000606838610020C3E770B5494C6568002D58
+:10D9F00006D0002A06D0002804D00023247809E0AD
+:10DA0000082070BD072070BD28265E43AE59002E49
+:10DA100004D05B1CA342F7DB042070BD2824012640
+:10DA20005C432E516419E26161600360002070BDA7
+:10DA300035494868C005C00D17D0103807D5020712
+:10DA4000120F083A920892005118C96904E081083F
+:10DA50002E4A8900891809688007C00EC1408804D1
+:10DA6000000E012803D0032803D0022070470020B5
+:10DA7000704701207047FEB50446254817464268A6
+:10DA80000D46002A0CD001788C4201D2052D01D21E
+:10DA90000720FEBD2146282359435358012B01D0AE
+:10DAA0000820FEBD8818406801281DD00026FFF719
+:10DAB000BFFFC0001649019089684018694600F010
+:10DAC00050F9002812D001214460016011494968D1
+:10DAD0000830E2C00E4901988968411800984870E2
+:10DAE00000F068F80020FEBD2E46E0E70420FEBDF1
+:10DAF000F8B5074D04466868002832D029788C4272
+:10DB00002AD30720F8BD000000ED00E000E400E0AB
+:10DB100054200020001501402E2E5C2E2E5C2E2E4F
+:10DB20005C2E2E5C2E2E5C536F757263655C61708B
+:10DB3000705F636F6D6D6F6E5C6170705F74696D47
+:10DB400065722E6300000000FFFF7F00401101405E
+:10DB500080E200E000E100E0282161434058012814
+:10DB600001D00820CEE7FFF763FFC600A86869462A
+:10DB7000301800F0F6F8002809D0022112C0A86879
+:10DB800031180098487000F015F80020BAE704201A
+:10DB9000B8E710B50121924A48041060914A40103C
+:10DBA0009060904A403A90608F4841602F20FEF785
+:10DBB000E1FE10BD01208A490005803108607047F0
+:10DBC00010B58A4900238A78CC78A24212D0521C20
+:10DBD000D2B28A70022A00D18B708A78834B92006D
+:10DBE00018339A580260086910180002000A086188
+:10DBF000012010BD0360002010BDF8B57B48C1684E
+:10DC00000091457833E07948E90080680E1834784F
+:10DC10002AE0182060437168641C0818B178E4B2E7
+:10DC2000A14200D100240168022902D003291BD19E
+:10DC300013E06E4A40682821526841438F18397EAC
+:10DC4000002911D000F09FF8002038760CE028273A
+:10DC50007843C0180276406A03E0644900224B68AA
+:10DC6000C868471CF3D1C8607078A042D1D128465B
+:10DC70006D1EEDB20028C6D15C48C1680098814293
+:10DC800001D001203EE700203CE7F7B5574C0025C6
+:10DC90006768E3681EE028215943C9198E688642E7
+:10DCA00002D9301A886017E0801B751900268E6033
+:10DCB0000E764E699C464B6AB646002E0AD0019EEF
+:10DCC00076193602360ACE6076460E6116684E62C6
+:10DCD00061461160591CDED1E360FEBDF8B54349D1
+:10DCE000CA68531C3AD028235A434B68D218966806
+:10DCF0003F4A54680F69401CE11B0D022D0AED1CC0
+:10DD00000121002810D1374A08045060354A403AB2
+:10DD10005060384A40001060314A803A1060324802
+:10DD200001602F20FEF726FEB54200D23546E819E5
+:10DD300000022F49000A403108602D494968001B44
+:10DD4000091B0902090A0002C91C000A814204D900
+:10DD500001202349400480310860D3E6FFF719FF12
+:10DD6000D0E642788378521C934200D10022037897
+:10DD7000934201D1002070470A6041684078182220
+:10DD800050430818704770B5184DEA686B68144620
+:10DD9000114606E0814207D00A4628267143C91879
+:10DDA000496A4E1CF6D170BD002EFCD08A4204D1C7
+:10DDB00028204443E018406AE86028204143C818FE
+:10DDC000282481686243406AD2185062421CEAD01B
+:10DDD00028225043C01882685118816070BD00002D
+:10DDE00080E100E040130140001001405420002079
+:10DDF0000015014080E200E030B5CB0008339DB251
+:10DE000093070024002B01D0072030BD564B9A60A9
+:10DE10005219DA605C701C7058809980002030BD07
+:10DE2000F7B5514C82B060880F4681426CD8002013
+:10DE3000694608704E494D4D4868C005C00D16D062
+:10DE4000103807D50207120F083A920892005118AD
+:10DE5000C96904E08108474A890089180968800770
+:10DE6000C00EC1408804060E012E01D10AE004262E
+:10DE700068462BDF02280BD0002803D03EA2592190
+:10DE8000FEF714FE6078A188884203D2401C02E0AD
+:10DE900072B6F7E700202278C0B2904207D06578CA
+:10DEA0006078884201DA401C00E000206070012E9A
+:10DEB0000BD062B6684600782CDF022805D0002817
+:10DEC00003D02DA26121FEF7F1FD2848854219D02B
+:10DED000A068EE0004998151029900290CD0002F0E
+:10DEE0000AD060883A464543E068281801F04AFCA9
+:10DEF000A0683018878002E000213018818000205F
+:10DF000005B0F0BD0420FBE70920F9E70EB504E0F9
+:10DF100068468188029A0098904702AA01A968463B
+:10DF200000F003F80028F3D00EBD70B50E4B0524A9
+:10DF30005D781E78B54215D01D781C789E88B44255
+:10DF400001DA641C00E000241C705C88DE686C430D
+:10DF5000A41904609B68E800C418A4880C801858B1
+:10DF600000241060204670BD74200020FFFF0000D8
+:10DF700000ED00E000E400E02E2E5C2E2E5C2E2E44
+:10DF80005C2E2E5C2E2E5C536F757263655C617027
+:10DF9000705F636F6D6D6F6E5C6170705F736368EF
+:10DFA0006564756C65722E6300000000F8B59048DA
+:10DFB000006900908F490020C863032504462D04A2
+:10DFC00037E01421426861438B1801228068A24027
+:10DFD00002422CD0D868C2430098424018680240E0
+:10DFE000002001268640114631420FD0DF683946B5
+:10DFF000314223D02946B743DF607F4E8700BE19E8
+:10E000003768AF43376037680F433760401C2028BC
+:10E01000E7D300989968164686433140009E5868B9
+:10E020001640304002460A4301D01A699047641CEA
+:10E03000E4B2724841788C42C3D3F8BD012149044F
+:10E040003743D9E7F0B56D4A002153681422504395
+:10E050000124694D03273F041E5822468A40164278
+:10E0600006D08A0052191668BE43166016681660FC
+:10E07000491C2029F0D3F0BD10B5002903D08A0730
+:10E080000024002A01D0072010BD5C4A0B465160D5
+:10E0900010701421547041431846946001F0D1FB74
+:10E0A00000205749C0438860564840210160564AC5
+:10E0B0001068FF231B0498430B0418431060534857
+:10E0C0000160002010BDF8B54C4F84467D68002DDE
+:10E0D00007D0002B07D078783C78A04205D30420E5
+:10E0E000F8BD0820F8BD0720F8BD0E4614241643DD
+:10E0F00044432E5164192361A26061606146087037
+:10E10000411C7970FFF79EFF0020F8BDF0B53B4A37
+:10E110005168002904D05378984203D30720F0BDFA
+:10E120000820F0BD334B0025DD63314B1C69976837
+:10E13000002F02D1324EDB057360012686403E433C
+:10E140009660142250434218D560002201230D58D6
+:10E1500093401D4216D025461D4202D003252D04B2
+:10E1600005E001256D044618F7681F43F760224B50
+:10E170009600F3181E6803273F04BE431E601E6806
+:10E180002E431E60521C202AE0D30020F0BD70B543
+:10E190001A4C05466068002804D06078854203D395
+:10E1A000072070BD082070BD2846FFF74BFF0121F6
+:10E1B000A068A9408843A06003D101201049C0078E
+:10E1C0008860002070BD0D4B5A68002A04D05B782F
+:10E1D000984203D307207047082070471423584300
+:10E1E0008018034A12690068024000200A607047E4
+:10E1F00000050050406100400007005084200020CE
+:10E200000063004080E200E004E400E000E100E0A0
+:10E21000F8B55D4C054669466078FFF7D4FF0028E5
+:10E220002AD10099E0680B460140A0682E46984329
+:10E230000843064020D000251BE00C20616868439D
+:10E240004118087801228240324210D08A68002AA0
+:10E250000DD06369002B09D001461046984700286D
+:10E2600005D04AA22921FEF721FC00E090476D1C51
+:10E27000EDB220788542E0D3F8BD70B5424D04463A
+:10E280000E46A869FFF734FC002805D13443224626
+:10E290002969A869FFF7EFFB70BDF8B50C46052AA0
+:10E2A00001D20720F8BD384D002168602C70E9606C
+:10E2B0006B612A61A9600A4617E00C2363431B18AF
+:10E2C0001D785E683D4FB600AD00ED192E605E789A
+:10E2D000002E01D0012500E000251F78BD40294314
+:10E2E000002E17D00023BB401A432346641EE4B21D
+:10E2F000002BE2D12448324B8260C160401CFFF702
+:10E30000E2FE0028CED120482E4A00211830FFF727
+:10E310006BFBF8BD0123E6E710B51B4841680029F7
+:10E3200003D04078FFF7F2FE10BD082010BD10B5F5
+:10E33000154C6068002808D06078FFF728FF002897
+:10E3400002D1A069FFF7D4FB10BD082010BDF8B5BD
+:10E350000D4C064660680D46002811D0694660786D
+:10E36000FFF731FF00280AD101220098B240024293
+:10E3700008D0E068104000D0012028700020F8BDCF
+:10E380000820F8BDA068F5E7902000202E2E5C2E16
+:10E390002E5C2E2E5C2E2E5C2E2E5C536F757263BF
+:10E3A000655C6170705F636F6D6D6F6E5C617070E6
+:10E3B0005F627574746F6E2E63000000000700507A
+:10E3C0007BE2030011E2030010B50446002A02D0EC
+:10E3D0001088002210E00A48FBE7030A000203430A
+:10E3E000A05C584003061B0F43401803584083B2FB
+:10E3F0001806C00C5840521C8A42EED310BD0000D3
+:10E40000FFFF000010B508461146FEF75AFB10BD8D
+:10E41000F8B5394C2078002837D02069002807D07B
+:10E420000025E068002805D00026002D04D013E068
+:10E430000125F6E70126F8E768464EDF052806D0F5
+:10E44000002806D02DA26921FEF730FB04E001254B
+:10E4500002E0216900988847002E12D16088694641
+:10E460000880A06860DF052806D0002806D023A217
+:10E470008021FEF71BFB04E0012602E0E168A068B2
+:10E480008847002DD8D0002ECFD0F8BD70B5002918
+:10E4900001D08C0701D0072070BD174C0125A16069
+:10E4A00062802449636010DF0028F5D125701620B2
+:10E4B00023DF70BD002803D00F49C86000207047DB
+:10E4C0000E207047002803D00B49086100207047D8
+:10E4D0000E20704710B508484068002808D08047D3
+:10E4E000002804D0FF2105A23331FEF7DFFA10BD6A
+:10E4F000FFF78EFF10BD0000AC2000202E2E5C2EFA
+:10E500002E5C2E2E5C2E2E5C2E2E5C536F7572634D
+:10E51000655C73645F636F6D6D6F6E5C736F667463
+:10E520006465766963655F68616E646C65722E63AD
+:10E530000000000005E4030018225043F94A0021BE
+:10E540008018017181604161012281610261C160B5
+:10E55000704770B5F34E18223078F34C504382194F
+:10E56000121D13780F211069E568042B02D0022BCD
+:10E570000DD024E001210907096989B201F074F97D
+:10E58000401950DF01001AD1E068401C14E05169C5
+:10E590009368526840194919521B01251818AD0299
+:10E5A000AA4202D2920851DF02E0FF22013251DF7B
+:10E5B000010004D1E0684019E0600120B070084615
+:10E5C00070BDF8B5D74C0546A77826460420767866
+:10E5D000002F01D1002E17D00A2E28D020788019C4
+:10E5E000C0B20A2801D30A38C0B2182670430019F5
+:10E5F0000571826106C98360426101610699C1604B
+:10E600006078401C607011E0002020702571A261CC
+:10E6100003C9A360616120610698E0600120607019
+:10E62000FFF797FF002801D0112800D10020F8BD86
+:10E6300038B50246BB4818230178594308180369C6
+:10E640000179022B0CD014246343B64CF434E45803
+:10E65000042909D08368009383691030A04738BD2E
+:10E66000B14B10331C68F3E70023F4E710B5AD4954
+:10E6700002468B780020012B1CD100238B70022ACC
+:10E6800003D0032A16D10D2012E00A7818235A432A
+:10E690005118091D0A78042A04D1A34A4968D2688E
+:10E6A000914201D8FFF7C4FF00F0A8F9002801D07B
+:10E6B000FFF7BEFF10BD70B500249B4D9948EC607C
+:10E6C00004704470847026463046FFF735FF761C90
+:10E6D0000A2EF9D3012109076C6048690969401EB7
+:10E6E00089B24843EC60A8608E48F43004608460CE
+:10E6F0000461C4608C48103004608480012028705C
+:10E70000002070BDF0B5884D2A78002A1DD0002861
+:10E710001DD000291BD00268002A18D0012424072C
+:10E72000426823699BB29A420DD8102A0BD38368A2
+:10E73000002B08D05343AA6866699B182769BFB2AB
+:10E740007E43B34205D90720F0BD0820F0BD0E205E
+:10E75000F0BD6B68012B1CD00B604A601946142574
+:10E760006943704DF4354E19726007686F50416807
+:10E77000B1608168F16041688068002541436D1C8B
+:10E780002069ADB280B2884205D2206980B2091AF0
+:10E7900002E00420F0BD0021206980B282182069C7
+:10E7A00080B28842EBD960485B1C8260356143606F
+:10E7B0000020F0BDF8B505465B481F4600781446BA
+:10E7C0000E46002807D0002E07D0002D05D028685F
+:10E7D000002818D103E00820F8BD0E20F8BD5148EC
+:10E7E000F430016800290ED0C268816840684A434D
+:10E7F00010186A68904206D9002C04D0A14202D3B6
+:10E80000E019884201D90720F8BD304600F0F0F841
+:10E8100000280CD0F01900F0EBF8002807D02346B0
+:10E820003246294602200097FFF7CBFEF8BD1020A4
+:10E83000F8BDF8B507463C481D46007816460C461C
+:10E84000002807D0002C07D0002F05D02068002812
+:10E8500018D103E00820F8BD0E20F8BD3148F4308F
+:10E86000016800290ED0C268816840684A431018C8
+:10E870006268904206D9002E04D0B14202D37019CA
+:10E88000884201D90720F8BD384600F0B1F80028C9
+:10E890000CD0781900F0ACF8002807D06068324638
+:10E8A0004119384600F06EFF0020F8BD1020F8BD79
+:10E8B00038B51D490978002905D0002805D0016820
+:10E8C000002912D103E0082038BD0E2038BD154ABA
+:10E8D0000021F4321368002B07D09468D368634397
+:10E8E00054681B194468A34201D8072038BD136936
+:10E8F0000091014600220420FFF763FE38BD0A4A5A
+:10E900001278002A12D0002812D0002910D00268F4
+:10E91000002A0DD0044A10321368002B0AD00420BC
+:10E920007047000078250020C02000200820F7E76D
+:10E930000E20F5E702230B60006810600020EFE76F
+:10E94000F8B505463F481E46007817460C46002895
+:10E9500007D0002C07D0002D05D0286802281BD135
+:10E9600003E00820F8BD0E20F8BD364810300068DE
+:10E97000002811D0084600F03BF800280ED0A0195E
+:10E9800000F036F8002809D03B46224629460220EE
+:10E990000096FFF716FEF8BD0720F8BD1020F8BD61
+:10E9A00038B5044627480A460078002805D0002CD0
+:10E9B00005D02068022819D103E0082038BD0E20B8
+:10E9C00038BD20481030006800280FD00120000713
+:10E9D000006981B2501E00F047FF0021431C0A4627
+:10E9E000009121460420FFF7ECFD38BD072038BD1B
+:10E9F000800701D0002093E7012091E770B5124D08
+:10EA0000182128780F4C414349198968E2689142DE
+:10EA100009D8FFF791FD0020E0606878401E68701B
+:10EA20002878401C287068780024002807D0FFF759
+:10EA300090FD040003D0112C01D0FFF7F9FD204612
+:10EA400070BD0000C0200020782500204B48002128
+:10EA500001704C484A4A02608160C160016108222D
+:10EA60004161426081610846704710B500291DD0A0
+:10EA700000220A60434A5368002B1BD0202817D875
+:10EA80005B1E5360D0682423401CD060106914685A
+:10EA90004343E3180B60012383409169401C1943F1
+:10EAA0004007400F91611061002010BD0E2010BD85
+:10EAB0000C2010BD042010BDF0B5324A0646916806
+:10EAC00000292BD057691020791A4907490F14687B
+:10EAD0000B4624254D436519B54206D1012495699D
+:10EAE0008C4065400020956104E0491C4907490FAE
+:10EAF0008F42EED1491C4E07760F956901210C46D5
+:10EB00009C402B4623420AD19368002B07D05B1E02
+:10EB1000936053685B1C53603346F0E70420F0BDFC
+:10EB2000184A2423117C1268491E4907490F59438A
+:10EB3000203150500020704770B500281AD00029AD
+:10EB400018D0104AD368002B16D05B1ED360936890
+:10EB500024265B1C9360536915681C467343EE18AA
+:10EB600020330660E858641C08606007400F50615D
+:10EB7000002070BD0E2070BD042070BDD820002084
+:10EB800080260020A027002010B500280BD0FC48CC
+:10EB9000FC49808888420FD0132176DF00280BD0F3
+:10EBA000F9A2702106E00846FFF786FF002803D08F
+:10EBB000F5A27621FDF77AFF10BD08280CD004DC01
+:10EBC000002807D006280FD108E00B280AD00C280F
+:10EBD0000AD105E0012070470220704703207047EA
+:10EBE00004207047042901D0062070470520704793
+:10EBF00010B50A46044603211046FFF7DEFF024621
+:10EC000003212046FEF780FB002803D0DEA2B821B6
+:10EC1000FDF74CFF10BDF0B5054608790E4685B0EE
+:10EC200081070AD0032211462846FEF76DFB002813
+:10EC300021D0FF21D4A2253146E0D14900901031E6
+:10EC4000FFF713FF010013D1CD4CB168009A206982
+:10EC500000F098FD0098FFF763FF002801D00146FF
+:10EC600006E0C74869461030FFF766FF010004D090
+:10EC70002846FFF7BDFF05B0F0BD00988008029060
+:10EC8000032001902069039001A8FEF760F90700B6
+:10EC90000CD0092F1BD02069FFF70EFF002803D0EE
+:10ECA00001462846FFF7A4FF3946E1E73079E188BD
+:10ECB00001224018E08003212846FEF725FB0028AA
+:10ECC000D9D0FF21B0A25531FDF7F0FED3E730795E
+:10ECD000E188401881B2E18060780028CBD060895B
+:10ECE000401E0004000C6081C5D12846FEF743FC9D
+:10ECF000002804D0FF21A4A26631FDF7D7FE2089A9
+:10ED00006081B8E710B5FF219FA2A131FDF7CEFECB
+:10ED100010BD10B59A4C9B49A088884208D0132199
+:10ED200076DF002811D098A29D49FDF7BFFE0CE0C8
+:10ED3000A078002809D074DF002804D0984992A256
+:10ED4000FF39FDF7B3FE0020A07000F05CFA002848
+:10ED500004D093498CA20931FDF7A8FE002010BD14
+:10ED600070B50D6804460120854A2B0000F05DFE59
+:10ED70000A333032061624464B354F23FEF743F94B
+:10ED80000421FFF71AFF024604212046FEF7BCFAD1
+:10ED9000002810D0FF217CA2D33140E0FFF7B9FF5B
+:10EDA000002804D0FF2178A2D931FDF77FFEFEF7BD
+:10EDB00050F9002809D170BDFFF7ABFF002804D03F
+:10EDC000FF2171A2E531FDF771FEFEF774F970BD08
+:10EDD000022000E00320D06070BDD2682046012AE6
+:10EDE00006D0022A07D0032AF6D1FFF714FF70BD20
+:10EDF00000F0E8F870BD00F00EF970BD5070888822
+:10EE00001081508170BD00205070108170BDD1887C
+:10EE10002046FEF779FB0028F8D05BA26149FDF798
+:10EE200045FE70BD10B5564CA07800280AD15E484A
+:10EE300073DF002804D05B4953A21331FDF736FE7F
+:10EE40000120A07010BD10B54D4C0188A388132976
+:10EE500025D007DC102917D0112914D120780028DB
+:10EE600017D018E0522925D055290CD180790028D7
+:10EE700009D11321184676DF002804D0494942A25F
+:10EE80005C31FDF713FE10BD8088A0800020A070CB
+:10EE900010BDFFF7C7FF0020C043A08010BD384A57
+:10EEA0001846143200217FDF0028F7D03D4936A2F2
+:10EEB0005431E6E7002211461846A9DF0028EDD0BC
+:10EEC0004D2131A2C900DCE710B5044600F0CCF9B1
+:10EED000354821461430FEF7DDFA2046FFF7B3FF30
+:10EEE00010BD10B5B72128A28900FDF7DFFD10BDC8
+:10EEF00010B5234888B00024C4602C48FFF7DAFA24
+:10EF000000283BD12A48FEF706F8FFF79FFD0028AE
+:10EF100034D100F0B1F827480090274801902248EA
+:10EF200069461430FEF77CFA002804D01C4916A26A
+:10EF30003B39FDF7BBFD00F0C3F81C21684600F02B
+:10EF400080FC1E4801900120800302900094032160
+:10EF500068460173C4810474194806900594684694
+:10EF600000F02DF9002804D0FF2107A2B831FDF7E9
+:10EF70009DFD00F0DAF8FFF755FF002008B010BD46
+:10EF8000E0200020FFFF00002E2E5C6466755F7499
+:10EF900072616E73706F72745F626C652E630000D5
+:10EFA0002A03000006020000BC270020C9EE03006F
+:10EFB00089EB030061ED0300E3EE0300CD0C0000DC
+:10EFC00005ED030070B505460879042809D0032231
+:10EFD00001212846FEF798F900281BD05B4ACC2176
+:10EFE00016E08C68204600F02EFCE1780002000A52
+:10EFF00009060843FDF792FF0121FFF7DEFD0246F7
+:10F0000001212846FEF780F9002803D04F4ADD2170
+:10F01000FDF74CFD70BDFEB50446012000908868E8
+:10F0200002900879002283070FD08007800F042206
+:10F03000121A0020034606E00E79029D3618B6002B
+:10F04000401CAB51C0B29042F6D3087980188008BA
+:10F0500001906846FDF7B2FF0221FFF7AEFD0246C0
+:10F0600002212046FEF750F9002804D0FF21374A3C
+:10F070001031FDF71BFDFEBD0EB51120694608726B
+:10F08000072233A102A87CDF002803D02F4A32498F
+:10F09000FDF70CFD002000900922694601900A80CE
+:10F0A0000C224A808880FF209130C88068467ADF31
+:10F0B000002804D05521254AC900FDF7F7FC0EBDF4
+:10F0C00010B592B00621684601712448017968465E
+:10F0D0008170234901803C2102A800F0B2FB02208C
+:10F0E00002900024684644730121018201A8059022
+:10F0F000684681830890214602A800F025FA00287E
+:10F1000004D01549114A2831FDF7D0FC13481421C9
+:10F11000143800F096FB11481438047044600472EF
+:10F1200028210182448212B029E70E491E2008805E
+:10F13000887801221043E12210400C30DF22104079
+:10F1400088700720C87010200871704788EF03008E
+:10F1500044667554617267009E020000D02700204B
+:10F1600030150000F420002038B56749674A488808
+:10F1700090420FD04A78664C521CD2B24A70237B20
+:10F18000934208D3083175DF002803D0A169002914
+:10F1900000D0884738BD00254D70217C002907D05C
+:10F1A0003B2176DF002803D0A169002900D08847E1
+:10F1B00061690029EED068460095884738BD70B572
+:10F1C000054601461C225248FDF7E4FB4E4C002642
+:10F1D00026702968002907D00822A01800F0D2FA6A
+:10F1E000204608307ADF02E0474808307BDF0028FD
+:10F1F00008D1401E608044486670464A0021001DC8
+:10F20000FEF7F2FB70BD10B53F484068FEF770FC9A
+:10F2100010BDF8B53C48103000F069F800263A4DB2
+:10F220003B4C002806D06169002919D001200090CC
+:10F23000684614E02878002804D0616900290FD0BE
+:10F240000096F5E7687800280CD0A168002268686D
+:10F25000FEF711FC002803D0A169002900D08847DF
+:10F260002E70F8BD6168F1E7F8B5294C02880027D7
+:10F27000254DE689102A18D029464968112A21D03F
+:10F28000122A2DD0502A0FD1801D0288B2420BD1F4
+:10F29000028B022A08D1C27E837E10021843C00767
+:10F2A000C00F13D0FFF7B5FFF8BD81886980014614
+:10F2B000154808220E31103000F064FA6F70002EED
+:10F2C000F0D0F8BD0020C04368806F700846FEF79C
+:10F2D0000FFC0028F5D0A1690029F2D08847F8BDBD
+:10F2E000811D09480822103000F04CFADAE7418805
+:10F2F000054808300288914204D34088814201D8F1
+:10F300000120704700207047FC200020FFFF000014
+:10F31000F827002069F10300FFB583B007460020FD
+:10F320000C9C8646267805463AE07868A900411884
+:10F330000A88684682804988C1800022694601A8FF
+:10F3400064DF002810D1684601780598814226D1F3
+:10F350007046002801D0002200E00222207889189F
+:10F3600041181F2902D90C2007B0F0BD71460029B1
+:10F3700008D1401CC0B2411C069B049A21701A544B
+:10F3800001208646217806980A18694601A864DF9C
+:10F390000028E9D1694620780978401820706D1C52
+:10F3A0003888A842C1DC7046002804D0207806992D
+:10F3B000801B401E88550020D6E7F8B51546069CF0
+:10F3C0001E46074602220094FFF7A6FF002806D13A
+:10F3D00033461022294638460094FFF79DFFF8BDBA
+:10F3E000F7B582B00026054616700068144600285E
+:10F3F00005D02846039900F0DFF806002DD1687982
+:10F4000000281BD02078039F001D1F2824D86846A1
+:10F4100079DF002821D121780322481C20707A54FA
+:10F4200021781922481C20707A542078C119684626
+:10F43000008800F0BCF82178401820702989002944
+:10F4400023D001208446EA680398002A07D0227856
+:10F4500053189B1C1F2B04D90C2005B0F0BD0720AE
+:10F46000FBE71346521C491C2270C15422786746A0
+:10F47000511C2170875423782A891818E96800F0F4
+:10F4800081F92078297A401820702869002815D041
+:10F490000021415622788C46D01C03991F28DBD8C6
+:10F4A000501C022320708B5422780A23501C207099
+:10F4B0008B5420786246431C23700A54A88A002883
+:10F4C00009D028460094062202211430039BFFF73E
+:10F4D00074FF0600C1D1A88B002809D028460094EB
+:10F4E000072203211C30039BFFF767FF0600B4D1FE
+:10F4F000A88C002809D02846009415221421243015
+:10F50000039BFFF75AFF0600A7D1E86A002805D041
+:10F510002246039900F085F806009ED1286B00284A
+:10F5200005D02246039900F0BBF8060095D138209B
+:10F53000405D002806D022462846039900F0E2F8F4
+:10F5400006008AD1304688E770B50D4692B000219A
+:10F550006A46117007241171002812D00189002910
+:10F5600005D0C168002902D00978490702D4204695
+:10F5700012B070BD02A9FFF733FF0028F8D102AE28
+:10F5800000E00026002D0BD028890028EFD101AA29
+:10F590000AA92846FFF724FF0028E9D10AAA00E0BB
+:10F5A0000022684603790178304672DFE0E7087090
+:10F5B000000A487002207047F8B514780746A01C6E
+:10F5C00015460E461F2803D83879801C1F2801D9FC
+:10F5D0000C20F8BD1D20001B80B2694686460880BD
+:10F5E0003019801C7DDF0028F3D13868022805D14E
+:10F5F00068460088704501D8092107E0387908215C
+:10F60000002801D0704501D968460088421C325557
+:10F61000641CE2B2B1542978801C081828700020BC
+:10F62000F8BDF8B50D4611780646881D14461F280A
+:10F6300001D90C20F8BD33880720062BFAD31927EF
+:10F64000FF01BB4202D94E4A9342F3D17288062A87
+:10F65000F0D3BA4202D94A4FBA42EBD1484FBB422B
+:10F6600003D0BA4201D09342E4D8481C052220704E
+:10F670006A5420781222411C21702A5420784119A2
+:10F680003088FFF794FF21784018C0B220704119EC
+:10F690007088FFF78CFF2178401820700020F8BD9B
+:10F6A00070B5054600790E46801C1446C0B211782C
+:10F6B000821C8A181F2A01D90C2070BD0A46491CD9
+:10F6C000401C2170B0542078FF22411C217032541C
+:10F6D000207881192888FFF76AFF21784018C0B286
+:10F6E0002070AA88002A09D0A968002908D08019AA
+:10F6F00000F048F82078297940182070002070BD6B
+:10F70000072070BDF7B582B002981446406B0F46D3
+:10F71000002832D0029800252030009028E002987E
+:10F72000416B0C2068430E18217830794A1CC01CAC
+:10F730002270785420781622411C21703A54207887
+:10F74000C1193088FFF733FF21784018C0B220700C
+:10F75000B288002A09D0B16800290ED0C01900F083
+:10F7600011F820783179401820706D1C0098EDB2A6
+:10F77000007EA842D3D800206FE607206DE6000087
+:10F78000FFFF0000F8B5042A2CD3830712D00B78B2
+:10F79000491C0370401C521E83070BD00B78491C78
+:10F7A0000370401C521E830704D00B78491C037061
+:10F7B000401C521E8B079B0F05D0C91ADF00202367
+:10F7C000DE1B08C90AE0FDF7E5F8F8BD1D4608C9CB
+:10F7D000FD401C46B4402C4310C0121F042AF5D231
+:10F7E000F308C91A521EF0D40B78491C0370401C50
+:10F7F000521EEAD40B78491C0370401C521EE4D4FC
+:10F8000009780170F8BD01E004C0091F0429FBD28A
+:10F810008B0701D50280801CC90700D00270704799
+:10F8200000290BD0C30702D00270401C491E0229D8
+:10F8300004D3830702D50280801C891EE3E70022DF
+:10F84000EEE70022DFE70378C27819464378120614
+:10F850001B0219438378C0781B0419431143090222
+:10F86000090A000608437047002203098B422CD383
+:10F87000030A8B4211D300239C464EE003460B4300
+:10F880003CD4002243088B4231D303098B421CD362
+:10F89000030A8B4201D394463FE0C3098B4201D354
+:10F8A000CB01C01A524183098B4201D38B01C01A8C
+:10F8B000524143098B4201D34B01C01A5241030903
+:10F8C0008B4201D30B01C01A5241C3088B4201D3B2
+:10F8D000CB00C01A524183088B4201D38B00C01A5F
+:10F8E000524143088B4201D34B00C01A5241411A86
+:10F8F00000D201465241104670475DE0CA0F00D069
+:10F900004942031000D34042534000229C46030961
+:10F910008B422DD3030A8B4212D3FC22890112BAE7
+:10F92000030A8B420CD3890192118B4208D38901BF
+:10F9300092118B4204D389013AD0921100E08909D7
+:10F94000C3098B4201D3CB01C01A524183098B42B8
+:10F9500001D38B01C01A524143098B4201D34B01A1
+:10F96000C01A524103098B4201D30B01C01A524104
+:10F97000C3088B4201D3CB00C01A524183088B428B
+:10F9800001D38B00C01A5241D9D243088B4201D314
+:10F990004B00C01A5241411A00D2014663465241FF
+:10F9A0005B10104601D34042002B00D549427047FE
+:10F9B00063465B1000D3404201B50020C046C046FC
+:10F9C00002BD704770477047754600F023F8AE4699
+:10F9D000050069465346C008C000854618B020B5EA
+:10F9E000FDF750F860BC00274908B6460026C0C5A0
+:10F9F000C0C5C0C5C0C5C0C5C0C5C0C5C0C5403DE7
+:10FA000049008D4670470446C046C0462046FCF774
+:10FA1000A4FF000000487047142800200149182066
+:10FA2000ABBEFEE726000200704730B47446641E89
+:10FA30002578641CAB4200D21D46635D5B00E31871
+:10FA400030BC184723D1BCEA5F782315DEEF1212D1
+:10FA50000000000074FA03000020002014010000E0
+:10FA600004C9030088FB0300142100206413000074
+:10FA700020C903000024F40000000000080000007A
+:10FA80000300000000000000000000000000000073
+:10FA90000000000000000000000000000000000066
+:10FAA0000000000000000000000000000000000056
+:10FAB0000000000000000000000000000000000046
+:10FAC0000000000000000000000000000000000036
+:10FAD0000000000000000000000000000000000026
+:10FAE0000000000000000000000000000000000016
+:10FAF0000000000000000000000000000000000006
+:10FB000000000000000000000000000000000000F5
+:10FB100000000000000000000000000000000000E5
+:10FB200000000000000000000000000000000000D5
+:10FB300000000000000000000000000000000000C5
+:10FB400000000000000000000000000000000000B5
+:10FB50000000000000000000FFFF000000000000A7
+:10FB60000000000000000000000000000000000095
+:10FB70000000000000000000000000000000000085
+:08FB800000000000000000007D
+:040000050003C8C16B
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar_wanted.bin b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar_wanted.bin
new file mode 100644
index 0000000..b040cdf
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar_wanted.bin
Binary files differ
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo.hex b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo.hex
new file mode 100644
index 0000000..f5acd72
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo.hex
@@ -0,0 +1,4835 @@
+:020000040000FA
+:10000000481C0020992B0100F1160100CF2A0100A5
+:1000100000000000000000000000000000000000E0
+:100020000000000000000000000000000D2C010096
+:100030000000000000000000F1160100F1160100B0
+:10004000752C01007B2C0100F1160100F116010056
+:10005000F1160100F1160100F1160100F116010080
+:10006000812C0100F1160100F1160100872C01001E
+:10007000F11601008D2C0100B9020000FF81000083
+:10008000F1160100F1160100F1160100F116010050
+:10009000F1160100F1160100F1160100F116010040
+:1000A000932C0100992C0100F1160100F1160100BA
+:1000B000F1160100F1160100F1160100F116010020
+:1000C00000F002F812F04FFD0CA030C808382418D8
+:1000D0002D18A246671EAB4654465D46AC4201D180
+:1000E00012F041FD7E460F3E0FCCB646012633424C
+:1000F00000D0FB1AA246AB46334318475C2C0100E4
+:100100008C2C0100103A02D378C878C1FAD8520773
+:1001100001D330C830C101D504680C6070470000BD
+:100120000023002400250026103A01D378C1FBD813
+:10013000520700D330C100D50B6070471FB5C046D1
+:10014000C04612F093FC04B00FB41FBD826902498F
+:100150008161024810447047610100000100000005
+:1001600001B41EB400B50FF067FE01B401988646D5
+:1001700001BC01B01EBD0000F0B4404649465246E5
+:100180005B460FB402A0013001B50648004700BF2E
+:1001900001BC86460FBC8046894692469B46F0BC11
+:1001A00070470000C1000000401E00BF00BF00BF3C
+:1001B00000BF00BF00BF00BF00BF00BF00BF00BF47
+:1001C00000BFF1D17047000070B505460C461646D9
+:1001D00002E00FCC0FC5103E102EFAD2082E02D32B
+:1001E00003CC03C5083E042E07D301CC01C5361F3E
+:1001F00003E021782970641C6D1C761EF9D270BD55
+:100200008307FF22DB0E9A408907090E99400028D8
+:100210000BDA0007000F0838830828489B001B18DA
+:10022000D86990430843D8617047830824489B00ED
+:100230001B181868904308431860704710B50446AF
+:1002400000210120FFF7DCFF00211820FFF7D8FF75
+:1002500000210B20FFF7D4FF02211920FFF7D0FF68
+:1002600002210D20FFF7CCFF02210E20FFF7C8FF6F
+:1002700002210F20FFF7C4FF0221C81FFFF7C0FFB4
+:1002800003211620FFF7BCFF03211520FFF7B8FF5D
+:10029000204600F019F8002010BD49210180704768
+:1002A00010B500F04FF810BD0648704710B500F0CB
+:1002B0004AF810BD704770477047000000ED00E03D
+:1002C00000E400E003F900C330B50546384C95B0B2
+:1002D00006202070A01CFFF7E0FF5920A0803548C1
+:1002E00061880069344A80B2D269344B120C98425A
+:1002F00004D18A4208D032A1B42003E0884203D05E
+:100300002FA1B72012F0DDFB334802F057F9044665
+:10031000072000F0D7F92146254800F015FA6D1E98
+:10032000072D0AD8302168460170857001F0CCF99C
+:10033000002802D009A800F065FC204601F0BBFAB5
+:1003400015B030BD704710B50C46014660390B2919
+:1003500003D8214601F01CFF06E001466C39032951
+:1003600004D8214601F047FF206010BD01467039D6
+:100370001F2903D8214600F03FF8F5E701469039E0
+:100380000F2903D8214600F0C1F8EDE70146A03956
+:100390000F2903D8214600F029F9E5E70146B039D5
+:1003A0000F2903D8214600F006F9DDE70120DBE73D
+:1003B000140000200010001040000010FFFF00009B
+:1003C0007372635C636F72655F66756E6374696F89
+:1003D0006E732E63000000006D1C000070477047B4
+:1003E00070477047704770477047704710B50128D5
+:1003F00001D100F0CEF910BD10B57038030012F035
+:1004000065FC150C10141C20232A31363B3F434752
+:100410004E535A626A72797E8300086803F0FDFBCE
+:1004200010BD086803F050FC10BD0C790B7B8A6886
+:100430000868214603F06EFC10BD086803F0E8FC74
+:1004400010BD03F0BAF910BD08884A6880B21146A1
+:1004500003F06CFE10BD0A790888114680B203F0E3
+:10046000BCFE10BD087840B203F0C7FE10BD08887E
+:1004700080B203F0E3FE10BD086803F0F2FE10BD89
+:10048000086803F00AFF10BD086803F036FF10BDCE
+:10049000088982B209C9194603F061FF10BD05C978
+:1004A000114603F0B0FF10BD08884A6880B21146BB
+:1004B00003F0CEFF10BD0B7908888A6880B2194618
+:1004C00004F010F810BD0B7908888A6880B21946CC
+:1004D00004F0B9F810BD08884B688A6880B21946E4
+:1004E00004F0FAF810BD08884A6880B2114604F09A
+:1004F00045F910BD088880B204F05EF910BD088887
+:1005000080B204F07CF910BD012010BD10B5903808
+:10051000030012F0DBFB09060F161D242C363F46A4
+:100520004E0088888A6883B20888194680B204F031
+:1005300030FD10BD08884A6880B2114604F086FD7F
+:1005400010BD08884A6880B2114604F0C9FD10BD8C
+:1005500008884A6880B2114604F0FFFD10BD088883
+:100560004B688A6880B2194604F030FE10BD0889D5
+:1005700082B2888883B20888194680B204F065FE8A
+:1005800010BD08894B6882B20888194680B204F011
+:100590009AFE10BD08884A6880B2114604F0CAFE6F
+:1005A00010BD888882B20888114680B204F05EFFD0
+:1005B00010BD012010BD10B5B02805D0B12808D05D
+:1005C000B2280BD0012010BD088880B205F042FA95
+:1005D00010BD088880B205F06DFA10BD08884B6820
+:1005E0008A6880B2194605F076FA10BD10B5A038B9
+:1005F000030012F06BFB0B070E172028323C434D13
+:10060000545D65004B6808788A68194606F090FDCD
+:1006100010BD88888A6883B20888194680B206F0BF
+:100620009CFD10BD08884C68CB688A6880B2214662
+:1006300006F0A3FD10BD08884B688A6880B2194691
+:1006400006F0BDFD10BD8888CB6884B208888A6832
+:1006500080B2214606F0DDFD10BD8888CB6884B2EB
+:1006600008888A6880B2214606F0E3FD10BD08883C
+:100670004A6880B2114606F00BFE10BD088982B2AE
+:10068000888883B20888194680B206F00BFE10BD38
+:1006900008884A6880B2114606F024FE10BD088919
+:1006A0004B6882B20888194680B206F0A1FE10BDE0
+:1006B00008884B688A6880B2194606F05EFF10BD54
+:1006C000012010BD10B507F09BF80FF0CFF907F02F
+:1006D00049FD0FF01DFB07F0B3FD07F0D1FC10BD85
+:1006E0001CB50446002069460870204608F020FD2D
+:1006F0006946204608F0DEFB002803D1FBA1B120AB
+:1007000012F0DFF901A9204608F033FB002803D1DD
+:10071000F6A1B62012F0D5F9684600781CBD70B578
+:10072000F74D002428462C7620308471C47112F0D5
+:10073000DBFA284640380470203084738474847651
+:100740002C74AC7070BDEAE710B50C46ED49828898
+:100750008A8042884A800078087008460A38847087
+:1007600008F0DDFAFFF7DBFF204609F01FFDE44A41
+:10077000E0321146383908461446813808F04AFDFF
+:100780002146E0480AF0FDFF08F0C9FC12F0ACFA7F
+:1007900010BD10B50120FFF721FE10BDF8B509F01E
+:1007A0004CF9D84DD64C0A3D022802D0207C0028B6
+:1007B0007CD0207E0026102819D1A078002803D0F4
+:1007C000CAA1D14812F07DF9CD48E838817A89076D
+:1007D0000DD50146267160398989E180C17A21727F
+:1007E00081896181C089A0810120A0702676C44FD3
+:1007F000203FB87C002859D1C4486946808908F058
+:1008000059FB002805D06946687809784018687057
+:1008100004E0C520B5A1C00012F053F9207C0028E7
+:1008200038D0BA488189FF300930406D80898142D3
+:1008300004D0B548ADA1223012F043F9B348808905
+:1008400008F0DEFB002804D1AF48A8A1283012F040
+:1008500038F908F04CFC00281CD0AC488089FFF720
+:100860003FFF697840186870A5484038416D2031D5
+:100870000A7C012A0DD1A54A3E779289C287487C1D
+:1008800020700120B876207E102801D0282800D1C1
+:10089000267626746978002908D09C488289FF3022
+:1008A0000930C28601870120B8746E7009F0BAF869
+:1008B000002805D1207C002802D0A87801F0A2FEF3
+:1008C000F8BDF8B50F460446FFF768FF8C4D403D74
+:1008D00028788B4E002813D0002F10D1307E0028AE
+:1008E00004D0FF2081A1BE3012F0EBF82C22A91C0D
+:1008F000204611F049FF0E202070002028708FE064
+:100900007F4D203DA87B002818D0002FF7D1307EE6
+:10091000102808D0282806D0002804D0FF2073A172
+:10092000CA3012F0CEF80120E070E87BA070287C7D
+:1009300060700F2020700020A87371E00121204614
+:1009400008F00EFC002807D0307C002851D1394631
+:10095000204608F005FCF8BDA97C69480C380090D9
+:1009600068480A38002913D00178052910D2002FD1
+:1009700056D1491C0170002666700D2020700120A0
+:1009800028750622A01C009911F0FEFEAE7447E007
+:100990005C4800210A380170B078002814D0002F7C
+:1009A0003ED1307E002803D050A1594812F089F87A
+:1009B000002565700120524920700A22091DA01CE3
+:1009C00011F0E2FEB5702BE0394620460AF046FEF3
+:1009D000002825D1A87C002805D0002F20D1494827
+:1009E0000A380178C5E7A87E002802D0307C0028AC
+:1009F00001D00020F8BD002F12D1307E002804D095
+:100A00008D203AA1800012F05CF8002666700A2062
+:100A10003B4920700622091FA01C11F0B5FEAE76DE
+:100A20000120F8BD10B53648017E002908D1007CB0
+:100A3000012805D001210020FFF743FF002801D045
+:100A4000072010BD012010BD10B5012409F0F8FBEE
+:100A50000443FFF7E7FF044308F062FB014621432C
+:100A6000084610BDF8B51D4614460E4608F0A1F91B
+:100A7000002807D0684608F0A7F9002803D0002C0A
+:100A800007D101E00120F8BD992018A1800012F0E3
+:100A900018F808F045F9A04204D21D4813A15830B7
+:100AA00012F00FF8009807F0B9FD3146009807F0F2
+:100AB000C7FDE2B22946009807F07EFF08F096F9DC
+:100AC000002804D19D2009A1800011F0FAFF08F050
+:100AD00029FB0E4800244030C17B002902D0C4739A
+:100AE00009F080FC0948C480CCE700007372635CA5
+:100AF0006C6C5F6374726C2E73302E6300000000A8
+:100B0000E0020020240000200B06000098010020D5
+:100B10000D02000010B50179002907D001290AD083
+:100B2000F749FE2011F0CDFF002010BD831D428843
+:100B30000488022103E042880488831D01212046A5
+:100B4000FFF790FF10BDF8B51F4615460E46044648
+:100B500008F073FF022803D0EA48007C00281FD069
+:100B6000E9488089208008F04BFA002803D1E44945
+:100B7000E64811F0A6FF0524684608F04CFA002864
+:100B80000ED0009807F094FD3070022809D001289B
+:100B900007D008F080FA641E2406240EECD1002051
+:100BA000F8BD3946009807F01FFF2880002804D1BF
+:100BB000D648D349123011F084FF08F06CFA0028AF
+:100BC00004D1AF20CE49800011F07BFF0120F8BD99
+:100BD00038B50446831D821C6946FFF7B4FF002820
+:100BE0000DD00020607168460078012808D00228E6
+:100BF00006D0FF20C249203011F063FF012038BD2C
+:100C00002071FBE700215CE670B5BE4C0546403C18
+:100C10002078002803D1BB48007E002803D0B849C3
+:100C2000BB4811F04EFF287808F093FB28780AF0B3
+:100C3000EEFE00202071012060713921E1702070EA
+:100C400070BD70B5AF4D0446403D2878002803D1F3
+:100C5000AC48007E002804D0AD48A949183811F0EE
+:100C600030FFA94E2188B089884203D108F0E5FE03
+:100C7000022807D002202871012068713821E9700C
+:100C8000287070BD7F2070769F48E1782030C17356
+:100C9000A17881730020EEE710B59A4C403C207893
+:100CA000002807D19748007E002803D108F0C5FE30
+:100CB000032804D161209249C00011F002FF91493C
+:100CC00000202031C8712071012060713A21E1704B
+:100CD000207010BD70B58B4C0646403C2078002833
+:100CE00007D18848007E002803D108F0A6FE03281B
+:100CF00004D186488249783011F0E3FE814D2035D9
+:100D0000E87908280CD2E87910220001001968302F
+:100D1000314600F09FFDE879401CE871002000E0BA
+:100D200007202071012060713B21E170207070BDAF
+:100D3000F8B5744C0546403C2078002803D1714832
+:100D4000007E002804D072486D49443811F0B9FE85
+:100D5000A878002801D0012804D1A888FF21F53106
+:100D6000884204D96A4866493E3811F0AAFE664EA8
+:100D70002988B089884203D108F05FFE022807D095
+:100D800002202071012060713621E1702070F8BDD1
+:100D90005D48002720308772A988B185012131760E
+:100DA000A978012900D00021817257484030C07BCA
+:100DB000002801D009F016FB2771E3E770B5514C0C
+:100DC0000546403C2078002807D14E48007E002888
+:100DD00003D108F032FE002804D04D484849673856
+:100DE00011F06FFE287809F02EFA00202071012002
+:100DF00060713021E170207070BD70B5414C0546C6
+:100E0000403C2078002803D13E48007E002804D0D2
+:100E10003F483B490D3011F054FE287800280BD094
+:100E2000012809D0022807D06878402804D3384820
+:100E30003349143011F045FE284608F0F6FD00282D
+:100E400001D0002000E00C202071012060713421CD
+:100E5000E170207070BD70B52A4C0546403C20788A
+:100E6000002807D12748007E002803D108F0E5FDBF
+:100E7000002804D0264822495C3811F022FE297847
+:100E8000002914D00A2912D0142910D01E290ED0FE
+:100E900028290CD032290AD04B2908D0642906D041
+:100EA000FF2904D01A481649503811F00AFE284686
+:100EB00009F028FA00202071012060713321E170CF
+:100EC000207070BD70B50F4C0546403C207800285E
+:100ED00003D10C4A107E002804D00D48084975380B
+:100EE00011F0EFFD062229460A4811F04DFC0020C2
+:100EF0002071012060713221E170207070BD00000E
+:100F0000EC0A0000E002002098010020A30200008B
+:100F1000910500001D00002070B5F84C05462078B2
+:100F2000002804D120464030007E002803D0F44938
+:100F3000F44811F0C6FD00216956042914D0002997
+:100F400012D0081D10D0001D0ED0001D0CD0001DA9
+:100F50000AD0001D08D00A3006D0283104D0A120C4
+:100F6000E749C00011F0ADFDE74829780170012084
+:100F700060713121E1702070C0E710B5DF4C20783E
+:100F8000002804D120464030007E002804D067208D
+:100F9000DB49000111F095FD07F0C2FEE08007F08B
+:100FA00087FF207200202071012060710521E1700F
+:100FB000207010BDF8B5D14C07462034A07B2546E3
+:100FC0002035002805D1287E002802D1A8780028E5
+:100FD00004D0CC48CA492A3811F073FD08F02DFD21
+:100FE0001026022822D1C9483988808988421DD11B
+:100FF000C249483908460A7F6038807A002A03D0FF
+:1010000080070CD40C200CE0800708D40620087759
+:10101000BE484030C07B002801D009F0E3F92E76AD
+:101020000020E07326740120A073F8BD0220F8E7C9
+:1010300010B5B24C2078002804D120464030007E04
+:10104000002804D0AF48AE493C3811F03AFD0020EA
+:1010500020710E20A0700F20E070FF20A0710020F2
+:10106000C0432081AA480178A1728188A18140886B
+:10107000E08101206071207010BD10B59F4C207878
+:10108000002804D120464030007E002804D0DB2018
+:101090009B49800011F015FD0821A01D0EF082FD76
+:1010A00000202071012060712B21E170207010BDA3
+:1010B00070B5924D04462878002804D12846403067
+:1010C000007E002804D0B7208D49C00011F0F9FC43
+:1010D0008E4810222146303800F0BCFB8B4810228D
+:1010E000A118203800F0B6FB884830380EF061FEB9
+:1010F0008649102210392C46A81D00F0ABFB0020B9
+:1011000020710E20A0702A20E070012060712070F4
+:10111000F4E6F8B5794C05462034A07B2646203607
+:10112000002802D1307E002804D076487449DC388B
+:1011300011F0C7FCA978052912D0132910D0142961
+:101140000ED015290CD01A290AD0292908D03D29FA
+:1011500006D03B2904D06B486949D43811F0B1FC62
+:1011600028886C49884204D966486549CB3811F013
+:10117000A8FC08F062FC0C212827022809D163484A
+:101180002A888089904215D15C484838027E002A1E
+:1011900001D0E17310E0A97841760121017637761C
+:1011A0000020E07359484030C07B002804D009F08B
+:1011B00019F901E00220E07327740120A073F8BD43
+:1011C00070B54E4C05462078002804D122464032A6
+:1011D000107E002804D083204949C00011F071FC22
+:1011E0004648294660300622054611F0CDFA012016
+:1011F000A8710021217160711721E17020707DE6D6
+:10120000F0B5414F85B0403F3D7A06463B480078F7
+:10121000002804D13846A038007E002803D0384981
+:101220003D4811F04EFC3078002806D0012804D04B
+:101230000D203349800111F044FC082D39D2324889
+:1012400020380190C469307800282CD0012804D0BF
+:1012500031482B490F3011F034FC29460831012068
+:10126000884004430120A84020430090B179234CDA
+:1012700008027279690009191043FF310131888130
+:10128000B01C11F0E2FA717800020843A9000919B4
+:10129000C031C862387A401C387201990098C86120
+:1012A0000020207108E0294608310120884084434D
+:1012B000D8E7124807210171012110480B22417122
+:1012C000C270017005B0F0BD10B50C4C207800283C
+:1012D00004D120464030007E002804D00E48084942
+:1012E0000E3811F0EEFB11F0FFFC00202071012000
+:1012F00060710A21E170207010BD0000A002002082
+:10130000EC0A000006050000C00300209801002040
+:1013100024000020FF0E00003F03000010B508F07D
+:101320000AFF002803D0FC49FC4811F0CAFB07F073
+:10133000F5FE07F0D8FC0AF016FA002804D0F748AA
+:10134000F5490E3011F0BDFB07F039FF002804D03D
+:10135000F248F149123011F0B4FB11F0C5FCF0482D
+:1013600000240470FFF7DBF9EE480121047141719C
+:101370000222C2700170BFE770B5EA4D04462878BA
+:10138000002804D128464030007E002804D0EF20F9
+:10139000E149800011F095FB20781F2801D8601CDE
+:1013A00004D1DE48DC49DE3011F08BFB00202871CF
+:1013B0002078611C07F0BCFF012068712021E970D2
+:1013C00028709BE5F8B5D74C054620782646403670
+:1013D00000280CD1307E002809D108F02EFB00280F
+:1013E00002D1307C002807D0287800280ED0CB48C6
+:1013F000C949EB3011F065FB2878012806D0002898
+:1014000004D0C648C449F03011F05BFB0120607184
+:1014100028780027C44D01280BD0002008F074FE66
+:10142000002844D00C2020711B20E0700120207087
+:10143000F8BD0C20207107F003FF0028F4D0BA4853
+:1014400002210C300EF037FB002806D00F21A889AE
+:10145000090211F013FAA98100E0AF8101220321F2
+:10146000B14807F0E9FAB04808F051F8A88907F048
+:1014700059FC002803D1A849AC4811F022FBA889E7
+:10148000002107F053FE002804D0A848A249001DFF
+:1014900011F017FB317F708B08F0D9FE002804D0C3
+:1014A000A2489D49083011F00CFB2771BCE7277159
+:1014B000307C0028B8D1A889FFF712F9B4E770B5DD
+:1014C000984D04462878002804D128464030007EF4
+:1014D000002804D0954890493B3811F0F2FA207862
+:1014E0001F2801D8601C04D190488B493A3811F06C
+:1014F000E8FA002028712078611C07F02DFF0120F8
+:1015000068711A21E9702870F8E4F8B5854D044631
+:1015100028780C272E464036002806D1307E002839
+:1015200003D108F08AFA032804D16F207A49C00059
+:1015300011F0C7FA6079002801D001282FD1A079D5
+:10154000002801D001282AD1A07B002805D001283D
+:1015500003D0022801D0032821D1607B40071ED090
+:10156000618801208003814202D82288824201D909
+:1015700020790CE02079002804D0022805D0032827
+:1015800003D004E0202904D209E0A02A01D20128D6
+:1015900005D12088884207D92079012804D06348E2
+:1015A0005D495F3811F08DFA20887083207930779B
+:1015B0006079002802D0012803D00CE05C4A0021A9
+:1015C00005E0584A60329079002804D00121204675
+:1015D00007F03AFE074601202F7168711821E97063
+:1015E0002870F8BD70B54F4C05462078002804D10E
+:1015F00020464030007E002804D04C484649B63092
+:1016000011F05FFA08F019FA0C2102280ED14648B1
+:101610002A8883899A4219D10246C032137F002B4F
+:1016200004D1807E0E2803D00F2801D0217103E061
+:1016300005201077002020710E20A0702E20E07071
+:101640002888E08001206071207057E40220F2E7D2
+:1016500070B5344C05462078002804D1204640302F
+:10166000007E002804D031482B498A3011F029FA35
+:1016700008F0E3F90C2102280ED12B482A8883892F
+:101680009A421FD10646C036327F002A04D1807E9E
+:101690000E2803D00F2801D0217109E02148102223
+:1016A000A91C1E3811F070F804203077002020713A
+:1016B0000E20A0702D20E0702888E080012060714D
+:1016C00020701BE40220F2E710B501780B0011F046
+:1016D000FDFA3C90904590906590909090484B908A
+:1016E00090905E619090909090904F3590393D90A1
+:1016F00090909041909090909090905390575B90E4
+:101700001F319078686C7074907C90878B84809087
+:10171000801CFFF79DFF6AE0EC0A0000DF0200007A
+:10172000C0030020A002002098010020E90300006F
+:101730001D000020801CFFF755FF58E0801CFFF7BC
+:10174000E4FE54E0801CFFF7BAFE50E0801CFFF777
+:1017500039FE4CE0801CFFF70FFE48E0FFF7DEFD8E
+:1017600045E0FFF7B1FD42E0801CFFF749FD3EE098
+:10177000801CFFF725FD3AE0801CFFF7CAFC36E02D
+:10178000801CFFF795FC32E0FFF777FC2FE0FFF7B6
+:101790004FFC2CE0801CFFF70DFC28E0FFF7EDFB71
+:1017A00025E0801CFFF7B8FB21E0801CFFF78AFBD7
+:1017B0001DE0801CFFF74FFB19E0801CFFF71DFBAD
+:1017C00015E0801CFFF7FAFA11E0801CFFF7B0FA71
+:1017D0000DE0801CFFF77EFA09E0FFF75DFA06E0F6
+:1017E000801CFFF72EFA02E0801CFFF70DFA0120A3
+:1017F00082E5002080E510B51D491E4811F061F911
+:101800007AE570B51D4A012411461B4D4031030095
+:1018100011F05CFA05191C1C04191C00012200219E
+:10182000154807F009F91548002148380177417734
+:10183000C03808F068FD002804D00E480C49D330A9
+:1018400011F03FF964E40C74556561E46D200849BA
+:101850000001F5E730B5134606E0CC18203CE47FE4
+:10186000D51A44555B1EDBB2002BF6D130BD00000B
+:10187000EC0A0000CA05000098010020A002002028
+:1018800010B5030011F022FA070805080B0B0E0E25
+:10189000110003F0FAFF10BD01F0BAFF10BD0BF00C
+:1018A0009BFF10BD0DF004FE10BDFF20F8A17D30A0
+:1018B00011F007F910BD7FB5F94AFA4C51689268EA
+:1018C0000192009120700823F74A1946F7480EF05C
+:1018D00093FB0025F6480EF0ADFB6D1CEDB2072D15
+:1018E000F8D3F1490320803140020BF0C7FF0028F4
+:1018F00003D0E7A1912011F0E4F81E220221ED4867
+:101900000AF077FBEB481E22032110300BF0EBF8B6
+:10191000E8480722342174300AF0C4FAE5484C2123
+:10192000283010F090FFE3496A46743108464C387D
+:101930004164FF317B31816401211172039002F017
+:1019400016F902A80CF0CCFA002803D0D0A1A520EB
+:1019500011F0B7F8D54802222421A8380AF0A2FADB
+:10196000D24802222C215C380AF09CFAD2490B2082
+:101970000DF08AFE002803D0C5A1B22011F0A1F815
+:1019800003F070FF03F076F904F0D6FD6B46CB4A06
+:101990000821CBA002F04BF8002803D0BCA1B9204D
+:1019A00011F08FF8012005F0C8F8002803D0B8A185
+:1019B000BB2011F086F87921C900C44810F043FF1C
+:1019C000C249B74A0020135C0D18401CC0B2EB702E
+:1019D0000428F8D3002060606070A0707FBD70B5EF
+:1019E000BB4E0546706A94B00C46401C04D1B06AE8
+:1019F000C0430004000C0BD0306AC007C00F287031
+:101A0000706A10F033FFB06A2071000A607113E051
+:101A10002B206946087009A968460AF089FA00284F
+:101A200003D09BA1DF2011F04CF801202870062282
+:101A30000AA9204610F0A8FE2878002815D0607961
+:101A4000C0210843607117206946087000A806226B
+:101A50002146023010F098FE09A968460AF068FA9B
+:101A6000002816D08AA1F42011E0322069460870BF
+:101A700000A806222146023010F086FE09A9684619
+:101A80000AF056FA002804D0FF2081A1013011F09D
+:101A900018F814B070BDF0B58D4C0646206895B0AE
+:101AA0000D463746401C0837002808D16068401CA6
+:101AB00005D1A068401C02D1E068401C11D020680C
+:101AC000314610F0D3FE6068311D10F0CFFEA068E3
+:101AD000394610F0CBFEE06831460C3110F0C6FEFE
+:101AE00025E02B206946087009A968460AF020FA0B
+:101AF000002804D0FF2066A1203010F0E2FF082269
+:101B00000AA9304610F040FE2B206946087009A94A
+:101B100068460AF00DFA002804D0FF205CA12730A7
+:101B200010F0CFFF08220AA9384610F02DFE2069D8
+:101B30002E46401C0836002808D16069401C05D19B
+:101B4000A069401C02D1E069401C12D020692946DE
+:101B500010F08CFE6069291D10F088FEA0693146E6
+:101B600010F084FEE06929460C3110F07FFE15B0BC
+:101B7000F0BD2B246846047009A90AF0D9F90028A1
+:101B800004D0FF2042A1453010F09BFF082209AF8E
+:101B90000AA9284610F0F8FD6846047009A90AF061
+:101BA000C7F9002804D0FF2039A14C3010F089FF7C
+:101BB0000822391D304610F0E7FDD8E710B50021A6
+:101BC00008460EF0ECFA002101200EF0E8FA0021A0
+:101BD00002200EF0E4FA002103200EF0E0FA0021CA
+:101BE00004200EF0DCFA002105200EF0D8FA10BD1A
+:101BF00010B5364CA0780A2804D3FF2024A19630D3
+:101C000010F05FFF20786021484300190830002160
+:101C100001704178E722C908C900C91C1140417010
+:101C2000204A0121517010BD70B51E4C607800280B
+:101C30000ED0264800250178491CC9B201700A2936
+:101C400000D105708178491C81700EF072FB6570BF
+:101C500070BD70B5134C05466068002804D0FF20A5
+:101C60000BA1BF3010F02DFF656070BD70B50D4E3B
+:101C7000164DFFF7BDFF7168044600292AD0602287
+:101C8000FEF7A2FAFFF7D0FF00207060F1E7000036
+:101C90007372635C686F73745F636F72652E630049
+:101CA000F82C01002C000020C40300206C1100203F
+:101CB00081180000440A0020141000203412000093
+:101CC0006E52463531383232000000004C0C002094
+:101CD000800000102879002852D0FE480AF0F2F85F
+:101CE0006060002804D1FF20FB49DD3010F0E9FEE0
+:101CF00060680AF045F9002810D0204601F0A5F8E8
+:101D00006078010707D5C008C000401C60702879C2
+:101D1000401E287126E0EF48616829E0ED486168BF
+:101D20000AF0D9F8687900282AD0EA484C380AF035
+:101D3000C9F86060002803D1E749E84810F0C1FE07
+:101D400060680AF021F9002815D0204603F0DCFD78
+:101D50006078010709D5C008C000801C60706879F0
+:101D6000401E6871FFF760FF83E7DA4861684C380E
+:101D70000AF0B1F87DE7D74861684C380AF0ABF853
+:101D800070BDF7B505460078002700090C463E46B1
+:101D9000062804D0D148D049223010F092FE287A8B
+:101DA00000280ED0012814D0CC48CB49433010F085
+:101DB00088FE0298002C068001D0278066800020D3
+:101DC000FEBD02270926002C0ED0A889A080A87B82
+:101DD00008E003271426002C06D02869E060A88AB2
+:101DE0002082287B2072E4E702980680E7E770B53E
+:101DF0000E4600211C4619801546030010F066FFB0
+:101E00000723050B1711231D2300224629463046C0
+:101E100003F046FD70BD22462946304601F09BFA8C
+:101E200070BD22462946304604F081FA70BD224634
+:101E30002946304602F052FF70BD22462946304600
+:101E4000FFF79FFF70BD4D20A349C00010F039FE81
+:101E5000032070BD01469F4810B54C380AF03BF88E
+:101E60009F494879401CC0B24871012803D19D4860
+:101E7000007800F0C7FB10BDF8B505460720400705
+:101E80000F460A18012189038A4209D2002D02D087
+:101E90002818884204D2E81C80088000A84201D09B
+:101EA0001020F8BD8E488178002911D03988009122
+:101EB0004178602251430C18083420783B460007D3
+:101EC000000F00222146FFF792FF060004D015E024
+:101ED000002038800520F8BD002D13D039880098E7
+:101EE000814201D90C260DE020783B460007000F07
+:101EF0002A462146FFF77BFF060005D00C2E01D0B5
+:101F0000002038803046F8BD754D6878401CC0B25E
+:101F100068700A2801D100206870A878401EA87057
+:101F200061784807400F022810D00128EAD169489B
+:101F3000616809F0D0FF2879401CC0B228710128DF
+:101F4000E0D16848007800F05DFBDBE7C806D9D433
+:101F50006068FFF77FFFD5E770B504466248164614
+:101F60000D46814204D15D485B49DB3010F0A9FD8C
+:101F7000012E05D059485849EB3010F0A2FD70BD34
+:101F80005848012181706620207000202072A581B0
+:101F9000A17370BD70B516460D46040001D1FFF760
+:101FA00027FE662101700121017229680161A9885B
+:101FB00081820673002C01D1FFF736FE70BD072128
+:101FC0004907012241189203914201D31020704722
+:101FD0000721017000207047052210B5920390423E
+:101FE0000ED301239B04C21A404B9A4208D3404BA4
+:101FF000984205D2072252078A18DB139A4201D36E
+:10200000102010BD0DF079FB10BD052310B59B030A
+:1020100099420ED301239B04344CCB1AA34208D31C
+:10202000334B994205D2E3020124D318A403A342FF
+:1020300001D3102010BD022803D0102801D00920A0
+:1020400010BD0DF080FB0028FAD0052010BD70B542
+:1020500005239B03984212D301239B04234CC31AEC
+:10206000A3420CD3224B984209D2E4020D19DB1390
+:102070009D4204D2002A04D014199C4201D310209E
+:1020800070BD0DF086FB0028FAD0072070BD10B59A
+:1020900004460720400701212018890394B0884294
+:1020A00002D3102014B010BD01F0ADFD002801D006
+:1020B0001120F7E70F2008A9087369460BA809F05B
+:1020C00037FF0028EED16846007A207068464089C4
+:1020D00060800FE010110020901C0000FF01000044
+:1020E0004C0C00202C000020FFFF00000000FC1F13
+:1020F0000040002068468089A0800020D2E710B50B
+:1021000094B0044601F07FFD002801D01120C9E7FA
+:10211000002C01D00720C5E7392168460170002155
+:10212000817009A909F004FF002803D01549164859
+:1021300010F0C7FC0020B5E770B5144C0846A17834
+:10214000002913D000280FD0072252070123851839
+:102150009B039D4203D20568AA189A4201D310201E
+:1021600070BD8288002A03D0012903D0082070BDE9
+:10217000092070BD04F042FA0028FAD10021A170B4
+:1021800070BD0000901C0000790300002C000020AE
+:1021900010B56038030010F099FD07050A0E131AF8
+:1021A00021252C0005C91146FFF766FE10BD086801
+:1021B000FFF705FF10BD05C91146FFF70DFF10BD64
+:1021C0004B6808788A681946FFF71FFF10BD4B68F7
+:1021D0008A6808681946FFF73AFF10BD0868FFF7DC
+:1021E00056FF10BD08884A6880B21146FFF7A4FF69
+:1021F00010BD012010BD10B56C2801D0012010BD0C
+:102200000878FFF77CFF10BD10B5EFF31080C4070E
+:10221000E40F72B6D6484178491C417040780128D5
+:1022200001D10EF0ABF8002C00D162B610BD70B534
+:10223000CF4CE07800280AD10125E570FFF7E4FFD4
+:102240000EF0A4F8002804D000200EF077F800204B
+:1022500070BDC84865714560F9E770B5EFF310804F
+:10226000C507ED0F72B6C24C6078002803D1C2A139
+:102270008F2010F026FC6078401E60706078002887
+:1022800001D10EF07FF8002D00D162B670BD10B5FF
+:10229000B748C178002904D000214171C170FFF70F
+:1022A000DCFF002010BD10B504460EF06FF8B049F9
+:1022B000C978084000D001202060002010BDF8B58A
+:1022C0000246AB4C0026A6710820042101251027E8
+:1022D000130010F0FBFC0D080A0C0E101214161E51
+:1022E000262123252800257122E0022001E021710A
+:1022F0001EE020711CE027711AE02020F9E701267A
+:1023000016E0FFF781FF0EF041F80028FBD002260F
+:102310000EE02171A5710BE02771FBE7202000E0A2
+:1023200040202071F6E7FF2093A17E3010F0C9FB1A
+:102330000EF038F8002809D00EF03AF8B04205D176
+:1023400030460EF038F80028FAD024E0012080074B
+:10235000C5608D4A002151608C4A9661854B0222EE
+:102360005A6085608A4803690569DB43DB06DB1731
+:102370005B1C10273D430561834D00E020BF6F6863
+:10238000002FFBD0002B03D1076910239F43076167
+:10239000784882606960A07900280CD00DF0F6FFC3
+:1023A00005460DF053FF7B4A002D02D0A260E0608D
+:1023B00001E0E260A060002E01D100F0B1F8F8BDAC
+:1023C00010B504460DF0E8FF002805D0684901204B
+:1023D000C8704A78521C4A702046FFF770FF10BD43
+:1023E000F8B5694FB8680025012802D1BD600DF02D
+:1023F000A5FF7868012800D17D60386801265C4C13
+:10240000012814D13D606079002803D000200DF030
+:1024100095FF65712078002809D00DF0B7FF0028DE
+:1024200005D05948C038866300060661A670386931
+:1024300001282CD13D6100F068F801208007466139
+:10244000A079002815D00DF0A1FF00900DF0FEFE40
+:102450000099002901D0E16800E0A168411A022931
+:1024600001DA8A1C13DC0099002901D0E06000E049
+:10247000A060FFF7C9FE0DF089FF002806D0424892
+:10248000C038866300060661A67000E02670F86812
+:10249000012819D100F039F800F037F800F035F8CC
+:1024A000A078002804D1FF2033A1053010F009FBEB
+:1024B000FD60A5702570FFF7D0FE0DF042FA0028F0
+:1024C00002D03148C038C663F8BD10B5284CE0785A
+:1024D000002801D10DF056FF01208107886100F02E
+:1024E00014F8A07800280BD0274CE068002803D10E
+:1024F0000DF061FF0028F8D10020E06000F005F841
+:1025000000201C49C043886010BD08B550206946B2
+:1025100008806A461088411E11800028F9D108BD44
+:10252000F8B5144819278760174900200860C8606B
+:102530000DF02CFFBD0701240D4E002805D01248D8
+:10254000C03884632C61B47000E03470FFF75CFE27
+:10255000084847600D4930798863FFF7D6FFAC61C2
+:10256000FFF7D3FF0849002008616C61F8BD000047
+:1025700034000020000300407372635C736F635F7C
+:10258000636C6F636B2E6300000100400005004028
+:1025900000ED00E0FFFFFF7F01203F49400608609B
+:1025A0003E4908603E490A68FF231B029A43831292
+:1025B0001A430A60384980390860704710B50246EE
+:1025C0000420384904E0C3005B181B79002B0AD0B3
+:1025D0000346401EC0B2002BF5D133A1432010F0BA
+:1025E00070FAFF2010BDC300CA50002259184A716A
+:1025F0008A7101220A7110BD2A4A0021C000801888
+:102600000171704710B50446042803D326A1522057
+:1026100010F057FA2348E1000C182079012803D064
+:1026200021A1532010F04DFA6079A179401CC0B26D
+:10263000814200D060710120174940068031086056
+:1026400010BD70B5164800680004800F022803D042
+:1026500015A1692010F035FA124E194C0325207887
+:10266000C10088190279012A07D1427983799A42F7
+:1026700003D042798271705880472078401CC0B2E4
+:102680002070042801D30020207028466D1EEDB272
+:102690000028E4D170BD000080E100E080E200E0AD
+:1026A00018E400E08C1100207372635C736F635F49
+:1026B0007369676E616C6C696E672E630000000061
+:1026C000440000208107C90E002808DA0007000F27
+:1026D000083880082C4A80008018C06904E080080F
+:1026E0002A4A800080180068C8400006800F7047A2
+:1026F00010B50D20FFF7E6FFC4B20420C043FFF77A
+:10270000E1FFC0B2844203D021A11A2010F0D9F910
+:1027100010BD0121234A48031060234B00221A6098
+:10272000224A5160224A1060224A11601D498039B4
+:102730000860704701211B4A480310601D4A516020
+:10274000194A002111601A490860704710B51649EE
+:102750000868012804D00EA1562010F0B2F910BD6F
+:10276000154880680022C0B20A600DF041FA10BD21
+:1027700010B50D4801680029FCD0FFF7E7FF0120E4
+:102780000B494003086010BD00ED00E000E400E0EC
+:102790007372635C736F635F68616C5F726E672EE8
+:1027A0006300000080E100E000D1004000D3004061
+:1027B00080E200E000D0004000D5004030B40121AC
+:1027C000BB48C9020160CD1005604A030260B948E8
+:1027D00003681B021B0A036004680023240A240206
+:1027E0000460B5480468240A24020460B348012444
+:1027F00044608460B24C23606360A360B14B196095
+:102800001D601A60B04B19601A600121016030BC74
+:10281000704710B40121A648CC0204600A0202608D
+:102820000B060360A54841608160A549002008604F
+:1028300048608860A34804600260036010BC704771
+:102840000121A048C9020160C91001607047002839
+:1028500005D0012805D0022805D19C4870479C4826
+:1028600070479C48704710B59BA18B2010F029F948
+:10287000002010BD70B500219E4C9F4D9F4A904B8B
+:10288000002808D001281DD0022822D092A1B32010
+:1028900010F017F970BD01200004A060A86011605D
+:1028A0001960974B42109A60964A9060804A0012D5
+:1028B0001060954801608648016094480160944822
+:1028C000017070BD01204004A060A8605160596093
+:1028D00070BD01208004A060A8609160996070BD07
+:1028E000F8B59446834A844D00240127744E00288D
+:1028F00008D0012836D0022844D077A1E82010F073
+:10290000E0F8F8BD891E0902090A01200004906060
+:1029100034606860794A1160012B21D000217C4A23
+:102920007C4B517061463D31DC63DF637A4B5C6008
+:1029300002249C6004241C61734B196073490F606E
+:10294000604B891519606F4B58605F48016074488F
+:102950007249C16086606A49600348601770F8BDBB
+:102960000121DCE701205B4E40046E4F012B04D1B6
+:102970003460506068603960F8BD906034606860B1
+:102980003960F8BD0120514E8004674F012BF4D10E
+:10299000EEE766484068704770B5494D28680026E4
+:1029A000544C012806D1A068C00303D501200004BF
+:1029B000A0602E606868012809D1A068800306D550
+:1029C00001204004A0606E6001200EF05BFAA86850
+:1029D000012809D1A068400306D501208004A06029
+:1029E000AE6002200EF04EFA70BD10B5484908786E
+:1029F000002818D00120424AC0039060414A40009C
+:102A000090602B4A001210603F4A00201060304A4C
+:102A100010603E4A106008704A78002A02D0487060
+:102A20000EF030FA10BD0320FAE7012040490006FD
+:102A300008607047012023490006086070470120A4
+:102A40003B4940050860704701201E494005086069
+:102A5000704730490020C8637047410A354AC005B5
+:102A6000C00D5043801C5143400A0818704710B4F1
+:102A7000314C430B63431B0C5C020C602D4C6343D5
+:102A8000C31A2E485C0258432A4B400D4343E31AB5
+:102A90000124DB0324041B191B1613700A68101889
+:102AA000086010BC704710B50EF0B6FA10BD0000FB
+:102AB00080E100E008E400E018E400E000B000403D
+:102AC00040B1004080E200E000E100E048B1004099
+:102AD0004081004044B100407372635C72656D5F79
+:102AE00068616C5F6576656E745F74696D65722E82
+:102AF0006300000000B3004040B3004040B5004018
+:102B000000F5014000830040408500400082004005
+:102B100045000020C08F004000850040008000403C
+:102B200080F5014044B5004048B5004000B5004084
+:102B300000E200E0093D0000378600006F0C010054
+:102B400010B50EF055FA10BD012001218140064A52
+:102B5000116000BF00200549C8630120C8637047A9
+:102B600000200249C863704780E100E0C01F0040B8
+:102B700070B5FF4D044629680300A03110F0A6F897
+:102B800008053E08080E1D2C3242FAA1D22033E07F
+:102B9000887F012832D0F7A1D8202DE001F058FE1F
+:102BA00005282BD001F054FE062827D001F050FE56
+:102BB000072823D0EFA1DB201EE001F049FE032807
+:102BC0001CD001F045FE062818D001F041FE072870
+:102BD00014D0E8A1E0200FE0887F05280ED0E5A101
+:102BE000E52009E001F034FE052807D001F030FEB1
+:102BF000062803D0DFA1E8200FF063FF2868A0308B
+:102C0000847770BDDBA1EC20F6E7D949C1220968C1
+:102C1000525CD206920F05D1A0318A8A824201D13C
+:102C2000887D70470020704770B5044611202070E1
+:102C30000021CF4D61702968C0318978002908D002
+:102C400003290ED0042910D0FF20CAA116300FF09E
+:102C500038FF20780009012802D92868807E60703A
+:102C600070BD0007000F203002E00007000F303079
+:102C70002070EEE730B50388C249C34C8B4202D0C6
+:102C80009A1FA2421ED242888A4202D0951FA542B4
+:102C900018D2934216D883887D24E400A34211D829
+:102CA000C088884205D0B84D04460A3C2D1FAC426E
+:102CB00008D2884208D08A4206D05B1C5A43C00022
+:102CC000824201DD072030BD002030BDFFB500226B
+:102CD000099B002802D0994205DC5CE0002902D162
+:102CE000002004B0F0BD0920FBE7845C002C12D06A
+:102CF00085186F780D2F4CD010DC3B000FF0E6FFED
+:102D00000A421B2A2A303032323A3A42835C002B84
+:102D10003FD1521CD2B28A42F8DBE1E7122F31D008
+:102D200004DC0E2F35D00F2F2CD132E0142F11D010
+:102D3000152F27D116E0022CD5D1AB78039C072B99
+:102D4000237001D25B0701D40A20CAE7029B012449
+:102D50001B7814E0E343DB0708E0012C08D011E006
+:102D60000620BEE70F2523072D075B19002BF4D0A3
+:102D70003046B6E7029B1B789C070AD40224234303
+:102D8000029C2370835C521C9A18D2B28A4204DDE2
+:102D9000A9E70B20A5E7192676028A42A5DB9FE763
+:102DA00005E00278401C002A01D0002070470A4646
+:102DB000491E89B2002AF4D10120704730B56C4D0C
+:102DC0000021286887B0C943A0308182002484751F
+:102DD000214606200DF0E3F9002105200DF0DFF972
+:102DE000002102200DF0DBF90120FFF7C1FE286869
+:102DF000BF210C54C0300470012069460870684639
+:102E00000BF08FF807B030BD10B5594A94B0126876
+:102E1000A032927F042A0AD028236A461370508079
+:102E2000132906D03B2904D0072014B010BD082078
+:102E3000FBE71171104609A909F07AF8040002D1E4
+:102E40000420FFF795FE2046EFE7F0B59BB00400A5
+:102E500003D148A14D480FF034FE72202070606805
+:102E6000002701780826491F414D0B000FF02EFF67
+:102E70000F096ECBFB6E70F9F8AA6E6E6E6EF7F6E8
+:102E80006E002868A030807F032804D0972039A1E5
+:102E900080000FF016FE002108460DF080F96078E2
+:102EA00010233043607028680146C0314A781A43C5
+:102EB0004A7061688A783C2A45D08E880146012292
+:102EC000A0318A756268D2890A836268128A4A834D
+:102ED0006268528A8A838E8261680622C979C173C8
+:102EE0006168103008310FF04FFC0520FFF740FEFD
+:102EF0002868C2210F54017FFB2211400177B021C5
+:102F000009584A7A920892004A72C782304602F003
+:102F1000B5FC002804D01D4816A122300FF0D1FDC9
+:102F2000304601F0C7FE002804D04F2011A1C00098
+:102F30000FF0C7FD304603F00FFB002806D0134802
+:102F40000CA1273023E10120FFF712FE1BB0F0BDDA
+:102F5000878801F07DFC052820D001F079FC062847
+:102F60001CD001F075FC072818D001F071FC0FE0AF
+:102F7000480000207372635C6761705F636F726505
+:102F80002E630000FFFF00007B0C000053020000D6
+:102F9000042803D0FB49FC480FF093FD60783043D0
+:102FA00060702868C030417831434170FFF706FFF8
+:102FB000384602F068FC384601F082FE384603F0DD
+:102FC00001FBC3E701F044FC052810D001F040FCF0
+:102FD00006280CD001F03CFC072808D001F038FC92
+:102FE000042804D0E848E74913300FF06AFD606810
+:102FF000807902F000FD0028A8D06178314361702B
+:103000006168C880A2E701F023FC052810D001F018
+:103010001FFC06280CD001F01BFC072808D001F08B
+:1030200017FC042804D05520D649C0000FF049FDF4
+:103030006078304360706068C1882868A030018380
+:10304000616809894183616849898183002102207F
+:103050000DF0A5F82868A030C77777E70CE167E1A5
+:103060006FE070E0FFE701F0F3FB052810D001F0FE
+:10307000EFFB06280CD001F0EBFB072808D001F08D
+:10308000E7FB042804D0C048BE4935300FF019FDD5
+:103090002868BE21095C042993D0807D40063CD578
+:1030A000606802210C30FFF77BFE002835D0606895
+:1030B0000821001DFFF774FE00282ED02868014665
+:1030C00080310A6B527A920708D1C222125C002A20
+:1030D00008D1C28AD30505D5D20703D1C38A4022BD
+:1030E0009343C382C38A80229343C3822D236A46BB
+:1030F0001370A030808A5080CB698A694869096A58
+:1031000001AC0DC4049109A9684608F011FF00281C
+:10311000A3D09D489B49573039E062682868A421B4
+:1031200092890A5261680822091DA6300FF02CFB13
+:1031300010A806742868A630159014A80AF0F1FEAD
+:1031400004E70121817101F083FB052810D001F013
+:103150007FFB06280CD001F07BFB072808D001F08C
+:1031600077FB042804D0884886497B300FF0A9FCFF
+:103170002868BE21095C0429E2D061688A79002AA6
+:1031800002D08978002905D07F487E49E1300FF0D0
+:1031900098FCDBE6617831436170B0210958497AC7
+:1031A0008907890F01294DD1817D09064AD4017F04
+:1031B000490701D5042100E00321C03081702B2094
+:1031C0006946087009A9684608F0B2FE002804D0D4
+:1031D0006D486C4997300FF074FC69462868098D7A
+:1031E00001830E2210A90A7468491591027A0A70A7
+:1031F000024609324A600F320A61521D8A6010325B
+:10320000CA60133A4A618A328A61921CCA61423AA0
+:103210000A6210324A6210328A62403A8A63D21FCE
+:10322000CA63521C54300A64486414A80CF004F8B1
+:10323000022815D0002813D053485249BF300FF050
+:1032400040FC0DE0817D4906017F490701D504213D
+:1032500000E00321C0308170002106200CF09FFFA8
+:103260002868C18A0A0602D440229143C1828AB2E8
+:1032700080218A43C28269E62868A030807F0328C3
+:1032800004D041483F49ED300FF01BFC00210846B7
+:103290000CF085FF60781023304360702868014689
+:1032A000C0314A781A434A7061688A783C2A00D152
+:1032B00049E68E8801460122A0318A756268D2896A
+:1032C0000A836268128A4A836268528A8A838E827B
+:1032D00061680622C979C1736168103008310FF046
+:1032E00053FA0520FFF744FC2868C2210F54017FE0
+:1032F000FB2211400177C782304602F0BFFA002856
+:1033000004D0E3201F4980000FF0DBFB304601F0C2
+:10331000D1FC002803D01B491D480FF0D2FB3046DA
+:1033200003F01AF90028A6D019481649801C2EE788
+:1033300060783043607009E600290BD0888015481A
+:103340000068A030028BCA80028B0A81428B4A81BE
+:10335000808B88817047F7B5064600780C460027B9
+:10336000010982B03D4601296FD00A4800680090EB
+:10337000C03002296AD0072910D00A2967D0014934
+:103380000548DAE1742F0000860200000C120020CC
+:103390008F030000480000201105000071680A78C2
+:1033A000521F13000FF092FC0F09B054B0B02F5B06
+:1033B0005B47B0B0B0B0656FB0008A783C2A1BD0D4
+:1033C00010271625002C7DD08888A0807068A21D4B
+:1033D000C08920827068C089E0817068008A60823C
+:1033E0007068408AA082716808460831C07901F08F
+:1033F00034FA0020607375E019270725002CE2D00D
+:103400000021A17171E011270725002CDBD08988EC
+:103410000091A1807168F7228979A17141781140EA
+:103420004170009802F030FA009801F04DFC0098CD
+:1034300003F0D6F8ACE101270925002CC3D0888819
+:10344000A080706880792072A2E160E09DE178E060
+:10345000888812270E252146FFF76EFF98E118276E
+:103460000825002CAFD08888A080A01DFFF7DCFBCA
+:103470008EE11A270725002CA5D04888A080706807
+:103480000079A07184E18A783C2A32D01027162571
+:10349000002C98D08888A0807068C08920827068CD
+:1034A000C089E0817068008A60827068408AA0826A
+:1034B0007168607B497D40084000C907C90F084317
+:1034C000607300E036E17168C007497DC00F4908AC
+:1034D0004900084360737168A21D08460831C0792D
+:1034E00001F0BBF9FB480068C0304178EF22114081
+:1034F00031E119270725002C88D00021A1714278DD
+:10350000EF210A40427043E1F349F44815E1307A73
+:10351000012803D0F148F04917300EE112270E259B
+:1035200070892146FFF708FF002C87D0707840078C
+:10353000400F032888D1E7480068C0304178FB225B
+:10354000D5E7E4490968A031002C01D08A8AA2801D
+:10355000327A921E13000FF0B9FB073B4651EEDBA7
+:103560006B05EE0013270C25002C85D0F1688978B7
+:103570008907890F0129217A27D04908490021723A
+:10358000FD221140F268E32392785207D20F5200D5
+:10359000114321720022E2801940F3681B785B0717
+:1035A000DB0E19432172DF231940F3685B78DB07D8
+:1035B0009B0E194321726272F1680122C978A172CF
+:1035C00001781143F722114016E001221143D6E79A
+:1035D00015270C25002C8FD0F06806220068A11D4D
+:1035E0000EF032F8D4E016270725002C84D0317B6A
+:1035F000A1710178082219E00170C9E01427122591
+:10360000002C92D000980099C07BA21D103101F0CF
+:1036100024F9B089E081207C01210843F921084088
+:103620002074AC480068C030017802221143E3E7FF
+:1036300017273825002C7DD03221A01D0FF001F96D
+:103640000020A071207A03210843A24A2072116849
+:10365000FB260B7F30405B07DB0F9B00184320727B
+:10366000B0204058407A800751D0A07A8A7D400827
+:10367000D2074000D20F1043FD221040A0728B7D74
+:1036800030409B07DB0F9B00184308231843EF23B0
+:103690001840A0728A7DE07AD206D20F30409200A4
+:1036A0001043E072F72210408A7DD206D20FD2007A
+:1036B0001043E072088BA0812046102264310E3046
+:1036C0000FF062F88349A07F0968C0078A7EC00FA7
+:1036D00052001043A0770A7F400852074000D20FE3
+:1036E0001043A077084644304DC820344DC4303CC8
+:1036F0003D20405C224630323E3101F0AEF8754844
+:1037000000688030006B417A8908890041723FE08F
+:10371000327B022A14D017273825002C2ED0012AFC
+:103720001BD0032A1BD0042A1CD0052A1AD06A49B0
+:103730006A4801E022E024E0B1300FF0C2F927E04E
+:1037400019270725002C19D0898AA1800121A17190
+:1037500041784908490041701AE0012000E0022048
+:10376000A07106E0707B0007000F8030A071052A71
+:1037700002D00020E0710BE00120FBE704980580F7
+:103780000CE09F205449C000D7E7317A002908D0C7
+:103790000498002C058001D027806580002005B0AA
+:1037A000F0BD19270725002CE8D00021C943A180CE
+:1037B0000021A1714178FD2299E600B595B001F094
+:1037C00047F8022803D001F043F8032819D11B2140
+:1037D00008A801730021817369460BA808F0A8FBB3
+:1037E000002804D1684640781B2802D0032015B079
+:1037F00000BD002108460CF0D2FC68468078002805
+:1038000001D00820F3E70120FFF7B2F90020EEE72E
+:1038100070B500252F4C002807D0022817D0A9200A
+:103820002D49C0000FF04DF970BDFFF7C6FF00280D
+:10383000FAD1FEF7DDF9222101700572FEF7F4F9E5
+:103840002068C030417802221143417070BDFEF7FC
+:10385000CFF912210170012101722168A0318A8AF9
+:103860004281CD77FEF7E0F92068C030417804222C
+:10387000EAE770B50D46040004D155201649000151
+:103880000FF01FF92078012804D0134914480FF0D5
+:1038900018F970BDA18813480E4E814209D1E28803
+:1038A000824206D130681321A030808AFFF7ACFA3B
+:1038B00070BD814202D1E088002815D01220287006
+:1038C000687808210843687007CC083507C50021CF
+:1038D00011E0000048000020742F00003D040000AB
+:1038E0006E050000FFFF0000002278231146022031
+:1038F0000CF0B3FB02213068A030C17770BDF748EF
+:103900000068C0308078704738B5F44C05460178BF
+:1039100020680B00A0300FF0D9F909863506067132
+:1039200013365A758600807F052803D0EC49ED4890
+:103930000FF0C7F820680422017F114301775DE092
+:10394000A98800291ED0808AE74988421AD0A86831
+:10395000002804D1E348E2490F300FF0B2F8A8681C
+:1039600006220A38A86000902068AB88A030808AC0
+:10397000042101F0B7FE002804D0DA48D8491430F9
+:103980000FF09FF838BD2979807F02290BD00428D9
+:10399000F8D0284600F072FF20681321A030808AFA
+:1039A000FFF732FA38BD062804D0CE48CC491E3085
+:1039B0000FF087F8284600F061FF20680122C03030
+:1039C0004178114341700520FFF7D2F838BD00F06F
+:1039D0003FFF052808D000F03BFF042804D0C14871
+:1039E000BF493C300FF06DF80ECDC0480361C26096
+:1039F0008160A2210170FEF72CF938BD284600F045
+:103A00003DFF38BD00F024FF052808D000F020FF5E
+:103A1000062804D0B348B2494D300FF052F80720C1
+:103A2000FFF7A6F8EAE7AF48AD495630A8E7FFB57B
+:103A300093B00124684603218470C9021D460180A9
+:103A400009F063FF00226946012003F027F80646CB
+:103A500009F05FFF002E5CD1684615218470490291
+:103A6000018000271C2101A808970EF0ECFE012020
+:103A70000146103108A801700020014608A84170D5
+:103A80008178F9200140891C214308A8817068468B
+:103A9000017902263143017114998185C7851F215F
+:103AA000018608A80A9013980D906846099009F0BD
+:103AB0002CFF0EAA09A901A802F0D4FD074609F0BF
+:103AC00028FF002F02D0384617B0F0BD834F68465C
+:103AD0003968008F4880684684708549018008A84D
+:103AE0008078F9210840801C4108490008A88170AD
+:103AF00068468685068615A80D9009F006FF0EAA71
+:103B000009A901A802F0AEFD064609F002FF002E49
+:103B100001D03046D8E768463968008F88807449FC
+:103B200068468470C91C0180298810A801806988B2
+:103B30004180A9888180E988C18008216846818503
+:103B4000018610A80D9009F0E0FE0EAA09A901A8AF
+:103B500002F088FD044609F0DCFE002C01D020466E
+:103B6000B2E768463968008FC8800020ACE770B5BE
+:103B700004465E48C421A8300EF065FE5B48574DF0
+:103B8000A83000212860C943A030818200268675B4
+:103B90000120FEF7EDFF2868BF210E5401460931D0
+:103BA0000830FDF71CFF296808462D311D30FDF750
+:103BB00072FF002C26D02868B0210C501E21A18154
+:103BC000217A8F2211401031217201461831216172
+:103BD00009396161491CA1610839E161491C21620F
+:103BE0009B31616287392160103161601339E16274
+:103BF000091F21637E3121643039616310318430C3
+:103C0000A163E06370BD35480068A030807F042860
+:103C100001D0002070470120704730B504460520D0
+:103C2000800395B0844208D3012080043149201AD2
+:103C3000884202D33048844202D3102015B030BDF0
+:103C400026490868A030807F012801D00820F5E7C8
+:103C5000FFF7D9FF002801D01120EFE70D68012000
+:103C600028722278002A08D024491720012A0AD075
+:103C7000022A1FD0032A25D121E03220694608708C
+:103C80000020287205E0A2799209032A1AD1694618
+:103C9000087000A80622611C02300EF075FD28464F
+:103CA0000622611C09300EF06FFD09A9684608F074
+:103CB0003FF9C3E7A2799209012A03D1E7E7A27984
+:103CC0009209E4D00846B9E707214907012210B557
+:103CD00041189203914213D3102010BD48000020D8
+:103CE000742F000085050000FFFF0000AC110020CC
+:103CF000012A00000000FC1F0040002002320000EA
+:103D0000F949024609680B7A0931184600F0A5FD09
+:103D10000020E2E7FFB599B005460020694608712A
+:103D2000087208A9087408751E461446052001216A
+:103D300080038904ED4AEE4B002D06D085420DD359
+:103D40006F1A97420AD39D4208D2002C09D08442B0
+:103D500004D3601A904201D39C4202D310201DB0BC
+:103D6000F0BD2846204318D01F270CAB01AA0097AE
+:103D700028461A99FEF7AAFF0028F0D10DAB02AA37
+:103D8000314620460097FEF7A1FF0028E7D168469C
+:103D9000007AC10703D00A20E1E70720DFE78007A8
+:103DA00005D568460079800701D50B20D7E7FFF7D6
+:103DB0002AFF002801D01120D1E703AF002D0FD03A
+:103DC0001A20694608731A9888732946F81C1A9AAB
+:103DD0000EF0DAFC0EA903A808F0AAF80028BED15C
+:103DE000002C0ED02021684601738673324621468E
+:103DF000F81C0EF0C9FC0EA903A808F099F80028D9
+:103E0000ADD1B94908A80968007C08700020A6E770
+:103E1000F0B5044695B0002014900520800384423C
+:103E200075D301208004B14F201AB8426FD3B04837
+:103E300084426CD2207801280CD105216068890366
+:103E4000884264D301218904411AB9425FD3A84949
+:103E500088425CD200F0FCFC022809D000F0F8FC9B
+:103E6000032805D0A048BE210068095C012902D0C2
+:103E7000082015B0F0BDC121095CCA06920F03D11C
+:103E80008A0701D4490701D51120F2E721780129D9
+:103E900015D0228A974D1346203BAB4272D202299D
+:103EA00001D0032901D1A02A6CD3012907D00278BF
+:103EB000D20704D0628A002A64D0B42A62D80029CA
+:103EC00006D0012908D0022904D003295AD110E0D4
+:103ED000002512E0022510E061680125097800291B
+:103EE0000BD0012907D0022905D0032903D082482D
+:103EF000BFE7032501E001211491217A002907D0B1
+:103F0000012907D0022907D003293BD106E037E079
+:103F1000002604E0012602E0022600E00326002D30
+:103F200001D0022D3FD1002E3DD0E168002929D0DB
+:103F30000A79002A27D0082A24D80B7B9C46082B14
+:103F400020D8002A0CD005230A689B039A4217D375
+:103F500001239B04D31ABB4212D3654B9A420FD262
+:103F60006246002A13D0896805229203914207D342
+:103F7000012292048A1ABA4202D35D4A914206D3C0
+:103F8000102076E75EE00B7B002B5BD0D5E7017855
+:103F9000890702D05848401E6BE7022D03D1022E3C
+:103FA00050D0032E4ED0182269460A70228A4A80C9
+:103FB000228A8A808D71007A0127002802D0012888
+:103FC0007ED102E00020C87100E0CF711498087221
+:103FD000217802A80130012922D006210EF031FCFF
+:103FE00007216846C173067409A907F0A1FF0028DC
+:103FF000C7D10A206946087009A9684607F098FFEA
+:104000000028BED13A206946087009A9684607F021
+:104010008FFF0028B5D1002D08D0022D06D04AE030
+:1040200061680622491C0EF0AFFBD9E7002E42D092
+:10403000002623E00168B00009580978002903D060
+:10404000012905D0072014E700216A46917001E09C
+:1040500069468F70E16806220968095800A8491C62
+:1040600003300EF091FB0B206946087009A96846E1
+:1040700007F05EFF002884D1761CF6B2E068017973
+:10408000B142D7D8002612E08068B100415800A89C
+:10409000102202300EF078FB3B206946087009A917
+:1040A000684607F045FF0028CDD1761CF6B2E068DF
+:1040B000017BB142E8D81B2168460170877000E09F
+:1040C0002EE009A907F034FF0028BCD108A84079E8
+:1040D0001B2825D1002D15D0012D0FD0022D21D068
+:1040E000032D12D11EE00000480000200000FC1F3C
+:1040F00000400020E13F0000023200000320FEF7F4
+:1041000037FD11E00320FEF733FD608A00280BD055
+:1041100000228300114610460BF09FFF002803D0B9
+:104120000320A6E60220EEE70020A2E670B586B0E6
+:104130000C0006460CD00520800384424BD301209E
+:104140008004FD49201A884245D3FC48844242D26B
+:10415000FB4DBF212868095C022903D0C03040789C
+:10416000400702D5112006B070BD002C04D02046B7
+:10417000FEF780FD0028F6D13046FEF746FD012807
+:1041800003D0022823D0EF48EDE721001BD10820FF
+:1041900069468882286801ABC08805AA002103F01F
+:1041A00048F80028DFD16846808A082801D003201B
+:1041B000D9E7684681888181C188C18101890182EE
+:1041C0004189418203A9304601F0E5FBCBE7002C91
+:1041D00001D00620C7E71020C5E770B50C4605469C
+:1041E000FEF713FD012803D0022801D0D54870BD89
+:1041F00021462846FEF708FE70BD00B50146143082
+:1042000095B0192801D2880707D008461E3004D07F
+:104210000A3002D0072015B000BDFFF7F4FC0028DB
+:1042200001D01120F7E7C648312200684170684686
+:104230000270817009A907F07BFEECE701B582B03E
+:10424000022069460880BE4802AB00686A46808842
+:10425000002102F073FE69460988022900D003207C
+:104260000EBD38B502216A46118007214907012297
+:1042700041189203914201D3102038BDB049034642
+:1042800009686A468C880021204602F0D2FF694600
+:1042900009880229F1D0032038BD3EB50446082024
+:1042A0006946088005208003844208D301208004E9
+:1042B000A149201A884202D3A048844201D3102089
+:1042C0003EBD2046FEF7D6FC0028F9D1208869467D
+:1042D00088806088C880A0880881E08848819848E4
+:1042E00001AB00686A46C088002102F027FE6946DB
+:1042F00009880829E4D003203EBD1FB504460820E4
+:104300006946888105208003844208D30120800407
+:104310008949201A884202D38848844202D3102057
+:1043200004B0DAE486486B46006803AAC08800211E
+:1043300002F07FFF0028F3D169468989082901D05E
+:104340000320EDE769460988218069464988618034
+:1043500069468988A1806946C988E180E0E7FEB5A1
+:1043600005460520800317460E46814208D30121E9
+:104370008904714A731A934202D3704B9E4201D34F
+:104380001020FEBD1F2F01D90C20FEBD6C4C8542B4
+:104390002AD3681A904227D39D4225D2206801A9CA
+:1043A000408802F07DFD0028EFD1287869464871E9
+:1043B000206801A9408802F056FD0028E5D1694631
+:1043C0000090087802210843694608704979090776
+:1043D00003D0082108436946087020686946408870
+:1043E00002F0EBFC0028D0D169460F8120683346EB
+:1043F000408802AA002102F0A1FD69460989B9425C
+:10440000C3D00320FEBD38B50C4607210122490761
+:104410009203002802D04318934202D261189142BD
+:1044200001D3102038BD21886A461180002801D0B0
+:1044300000290BD04249034609684D8800212846CF
+:1044400002F0F7FE69460988218038BD0C2038BD8E
+:1044500010B50C460521890386B08C4208D3012192
+:104460008904354A611A914202D334498C4202D3FD
+:10447000102006B031E432490968A031897F05294E
+:1044800001D00820F5E7FEF7C0FB012803D0022881
+:1044900026D02C48EDE720881E2801D20720E8E727
+:1044A0000620FEF765FB052168460170007981084A
+:1044B000A0788900C007C00F014368460171FB2046
+:1044C0000140A0788007C00F800001436846017159
+:1044D0002188C18009F025FD0028CAD00320C8E743
+:1044E0000620C6E770B586B014460D46FEF78DFB74
+:1044F000012803D0022801D0124834E6104EC02112
+:104500003068095CC90706D0BE21095C042902D0C5
+:10451000002D02D05AE0082025E6052189038C42AF
+:1045200008D301218904044A611A914202D3034944
+:104530008C4209D3102016E60000FC1F004000202A
+:104540004800002001300000A178C906490F042965
+:104550000CD8E178072909D3102907D822798A4293
+:1045600004D3102A02D822881E2A01D00720FAE597
+:104570008030026BF7239172026B2179D172026B4A
+:10458000117A1940A3789B06DB0FDB0019431172E7
+:10459000026B21889181026BA378517ADB0789082D
+:1045A0008900DB0F19435172FB231940A378026B7A
+:1045B0009B07DB0F9B0019435172006BA278017AB5
+:1045C000D206C908C900520F114301720B20694677
+:1045D0000870852D25D008DC002D1AD0812D1AD029
+:1045E000822D1AD0832D08D119E0862D1BD0882D5D
+:1045F0001BD0892D1BD08A2D1BD00B2008710520C4
+:10460000FEF7B6FA684609F08CFC002813D00320A8
+:10461000A9E50020F2E70120F0E70220EEE7032001
+:10462000ECE70520EAE70620E8E70820E6E70920AE
+:10463000E4E70A20E2E73068C03001784908490021
+:10464000017000208FE570B5924E0D46316886B03E
+:10465000C03109781446090701D4082083E5FEF724
+:10466000D4FA012803D0022801D08B487BE5002D25
+:1046700013D005208003844208D301208004874999
+:10468000201A884202D38648844201D310206AE56A
+:10469000012D0BD0022D02D106E0002C01D0072005
+:1046A00061E50020029005E0022000E0012069465B
+:1046B00008710294032069460870684609F031FCCD
+:1046C000002801D003204EE53068F722C030017881
+:1046D00011400170002046E570B594B014460E46B6
+:1046E000FEF793FA012804D0022802D06A4814B0D9
+:1046F00070BD684D2868C0300078800701D408205C
+:10470000F5E7002C01D00720F1E7FFF77CFA00283D
+:1047100001D01120EBE7002E1DD02D21684601703D
+:104720002C68B420015B684641801022B11C01A8AE
+:104730000EF02AF8207FFB210840B17CC907490F01
+:1047400008432077B07CFF214008A076E08A8231C0
+:104750000843E08207E02E21684601702868A030F7
+:10476000818A6846418009A9684607F0E1FB29680B
+:10477000FD23C0310A781A400A70B8E710B50C461C
+:10478000FEF743FA012803D0022801D0424810BDA9
+:1047900005208003844208D3012080043F49201A69
+:1047A000884202D33E48844201D3102010BD2046E7
+:1047B000FEF73AFA002010BD10B594B00446FEF79B
+:1047C00024FA012804D0022802D0334814B010BDC6
+:1047D00030480068A030807F04280ED03820694619
+:1047E00008704C8001200871487109A9684607F0DB
+:1047F0009FFB0028EAD00B20E8E70020E6E710B591
+:1048000094B00446FEF701FA012803D0022801D033
+:104810002148DBE71F480068A030807F04280BD0C8
+:104820003820694608704C8000200871487109A939
+:10483000684607F07DFBC9E70020C7E71548006818
+:10484000A030807F052801D30120704700207047E9
+:1048500010480068A030807F704708B513460028D4
+:1048600006D010A00068009048796A468009105C64
+:1048700018700622581C0DF087FF08BD10B50446BD
+:10488000FDF7B6F9A22101700ECC08300EC0FDF77D
+:10489000CBF910BD48000020013000000000FC1FD3
+:1048A000004000200302FF01FFB581B001980E46D1
+:1048B000C078174610360E37022809D0032840D09A
+:1048C00005287DD0F2A1F7480EF0FBF805B0F0BD49
+:1048D000CC890A2060430E30188031230A98002AC0
+:1048E0000380F3D04868008890800020D080108139
+:1048F000097B9481891FCDB21AE0308871683880B5
+:1049000048780A7800021043F880C8788A78000254
+:1049100010433881BA1C091D28460AF014FF002DE7
+:1049200001D0002802D000203871788008360A377C
+:104930002046641EA4B20028DFD101990020C8706F
+:10494000C4E7CC890A2060430E30188032230A98CD
+:10495000002A0380BAD04868002500889080D5805E
+:104960001581087B401FC0B20090948142E07168BD
+:1049700032880878FA803A79C30752085200DB0F70
+:104980001A43FD231A408307DB0F5B001A43FB2306
+:104990001A404307DB0F9B001A43F7231A40030713
+:1049A000DB0FDB001A43EF231A40C306DB0F1B01AA
+:1049B0001A43DF231A408306DB0F5B011A4300E032
+:1049C00020E0BF231A404306DB0F9B011A433A71D4
+:1049D000C00978718A784B781002184338813A46BA
+:1049E000C91C00980AF0AFFE002801D0BD703D80C0
+:1049F00008360A372046641EA4B20028B7D10198B1
+:104A0000C57063E7087BCC89801E85B228460830D4
+:104A100060431030188034230A98002A03808FD016
+:104A200048681746008890800020D08010819481CB
+:104A30001037E000D581C0190CE03088388000982C
+:104A400078602A46716800980DF09EFE009808363E
+:104A50000837401900902046641EA4B20028ECD10B
+:104A60006BE7FFB50546C07881B00C460A9E03008F
+:104A70000EF02CF90BA3071733414F6D8F9D9D9DB1
+:104A8000A300207B1746082806D0032804D08548B9
+:104A90007FA153300EF015F804990E2008803020C5
+:104AA0000CE0207B1746042804D07E4878A17030A3
+:104AB0000EF007F804990E20088031203080002F76
+:104AC00044D060680088B880607AFF300130F88098
+:104AD000E08938810020B88137E0207B1746042820
+:104AE00004D070486AA18C300DF0EBFF04990E20C1
+:104AF00008803220E2E7207B1746022804D069486C
+:104B000063A1A8300DF0DDFF04990E20088033204A
+:104B1000D4E7207B1746042804D062485CA1C33048
+:104B20000DF0CFFF04981021018034203080002F39
+:104B30000CD060680088B880607AFF300130F8805F
+:104B4000E08938810020B881F881E870BEE6207BDA
+:104B50001746052806D0062804D052484CA1E0305C
+:104B60000DF0AFFF04981221018035203080002F16
+:104B7000ECD060680088B880607AFF300130F8803F
+:104B8000E0893881E089B88100203882A988F981DC
+:104B9000DBE7207B1746072804D042483CA1F730CA
+:104BA0000DF08FFF04990E200880362086E70096CE
+:104BB0002846049B00F02BFD88E635A13A480DF00D
+:104BC00080FF83E670B5054600780C460826030092
+:104BD0000EF07CF8124C3434241C380A0A0A0A0AF3
+:104BE0000A0A0A0A0A0A0A4C6878002804D02E48E1
+:104BF00027A12C300DF065FF002C03D12A4824A1F9
+:104C00002D3008E060783043607020E0002CF9D14E
+:104C100025481FA135300DF054FFF3E7002904D0DB
+:104C200021481BA13D300DF04CFFFCF7E1FF04468D
+:104C3000407830436070FCF7F7FF08E01A4814A191
+:104C4000473002E0184812A14C300DF03AFF002C1A
+:104C50000AD06078000707D593202070204658229C
+:104C600029460830FBF7B0FA002070BD0E4808A1B5
+:104C70005030EAE710B500200C4C0D490346C20045
+:104C80008C525218401C0006D370000EF7D010BD95
+:104C90007372635C67617474635F636F72652E63C4
+:104CA000000000005A020000B2030000FFFF0000F5
+:104CB0004C000020FD4908800120887000207047CA
+:104CC000FA4900208870704710B50021F748C943A1
+:104CD00001800021C17007F065F9D8E7F7B584B00D
+:104CE0000546002768460781878068680C4600886B
+:104CF00000F0EAFB0646287A032805D0002E03D1EF
+:104D0000EB49EC480DF0DDFE287A2146C01E123139
+:104D1000009103000DF0DAFF0FF1F0EF3D09AA4614
+:104D20005C6D34B3CCF28B8BEF00F078012803D0AC
+:104D3000DF49AD200DF0C5FEA8896946C0000E30E0
+:104D4000888030200881002C22D068680188A180EA
+:104D5000E7802781A989A18100200DE0C100B279F7
+:104D600009190A74B288CA8182005219D3894B8208
+:104D7000128A401C8A8280B2A1898142EED8D6E094
+:104D800002A8009001AB22462946304600F0CAFB3B
+:104D9000F0E002A8009001AB22462946304600F020
+:104DA00003FCE7E0F07806281AD0FF20C049223043
+:104DB00014E068680188A180E7802781A989A18122
+:104DC000B188E181E9892182EA89296900982BE08B
+:104DD000F078062804D0FF20B5493C300DF071FE74
+:104DE000E88969461230888035200881002CE0D19E
+:104DF000C0E0F078072804D0FF20AD4956300DF010
+:104E000060FEA88969460E30888036200881002C13
+:104E1000BED068680188A180E7802781A989A18127
+:104E20002046AA890E3029690DF0AEFC7FE0E889A2
+:104E30006946123080B2382288800A81002C78D0EE
+:104E400068680188A180E7802781A989A181287AE3
+:104E5000102809D00221A173E9892182EA892969F0
+:104E600000980DF091FC85E00121F4E702A8009084
+:104E700001AB224629463046FFF716FD7AE0F0786E
+:104E8000082803D08A498C480DF01BFE142069467F
+:104E9000888037200881002C6CD068680188A18048
+:104EA000E7802781A989A18167820120A0733EE064
+:104EB000F078092804D080487D4917300DF001FEB4
+:104EC000288A69461430888037200881002C51D008
+:104ED00068680188A180E78004212781A173A989DE
+:104EE000A181E9892182298A618220462A8A143097
+:104EF000696999E702E038E01CE024E0F0780A28CC
+:104F000004D06D486A4932300DF0DBFD142069464B
+:104F1000888037200881002C2CD068680188A18007
+:104F2000E78027810521A173A78127826782F77017
+:104F300020E017E002A8009001AB22462946304647
+:104F4000FFF78FFD16E00D206946392288800A811F
+:104F5000002C07D00120E08054480188A1802781DF
+:104F6000277307E00699088010E0524850493C300A
+:104F70000DF0A7FD6846069980880880002C05D0B2
+:104F8000684600892080684680886080002007B0DD
+:104F9000F0BDF7B594B015460F46149800F09FFA8F
+:104FA00004000AD0032000F087FB022802D2E07838
+:104FB000002804D0112017B0F0BD4048FBE71720AF
+:104FC000694601260883002D0FD003216846017130
+:104FD0001021018210A80246059004A928460AF073
+:104FE000D8FB00280DD00720E5E7082168460171AD
+:104FF00000210781C943418105218673C90281814E
+:105000000CE0A878A0712888A080684605218673E6
+:10501000C902818100210781C943418109AA023265
+:1050200006A901A806F0F7FF002802D000F06AFAEE
+:10503000C1E707A800906846038B04220321149857
+:1050400000F050FB0028B6D1E670B4E770B592B01E
+:105050000D0006460ED000F042FA04000CD00320EA
+:1050600000F02AFB022802D2E078002806D01120A6
+:1050700012B070BD1020FBE71048F9E71721684611
+:10508000818004210172298881816988C18101217F
+:1050900081740B4901820AAA023201A902A806F012
+:1050A000BAFF00280ED000F02DFAE1E74C000020F6
+:1050B000904C00003B04000063020000013000003F
+:1050C0000228000008A80090684683880422032173
+:1050D000304600F007FB0028CAD10221E170C7E783
+:1050E00070B592B00D0006460DD000F0F8F904003E
+:1050F0000BD0032000F0E0FA022802D2E07800286A
+:1051000005D01120B4E71020B2E7FA48B0E7172124
+:105110006846818004210172298881816988C18162
+:1051200001218174F44901820AAA023201A902A86C
+:1051300006F071FF002802D000F0E4F998E708A813
+:1051400000906846838804220321304600F0CAFAA2
+:1051500000288DD10321E1708AE770B592B00D006F
+:1051600006460DD000F0BBF904000BD0032000F080
+:10517000A3FA022802D2E078002805D0112077E7B0
+:10518000102075E7DB4873E7022168460172298821
+:1051900081816988C181172181800AAA023201A90F
+:1051A00002A806F038FF002802D000F0ABF95FE754
+:1051B00008A800906846838804220321304600F046
+:1051C00091FA0028DBD10421E17051E7F0B591B0EC
+:1051D00015000E4607460ED000F081F904000CD0F1
+:1051E000032000F069FA022802D2E078002806D0F5
+:1051F000112011B0F0BD1020FBE7BE48F9E71721E0
+:105200006846818004210172298881816988C18171
+:10521000B1788174318801820AAA023201A902A8F8
+:1052200006F0F9FE002802D000F06CF9E1E708A8CA
+:1052300000906846838804220321384600F052FA21
+:105240000028D6D10521E170D3E7F7B592B0154615
+:105250000E46129800F043F904000AD0032000F033
+:105260002BFA022802D2E078002804D0112015B0D1
+:10527000F0BDA048FBE70627002D12D06846077254
+:105280008681C581A5801720694688800AAA0232D6
+:1052900001A902A806F0BFFE002807D000F032F9ED
+:1052A000E5E70521684601728681EBE708A80090D2
+:1052B0006846838804220321129800F013FA00281C
+:1052C000D5D1E770D3E7F7B592B016460D000ED0F2
+:1052D000129800F004F904000BD0032000F0ECF960
+:1052E000022802D2E078002805D01120BFE7102064
+:1052F000BDE78048BBE7072768460772868117210C
+:10530000049581800AAA023201A902A806F083FE50
+:10531000002802D000F0F6F8A9E708A80090684637
+:10532000838804220321129800F0DCF900289ED122
+:10533000E7709CE7F3B5172091B00C46002915D013
+:1053400021780B000DF0C2FC062B05051A041C2B5E
+:105350001520C01EE28880B2002A02D0A368002B6C
+:1053600004D0824204D90C2013B0F0BD1020FBE71A
+:10537000042905D0A088002811D101E00620F3E718
+:10538000119800F0ACF805000BD02078092701280F
+:105390001AD0022807D0042824D0052835D00720A9
+:1053A000E2E75448E0E76846077161880181E188D7
+:1053B0004181A06808260390304600F07DF9072857
+:1053C00029D34C48801CCFE70C21684601716188C5
+:1053D0000181E1884181A06803900EE0E87800280F
+:1053E00011D118E00D216846017161880181A18801
+:1053F0004181E1888181A06804900326304600F055
+:105400005BF90228EAD31120AEE70E21684601714C
+:10541000217B0172F1E717216846018309AA023254
+:1054200006A901A806F0F7FD002802D000F06AF8EE
+:105430009AE707A800906846038B0422314611982A
+:1054400000F050F900288FD12178012907D00229D6
+:105450008AD0042905D0052905D0032084E7082136
+:1054600002E0EF7080E70A21E9707DE730B591B086
+:105470000C46054600F033F8002808D0032000F061
+:105480001BF9022805D31B48801C11B030BD1948F8
+:10549000FBE70F216846017104811721018309AAE6
+:1054A000023206A901A806F0B6FD002802D000F0DD
+:1054B00029F8EAE707A800906846038B0422032135
+:1054C000284600F00FF9E0E70C49884205D00C4966
+:1054D0000988814201D10A4870470020704710B501
+:1054E000FFF7F2FF002802D08178C90700D1002021
+:1054F00010BD00000130000003280000FFFF000085
+:105500004C000020002806D0012805D0052805D031
+:10551000062805D0032070471120704708207047E7
+:105520005C487047FFB583B003980C9EC0781D4659
+:1055300014460F46012803D05749D2200DF0C1FA76
+:10554000F889C0000E30288030203080387B001F62
+:10555000C0B20190002C26D078680088A08000207E
+:10556000E0802081F889A081002616E0F00005196E
+:10557000C01900902A4641690E3201980AF0E3F8FA
+:10558000002802D000202874E8810098761C008A48
+:1055900068820098B6B2408AA882A089B042E5D855
+:1055A00003990020C870F2E4F8B50646C0781F469B
+:1055B00014460D46042804D0FF20374903300DF06F
+:1055C00080FAA889062148430E3038803321069896
+:1055D000002C01801AD068680088A0800020E0803C
+:1055E0002081A989A18103460CE019460622514376
+:1055F0004A190919D789CF81977C8F74128A5B1C4D
+:105600000A829BB2A1899942EFD8F070F8BD70B5BB
+:1056100014460546142204981A8037220280002C72
+:1056200018D0486800260088A080487AFF300130F2
+:10563000E080C8892081C889A0816682E87808282E
+:1056400009D0092811D00A2819D0134913480DF0A0
+:1056500038FAEE7070BD087B0C2804D00F480E4954
+:105660000C380DF02EFA012012E0087B0D2804D032
+:105670000A48094908380DF024FA042008E0087B9C
+:105680000E2804D005480449001F0DF01AFA052021
+:10569000A073DEE702300000904C000081030000A0
+:1056A00001460020FA4A02E0401C082803D24300C9
+:1056B000D35A8B42F8D1704730B50446F44A0020E3
+:1056C000163A117953790AE05518AD79A54201D1FE
+:1056D000401CC0B2491CC9B2102900D100218B4224
+:1056E000F2D130BDFFB5EA4881B0163841790A9C45
+:1056F000491CCDB21E46102D00D10025E4481638B5
+:105700000079A84202D1042005B0F0BD0820FFF7BF
+:10571000D3FF0746072804D9FF20DEA1A5300DF0EE
+:10572000D0F90298082801D1072F17D001982080BE
+:10573000301D6080002060712071E6800398208118
+:10574000204606F019FC00280AD0D14802991638E4
+:105750004379821D995445710020D5E7D248D3E79B
+:10576000FF20CCA1B7300DF0ACF90320CCE7F0B5A9
+:105770008DB0044600256846057116468C46062005
+:10578000FFF79AFF00281CD121780127C8070028BD
+:1057900001D0132917D9684687766178C17602212E
+:1057A0008183C58304A8009070680C2300880522BB
+:1057B0000621FFF797FF002803D0B6A185200DF042
+:1057C00080F90DB0F0BDB24816380278002AF8D042
+:1057D000427863789A42F4D1012918D0132919D15B
+:1057E0006146062916D10570002101200AF0D7FC78
+:1057F00068460771706801886846C1800021C94306
+:105800000181607922790102114368461AE06146FC
+:10581000062908D0684600790028D2D0314601A870
+:10582000FEF727F8CDE70570002101200AF0B7FC4C
+:105830006846077160792279010211436846018147
+:105840000021C9434181E9E7914810B5002116388C
+:1058500001704A1E428041700171417101200AF0BD
+:105860009EFC10BD10B5FFF7EFFF002088490246EF
+:105870004300401CCA520828FAD310BD8449163987
+:10588000488000207047DFE770470EB50121684669
+:10589000017086498180C1800021FDF7EAFF0EBDBD
+:1058A000F7B505460078002700090C463E4601285A
+:1058B00004D0FF2077A168300DF003F9287A022880
+:1058C0000CD0FF2073A17E300DF0FBF80298002C65
+:1058D000068001D0278066800020FEBDEA897027FF
+:1058E00010460A3086B2002C0BD068680088A08071
+:1058F000A8892081E28020460A3029690CF044FF03
+:10590000E4E702980680E7E7F0B543680246D979F4
+:105910009C79090221435C7A1E7A25025C88981DD5
+:105920003543241F87B0A1421DD11B79022B1AD108
+:10593000042D1AD0052D2AD0062D1AD0402D12D3B1
+:10594000061D0F4614462846FFF7AAFE08280AD06F
+:105950001120207002202072A581E78126616078E5
+:1059600008210843607007B0F0BD001D00F0E1F8A9
+:10597000F9E7041D0D46FEF761FF0028F3D006216C
+:10598000684601700194057208F0CBFAEBE7001D40
+:10599000FFF7EDFEE7E710B53D4C8AB0163C2278E4
+:1059A000012A26D012236A46937363789B1CD37313
+:1059B000082313820B8853824B8893828B88D3826F
+:1059C000C988118301A900910C2305220721FFF743
+:1059D00089FE00280BD10022F023114601200AF095
+:1059E0003CFB012020706078801C607000200AB0B1
+:1059F00010BD1120FBE7F0B5254C0027163C87B001
+:105A00000646A51D1FE060792179884204D1112046
+:105A100020A140010DF055F82079405D042804D004
+:105A2000082808D17F1CFFB205E0072069460870EE
+:105A3000684608F076FA2079401CC0B22071102820
+:105A400001D1002020713046761EF6B20028DAD14E
+:105A5000384688E710B50446402801D2072010BD1B
+:105A6000FFF71EFE082802D03120000210BD0021E1
+:105A7000074802E0491C082903D24A00825A002A3A
+:105A8000F8D1082914D049004452002010BD00006C
+:105A90002E1300207372635C6C326361705F636FFE
+:105AA00072652E630000000003300000FFFF00005D
+:105AB0000420EBE700B5402801D2072000BDFFF726
+:105AC000EFFD082805D000213B4A4000115208464E
+:105AD00000BD052000BDF0B58BB016460C00074692
+:105AE00007D0002E05D06188402904D207200BB0D2
+:105AF000F0BD1020FBE72088002801D0172801D92D
+:105B00000C20F4E70846FFF7CBFD08280FD02588C6
+:105B100003A82A46314602300CF036FE01A8009058
+:105B200062882B4608213846FFF7DCFDDFE70520B9
+:105B3000DDE7F0B50E46074601468BB01446012559
+:105B4000304606F0E5FB08281DD10020694608858F
+:105B50000120FFF7B1FD002802D117206946088512
+:105B600003AB02330AAA39463046009406F0E3FF3D
+:105B700000280AD0022819D0032804D0FF200F499A
+:105B800002300CF09EFF2846B1E76846038D002BDB
+:105B9000F9D001A800906068042200880121FFF775
+:105BA000A1FD0028EFD00549EC20EAE76078002548
+:105BB000102108436070E6E72E130020945A00007D
+:105BC000002803D08178012939D101E010207047E5
+:105BD0000188FA4A881A914233D01BDCF84A881AA5
+:105BE00091422ED00BDC00292BD00320C002081AD2
+:105BF00027D0012825D001210903401A07E00128F8
+:105C00001FD002281DD0FF281BD0FF3801380028E4
+:105C100015D116E0FF220132811A904211D008DC22
+:105C200001280ED002280CD0FE280AD0FF2806D169
+:105C300007E0012905D0022903D0032901D0002063
+:105C400070470F20704700B50A2821D008DC0300F8
+:105C50000DF03CF80A1C2024241A24282224261A99
+:105C6000102819D008DC0B2816D00C2814D00D28C9
+:105C70001AD00F2808D111E011280FD0822807D0A0
+:105C800084280DD085280DD0032000BD002000BD44
+:105C9000052000BDCB4800BD072000BD0F2000BD82
+:105CA000042000BD062000BD0C2000BD70B50029F9
+:105CB0000BD0CB1FFA3B81241E46CDB2112B1BD239
+:105CC000012805D0022806D009E0002010701DE050
+:105CD000FF20043001E0FF200330814218D0330060
+:105CE0000CF0F4FF111613131613161613161616CE
+:105CF00013131313161316000846FF3881381F2894
+:105D000003D9FF39FE39022902D81570002070BD71
+:105D10001470072070BD00B503000CF0D7FF060417
+:105D200006040C080A0C002000BD112000BD07204D
+:105D300000BD082000BD032000BD00780207120F3F
+:105D400004D0012A05D0022A0AD10EE0000907D1A9
+:105D500008E00009012805D0022803D0032801D05B
+:105D60000720704708700020704706207047002801
+:105D700007D0012807D0022807D0032807D0072022
+:105D80007047002004E0112002E0212000E03120D3
+:105D900008700020704738B50C4605004FD06946A2
+:105DA000FFF7CBFF002822D12088032189028843F6
+:105DB000694609788907090D084320806946681CEF
+:105DC000FFF7BBFF002812D1218803200003814385
+:105DD000684600788007800C01432180A87840073E
+:105DE000820F2020012A03D0022A03D0072038BDC9
+:105DF000814300E00143218088B20105890F08D06A
+:105E0000012189038843A9780907C90F8903084339
+:105E1000208080B28104890F0AD0A9784004C90685
+:105E2000C90F400CC903084320808004800F02D1B1
+:105E30002088400403D5208840210843208000208A
+:105E400038BD70B504460020088015466068FFF72D
+:105E5000A2FF002815D12189A089814210D861684C
+:105E6000594E8978C90707D0711E884208D8314633
+:105E70000CF004FD298009E0FF21FF31884201D99F
+:105E80000C2070BDFF30FF300330288060688078C0
+:105E9000C007A08903D031460CF0F0FC03E0FF30CE
+:105EA000FF30033081B22980206881784748017330
+:105EB00020684649008820394885002070BD10B50B
+:105EC000137804785B08E4075B00E40F2343137046
+:105ED000FD2423400478A407E40F640023431370D7
+:105EE000FB24234004786407E40FA40023431370C9
+:105EF000F724234004782407E40FE40023431370BD
+:105F0000EF2423400478E406E40F240123431370B4
+:105F1000DF2423400478A406E40F640123431370B4
+:105F20000078BF244006C00F234080010343137054
+:105F3000002906D00878C10701D1800701D50120CA
+:105F400000E00020C0015906490E0843107010BD42
+:105F500030B50A8803239B0204889A4323059D0FCA
+:105F600002D1A3049C0F01D09B0F00E001239B02F0
+:105F70001A4303230A801B039A4303889804840F5F
+:105F800002D11805830F01D0800F00E0012000032B
+:105F900002430A8030BDF3B591B00D0018D01198BE
+:105FA000002818D0122128460CF04BFC01A9012032
+:105FB00007F0A8FD00242646374677E002290000B6
+:105FC00001280000023000000102000060130020E0
+:105FD000102013B0F0BD0720FBE76846007C0128C5
+:105FE0000BD16846C1890520C002081A0AD00128D1
+:105FF0000AD002280CD003280CD0042C0ED0052C7B
+:106000000FD10DE0012400E002246846868908E0F3
+:10601000032406E068460424878902E0052400E0A2
+:10602000062468468189119881423FD12C74002E44
+:106030003AD00BA800900CAB10220021304607F09C
+:10604000F3FD002820D16846808D2A46C0B20CA9F5
+:1060500009F079FB002817D1AE81002F24D00BA8BE
+:10606000009006AB13220021384607F0DDFD002822
+:106070000AD16846808D06A9C01E0331C0B22A1D10
+:1060800009F061FB002801D00320A2E76846817E69
+:10609000427E08021043E881062C05D16846007C48
+:1060A000A8726846C0892881002092E701A807F0FD
+:1060B00031FD002891D0FFF7C6FD8AE7002804D003
+:1060C000012903D0022904D003207047F949C98D62
+:1060D00002E0F8494031C988814201D1002070476F
+:1060E0000720704730B5F34C0025608B91B0C00B92
+:1060F0002ED1216900292BD0207B800728D40122B2
+:1061000068460271027200224272228B8281A28A48
+:10611000828204911721018309AA0023023206A971
+:1061200001A807F0BBF8002803D0FFF7F4FD11B079
+:1061300030BD207B02210843207307A800906946E8
+:106140000B8B208804220121FFF7CCFA05460BE0D7
+:10615000FBF74EFD842101700921017218341ECC19
+:106160000C301EC0FBF760FD2846E0E710B5D14CAF
+:10617000034621690020002909D02146012210315F
+:106180001846FBF707FF00202061A0820120217B39
+:10619000F9221140217310BD70B50C4605461C2133
+:1061A00020460CF04EFB00202080002D08D0012D51
+:1061B00004D0C1A1C5480CF084FC70BD062000E0ED
+:1061C0000520A07070BD10B507F090FA10BDFEB5A7
+:1061D0000546007800260C46374603000CF076FD95
+:1061E0000C91070C1D962F462F46486C89916868C4
+:1061F0000A38FBF72FFE89E0002904D0B348AEA18E
+:106200001B300CF05EFCFBF7F3FC044640780821E1
+:1062100008436070FBF708FD78E0002C04D1BB2038
+:10622000A5A180000CF04DFC284601F05BFA002887
+:106230006CD06078082108436070022666E0E88828
+:10624000694608800190002C04D1A0489AA12F3003
+:106250000CF037FC287807281CD10198C00B19D006
+:10626000944800218171A988818012E003264DE0C5
+:10627000002C04D1C52090A180000CF022FC8D4898
+:10628000017B89070BD50069002802D0E888C00B84
+:106290003CD00226607808210843607036E0291D52
+:1062A0008EC918308EC02838018802260122204667
+:1062B000FBF752FE0127EDE7002C04D183487EA1B5
+:1062C00064300CF0FEFB7B480821007B4007C00FC8
+:1062D0004600607808436070002E17D128790128A5
+:1062E00002D16879002811D02046FFF73FFF07460A
+:1062F0000CE0002CCED10D206FA180010CF0E1FB51
+:10630000C8E772486CA17A300CF0DBFB002C0CD093
+:106310006078000709D5002F07D18420207020461F
+:10632000582229460830F9F74FFF3046FEBDF7B531
+:10633000027A88B00C46054620460C30049006923E
+:1063400016300027921E02903E460A31594813002B
+:106350000CF0BCFC0ADF06E62AE62AE66A98C6E6E6
+:106360004288002A02D052270726DDE051271E2648
+:10637000002C7DD06A684F481288A2800122A27149
+:106380008079C0004019C089FFF705FE002877D149
+:1063900048488179C9004919C98921818079C0009B
+:1063A0004019408AA083BFE0688A009006980728B9
+:1063B00017D1E889C00B14D000985127223086B23B
+:1063C000002C55D0A8890499FFF7E5FD002857D186
+:1063D00068680088A0800220A071A889208101201F
+:1063E00041E000985027203086B2002C40D0A88988
+:1063F000FFF7D1FD002843D168680088A080A889F4
+:10640000E080287A07280AD002202072288AA083F8
+:106410000098E083204669692030009A01E001205D
+:10642000F3E70CF0B1F97FE0698A00910169002976
+:1064300002D0E989C90B22D00099512722318EB2AE
+:1064400000218171A9898180002C5FD00088A08003
+:10645000A8890499FFF79FFD002811D10220A0719F
+:10646000A88920810420A072288AE083009801E096
+:106470004CE005E020846969009A0298D1E7032086
+:106480000BB0F0BD007B400702D55127222601E06A
+:1064900050272026002C39D06868502F0088A08013
+:1064A00016D00220A0712146287B0831FFF774FE28
+:1064B0003AE00000401300207372635C67617474FB
+:1064C000735F636F72652E6300000000CB020000F3
+:1064D000287BA11DFFF760FE0020FFF747FE23E0A9
+:1064E000A9890089884207D154270626002C0DD09F
+:1064F00068680088A08017E053270826002C05D084
+:1065000068680088A080A889E0800DE00A9806806D
+:1065100010E055270726002CF8D00020A07103E0DA
+:10652000FD49FE480CF0CDFA0A98002C068001D0F7
+:10653000278066800020A3E7F948002101722038F7
+:10654000418081718180027BF923520852001A40F8
+:10655000027301618182704770B5F14C86B0203CB6
+:10656000208000206080A071A0806946012007F093
+:10657000C9FA102608E00199088802461207D20FCE
+:10658000B043120110430880684607F0C3FA0500C3
+:10659000F1D02069002804D0E048DF4931300CF008
+:1065A00090FA207B800704D5DC48DB4932300CF0C0
+:1065B00088FA822D04D02846FFF745FB06B070BD4F
+:1065C0000020FBE7D64810B52038017B012211439B
+:1065D0000173002141808171818006F05BFA10BD5A
+:1065E00010B5CF4C0020C043203C20800020FFF796
+:1065F000BDFD207B40084000207310BD70B5C84D24
+:106600000446203D287B800704D5C448C249493050
+:106610000CF057FA287BC00706D12888C149884268
+:1066200002D02869002801D0082070BD002C08D0B5
+:10663000A088162801D2092070BD20682861A08892
+:10664000A882FFF74FFD70BD10B50C4607F04BFA5E
+:10665000002803D0B049B4480CF033FA2046FFF7C5
+:10666000F2FA10BDF0B5AE4D0446203591B00020D1
+:10667000089068820E462882E8812946E8804039E1
+:106680000886694608830885088688838882A44826
+:106690000E90007A1746012808D0022806D0032859
+:1066A00004D0042802D0082011B0F0BD05239B03BC
+:1066B0009C421CD3012080049C49221A8A4216D392
+:1066C0009B4A944213D29E4211D3331A8B420ED36B
+:1066D00096420CD26268002A16D005239B039A4288
+:1066E00005D3101A884202D39148824201D3102068
+:1066F000DAE760892189884203D801225202914257
+:1067000001D90C20D0E7089010AA0CA93046FFF759
+:1067100098FB0028C8D106A92069FFF73CFB002898
+:10672000C2D1206900280CD0607880070028684614
+:10673000008B03DA8004800F56D002E08004800FC3
+:1067400052D105A96069FFF726FB0028ACD160692A
+:10675000002808D06846808A0105890F012943D1A5
+:106760008004800F40D007A9A069FFF714FB002820
+:106770009AD16846008B800636D46846808A8006A7
+:1067800032D46846808B81062ED4A169002906D0B8
+:106790000105890F012927D18004800F24D0E068EA
+:1067A000002804D0007800281ED01C281CD25C4A87
+:1067B000611C123220460992FFF781FB0321002061
+:1067C0008902884301218902411868460D9101859B
+:1067D0000121817457490182514A0FA9153230684D
+:1067E00008F0D7FF002801D007205DE708A8007F48
+:1067F0004B49C01CC2B26A7100201031FF320090B8
+:106800000190FF3203460291039003320AA904A8C3
+:1068100007F004F9002827D141482038008E0B905A
+:106820003F4833893830326901461239029100936A
+:106830000192039010A90A8873890CA9306807F0A7
+:10684000EDF801007AD13648E98811308170090AE3
+:10685000C1700026009631386A79008E3146099B56
+:1068600007F05BF8002802D0FFF7EDF91CE70E985F
+:10687000807CC00928D068460D990185012181746A
+:10688000292109020182AE81287B61784008C9076D
+:106890004000C90F08432873FD2108406178204A51
+:1068A0008907C90F4900084328732A32901C022126
+:1068B000029200910190002303961F4A0AA904A89E
+:1068C00007F0ACF80100BDD1606800283FD0206916
+:1068D00000280DD106A90CA8FFF73AFB60788007C5
+:1068E00006D46946088B0321090388436946088357
+:1068F0000120694688740F48FE3008820E492089BD
+:10690000891E0BF0BBFF62680548089B2E3003967A
+:1069100000930192029012E0B8640000220400008B
+:1069200060130020FFFF0000260600000000FC1F8F
+:1069300000400020032800000302000086E00A4611
+:10694000002306A904A807F069F801007ED1207889
+:10695000C10601D480062BD56846068460690028EC
+:106960000DD105A90CA8FFF7F3FA6846818A032028
+:1069700080028143012080020918684681826946AD
+:10698000888A482108436946888201208874F8482B
+:106990000882F84908AA022001920291009000237F
+:1069A0000396F54A05A904A807F038F8010062D15A
+:1069B0002078C0072DD068460684A06900280DD134
+:1069C00007A90CA8FFF7C4FA6846808B0321890247
+:1069D0008843012189024118684681836846818B7A
+:1069E000402001436846818301218174E04908AA5F
+:1069F000491C0182DF480221801C01920091029013
+:106A000000230396DC4A07A904A807F007F8010051
+:106A100031D1E068002832D068460D990185012106
+:106A20008174D349891C0182E16808A80A78027040
+:106A300049784170E068418868464184E06801799E
+:106A400008A80171E068C18808A800E013E041715E
+:106A5000090A8171C7480722001D08A90092019107
+:106A60000290412200230396D2000AA904A806F04E
+:106A7000D5FF010003D00B98FFF7E6FD14E60321D4
+:106A80000E98002F017207D0E8883880E889788056
+:106A9000288AB880688AF880002005E6F0B50124CD
+:106AA0008BB016460F46012802D002281BD104E005
+:106AB000684605218474C90202E06846AF498474BF
+:106AC0000182002F11D00321002089028843012177
+:106AD000890241186846018506AA05A9384608F0CA
+:106AE00058FE002803D00720CAE41020C8E4A14DB6
+:106AF000B878303D287338882F46203F78856A461D
+:106B0000127D0020294606AB00920E310193FF3220
+:106B1000029103900346FF3203320AA904A806F04B
+:106B20007DFF002802D0FFF78EF8A9E4002E01D0E7
+:106B3000F88D30802C720020A2E470B592B0064629
+:106B4000012508A885708E496846018406F0DDFE9F
+:106B5000002208A90120FFF7A1FF044606F0D9FE94
+:106B6000002C02D0204612B070BD0024002E3ED072
+:106B70001C2168460BF067FE68460178202001431F
+:106B80006846017008A885707E49684601841194A2
+:106B90000794817FF9200140891C68468177002095
+:106BA0000146684601770020014668464177042186
+:106BB0008185C485018607A80A9011A80D9008A8B0
+:106BC000099006F0A2FE0EAA09A96846FFF74AFD41
+:106BD000054606F09EFE002D01D02846C3E7654815
+:106BE0006946098F503801816946898F4181614822
+:106BF000303804720020B6E7F7B55E4E9CB0002135
+:106C0000303E0091317A012904D0022902D00820B7
+:106C10001FB0F0BD57495039CA8D824201D00620BD
+:106C2000F6E71D98824201D10720F1E75348012180
+:106C300010AA9176401C1083002003239B02024679
+:106C40009A438B02D31810AA93846A4691844E49C2
+:106C5000D18410AA9077908317AA0A926A469185E8
+:106C60000C9009A806F075FF00242546274604A9C4
+:106C700009A806F071FF002810D0822877D1002CD7
+:106C80006AD0002D68D010A80481458100240475C5
+:106C900018A8807812AD012860D077E06846807D22
+:106CA000002F1FD0012853D16846818A3348401CE9
+:106CB000814219D114A800906846408A0EAB102278
+:106CC000002106F0B1FF002874D110A8008A042822
+:106CD00001D0062849D16846018F1D98814237D1DD
+:106CE0000F2095E7012833D16846808A0521C90223
+:106CF000884202D0491C88422AD11E485038C18D92
+:106D00006846408A814201D1012700E00027002C1B
+:106D100001D0002D0DD01D99884219D114A90091E0
+:106D200004460EAB1022002106F07EFF002841D160
+:106D300001E0009D0CE010A8008A022801D0102874
+:106D400013D1C0B218AA0EA908F0FDFC00280CD17E
+:106D50006846408A00908AE7052059E72A1D15A950
+:106D600018A808F016FD002810D0032050E721E0F5
+:106D700002290000901300200302000001280000F7
+:106D800001180000052A0000FFFF000010A8007D88
+:106D90000023001DC2B210A802751E98029019A906
+:106DA00001950394009216A806F038FE002801D140
+:106DB00002213172FEF747FF2AE73EB50B46401E1F
+:106DC00084B201AA00211846FFF779F806F09DFD6C
+:106DD00002A8009001AB01220021204606F09DFD93
+:106DE000044606F096FD68460089012803D0FE4956
+:106DF000FE480BF066FE2046FEF725FF3EBDF0B5CF
+:106E0000FB4E0446307A89B00F46032804D004288C
+:106E100002D0082009B0F0BD04AA06A92046FFF759
+:106E200010F80500F6D1F24823893830226901466E
+:106E30001039029100930192039069460A8A63898E
+:106E400006A9206806F0EAFD002802D0FEF7FBFE46
+:106E5000E0E7002F03D0E648203000893880042086
+:106E600030722846D6E738B50C00054608D0002217
+:106E7000694606F033FF002804D0FEF7E4FE38BD73
+:106E8000102038BD69462046FEF785FF0028F8D15E
+:106E9000A0786946C207D20F284606F03AFFECE711
+:106EA0003EB50C0008D002AA694606F017FF00287C
+:106EB00004D0FEF7C8FE3EBD10203EBD0321204693
+:106EC0000BF0BFFC6846008801A90005800FFEF7A3
+:106ED0004EFF00280BD16846007920706846008874
+:106EE00001A98004800FFEF742FF002801D0032093
+:106EF0003EBD684600796070A278EF200240684687
+:106F00000088C10B09010A43F7210A404104C90F57
+:106F1000C9000A43A270F9210A40800601D5012068
+:106F200000E00220400069460243097A5008400010
+:106F3000C907C90F0843A07000203EBDFEB51D461D
+:106F400014000E46074615D0002D13D006F0DDFCC8
+:106F500001A8009022882B463146384606F0DDFC19
+:106F6000054668468088208006F0D3FC2846FEF758
+:106F70006AFEFEBD1020FEBDF0B50C46002199B0A2
+:106F80000746684681850D46002C11D0E068002830
+:106F900006D0A06800280BD002886B469A85018035
+:106FA000A078012806D0022804D0072019B0F0BD2F
+:106FB0001020FBE72088002807D0401E80B201A9DE
+:106FC00006F0A0FD002842D136E08A48EEE7694687
+:106FD0008A8921888A420BD26846007C00250128D4
+:106FE0002CD16846C0898449884227D1012525E0F3
+:106FF0008A4203D1002D2FD06D1C01E0022D02D05A
+:10700000032D1BD31FE06946097C012916D169466F
+:10701000794BCA895B1ED11A9A421DD005DC77488C
+:10702000101A19D0012809D116E0012914D0FF390E
+:10703000013903D1032506E00D26B60201A806F0AA
+:1070400069FD0028C3D0822804D0002806D0FEF7AE
+:10705000FAFDABE7022DFAD13046A7E7E068002839
+:1070600013D006F052FC0BA800906A46A188208835
+:10707000928DE36806F051FC054606F04AFC002DAF
+:1070800019D16846A168808D088002980078C006F2
+:1070900001D55B488AE706F038FC0EA800906846E8
+:1070A00080890CAB0222002106F0BEFD054606F0E9
+:1070B00030FC002D01D02846C9E76846008F022821
+:1070C00001D0032072E7A078012808A8007C03D033
+:1070D00080070ED4082069E7C007FBD00820FEF720
+:1070E000EBFA072802D34348401C5FE7082502203B
+:1070F00001E00225032069460876218868468183DD
+:107100001721818611AA002302320DA906A806F0D4
+:10711000C5F8002802D0FEF7FEFD47E70FA8009053
+:107120006846838E042229463846FEF7DBFA3DE79F
+:1071300070B5064615460C460846FEF741FD002888
+:107140000AD106F0E2FB2A4621463046FFF7A6FCAC
+:10715000044606F0DEFB204670BD70B514460D46B1
+:10716000064606F0D2FB224629463046FFF744FD8C
+:10717000044606F0CEFB204670BD70B51E46144690
+:107180000D001AD0002C18D06168002915D00121FB
+:10719000FEF794FF00280FD12068FEF711FD0028AC
+:1071A0000AD106F0B2FB324621462846FFF75AFACA
+:1071B000044606F0AEFB204670BD102070BD70B5D1
+:1071C00015460C0023D00221FEF778FF00281DD1C0
+:1071D0002068FEF7F5FC002818D106F096FB29463A
+:1071E0002046FFF70CFE0DE0B86400003C060000EE
+:1071F0006013002002300000032800000028000077
+:1072000001340000044606F084FB204670BD1020C7
+:1072100070BDF8B51C4615460E46074600F01FFA2D
+:10722000002805D123462A4631463846FFF786FE18
+:10723000F8BDFFB583B01E4615000F460FD006F00F
+:1072400064FB01A800900023F74A3946039806F032
+:10725000EBFC044606F05DFB002C03D014E010208C
+:1072600007B0F0BD002E0CD006F04FFB00200090C0
+:107270002A8833463946039806F0D6FC044606F0C1
+:1072800048FB6846808828802046FEF7DCFCE7E75C
+:10729000002906D0E54B0A885B899A4201D8E44868
+:1072A000704769E610B586B004236C46A382DF4BB5
+:1072B0005C898C4201D2914202D9DD4806B010BDF2
+:1072C0006C462182628200210091019119892180FE
+:1072D0000221A17005A9029104A903916946FFF753
+:1072E0004BFEEBE7F0B591B00D4681206946087181
+:1072F00005F002FC0646002D08D02878CB4C01286A
+:1073000006D0022828D0072011B0F0BD1020FBE7DE
+:10731000A98801AAFEF7CAFC0028F5D1B00734D528
+:1073200068460079002820D1A879C0071DD006F052
+:10733000ECFA002000906A892989A088EB6806F0A1
+:10734000ECFA6946087106F0E4FA69460879002803
+:107350000BD0FEF778FCD7E7A98801AAFEF7A6FCB8
+:107360000028D1D1342006420FD001216846017295
+:10737000017301794173F00609D5A188684601823D
+:10738000A18A01832069059004E00820BCE7A08859
+:1073900069460882FAF72CFC05461720694688835F
+:1073A0000AAA2B46023207A902A805F077FF074672
+:1073B0006878000701D5FAF737FC002F03D038466C
+:1073C000FEF7A9FCA0E7F00603D5207B06210843C1
+:1073D0002073B00602D50020FEF7C8FE08A8009072
+:1073E00069468B8B208804220121FEF77BF98BE70D
+:1073F000F0B5002695B014460D4600290FD0022C9A
+:107400004FD3A71EBAB288480AF02EF929191039AD
+:10741000CA7B8B7B11021943884242D1BCB201A9BD
+:10742000012006F06FFB7AE0029F3888010776D5CD
+:10743000002D41D0A9190691CA788B78361D11020A
+:10744000B6B219438919A1422BD869468A8906998F
+:107450004B7809781B020B439A4222D1C00623D5F0
+:1074600006F053FA07A800900698AB19C178807807
+:107470000A0206990243487809780002084300216D
+:1074800006F04BFA009006F044FA009800283ED12E
+:107490000698C178827808026946898B1043884231
+:1074A00002D00B2015B0F0BD0698C1788278080292
+:1074B0001043801986B22EE0C0062CD5002007AA02
+:1074C00001461154401C80B21028FAD306F01DFA70
+:1074D00006A800906846002380891022194606F00D
+:1074E000A3FB0090002803D006F013FA00980EE0EA
+:1074F0000BA86946009088890A8B07AB002106F02B
+:107500000CFA009006F005FA0098002803D0FEF768
+:107510009AFBC7E703E0388810218843388001A828
+:1075200006F0F8FA002800D17EE7404D698800296E
+:1075300021D0012268460276027700244477018434
+:10754000172181850EAA234602320BA906A805F051
+:10755000A5FE002802D0FEF7DEFBA3E70CA80090F2
+:1075600069468B8D288804220121FEF7BBF800288C
+:1075700098D16C8096E7002094E7F0B5002487B09E
+:1075800015460E46002A04D002A9012006F0BAFAD8
+:1075900040E0102064E60398007800073AD506F032
+:1075A000B4F901A8009068460023008A1E4A1946D3
+:1075B00006F03AFB074606F0ACF9002F23D1002E67
+:1075C00023D068468088298820183719001D8142F9
+:1075D00036D36946098A3970090A797069468988FB
+:1075E000B970090AF97006F090F901A8694600908F
+:1075F000088A8A883B1D002106F016FB074606F024
+:1076000088F9002F01D003202AE6684680882018D8
+:10761000001D84B202A806F07DFA0028BBD08228A3
+:1076200008D0FEF710FB1BE6FFFF00004013002010
+:1076300002300000002E0ED02988A01C814201D209
+:107640000C200DE62246314639480AF00DF8311972
+:107650000870000A4870A41C2C80002000E600B5C9
+:1076600085B06946FEF797FC00280AD16846007C81
+:1076700003000BF02BFB08052F2F2F2F08080531D7
+:10768000032005B000BD68468078012807D1684610
+:1076900000880321C902401A1CD001281AD068466C
+:1076A0008079012806D16846808815214902401A50
+:1076B00005280FD96846807A012811D168460189CA
+:1076C00029200002081A05D0022803D0032801D07F
+:1076D000042805D10F20D4E7164917480BF0F1F91B
+:1076E0000020CEE738B5154A0021518003791AE011
+:1076F000CC002418A46800946C462488250707D57C
+:10770000E50605D5D90008182038C08B508006E062
+:10771000640406D59171C9000818C08890800120C2
+:1077200038BD491CC9B28B42E2D8002038BD0000E8
+:10773000FFFF0000B8640000330200004013002087
+:10774000F8B50125F84902260E603F27F7493F02A8
+:107750008F60F7490022CA63CD63F649C96A0907F9
+:107760000ED4F4494031CB6AF34A53620B6B9362F7
+:107770004B6BD3628B6B1363C96BD3051943516396
+:10778000EE49EF4CC969002829D001282BD0FF20F1
+:10779000ECA16E300BF095F9EE48A063FF200430A9
+:1077A00060632563EC49032008602061E44996206A
+:1077B00040314860DD48E94940304163E649FC39E1
+:1077C0000163E649091FC163E349F0398163D74882
+:1077D0004760E34910204860E2480660F8BDE2488F
+:1077E0006061E24804E0E148E0306061DF48801F0A
+:1077F0000143A161D0E70120D0494006C86170472C
+:1078000010B5CE4C0020A070214660702031487029
+:1078100008746061A072A06209F02AFBA061204692
+:10782000343009F038FF002804D0FF20C5A13A30D9
+:107830000BF047F901204006E0610020FFF780FFD0
+:1078400010BDBE49012008707047BC490020087077
+:10785000704770477047BA4940310028086802D025
+:107860000122104301E0400840000860704770B5F5
+:107870000C46B24D01460622E81C0AF085FF6C72E8
+:1078800070BDAE48203040787047AC4A917050705F
+:10789000704770B50D460446082904D9FF20A9A1F8
+:1078A000CB300BF00EF90022B14809E0910063588B
+:1078B00009180B6053001B191B8C0B62521CD2B2AF
+:1078C000AA42F3D3206BAA494031086070BD0B2354
+:1078D000DB4310B5C21A9A4998421FD008DC1C320B
+:1078E00022D00A2A20D0142A1CD0182A08D117E046
+:1078F000083011D004280DD0082809D00C2805D054
+:10790000FF2090A1F7300BF0DCF810BD04200CE054
+:1079100000200AE0FC2008E0F82006E0F42004E063
+:10792000F02002E0EC2000E0D820C86010BD8348C1
+:107930002030007B704710B5814CC17861620AF03D
+:1079400084FF0002E06110BD252808D0262808D059
+:10795000272808D041000A2807D8091D06E002217F
+:1079600005E01A2103E0502101E0891DC9B2744AE3
+:107970009160734940314861704770494861704770
+:1079800070B56E4DA87200F028FBA87AC0073CD0F5
+:10799000714C2068800703D46AA176480BF091F8F7
+:1079A000A87A010619D5800707D5724865A1801C01
+:1079B0000BF087F8A87A00060FD55C4E2878403681
+:1079C000012811D0002804D0A3205EA180000BF074
+:1079D00078F869487061A8693061A87A800714D581
+:1079E0002068C00708D102E06348001FF2E7A52025
+:1079F00054A180000BF065F8A87A4007206801D5F3
+:107A0000042100E008210843206070BD70B5012406
+:107A10004A4D002807D0012818D002281AD055480E
+:107A200048A145380BE000F0D8FA53482978001FE8
+:107A3000012907D0002907D04E4842A158380BF041
+:107A400040F870BD046070BD446070BD8120FFF7D8
+:107A500097FF70BD00F0C1FA6869002804D145485D
+:107A600038A150380BF02DF86969A86A40184349CD
+:107A7000C8602E484249403001623F490C314162A2
+:107A80002A49001548603F4884602C48203004741F
+:107A900070BDF8B50C2069460870314C6068C006AE
+:107AA000C50F1026A66034480021FC300161324B1E
+:107AB00001221B1F1A610BE000BF00BF00BF00BF07
+:107AC00000BF00BF00BF00BF6B461A78521E1A707D
+:107AD0006A461278002A02D00269002AECD00161BD
+:107AE00068460078002804D1224816A131380AF0EF
+:107AF000E8FF002D00D06660F8BD10490020C86185
+:107B0000704710B50AF0A1FE00020D49000AC863D3
+:107B100010BD054902200860704703490220086033
+:107B2000104908607047000080E100E000F5014066
+:107B3000C01F004080000010001700409C13002070
+:107B4000001500407372635C68616C5F7263732E32
+:107B5000630000005B06000000120040448000400B
+:107B60000013004080E200E006010200250003004F
+:107B7000001600407B0200000410004040850040D9
+:107B80004C81004000050040FB4902200860C9E725
+:107B9000FA490870C6E710B5F94809F084FD0028D5
+:107BA00004D02B20F74900010AF08BFF10BD10B55F
+:107BB000F34809F090FD10BDF3494860B2E7F04981
+:107BC00010B53439F14B0022C8605A60896A081830
+:107BD000EF49486000F008FA10BDE94810B5C2212D
+:107BE0003438C160E94A00215160806AE849C230F6
+:107BF000486000F0F9F910BDE64900208861C861CD
+:107C0000DF493439C860E24948608BE7DC4900202D
+:107C10003439886286E73F20DE49000240398860B7
+:107C200080E7D748DA493438806AFE30886079E7DF
+:107C3000D7490020886075E7D74801681022914332
+:107C40000160D649012088616CE7D5490020C861F0
+:107C5000D148016810221143016063E700B5FFF7C6
+:107C6000EBFFC74900203439087400BD00B5FFF7A9
+:107C7000ECFFC34901203439087400BDC849CA6902
+:107C8000012A01D000204DE7BF4A403292685206D7
+:107C9000520E524202700020C861012042E7F8B53E
+:107CA000BF4C2069012806D00021B548343800783F
+:107CB000012802D004E04021F7E7E268012A04D05D
+:107CC00000220A43012802D004E02022F9E761687B
+:107CD000012905D000211143B24A002802D007E053
+:107CE0001021F8E71368012B02D1E368012B04D0BF
+:107CF00000230B43002802D007E00823F9E71168AE
+:107D0000002902D1E168012905D000221A439F4EC3
+:107D1000002802D004E00422F8E77168012904D0A9
+:107D200000211143002802D004E00221F9E7606835
+:107D3000012829D000259C480D4301680906090E39
+:107D400002D06169012900D000218D4F143F3973A1
+:107D500000680006000E02D0A069012800D00020B3
+:107D600078738B488068002803D000F0ABFA0128B4
+:107D700000D00020B8730021E16021616160616181
+:107D8000A16171602846F8BD0125D4E77C48012136
+:107D90001438C173C6E6F8B5794E0127143E307C1D
+:107DA0000025002827D07C4C206800902560FFF734
+:107DB00070FE009820607A48C560056145604561A5
+:107DC000856174490015403988607848856030467F
+:107DD000203801787148012909D0002909D0694962
+:107DE00073480AF06EFE0AF06BFF3574F8BD076049
+:107DF000F9E74760F7E7FFF752FF04460020F0730A
+:107E0000634842685E4D343D6A620068A862297822
+:107E1000002909D1A978002906D05B4B5B681B7843
+:107E20000B406978994309D000213170E10707D0F0
+:107E3000104602F031FC0121A86A08E03770F5E72E
+:107E4000A10601D5022102E0A10702D5002102F01E
+:107E500030FC4D4F796806220931E81C0AF067FCB6
+:107E6000002807D1687A79680978C909884201D160
+:107E7000012000E000207070204600F0BBF83F4871
+:107E8000C2270078002815D0012828D002283BD02E
+:107E900003285AD03B4947480AF013FE287C0028A3
+:107EA00004D02878002865D0FFF7C6FE287800287F
+:107EB00061D08BE0A00701D501F001FC200703D5BC
+:107EC0000120EF6001F034FC600703D50020EF6073
+:107ED00001F02EFCA006E1D501F09EFBDEE7A00735
+:107EE00001D503F08BFE200703D50120EF6003F0DE
+:107EF00005FE600703D50020EF6003F0FFFDA0063C
+:107F0000CCD503F087FDC9E7A00703D5BF20044007
+:107F100009F07EFB200705D5BF2004400120EF605B
+:107F200009F075FB600705D5BF2004400020EF6015
+:107F300009F06DFBA00603D5BF20044009F066FBE5
+:107F40006006ABD509F065FBA8E7A00701D509F0ED
+:107F500063FB200703D50120EF6009F05CFB60079D
+:107F600003D50020EF6009F056FBA00696D509F076
+:107F700051FB93E720E022E000E100E05400002004
+:107F8000D0130020447B00000015004040810040D9
+:107F90004085004040F501400012004000100040C4
+:107FA0000011004000140040401600400005004051
+:107FB0006F0300009F040000FFF747FE76E7E868C4
+:107FC000002803D0A96A091826484160F07B0028E0
+:107FD00000D10BE70AF074FEF8BD234903200860C6
+:107FE0002249002008619DE520482149C1612149BD
+:107FF000816197E570B50546FFF7EFFF1E4CA17A4A
+:10800000080701D568071CD41C4AC80605D5507B53
+:10801000002802D0907B002813D0880602D5107863
+:1080200000280ED1480602D55078002809D000203B
+:108030008A070026002A07DA4A0704D5012222709F
+:1080400002E00120F4E72670CA0709D0AA0705D488
+:10805000890705D5002803D0A80601D4FFF719FD2C
+:10806000A67270BD408500400012004040F50140FE
+:1080700010100040448100409C130020BC130020DD
+:108080002E48002101704170704770B506461446B5
+:108090000D46012000F072F828490120284B087095
+:1080A0009E60DC601D6170BDF8B50446012000F0E3
+:1080B00065F822490120087021494C6021490026B9
+:1080C0004E601121204D8902A960204F002C0AD05A
+:1080D000012C03D01EA140200AF0F3FC3E601120C9
+:1080E00080026860F8BD386001208002F9E710B5B1
+:1080F0001248017800290ED01121134A890291609B
+:1081000010494A680021002A03D0154A12684270BB
+:1081100000E041700170002000F030F810BD074809
+:108120000178002907D007484068002802D00C4891
+:108130000068C0B2704740787047000055000020CA
+:1081400000F5004000F1004000F5014000F2004061
+:108150007372635C68616C5F63636D2E6300000023
+:1081600000F4004001202949C0030860284900208C
+:1081700008701120274980028860704770B5244D2F
+:1081800004462878A04207D0002C05D0002803D050
+:1081900021A14D200AF095FC2878A04210D00020A3
+:1081A00022492C70002C23D01A4A214D214B8032B9
+:1081B000012C06D0022C13D017A16A200AF081FCF2
+:1081C00070BD0860022008604D6112481A494030B5
+:1081D00001624362081D10601648001D506070BDAA
+:1081E0000860032008604D6114481060536070BD42
+:1081F00008600860112007498002886070BD10B5D2
+:1082000005A173200AF05DFC10BD000080E100E0D4
+:108210005700002000F501407372635C68616C5F79
+:1082200063636D5F6161722E6300000000F50040C2
+:10823000D413002000F000400011004048810040AD
+:10824000364800210170417010218170704770B56F
+:10825000064614460D460220FFF790FF01202F49E5
+:108260002F4A0870E41E14619660556070BD10B509
+:108270000220FFF783FF29490120087029480021C7
+:1082800001604160816028490014486010BD10B54C
+:10829000224C2078002811D00120234980038860D7
+:1082A00000F02EF80021002804D0012060701F4843
+:1082B000006801E061701020A07021700020FFF7BD
+:1082C0005DFF10BD10B515480178002905D000F0FC
+:1082D00017F8002800D0012010BD407810BD10B55F
+:1082E0000E480178002909D000F00AF8002803D0D0
+:1082F0000E480068C0B210BD102010BD807810BDBF
+:1083000008480168002905D04168002902D080682A
+:10831000002801D00020704701207047580000203D
+:1083200000F5004000F1004000F5014000F400407D
+:1083300010B528210AF085FA10BD40788006800E1D
+:10834000704740788006800EC01C70472820704718
+:1083500070B5054600780A0700090001120F1043A6
+:1083600028700B000AF0B2FC070507050705090590
+:108370000B00062408E00C2406E0222404E000247C
+:10838000FEA158200AF09DFB6878800980012043F7
+:10839000687070BD00780007000F704710B50622A6
+:1083A000C01C0AF0F1F910BD0B4610B5C11C062225
+:1083B00018460AF0E9F910BD10B5062209300AF096
+:1083C000E3F910BD0B46014610B5062209311846E7
+:1083D0000AF0DAF910BD0278BF23C9071A40490E26
+:1083E0000A430270704700784006C00F7047027859
+:1083F0005206520EC9010A43027070470078C00944
+:10840000704770B50C460546C11C2046062209304F
+:108410000AF0BAF920784006400E20702978490603
+:10842000C90FC9010843207070BD70B515460E46CE
+:1084300004461F2A03D9D1A1A9200AF042FB2046F5
+:108440002A46314609300AF09FF96078AD1D80094F
+:108450008001A906890E0843607070BD70B505469D
+:1084600040780E468406A40E062C03D2C3A1B92080
+:108470000AF027FBA41FE4B21F2C00D91F242946B1
+:108480002246093130460AF07FF9204670BD70B5AA
+:1084900015460E4604461F2A03D9B8A1CD200AF07E
+:1084A00010FB20462A46314609300AF06DF9607803
+:1084B000AD1D80098001A906890E0843607070BD5A
+:1084C00070B5044640780E468506AD0E062D03D2E3
+:1084D000AAA1DE200AF0F5FAAD1FEDB21F2D03D9D7
+:1084E000A6A1E2200AF0EDFA21462A4609313046DB
+:1084F0000AF04AF9284670BD10B504220F300AF080
+:1085000043F910BD0B46014610B504220F31184641
+:108510000AF03AF910BD10B5032213300AF034F90D
+:1085200010BD0B46014610B50322133118460AF060
+:108530002BF910BD4176090A81767047817E427E13
+:10854000080210437047C176090A01777047017F1E
+:10855000C27E0802104370474177090A817770474D
+:10856000817F427F080210437047C175090A017676
+:108570007047017EC27D08021043704781757047C5
+:10858000807D704720300279C90652095201C90E18
+:108590000A430271704720300079C006C00E704750
+:1085A00020300279D206D20E49010A430271704787
+:1085B000203000794009704710B505221F300AF0BD
+:1085C000E3F810BD0B46014610B505221F311846D1
+:1085D0000AF0DAF810BD30B5411C837E0A46190254
+:1085E000D37D447E927D1B0221431343674D827DE0
+:1085F0008C1FAC4210D8002A0ED0082A0CD88A4210
+:108600000AD28B4208D8817F427F08021043A91DFD
+:10861000884201D8012030BD002030BD00210A462B
+:108620004254491C2229FBDB70474078C006C00E2B
+:1086300070474078C006C00EC01C704722207047AB
+:1086400010B502788B07920892009B0F1A430270B4
+:108650004278520952014270012908D0022906D0FD
+:10866000032905D0FF2045A1A3300AF02AFA10BD46
+:1086700001210A43427010BD10B502788B079208A1
+:1086800092009B0F1A4302704278520952014270C5
+:10869000012908D0022906D0032905D0FF2037A1DF
+:1086A000BD300AF00EFA10BD01210A43427010BD20
+:1086B00000788007800F70470278FB23C9071A40B3
+:1086C000490F0A430270704700784007C00F704797
+:1086D0000278F723C9071A40090F0A43027070474E
+:1086E00000780007C00F70470278EF23C9071A40CF
+:1086F000C90E0A43027070470078C006C00F704769
+:1087000070B50546C1700B000AF0E0FA0E080A0CBD
+:108710000E1012120C14141212160C180C2413E062
+:10872000082411E002240FE017240DE00D240BE0D3
+:10873000012409E0092407E0062405E0452000247F
+:108740000EA1C0000AF0BDF968784009400120433D
+:10875000687070BDC078704770B5044640780E46AA
+:10876000C506ED0E1B2D03D904A109480AF0A9F98D
+:108770006019C01C042231460CE000007372635C77
+:10878000756C5F7064752E63000000007A0C000049
+:108790003A02000009F0F8FF70BD70B50446407859
+:1087A0000E46C506ED0E1B2D03D9A049A0480AF0C0
+:1087B00088F96119C91C0422304609F0E5FF70BD33
+:1087C000C171090A01727047017AC2790802104327
+:1087D00070474172090A81727047817A427A0802B1
+:1087E00010437047C172090A01737047017BC27A56
+:1087F0000802104370474171090A817170478179FD
+:108800004279080210437047017170470079704740
+:108810004173090A81737047817B427B08021043D0
+:10882000704730B5411C037A0A46C47919022143C6
+:10883000537914791B0223437E4D00798C1FAC427F
+:1088400010D800280ED008280CD888420AD28B42B3
+:1088500008D8D07A917A00020843A91D884201D82D
+:10886000012030BD002030BD10B50522001D09F0EB
+:108870008BFF10BD0B4610B5011D0522184609F0EF
+:1088800083FF10BD4172090A81727047817A427A72
+:10889000080210437047017170470079704710B5A6
+:1088A0000822001D09F070FF10BD0B4610B5011D18
+:1088B0000822184609F068FF10BD0A78027349784B
+:1088C00041737047027B0A70407B4870704710B557
+:1088D00008220E3009F058FF10BD0B46014610B5B6
+:1088E00008220E31184609F04FFF10BD10B50422C2
+:1088F000163009F049FF10BD0B46014610B50422A1
+:108900001631184609F040FF10BD10B50822001DB1
+:1089100009F03AFF10BD0B4610B5011D082218469C
+:1089200009F032FF10BD10B504220C3009F02CFF05
+:1089300010BD0B46014610B504220C31184609F053
+:1089400023FF10BD017170474171090A81717047A1
+:10895000C171090A017270470079704781794279C3
+:10896000080210437047017AC27908021043704729
+:108970000171704700797047017170470079704745
+:1089800010B50822001D09F0FFFE10BD0B4610B502
+:10899000011D0822184609F0F7FE10BD10B5082287
+:1089A000001D09F0F1FE10BD0B4610B5011D082297
+:1089B000184609F0E9FE10BD70B515460E4604468E
+:1089C0001B2A04D93720194900010AF07AF82A46EF
+:1089D0003146E01C09F0D8FE6078E9064009400104
+:1089E000C90E0843607070BD70B5054640780E46EC
+:1089F000C406E40E1B2C04D9DF200C4980000AF0C9
+:108A000060F82246E91C304609F0BEFE204670BDE3
+:108A10004078C006C00E1B2801D8012070470020F6
+:108A2000704710B5222209F0AFFE10BD7C87000010
+:108A3000430200007A0C0000FEB50F4601460646D0
+:108A40000546C031203640350446032F04D0002FA0
+:108A50002BD0012F29D049E000206080A080E08049
+:108A600020816081A082E082E873A074E074A07627
+:108A7000E076A073E0732074607430740123AB73EC
+:108A80006882E88208762146A883603108702883CE
+:108A90002873687320776077B072B0730872487279
+:108AA00088720A7488746883FEBD00206882E88238
+:108AB000012F50D0E08B0090608C0190C000009995
+:108AC00009F0DCFE401C80B2A882009919224143C3
+:108AD0009202914201DD401EA8827D200002009991
+:108AE00009F0CCFE401CE883002F01D0022FDBD11F
+:108AF000307AC006C00E30720020E872221824219D
+:108B00008B5C4032D9075B08DE07C90FF60F71187E
+:108B10005B08DE07F60F71185B08DE07F60F7118A9
+:108B20005B08DE07F60F71185B08DE07F60F711899
+:108B30005B08DE07F60F71185B0859189171EA7A25
+:108B4000401C5118C0B2E9720528D7D3002FABD111
+:108B500000202874FEBD4A7F2046E030022A12D051
+:108B6000097F022913D050A1722009F0AAFF012029
+:108B700000900190E08B698B4843009909F08CFECE
+:108B8000688301989AE7818800910089F1E7018A5A
+:108B90000091808AEDE770B504464034E67A0546D8
+:108BA000002E68D0252E66D8002964D03C20405D78
+:108BB000227B48431018252109F060FE08462173E6
+:108BC0004207C908520F3C4B691820319A5C097959
+:108BD0008A4367D0314609F051FE491CCAB20020D1
+:108BE00006E0002804D0291840314979511ACAB248
+:108BF000291846235B5C93423AD320310979C94353
+:108C0000CB07DB17D21A521E1206120E34D08B0776
+:108C1000DB17D21A521E1206120E2FD04B07DB178B
+:108C2000D21A521E1206120E2BD00B07DB17D21AC5
+:108C3000521E1206120E27D0CB06DB17D21A521E76
+:108C40001206120E23D08B06DB17D21A521E120602
+:108C5000120E1FD04B06DB17D21A521E1206120E2E
+:108C60001BD00906C917511A491E0A06120E17D041
+:108C7000401C0528B5DB70BDC00013E0C000401CDF
+:108C800010E0C000801C0DE0C000C01C0AE0C00065
+:108C9000001D07E0C000401D04E0C000801D01E091
+:108CA000C000C01D607370BD7372635C6C6C5F75D7
+:108CB00074696C2E63000000042D010010B5FF489C
+:108CC0000021017041708170C17041718171C17169
+:108CD000083008F0E0FC002804D0FF20F8A1843020
+:108CE00009F0EFFE10BD10B5F44900204872081DD0
+:108CF00008F0D1FC002804D0FF20F1A1C33009F016
+:108D0000E0FEFFF7DBFFF148FFF788FC0021EF48AA
+:108D1000FFF7EAFC0121ED48FFF792FC10BDE2E706
+:108D20001B207047E5494A7A002A01D0002070478D
+:108D3000488101204872704710B5E0494A7A002AFC
+:108D400002D04989814201D0002010BDDB48001DBE
+:108D500008F0A9FC002804D0FF20D9A1B43009F004
+:108D6000B0FED648001D08F0B6FCFFF7A7FF0120B3
+:108D700010BD70B5D14C0025627A002A02D06289FC
+:108D8000824201D00D700DE0227863789A4203D3BD
+:108D900022786378D21A04E062782378D21A1023FA
+:108DA0009A1A0A70FFF7C8FF002801D065720120E7
+:108DB00070BDC2494A7A002A04D04989814201D152
+:108DC0000120704700207047BC490A784B78521C3C
+:108DD0001207120F9A4207D0097822225143BC4A47
+:108DE000891801600120704700207047B34801785E
+:108DF0004278491C0907090F914206D00178491CA5
+:108E00000907090F01700120704700207047AB4926
+:108E10004A7A002A04D04989814201D10120704751
+:108E200000207047A5490A784B789A4207D04978C4
+:108E300022225143A64A8918016001207047002070
+:108E4000704710B59D4C20786178884216D06078C4
+:108E5000401C0007000F6070201D08F024FC002853
+:108E600004D0E078401CE070012010BDA078401CC8
+:108E7000A0709248001D08F02EFCF5E7002010BD00
+:108E80008E4801784078814201D10120704700204E
+:108E900070478A4801784278914202D3017840783D
+:108EA00003E041780078081A1021081AC0B2704710
+:108EB0000F20704770B5814C0D46617A002916D09D
+:108EC0006189814213D100262E70201D08F0EBFB32
+:108ED000002805D1A0782870A670201D08F0FBFBA3
+:108EE0002878E17840182870E670012070BD0020D5
+:108EF00070BD76490160704770494A7A002A04D0F3
+:108F00004989814201D101207047002070476B4997
+:108F10004979002901D0002070476E490160012085
+:108F2000704766484179002901D00020704701212F
+:108F300041710846704761494A7A002A04D049893C
+:108F4000814201D101207047002070475B49497977
+:108F5000012901D0002070475E490160012070475F
+:108F600056484179012901D0002070470021417104
+:108F70000120704751484079012801D001207047F5
+:108F8000002070474D494A7A002A04D0498981421D
+:108F900001D1012070470020704770B5474C05464D
+:108FA000A0790721401C09F069FCE079814208D0D2
+:108FB000A0792221484347492231401828600120E6
+:108FC00070BD002070BD10B53C4C0721A079401C3D
+:108FD00009F054FCE079814207D0A0790721401CB8
+:108FE00009F04CFCA171012010BD002010BD3348D8
+:108FF0008179C079814201D10120704700207047FA
+:109000002E494A7A002A04D04989814201D101209F
+:1090100070470020704710B504462848083008F013
+:1090200042FB002815D125498879CA7990420CD095
+:10903000C8792221484327492231401820601F481F
+:10904000083008F048FB012010BD1C48083008F02B
+:1090500042FB002010BD10B504461848083008F047
+:1090600022FB002815D115498879CA7990420CD085
+:10907000C8792221484317492231401820600F48FF
+:10908000083008F028FB012010BD0C48083008F01B
+:1090900022FB002010BD094810B5083008F003FB82
+:1090A000002822D1054CA079E17988421AD0E079D4
+:1090B0000721401C09F0E2FBE1710DE05C0000209B
+:1090C0007372635C646D5F712E6300002F17002064
+:1090D000FF1300201F1600202046083008F0FBFA7E
+:1090E000012010BD0C4808F0F6FA002010BD0A4817
+:1090F00008388179C079814201D101207047002070
+:109100007047054808388179C079814201D1012032
+:1091100070470020704700006400002070477047CF
+:10912000FF2070477047704700207047002070474D
+:1091300000207047002070470020704700207047D3
+:1091400000207047002070470020704701207047C2
+:1091500000207047002070470020704700207047B3
+:10916000F8B5FA4D0446A87F002600280CD0002947
+:1091700023D1667010202070E87FA0702846203030
+:109180000078E070AE7718E0287A012801D000203E
+:10919000F8BD002911D16670EC49687A01270A31BF
+:1091A000002801D0132000E0052020701422A01C0C
+:1091B00009F0EAFAA7716E722E720120F8BDF8B5B7
+:1091C000E3480078002802D00C273846F8BD002775
+:1091D000DE4D3C46203DAF74EF742F7528466F730B
+:1091E0002038DA4E47737771687D002804D0FEF787
+:1091F0001FFDFFF74CF86C7534727472B477D34866
+:109200002430FFF795F8D1484C30FFF791F8D0485B
+:109210004470DAE710B5CE4C00232370CB4C203CD1
+:109220006375CA4B01241C71603B583307C3FFF7B9
+:10923000C6FF002803D0C7A1FF2009F042FC10BDE3
+:10924000C2482038807C7047F8B5C04D0646407B48
+:10925000203DE873BD4837791346AF73B27B827106
+:109260000446603C217006221946601C09F08CFA05
+:10927000B07960730622F11DE01D09F085FA687B64
+:109280000126002800D0EE74B0484038407B00280A
+:1092900000D02E75002F09D0012F09D0022F24D025
+:1092A000032F43D0FF20ABA14B3013E000211DE082
+:1092B000A64801212430FFF74BF8A448E11D2430D3
+:1092C000FFF77AF8607B002807D0012807D0FF203D
+:1092D000A0A1413009F0F5FB0CE0002100E00121E4
+:1092E0009A482430FFF783F804E006219748243099
+:1092F000FFF72EF89548611C2430FFF74FF893488C
+:1093000021782430FFF767F8904804214C30FFF7AC
+:109310001FF88E48611C4C30FFF740F88B482178CD
+:109320004C30FFF758F8AE740020F8BD0221DDE79D
+:1093300070B50446854D0020203D287528462246FC
+:10934000323809F021FA2846203844730120287564
+:1093500070BD7E490871704710B57C4C0022203CDE
+:10936000E274607302462046123809F00DFA0120BB
+:10937000E07410BDF8B500F02DFB744C0025203CC6
+:10938000607D002804D0FEF753FCFEF780FF657572
+:109390006F4E3570FEF70BFCA07B012804D0002136
+:1093A000084601F02DF9F8BD0021022001F028F94E
+:1093B000664C207A0127002809D0A07F0028F2D12E
+:1093C0000520E077204620300570A777F8BD70783B
+:1093D0000028FBD05D4906226039487BE073C91D37
+:1093E0000846693009F0D0F93C20A07227727570E8
+:1093F000F8BD10B5554C203CE17B207CCA0701D05C
+:10940000C2070BD08A070FD582070DD42620FEF79E
+:109410009BFA207C02210843207410BD2520FEF712
+:1094200093FA207C0121F6E74907F6D54007F4D4EA
+:109430002720FEF789FA207C0421ECE770B5444828
+:109440000078002861D1414C203CA07C00285CD0F1
+:10945000FEF7A1FB0026267466743046FEF798FBE3
+:109460000020FEF76DF93F48FEF765FA2546403DBE
+:10947000296E8857FEF72BFA3A48C01EFEF741FBCB
+:10948000FEF7BAFBFFF7B5FFFEF7DBF9FEF77CFB53
+:109490000120FEF7BBFA0F210520FEF7F6F9297827
+:1094A000681CFEF7E4F9A07B01280AD0E07C0028C4
+:1094B00007D0214612390846627B5630FEF7B5FFC9
+:1094C000E674207D002808D0204840380146427BC1
+:1094D00012398C30FEF7DBFF2675E86D0178002924
+:1094E00003D00178001DFEF7D4F9A86D017800299A
+:1094F00007D00178154A401C7732FEF7A8FE0120FC
+:109500006075FEF754FB002070BD0C2070BD104943
+:109510004860704770B50546FEF76EFB002D06D01B
+:109520000020FEF72DFAFEF78CF9FFF762FF074CDB
+:10953000203C607C002819D0A07B012803D105A124
+:10954000094809F0BEFAFFF715FF70BDB4170020F7
+:10955000680000207372635C6C6C5F6164762E63DC
+:10956000000000000F2D0100CF0300000126002D98
+:1095700004D00220FEF74AFAFE484671FD48243026
+:10958000FEF71AFB012008F03CF8FEF762F9A07B19
+:1095900000280ED001280CD002280AD003280AD0B7
+:1095A000F549F64809F08DFAE07B217C884306D026
+:1095B00009E0032000E00120FEF7E2F9F4E7A07BD8
+:1095C000012803D06674EE480670BEE700202074C0
+:1095D000F9E710B5FEF7DFFAE948007800280ED168
+:1095E000E4482038807C002809D00020FFF792FF53
+:1095F000F6F7F9FEDF480079012806D007E000F011
+:10960000E9F9FEF7D4FA0C2010BD09F059FB00204F
+:1096100010BDDB494870704770B500F0AFFE002800
+:1096200019D0FF202D30FEF7A8F9D54E3078D14C57
+:10963000012813D0022801D003282ED0CE49D148CA
+:1096400009F03FFA3078002807D0F6F7CCFE2079F1
+:1096500001282CD030E0FFF78DFE76E7C54D203D88
+:10966000A87B032819D0FEF7B8FA687D002803D03C
+:10967000FEF7FDFDFEF7D5FABE487430FEF79CFA02
+:10968000012007F0BFFFA87B01280BD0A1796F2034
+:10969000012906D0032904D004E00120FFF73AFF96
+:1096A000D0E77F20FEF76CF902203070CAE76079BE
+:1096B000002801D1FEF76AFB0020607145E770B514
+:1096C000AC4C203C607D002803D0FEF7B1FAFEF7D9
+:1096D000DEFD00F053FE00281CD0A94D287802289A
+:1096E00004D0A848A4492B3009F0EBF9A07B01284D
+:1096F00013D0FF202D30FEF740F90120FFF70AFFBD
+:109700002878002808D0F6F76EFE9A4C20790128B8
+:1097100006D00AE0FFF72EFE17E799208000EAE75F
+:109720006079002801D1FEF731FB002060710CE761
+:10973000F8B50446FEF7FBF80546FEF7C3FD012821
+:1097400000D0002000908E480078022804D08D4878
+:109750008949673009F0B5F9864E203E707D0028B2
+:1097600003D0FEF765FAFEF792FDFEF745FA814851
+:109770007430FEF70FFE21007E4C07464DD0FEF7F9
+:1097800080F80028FAD03B0009F0A0FA06474747C6
+:1097900004471D47B07B0128F0D00098054304D151
+:1097A000A079002801D0022837D172484C30FEF74A
+:1097B00003FA012007F025FF0120FEF7E1F87048C9
+:1097C00003210170F5E06B4F74373846D438F978CF
+:1097D000C27991421BD13979027A914217D17979B4
+:1097E000427A914213D1B979827A91420FD1F979B3
+:1097F000C27A91420BD1397A027B914207D13978F2
+:10980000407B4906C90F814201D1012100E00021BE
+:10981000B07B012802D0002803D0C3E0002908D182
+:10982000C0E00098054304D1A079002801D00128A8
+:109830007ED150487430FEF7CEFE002878D0504DCF
+:109840004C49686804228331323008F09DFF387833
+:109850003E214006C20F68680A540622F91C3F30B8
+:1098600008F092FF4349686803228731363008F0D8
+:109870008BFF6868BA7D39210A543E4974310A7EEB
+:10988000CB7D12021A4342878A7E4B7E12021A4314
+:10989000C2830A7FCB7E110219430184354974319A
+:1098A0008A7F4B7F1102194341843249052293314B
+:1098B000243008F069FF2F486D68943001792F46F5
+:1098C000C906C90E20373977007940097877207AA0
+:1098D000002810D0A07F002858D1607A002801D03D
+:1098E000132000E005202349E07700202031087094
+:1098F0000120A0774AE01F48717D1030002925D053
+:109900000021A172A989A181B97FE17329460622AC
+:109910003F3108F039FFE88BE082288C2083688C87
+:109920006083787F2077607F00994008400000E0E6
+:1099300038E008436077FEF7D2FC617F4000C9073A
+:10994000C90F01436177012060721EE00021A172FE
+:10995000A989A181B97FE173294606223F3108F028
+:1099600013FFE88BE082288C2083688C6083787FEB
+:10997000207709E0B417002054950000ED030000A3
+:10998000680000206B02000001202072194D0020A9
+:10999000287000F01FF8FEF70AF90120696800F04E
+:1099A0002FFE06E0FF202D30FDF7E7FF0120FFF737
+:1099B000B1FD1048007800280BD0F6F714FD20798F
+:1099C000012804D16079002801D1FEF7DFF90020D9
+:1099D0006071F8BD10B5FEF719F9FEF70DF9FEF745
+:1099E00058F80020FDF7CCFFFEF715F9FEF795F8C3
+:1099F00010BD0000680000208107C90E002808DAA9
+:109A00000007000F08388008F94A80008018C069F4
+:109A100004E08008F74A800080180068C84000060B
+:109A2000800F7047F448C07D7047F44800780028E4
+:109A300001D00020704701207047F048007870473F
+:109A400010B5EE4A1378EC4CA47DA34202D007F087
+:109A500059F910BD1078032803D1E8490120891D68
+:109A6000887000F04AFE10BD38B5E44DE24CAD1DE3
+:109A7000687801281ED00121684606F041F8684642
+:109A80000078DF49000208F0F9FE68684118606854
+:109A900007F08FF86060DB48A060A18A00200029F1
+:109AA00010D06070032121702073A07ED249FFF78F
+:109AB000C7FF38BD7D21C900606807F07AF8606093
+:109AC000D148E9E70121A18202216170EAE7FFB5EF
+:109AD000C94C85B01C3461680191A1680391C749E4
+:109AE0001E46891E4A6807995388C91A89B202918D
+:109AF000002E04D025463C3521464C3102E0BE4DB7
+:109B0000114664310091BC4F03213C372970002875
+:109B100018D0BA49891E4968403101287ED00228F0
+:109B20005CD003287BD0B9A1BC4808F0CAFF2878D4
+:109B3000002E75D0032804D0B848B4A1093008F02D
+:109B4000C0FF35E1A068002804D1B448AFA1663851
+:109B500008F0B7FFA948B149801E40686031408FC6
+:109B600048434018069900F0CEFDE061A348AB4998
+:109B7000801E40686031C08B4843069900F0C3FDE9
+:109B80009E492062891E4B68A44A598FA0686032A2
+:109B9000514386464118E069A04A091A4C3A89188F
+:109BA0008C462033E1629D4A597E60325143411810
+:109BB0000818FF3016306062A06261467046081ACD
+:109BC000FF38974935388842B1D29649884204D245
+:109BD00092488EA1593808F074FFD0E0508F8F4A18
+:109BE0002169603250430818069900F08CFDE0614D
+:109BF00082488A49801E40686031C08B484306997C
+:109C000000F081FD2062A068002804D183487FA174
+:109C1000513808F056FF7948801E02E02FE05EE0E0
+:109C2000C1E040685621095A7F4B0029418F2269C3
+:109C30001DD059435118E269891AE1626269E168ED
+:109C4000794B5143E26989183922125C5A438A18C8
+:109C50005118FF3114316162C08B216A5843411A97
+:109C600072480818A062A168E06A401A81E059436E
+:109C70005118E269891A6268D3398918DDE7C88A00
+:109C8000002802D0A068002804D164485FA13938B8
+:109C900008F017FF59486449801E4068C28B4A4348
+:109CA000216A8E46511AE1628C4656226369125A25
+:109CB000E168D21A5943E3692030CB187146514309
+:109CC000407E594A5918504308184018FF30143044
+:109CD0006062564861466044A062A06848E0D08B4C
+:109CE000514A5043226A801A029A5043E062C88A5D
+:109CF000002805D0002E19D0B87D002816D0A1E08C
+:109D0000002E02D0B87D0028F6D10198002802D09C
+:109D10000398002804D141483CA1213808F0D1FE25
+:109D20000198E16AD3380818E06207E0019800283A
+:109D300004D08D2035A1C00008F0C3FE2F48801E3E
+:109D400042685620815A02980818216A4843400008
+:109D5000FF3014306062D08B334A5043411A33488D
+:109D60000818A0622448C07D00280BD0E16A03983F
+:109D7000081AFF382A492338884200D3D7E6022040
+:109D80002870D4E606F072FC01461B48006907F013
+:109D9000C7FBE16A081AFF3821491E388842EDD214
+:109DA000012009B0F0BD032802D1144907204870F2
+:109DB0001148E16A006906F0FCFE6860A16A606A09
+:109DC000884202D90098016001E00099086000987B
+:109DD000174900680818A8600848801E40688188F4
+:109DE0000798081A00B2002824DD022023E00000B2
+:109DF00000ED00E000E400E05018002072000020B8
+:109E000010270000F82A0000B78913007372635C02
+:109E10006C6C5F6C6D2E73302E630000820400004A
+:109E20004707000082020000E204000061FCFFFF1F
+:109E3000EF160000002068702E73002E04D0B87D4D
+:109E4000002801D00220ACE701204640BE76F7484A
+:109E5000807E2946FFF7F4FD0020A2E7F8B5F3481D
+:109E60003C30807EF14FF24D3C461C3400280CD033
+:109E70006968208F4988884207D17878002804D102
+:109E8000A920EC49C00008F01CFE06F0EFFB0146DB
+:109E9000386907F045FB00F044FC6968228F4B8865
+:109EA0001E18B24202DB521C228702E0401C181826
+:109EB0002087208F0A89904201D1401C2087B88AD0
+:109EC000032802D2401CB88201E0208F8880084617
+:109ED0004030828A408A4988101A401E401886B253
+:109EE00017E028786B6841002033D3485B7F415AE4
+:109EF0005B00C05A081881B2207E0023FFF7E7FDFF
+:109F0000002811D0012810D00B20CA49C00108F048
+:109F1000D8FD228FB01A00B20028E2DA6868082162
+:109F20002030417400F0A7FDF8BD208F401C208731
+:109F3000EFE770B5BD4C00261C3466600120A660BA
+:109F400000F0C9FBBA481F21801C41700078B74D52
+:109F5000030008F0BBFE044545033745B3482670AF
+:109F60003C30807EB24E002806D106F07FFB216C8B
+:109F700007F0D6FA002811DC7068228F41888A42E7
+:109F800004D10289511A4181428003E0511A418172
+:109F9000218F41806868206428610BE0A18E706881
+:109FA0004288891A4181A18E4180216C69602961B2
+:109FB000E16C4166706801F0FFFB00280DD09D49FF
+:109FC0009E4808E068682861FFF738FA002804D046
+:109FD0009A489849401D08F074FDF6F704FA70BDE0
+:109FE000964894490C30F6E7F8B505468F4A0120AB
+:109FF0003C3290758D4C17466576213F00260B004C
+:10A0000008F064FE09061D2E4E2B69691C64690068
+:10A0100020768748801C0078022807D0384607F051
+:10A0200042FB002803D1A07EA84200D12676207EE4
+:10A03000002803D1FFF77DFF00F0A0FBF8BD207ED4
+:10A04000002806D006F064FA6676384607F043FB2F
+:10A0500001E000F075FB2676F8BDFDF79CFEF8BD2B
+:10A060007348801C017802290ED0A17E0078A94295
+:10A070000DD0002804D0FF206E497B3008F021FD70
+:10A08000284606F0D8FAF8BDFFF7E8FEF8BD032829
+:10A0900003D0FF206749813015E0FFF7E5FCF8BDEC
+:10A0A000A07EA84204D0FF206249873008F009FD55
+:10A0B0005F48801C01780229E6D000780328ECD0A4
+:10A0C000FF205C498E3008F0FCFCE6E7284606F0ED
+:10A0D000B2FA6676F8BDFF2056499D3008F0F1FCD3
+:10A0E000F8BD524988755248801C00E020BF0278B4
+:10A0F0008B7D9A42FAD00078002803D000200022FD
+:10A100008A7570470120FAE710B500280BD00128A6
+:10A1100005D04A484749853808F0D3FC09E00320B8
+:10A12000FFF7DFFF01E000F049FB002801D000202D
+:10A1300010BD0C2010BDF8B5FF273D4D1F24D037B2
+:10A14000AD1C2E78330008F0C1FD040811030C117A
+:10A150000220FFF7C6FF002801D000240FE00C24E6
+:10A160000AE00120FFF7D0FF044603E031493846FA
+:10A1700008F0A7FC002C02D02878B042E1D1287862
+:10A18000002804D0FF202B49D53008F09AFC27493D
+:10A1900000201C3108761C39887501226A70244A17
+:10A1A00008325070C87508612046F8BD70B5044685
+:10A1B0000120FFF721FCC5B20B20FFF71DFCC0B248
+:10A1C000854204D0FF201B49A73008F07AFC01200B
+:10A1D000FFF712FCC5B21820FFF70EFCC0B2854293
+:10A1E00004D0FF201349A83008F06BFC0420C043C2
+:10A1F000FFF702FCC5B21920FFF7FEFBC0B2854293
+:10A2000004D0FF200B49A93008F05BFC08484470DB
+:10A2100006481B3007F03FFA05490020891C0870EA
+:10A2200002498875FFF787FF70BD000050180020B5
+:10A23000700000200C9E0000142D0100220300007D
+:10A24000F74840787047F649891E08707047F3B5A3
+:10A2500081B006F0E9F9F349884200D20846FF30A0
+:10A260009930EF4D87B22878002801D00C20FEBD30
+:10A27000ED4806F08CF9ED4CA076E9490320087012
+:10A2800000268D1DAE70A07E002804D19720E849DD
+:10A29000800008F016FC0298012827D0E5490198B3
+:10A2A00048436860012028700146684605F028FC94
+:10A2B00068460078E049000208F0E0FA0D4606F032
+:10A2C000D5F9791906F075FC6060DC48A0600320C0
+:10A2D0002070022060702673A07ED449FFF7B0FB87
+:10A2E000CF48A682072141700020FEBD06F0BEF9CE
+:10A2F000394606F05EFC6060D148A0602E700120F7
+:10A300006870E4E7704770B5C5490A78002A01D043
+:10A310000C2089E702220A70C14CC44DA41E1C35D2
+:10A320006060287E002804D0C248C1494E3008F041
+:10A33000C8FB207800234100C248425A616820319E
+:10A34000497F4900405A101881B21A461846FFF753
+:10A35000BEFB002804D0B748B549503008F0B1FB27
+:10A36000002068610121E8602976B049888262682E
+:10A370005188491E51802887A88655E770B5A8489E
+:10A380000124801D4078A94D002813D028461C3098
+:10A390008168AD48814202D8AA7D032A00D10024F9
+:10A3A000814207D9A87D032801D0012000E00020C8
+:10A3B000FFF72FF9A87D032800D10024204633E7BA
+:10A3C0009A481C300178491C0170026B81689142E7
+:10A3D00004D8007E012801D001207047002070477A
+:10A3E0000020704770B5914C1C34207E032849D161
+:10A3F0000021204620308175894DAD1E68684030AF
+:10A40000007C00283ED106F031F988490A690146EE
+:10A41000104607F085F8002834DD00F082F96968FD
+:10A42000401C4A888018A0860889A28E904229D9AB
+:10A430004888088140318A8A498A511A491E081879
+:10A4400086B21AE0287841007E48425A6968203175
+:10A45000497F4900405A1018A28E81B2207E012304
+:10A46000FFF735FB00280DD001280CD0022809D0B9
+:10A470006C486F49C43808F024FBA08E301A00B233
+:10A480000028DFDAD0E6A08E401CA086F5E7F8B5FC
+:10A49000664C634F00251C34BF1E012819D00720CD
+:10A4A000B91C487006F034F8604E304675761B30A3
+:10A4B00007F011F97878F8F7A5F8B5827868314691
+:10A4C0004088208701203C318875002000F003F986
+:10A4D000F8BD267E52495B48891E0A7853004A68B7
+:10A4E00011462031032E18D0267E022E21D0267E42
+:10A4F000012ED7D1497FC35A4900405A12891818F2
+:10A5000081B200230120FFF7E2FA0028CAD04548B3
+:10A510004749213808F0D5FAC4E76561E560497F0D
+:10A52000C35A4900405A1289181881B200230320E7
+:10A53000E9E75626B65A6661497FC35A4900405A30
+:10A540001289181881B200230220FFF7C0FA0121F6
+:10A550002176DAE7F8B5324E0021B61D7078334C1B
+:10A560000D46002801D075701AE03078002809D017
+:10A570000121684605F0C4FA684600782E490002B9
+:10A5800008F07CF970684118606806F012FB6060A2
+:10A59000257302206070607E2449FFF751FAA5827E
+:10A5A00005F0B6FF214865761B3007F094F81C488B
+:10A5B000801E4078F8F726F8002000F08CF8F8BDEF
+:10A5C00010B5030008F082FB060A0E0406130916F4
+:10A5D000012000E0002000F037F910BD0120FFF756
+:10A5E00056FF10BD114903201C31087610BD00F044
+:10A5F0003DF910BD0B480E498E3008F062FA10BDCF
+:10A6000070B50A4D002821D0054EB61D012828D06E
+:10A61000022837D003480649AD3008F052FA03E665
+:10A6200072000020F6050000E99F0000501800208D
+:10A630000C9E00007102000010270000F82A0000A4
+:10A64000B7891300142D01002E841300FFF782FF39
+:10A65000A97D9448002901D01F2100E00721417005
+:10A66000E2E5002490487470047600F046F8032078
+:10A67000F7F7C7F805F04CFF8B486C76401E07F0E3
+:10A680002AF8D1E5FFF766FF0120B07000F035F839
+:10A690000420F7F7B6F8C7E582490978022907D1FF
+:10A6A00081490A78002A03D148600A6B10180863B0
+:10A6B000704710B57C4A00290BD0012906D0022929
+:10A6C00006D07A497A4808F0FCF910BD401E00E037
+:10A6D000401F906010BD744910B51C39C875002822
+:10A6E00005D0F5F781FE0220F5F778FE10BDF5F7ED
+:10A6F0007CFE0120F5F77AFE10BD6A48002101704A
+:10A7000001214170704710B504460020002907D090
+:10A71000684808F0B3F80146204608F0AFF8401C3E
+:10A7200010BD10B500280AD05E49634A891E4968E9
+:10A73000C98B51435C4A126A891A08F09FF810BD10
+:10A7400010B558480078030008F0C0FA0414140348
+:10A750000A1401F035F900280BD05449574806E097
+:10A76000FEF737FF002804D054485049001D08F078
+:10A77000A8F910BD51484D490B30F8E710B505F068
+:10A7800053FF4849891E4968CA8B4B494A43464989
+:10A790000B6AD21AD33AFF2332330A63984202D2A9
+:10A7A0004748101802E0101A464A801808634648C5
+:10A7B0000A6B824200D81046086310BDF0B53A4CCF
+:10A7C000032685B01C3CA67520461B30009001E096
+:10A7D00020BF009806F067FF0028F9D10025A57575
+:10A7E00030480178032903D0007800281DD021E0EB
+:10A7F000A07E002803D12D49344808F062F9A77ED5
+:10A80000684606710221417105F030FF0290FF2079
+:10A81000F5300390012168460174A57601A93846F8
+:10A8200006F070FAFFF769FF0CE01E48801D817882
+:10A83000012906D00024009806F04DFF204605B0FF
+:10A84000F0BD85700124F6E710B5002803D0002084
+:10A85000FFF71DFE04E01348801E4078F7F7D2FE94
+:10A86000FFF74BFF0020F6F7CCFF10BD10B50E4AE6
+:10A87000114B106AD0600B48801E4068C18B594351
+:10A8800011610146E0314B8843870C7839231C5411
+:10A890008B88C383CB880384098941840220107686
+:10A8A00010BD0000720000206C1800200C9E0000FB
+:10A8B000C306000040420F00E20400004303000012
+:10A8C000A5F8FFFFD6F9FFFF1612000029020000CD
+:10A8D000F8B5FEF7DEFA0646FEF74CFBF94D0746E3
+:10A8E0006879F94C002809D0012823D0022826D005
+:10A8F00003282ED0FF20F5A1BC3033E0F2481430FD
+:10A90000FEF724FB002801D003200FE0EE481430AE
+:10A91000FEF788FA002804D020696030007A002809
+:10A9200006D0E9481430FEF7E4FA012068711BE014
+:10A930000220FBE7E4481430FEF7DBFA14E0E248BB
+:10A940001430FEF76FFA00280ED1FF20DFA1AE30E1
+:10A9500008E0DD481430FEF7F9FA002804D1FF20A2
+:10A96000DAA1B63008F0ADF86169F7220878104036
+:10A970000870AA79D207120F1043FB22104008700A
+:10A98000EA79D207520F104308706B79EF22022B3D
+:10A9900004D0012B07D0032B07D00CE0012E06D8E2
+:10A9A000002F04D007E07F1E3E43002E03D010404E
+:10A9B0001022104300E010400870287C002811D0BD
+:10A9C000687901280ED0BF484A38FDF7F5F8BD492F
+:10A9D00020694A3978306269FDF757FB0020FDF79E
+:10A9E00063FB04E00846FDF7E7F8FDF780FB6069CC
+:10A9F0000078C00606D4A0690078C00602D4E079C9
+:10AA0000002802D0A079002801D0012000E0032016
+:10AA1000FCF7B6FF0320207001202071F8BDAA4882
+:10AA200010B51830FEF7B9FAA74C002802D0002064
+:10AA3000607004E001206070A2484A38A061A1481B
+:10AA4000407C002802D06078002805D0A069FDF77E
+:10AA5000B3F8FDF74CFB10BD9A484A38FDF7ACF847
+:10AA6000984A20694A3AA030A169FDF70EFB0120FF
+:10AA7000FDF71AFB10BD10B5934900220869302379
+:10AA80008276C27601221A544030007C002803D01E
+:10AA90000A700021022001E000210320FFF790FD51
+:10AAA00010BD70B5884C6079C20620460169084621
+:10AAB0004030002A01DA002202E0C28A4B89D21813
+:10AAC0000B46C282C0331A7E002A03D0428B4D89C6
+:10AAD00052194283627A002A03D03D2001F0A3F884
+:10AAE00052E08A7E032A4FD0227A002A13D05007E0
+:10AAF00001D4D00601D51E2036E0100701D53D2037
+:10AB000032E0D00705D1900703D470A1734807F055
+:10AB1000D8FF2A2028E060310978002905D0818BF0
+:10AB20004A1C8283C28B91420FD2597F062902D0E0
+:10AB3000197F062905D1018B4A1C0283C28B9142E1
+:10AB400003D2428B818A8A4201D322200CE0827B8D
+:10AB5000408A002A0FD006280FD35A48C07B01280C
+:10AB600001D03E2000E0082001F05DF82069807EE1
+:10AB7000032809D001E08842F5D20120207000218D
+:10AB80000846FFF71DFD70BDFFF775FF70BD10B5DE
+:10AB90004C494D48CA7B002A2BD0012A29D0022AD1
+:10ABA00027D0032A04D049A14D4807F08AFF10BDE1
+:10ABB000897B02290FD007291BD00069014640314B
+:10ABC0008A8A498A511A891E89B2032900D303212E
+:10ABD000028951180BE00069014640314A8A032A74
+:10ABE00001D2018903E04288898A5118491C818079
+:10ABF00010BD0069F5E700B5030008F067F806042A
+:10AC0000070B0F12121700290ED00FE0491E022960
+:10AC10000AD90BE0491F012906D907E0072903D00B
+:10AC200004E00A390C2901D8012000BD002000BD34
+:10AC3000FEB5054624481430FEF769F9002804D112
+:10AC40003D2022A1400107F03CFF1F4C6069FDF749
+:10AC5000E5FC03216069FDF70FFD6069EF220178D3
+:10AC6000114001702946FDF74BFD002601272B00FE
+:10AC700008F02CF80E5D5D085D1D6161155D4D5D90
+:10AC8000613D385D20697121095C002901D00621F0
+:10AC900001E0C030417E6069FDF7FDFD4BE0A06939
+:10ACA000FDF758FD01466069FDF766FE43E0216946
+:10ACB0006069D031FDF729FE216960699531FDF7A2
+:10ACC00032FE38E006190020800000207372635CB9
+:10ACD0006C6C5F736C6176652E630000610200002E
+:10ACE0006F08000006216069FDF742FE23E0E0687E
+:10ACF00001786069FDF726FEE06881886069FDF7EC
+:10AD000023FEE06841886069FDF722FE13E00096AB
+:10AD1000019620696030007C002803D069460878DD
+:10AD20003843087069466069FDF738FE03E0FA4968
+:10AD3000FA4807F0C6FEFEF7F4F8002804D1F748F9
+:10AD4000F549801D07F0BDFE0C2D07D0072D04D05E
+:10AD500020695C210E5260300770FEBD20694030D2
+:10AD60000683FEBDF0B5EE4CDC2021698DB0405C61
+:10AD7000042809D0052834D16031487A002829D028
+:10AD800001204874022026E01022EA31684600F0D3
+:10AD90007AFF21691022C83104A800F074FF6846C8
+:10ADA00005F007F8216908AA6CCA0F46CB67783707
+:10ADB0008A670846FE608030BD60074620376CC752
+:10ADC0000023036343630120A0310876D54948740A
+:10ADD000052000E00D20FFF72BFF21690020C03186
+:10ADE00008770DB0F0BDF8B5CD481430FEF78FF8F8
+:10ADF000002842D0CA4C207A00283ED12069002584
+:10AE0000C030007EC74E00280BD0B17B0120FFF779
+:10AE1000F2FE002805D1B17B0420FFF7ECFE0028EC
+:10AE200006D020690127C030407F062807D00CE0FB
+:10AE300020695A210D526030457402202FE0B17B09
+:10AE40000420FFF7D8FE002810D0B07B030007F0E5
+:10AE50003DFF173F3F3F3F1E3F3F3F3D3F203F3FAE
+:10AE60003F292C3F3F3F3F3F3F2F3F0020696A2152
+:10AE7000095CC90702D0C0304577F8BD0C20FFF748
+:10AE8000D7FE20696030817A39438172F8BD07208E
+:10AE900005E0FEF7ACF80028F8D075740B20FFF73A
+:10AEA000C7FEF8BD00F0FEFEF8BDFFF75BFFF8BD82
+:10AEB0002069002180308160C160057437740620EC
+:10AEC000FFF7B6FE206960300570F8BD0920E6E79F
+:10AED00000F0B2FEF8BD70B5924DA87B072831D1C5
+:10AEE0008F4CDE2220694188125A491C914229D197
+:10AEF000217A002926D10146E0318B88C28B93420A
+:10AF000007D1CA88068CB24203D10A89468CB24264
+:10AF10000AD0844A8689283A9680D380CB881381C8
+:10AF2000098951810121117001221146FDF784FD2B
+:10AF300000210420FFF744FB21690020C03148773D
+:10AF4000A873E87370BD70B5764CA07B162803D04B
+:10AF50007149754807F0B5FD7148002102697148D3
+:10AF60006032117211702838067C0B250123002EE7
+:10AF700006D0027B002A12D14573817303730EE061
+:10AF8000567A002E06D051722288828281740C2259
+:10AF9000027404E022888282817483750574A1732F
+:10AFA00070BDF8B55E4DA879800723D5287A0028B2
+:10AFB00020D15C4C0120A17BFFF71DFE002819D198
+:10AFC00068690026C0780127030007F07FFE0E594C
+:10AFD0005908592E3B4F0A591459205245590220FD
+:10AFE00021E0A07B042804D04F484B49333807F0B8
+:10AFF00068FDA673F8BDA07B082804D04A484649DE
+:10B000002D3807F05EFD286960300670F1E7A07BFF
+:10B010000A2804D015204049800107F052FD286914
+:10B02000603007720B20A073F8BDA07B0E2804D0FF
+:10B030003D4839491F3807F044FD286960300772E0
+:10B040000F20F0E7A07B0F2804D03748324918388A
+:10B0500007F037FD1120E6E7A07B0F2804D0324827
+:10B060002D49123807F02DFD1320DCE7FFF76BFFA9
+:10B07000F8BD2869C030417F0629F9D14677F8BD6F
+:10B0800029482549813007F01CFDF8BD10B5254C35
+:10B090000020A17BFFF7AFFD002804D1204801224A
+:10B0A000017A114301720420A07310BD10B51C4C2D
+:10B0B000DD212069095C002903D0217A0122114396
+:10B0C00021726030807A800715D4A069FDF744FCB6
+:10B0D00021696031C872A069FDF740FC21696031C7
+:10B0E0008881A069FDF73FFC216902226031C88197
+:10B0F000887A10438872206900220146C0310B7F94
+:10B10000062B13D06A231B5CDB0703D106234B7786
+:10B110004030028310BD0000CCAC0000E40700000A
+:10B120008000002006190020660500000A77F1E77C
+:10B13000F8B5FE48817B0020FFF75DFDFC4C012641
+:10B14000002807D120696030407A002802D1207A97
+:10B1500030432072216900255C204552602046540E
+:10B16000C831A069FDF7B9FB2169A0699131FDF7EC
+:10B17000C3FB2169042208469131B93007F004FB72
+:10B18000EA482838017C0827002906D0017B0029DD
+:10B1900012D14773857306730EE0216905468989CC
+:10B1A0004182E249A0691439FDF77FFBDF49A069BC
+:10B1B0000C39FDF787FB2F74DC480E218173F8BD35
+:10B1C00070B5DA4D0020A97BFFF715FDD84C00289B
+:10B1D00003D1207A012108432072A069FDF721FBE9
+:10B1E00000280ED0A069FDF717FB2169DE2250521E
+:10B1F000498800F0A2FD002806D0282000F013FDA9
+:10B2000070BDFFF743FF70BDA069FDF7FFFA21692C
+:10B21000E0310870A069FDF7F2FA2169E031488059
+:10B22000A069FDF7D1FA2169E0318880A069FDF7B6
+:10B23000D4FA2169E031C880A069FDF7D7FA216905
+:10B24000E03108810720A87370BDF8B5B84CA0792B
+:10B25000C0076ED0207A00286BD1B44D0120A97BA5
+:10B26000FFF7C9FC002853D1A0690027C17802224A
+:10B2700001260B0007F02AFD0D161308354A4A383F
+:10B280004C474A1929444A00FDF707FB2169DA2295
+:10B290005054AE735C20475260310E7038E000F0BD
+:10B2A00057FD35E0FFF78CFF32E0A97B0020FFF768
+:10B2B000A2FC002802D1207A3043207220695C2150
+:10B2C0000F52603006700A2018E0A87B0B2802D0CD
+:10B2D000207A104320722F742069603046720C204F
+:10B2E0000CE0FFF725FF13E0A87B112802D0207A9D
+:10B2F000104320722069603007701620A87307E0A1
+:10B30000FFF7D4FE04E000F0F0FC01E0FFF7BEFE22
+:10B31000FDF759FE002803D18649874807F0D1FB85
+:10B32000206900238030016B426B491C5A41426303
+:10B330000163F8BDF8B57D4F787C002802D1387CD8
+:10B34000002801D0FCF7D3FEFCF760FCFCF754FCAE
+:10B350000020FCF715FBFCF79CFBFCF75CFCFCF702
+:10B36000DCFBFCF724FCF87B01260025704C002850
+:10B370000FD16079C10705D00220F87320694030F1
+:10B38000857302E0800717D5FE7300210120FFF7C7
+:10B3900017F9F87B012802D0022808D00CE0607968
+:10B3A000C00709D00220F8732069403085736079A6
+:10B3B000000701D50320F87300F0EEFCFFF713FD42
+:10B3C0002079002801D03D8102E03889401C388175
+:10B3D0006079C007206904D072210D544030458245
+:10B3E00003E04030418A491C4182E079002806D0C0
+:10B3F00021696031887C022806D8401C8874206945
+:10B400006030807C022804D93D817D8120696030D4
+:10B410008574B97B0020FFF7EEFB002802D1B87BD2
+:10B4200006284BD120690146C0310A7F062A45D043
+:10B43000497F062942D03D49C97B03293ED160306E
+:10B44000807C00283AD1FDF71BFD002836D0FDF79F
+:10B4500091FD002832D02169C88801282ED90A46DA
+:10B460004032D673908A578A831E9F4201DB0120A7
+:10B4700002E0C01B401E80B22C4B0F8C1B89BB42CC
+:10B4800001D3012302E0FB1A5B1C9BB2984200D956
+:10B490001846012800D1D5732A22525C002A11D007
+:10B4A000224A898D52898A4201D3012102E0891AF8
+:10B4B000491C89B2884205D9084603E02169012068
+:10B4C0004031CD7321694A8810180881FFF75FFB6E
+:10B4D0002069122215490C3007F056F9FFF7E1FAFE
+:10B4E000FEF77EFF002808D010482838817F002909
+:10B4F00003D121698989018486770D481830FDF7C9
+:10B50000AAFD00280FD0A06900788007800F0128CD
+:10B5100009D0022807D0FDF7BEFD002803D1054958
+:10B52000064807F0CEFA2069403009E006190020ED
+:10B5300080000020CCAC0000DF040000720300009B
+:10B540000574F8BD70B5FE4C607900283DD0FD4D06
+:10B55000022811D1FDF775FC002804D17320FA49A7
+:10B56000000107F0AEFA2A69002380329068D168A2
+:10B57000401C5941D16090600026667120790128F5
+:10B5800004D12671A87910210843A871E078012818
+:10B5900016D1E670A87908210843A871FDF7E0FCF0
+:10B5A000002804D1E920E849C00007F08AFA296997
+:10B5B000002380318A68C868521C58418A60C8607C
+:10B5C000A079012802D00120A07170BDA67170BDC4
+:10B5D000F8B5DC4CDA4DA269002710780421830706
+:10B5E0009B0FE8790126012B11D0022B0FD0032BE2
+:10B5F00001D0207A2FE06178002905D1AE70A179C1
+:10B600003143A17122E0EF71F8BDEE71F8BD5278BF
+:10B61000D3061BD060780028F8D1D006C00E1B28B6
+:10B6200017D8607908436071FDF7CDFC002803D17D
+:10B63000C549C64807F045FA206900238030026BEF
+:10B64000416B521C594102634163E8790128DCD106
+:10B65000D9E7207A102108432072F8BD70B5B84DA3
+:10B660000446283D287B002600280AD0002976D1F0
+:10B67000667010202070687BA070A87BE0702E732D
+:10B680006DE02878002810D0002968D16670072066
+:10B69000207005E02E700A22A91CA01C07F074F887
+:10B6A00028780028F6D1A67059E0287C002839D0E7
+:10B6B000002954D1297CA3480B0007F007FB0D2E6D
+:10B6C0002E2E2E2E2E2E2E112E2E22082E0066709D
+:10B6D0000C212170A97CA17000698089A0801AE0EA
+:10B6E00008216670217000690A468089944960804B
+:10B6F0001439201D07F048F891484A38C08FA081BE
+:10B7000009E066700B212170A97CA1700069808915
+:10B71000A080A87DA0712E7421E08B498C4807F091
+:10B72000D0F91CE0AA7F86480838002A08D00029F2
+:10B7300015D166701121217000886080AE770EE00F
+:10B740007F4A083A9378002B0BD0002907D1667006
+:10B750001221217081886180C088A08096700120AC
+:10B7600070BD002070BD77480078012801D00C2002
+:10B770007047734900202839087008730874887767
+:10B78000704770B56F4C064620780D46002804D0EF
+:10B790006F486D493F3007F094F90120E660E07290
+:10B7A000E5612070FFF7DFFF002804D09320664991
+:10B7B000000107F086F970BDF8B5624C21780129C7
+:10B7C00002D12178012901D00C20F8BD014605469F
+:10B7D000206112220C315A4806F0D6FF012740356D
+:10B7E0002F74574D2888FDF712FB002827D0288892
+:10B7F000FDF7C8FB002822D02888FDF77DFB002834
+:10B800001DD02888FDF797FB002818D0FCF7C3F956
+:10B8100020690026C088002824D04A481430FDF74B
+:10B8200076FB00281ED02069C030007E002819D089
+:10B83000A97B0120FFF7DFF9002802D012E01220D7
+:10B84000F8BDA97B0420FFF7D6F900280AD12169A9
+:10B850005A20465260314E740220FFF7E9F9206900
+:10B860004030C67320694189491E8AB229898918E6
+:10B870002981297B002902D06E812E7302E069891B
+:10B8800089186981014640314B8A9B184B82C388D5
+:10B89000012B01D85B1CC380002A01D072221654F0
+:10B8A000AA7B032A16D0C97B002915D02989008CD0
+:10B8B000814211D2FDF7E4FA00280DD020692A2137
+:10B8C000095C00290BD06989808D814207D3A6705D
+:10B8D000E7700CE0A7700AE0A670E67007E06889E0
+:10B8E0000021401C6881A7700520FEF769FE2069D1
+:10B8F0004F210E54A178002930D12030807A0028C1
+:10B9000000D06E810120FBF71BFF20693630FCF769
+:10B91000F8F820693230FCF70EF8E169002008568B
+:10B92000FBF7D5FF0120FCF733F9FBF78EFFFCF79F
+:10B930002BF90120FCF76AF82069406E0AE000004C
+:10B940000619002080000020CCAC00007B0700001E
+:10B95000E7080000FCF733F9FFF761F8A87B05283A
+:10B9600001D0062816D12069DE224188125A891A90
+:10B9700009B200290EDB01460522E0312430F4F73C
+:10B9800023FC012202212069FDF756F82069C0300E
+:10B990004677AE7320694189FDF7FDF82069403094
+:10B9A000407BFBF7D1FF6671E671A6712672A67225
+:10B9B0006672267102202070FCF7F9F80020F8BDAD
+:10B9C00010B5FE4C2078022801D00C2010BDFCF7E9
+:10B9D000E2F8A078002802D0FFF7ACFC15E000F0F8
+:10B9E0001AF920692030807B012809D0FCF736F94C
+:10B9F000FBF730FFF4F7F7FCE07A012803D004E00E
+:10BA0000FCF734F9F4E707F05BF9002010BDEB49CF
+:10BA1000C872704710B5E94C2078032803D0E84974
+:10BA2000E84807F04EF8E84801218278002A06D05D
+:10BA3000002282700171A27904231A43A271626903
+:10BA40001378DB439B0707D1C378002B04D1C17067
+:10BA5000A07902210843A0711078C00606D4A0691D
+:10BA60000078C00602D4E07900280CD06078002865
+:10BA700009D1A079002806D1FEF7A2FC002802D047
+:10BA8000207A002802D0FFF755FC03E0FEF7C7FF3D
+:10BA900000F0C1F82078012806D0F4F7A4FCE07A81
+:10BAA000012801D1FCF772F910BD38B5C34C2069EB
+:10BAB0002030807B012820D1A07A00281DD1684643
+:10BAC000FCF7DCF8002818D021692F20405C012801
+:10BAD00010D1BD4A0D236D460020D356285683420F
+:10BAE00008D050738989283A918411462031887191
+:10BAF00001208870A07A401CA07238BD70B5AF4C90
+:10BB000006462078042804D0AE48AD49553006F0EA
+:10BB1000D8FF607910210843AB4D6071002E47D0EB
+:10BB2000FCF7FDFA61780126084300280ED1687CF5
+:10BB300000280BD0A0694178C90607D00078E979C0
+:10BB40000007C00F884201D1667247E0E078002804
+:10BB500009D0A0694178C90605D10078C00602D491
+:10BB6000FFF7A3FF3AE0FFF7A0FFA069A9790078EB
+:10BB70004007C00F884205D0FFF7E4FC6079082138
+:10BB800008436071A069E97900780007C00F884216
+:10BB900001D1FFF71DFD6079304360710020E07135
+:10BBA000A079000702D5A87B022817D0207A13E0DD
+:10BBB000022108436071E079401CC0B2E0710128A5
+:10BBC0000CD8687C00280CD07F484A384078C106E1
+:10BBD000C90E052905D2C006002802D0FFF7AAFB2E
+:10BBE00001E0FEF775FE2078012806D0F4F7FBFB94
+:10BBF000E07A012801D1FCF7C9F870BD10B56F4893
+:10BC00000078042804D06F486D49B73006F059FF1A
+:10BC1000FFF790FB10BD10B50720FBF7B1FE674999
+:10BC20000420087010BD6549312209695054664AE4
+:10BC3000032090738876704710B5604C2069C0303F
+:10BC4000007F00281ED06048817B0020FEF7D3FFD4
+:10BC5000002817D02069DC21095C0B0007F036F8BA
+:10BC6000071212121212120512006030807AC007F9
+:10BC700008D10C20FEF7DCFF206901226030817AB8
+:10BC80001143817210BD10B5002A0AD0002306E0CE
+:10BC9000D41A6418203CE47FC4545B1CDBB293428A
+:10BCA000F6D310BD10B503F02AFF0C281CD3434C6B
+:10BCB00008212069D03003F023FF002806D0206936
+:10BCC0000421953003F01CFF002803D13C493F4874
+:10BCD00006F0F7FE2169042208469531BD3006F0D2
+:10BCE00053FD0420FEF7A4FF10BD7CB5364E0020A6
+:10BCF000B17BFEF780FF0125304C002802D1207A6D
+:10BD0000284320726946A069FCF74EFE6846007819
+:10BD10000021C207D20F684602702069002A02D0B3
+:10BD20006030057401E06030017420695C221152BA
+:10BD3000603005700820B0737CBD401A244900B201
+:10BD4000884201DC002801DC012070470020704798
+:10BD500070B51D4D0020A97BFEF74DFF174C002844
+:10BD600003D1207A012108432072A069FCF78EFDDF
+:10BD70002169DE2250524988FFF7DFFF002803D0F7
+:10BD80002820FFF750FF70BD2169A069E031FCF762
+:10BD900071FD0520A87370BD70B500F054F8074C14
+:10BDA000094D6079400716D5A97B0520FEF723FFD2
+:10BDB000002810D0207A082108430BE080000020E2
+:10BDC000CCAC00001D0A000006190020640600002B
+:10BDD000FE7F00002072FFF738FA00F012F8FFF73C
+:10BDE000E0F8A079C00609D5A87B030006F06EFF35
+:10BDF00006060606060604060620A873FFF76BF87B
+:10BE000070BD10B525488179490714D5017A0029FC
+:10BE100011D12349897B0B0006F058FF080D050D51
+:10BE20000D0D0E0D100D0069002260210A54C03066
+:10BE3000807EFFF7F8FE10BD012100E002210069BD
+:10BE4000C030417710BD10B51448817909071DD560
+:10BE5000017A00291AD1124A947B230006F036FF9A
+:10BE60001416160B1616161616161616161616167F
+:10BE7000161616161716006960300170407C0028EF
+:10BE800001D0062000E01620FFF7CDFE10BD0069AE
+:10BE9000603001720170917310BD000080000020BD
+:10BEA0000619002010B5031D03600020521E04E097
+:10BEB0005C181C60401C2346C0B29042F8DB002096
+:10BEC000186010BD01460A680020002A02D0104602
+:10BED00012680A60704702680A60016070470000DB
+:10BEE00000B51A2822D00ADC030006F0EFFE0D117F
+:10BEF0001F131F1F191915171F1F1F1B1F002A288B
+:10BF000014DD3A38030006F0E1FE030F11091100B9
+:10BF1000002000BD1E4800BD042000BD0D2000BD56
+:10BF20000F2000BD082000BD112000BD032000BD72
+:10BF300010B50C46F5F7C8FB00281AD02046F4F7D8
+:10BF400061FE002812D020780E280BD00F2809D0CF
+:10BF5000022807D0032805D00EA1772006F0B1FDF6
+:10BF6000002010BDA078FFF7BBFF10BD09A17D2008
+:10BF7000F4E708A18320F1E710B5F4F7CBFD10BD7D
+:10BF800010B5F4F73FFE10BD10B5F4F721FE10BD5B
+:10BF9000013000007372635C686F73745F6863697B
+:10BFA0002E630000F0B597B00021032004F0F7F8ED
+:10BFB0000025FE4E022775807574347C12E0F0680F
+:10BFC000E1004018818800290CD0858069460F70F7
+:10BFD0004D7001680291808869468880002168461A
+:10BFE000F8F7F0FD2046641EE4B20028E7D117B050
+:10BFF000F0BDEE4BD86019741A80D3E7EB49EC4BD7
+:10C000004A8800201A4200D00120497C002901D032
+:10C01000082108437047F7B504460E460078012111
+:10C02000E34A8140521C114098B0E04A0091518887
+:10C03000E04B994205D0009B002B05D0DC4B194208
+:10C0400002D001201BB0F0BD009BD84A194351809B
+:10C050001A9D002D11D00020287022781A980027F0
+:10C06000401C130006F032FE10EF0D152137555D10
+:10C070006A39AFAB85B3EEEDECEF0B28EDD00420C1
+:10C08000E0E702212970A1880170090A41700320AC
+:10C0900093E004212970A1880170090A4170E188A8
+:10C0A0008170090AC170052087E006212970A188E6
+:10C0B0000170090A4170E1888170090AC170218903
+:10C0C0000171090A4171A289E81D216906F05CFB32
+:10C0D000A089C01D71E0082129702178082901D1AB
+:10C0E00010212970A1880170090A4170E1888170CE
+:10C0F000090AC1700520308020466A1D01A9083058
+:10C1000003F047FB00287DD1694630880979401843
+:10C1100053E00A212970A1880170090A41700320A7
+:10C120000AE00C212970A1880170090A4170E18898
+:10C130008170090AC170052030809DE0A088844686
+:10C140004000401C81B2308888425BD3052959D316
+:10C150000E202870002008E0A36842009B5A521964
+:10C1600053701B0A401C937080B26045F4D3318039
+:10C17000B6E08E49487C002873D0401E4874C868D9
+:10C1800021790822C9004518A9882868401808386C
+:10C19000A16806F0F9FA0221684601710021417197
+:10C1A00028680390A98868460181002101A8F8F752
+:10C1B00009FD0020A880002E00D0308090E0297872
+:10C1C000802211432970297840221143297029784F
+:10C1D0008909890112312970A1880170090A417009
+:10C1E000E288E81CA16806F0CFFAE088C01C308025
+:10C1F0002878410640D5C00972D0012168460171F6
+:10C20000002100E02BE041713188ED1C091D018106
+:10C210001A980390E08840190490001D634D059022
+:10C22000297C68460176002101A8F8F7CBFC074677
+:10C2300030880C303080022F06D0002F50D060E0C4
+:10C240003CE032E01CE059E06946097EE868CA003B
+:10C2500080182A7C914202D28188002902D00427CA
+:10C260004FE02EE0697C491C69741A99016031889D
+:10C2700081800020308044E04C48A188C1802FE0BC
+:10C2800029788909890116312970A1880170090A64
+:10C290004170E1888170090AC1702289681DE168D6
+:10C2A00006F072FA2089401D46E72878800980014F
+:10C2B000183028702079687002207EE73B480A0415
+:10C2C00001D405271DE00289A3889A4201D00627E0
+:10C2D00017E01E222A70012249043280490C418055
+:10C2E000009800280DD0314D002228881146830087
+:10C2F000032003F0B2FE2078287107E00020308090
+:10C3000003272A48009942888A434280384699E6A2
+:10C31000F7B59AB002000C4606D0172A04D8234875
+:10C32000244B4088984202D107201DB0F0BD2378ED
+:10C330005D0601D4DB0901D00820F6E700236D4635
+:10C340002B706B701D462378611C9F06931E1893FB
+:10C35000531E19939BB2169302AB1793134BBF0E48
+:10C36000DE883B0006F0B2FC208511F15EF16BF136
+:10C37000A3F1C6F1F2F1FBF1EEF1EDF1ECF1F1F127
+:10C38000EBF1EAF1E9F1E8F185F1052A71D1042236
+:10C3900069460A7005490A7969460A71E178A37805
+:10C3A0000A021A436946CA80227905E0181900205A
+:10C3B000FE710000FFFF00004A7061788906890E57
+:10C3C0000C2923D009DC891E0B0006F07FFC091321
+:10C3D00052155219521B521D520012291CD004DC56
+:10C3E0000E2915D01029D1D114E0162916D01829FC
+:10C3F000CCD115E0800700E04007002839DA2AE1B7
+:10C400000007FAE7C006F8E78006F6E74006F4E71B
+:10C410000006F2E7C005F0E7C004EEE78004ECE7B1
+:10C420004004EAE7800724D5032AAFD105206A46F5
+:10C430001070487809780002084390800BE14007AB
+:10C44000F1D5062A15D31898617880B2012902D057
+:10C4500002299BD101E0022700E01027062269464D
+:10C460000A7000228A8001AEA11C0236BA1C179203
+:10C4700018E0B6E04A780B7812021A433280801E28
+:10C48000891C1890B21C1691384603F05CF9169975
+:10C4900018986B469A88C919C01BB61D521C9A8001
+:10C4A000179A80B28242E5D900289CD1D3E00007D8
+:10C4B000B9D51998694682B2072008700020888093
+:10C4C000601C891D11E0437806781B0233430B8002
+:10C4D000C37886781B0233434B806E46121FB388A5
+:10C4E000001D091D5B1C92B2B380042AEBD2002A06
+:10C4F00077D1B0E0C00674D5022A72D3189808210B
+:10C5000082B2684601700021C18063780371A01C6B
+:10C5100017990EE04678077836023E430E80861C57
+:10C520004E606F46D21AFE88C0180831761C92B24F
+:10C53000FE809342EED9DAE76FE076E065E051E005
+:10C5400046E01EE014E00AE000E0A0E0800648D5E6
+:10C5500009206A46107096801698D0800FE0400639
+:10C560003FD50A22684602708680169AC28006E08D
+:10C57000000636D50B206A461070169890800291FE
+:10C5800069E0C0052DD5022A7FD318980C2182B20C
+:10C59000684601700021C18063780371A01C17995F
+:10C5A00013E04678077836023E430E80C6788778D7
+:10C5B00036023E434E80061D4E606F46D21AFE88FC
+:10C5C000C0180831761C92B2FE809342E9D98EE7FA
+:10C5D000C0045AD5012A58D10D21684601708680C1
+:10C5E00039E052E0800450D5052A4ED30E23684628
+:10C5F00003708680C8788B78010219436846C18031
+:10C60000521F0281601D039025E040043DD5012AA0
+:10C610003BD10F20694608701DE0030435D44B78E8
+:10C620000E781B023343244E3381032A2DD31B2F54
+:10C6300027D011236E46337001261F4BF60330437B
+:10C64000588048780B780102194368468180D21ED1
+:10C65000C280E01C029020788006800E1B280AD041
+:10C660001D2808D00021032003F099FD12484188BD
+:10C67000C90BC903418068461C99F8F7A3FA2846FC
+:10C6800053E610206B461870DBE70725F7E708250F
+:10C69000F5E700B50022D243074997B04A80032846
+:10C6A00007D1032268460270097901710021F8F769
+:10C6B00089FA17B000BD000018190020FFB589B035
+:10C6C0000020019009981027FE4C1E4615460828A8
+:10C6D00006D0E06901F05EF8002809D03770BEE0AE
+:10C6E000288809213843108013980227017016E02A
+:10C6F000E169012088710521E269C9029180E1693F
+:10C700008872E169F0480881E1690020887328880F
+:10C7100020210843288011211398042701701398C1
+:10C720000225801C0290307806900A203070E5487F
+:10C730001830049001F00DFA0020059020462C30AE
+:10C7400003906DE00998102808D1022D06D00199B8
+:10C750000298A28D401A8270110AC170E08D0A9968
+:10C76000884202D901F0D5F806E0884204D1069843
+:10C77000002801D030701CE00298E18D0170090A98
+:10C78000417012980088401BC01B82B2FF20C01B62
+:10C79000904200D2024607A8009002980021C319D7
+:10C7A000E08D01F041FA3070002805D0C0B2832836
+:10C7B00058D0E08D20833EE00598002804D0206CFE
+:10C7C00000790A282CD336E06846808BC119C9B29B
+:10C7D0000191022D0DD01399019A4978914202D10D
+:10C7E000228F824208D00191206C0178032908D061
+:10C7F00023E0084613994870206C0178042906D07C
+:10C8000007E000790A2818D20120059008E0E18DA0
+:10C81000818002990198081802900198281885B221
+:10C820000399049801F098F9002804D1129800881F
+:10C83000401BB84286DA022D0DD00998102806D187
+:10C8400002990198A28D081A8270110AC17012987B
+:10C85000058000203070206C0078032802D0002072
+:10C860000DB0F0BD0220FBE7F8B5964A0026126D28
+:10C87000002A2ED0401F934D84B24035E88A2346CB
+:10C880000833AF8AC318BB4222D88B784F781B027B
+:10C8900010183B4303701B0A43700B79CF781A02C0
+:10C8A0003A438270120AC2700471220A427122460F
+:10C8B000491D801D05F068FFE88AA41D001980B29B
+:10C8C0008049E882096D002208180270427000E079
+:10C8D00009263046F8BD30B57A4B028840339B8A32
+:10C8E000934213D9774B1C6DA3185C781D782402F2
+:10C8F0002C430BD05C791D7924022C436404640C16
+:10C90000A41D1219028000200B6030BD822030BDB2
+:10C91000F0B585B0074600266846068155E00198C7
+:10C92000417802780D0215434179027908021043DB
+:10C9300000044AD43D8003A8002301220090520243
+:10C940001946284601F070F9040044D1684601896F
+:10C9500001820198417902790902114343780278F2
+:10C960001C021443AC421CD10A041AD44A0401210B
+:10C97000520C89030A430096C1788078090201436A
+:10C980000023204600F0C9FF040010D10199487926
+:10C990000A79000210430122D20310430871000AF1
+:10C9A000487101A904A8FFF796FF0400D1D00199AE
+:10C9B00000964878097800020843694600238A896E
+:10C9C000194600F0AAFF822C05D101A902A8FFF7A1
+:10C9D00082FF0400A3D06846068109E001994879E6
+:10C9E0000A79000210434004400C0871000A4871A3
+:10C9F00001A902A8FFF76FFF0028EFD0822C02D018
+:10CA0000204605B0F0BD0020FBE7F7B584B0144622
+:10CA10000646002700F079FF2A480025006D00280F
+:10CA20002FD0059801282CD12046FFF771FF070071
+:10CA300027D1002E29D06846058118E00199487851
+:10CA40000978000208432080019B009558791979E4
+:10CA50000202D8780A4301029F78587839431F7838
+:10CA600000029B1D384300F058FF002805D101A9A2
+:10CA700002A8FFF730FF0028E0D0822800D1002074
+:10CA80000746002E01D00F48056500F042FF3846EA
+:10CA900007B0F0BDF0B597B00021042003F07FFB94
+:10CAA000084F00243D467C8040356C73AC73287B76
+:10CAB000B96CC00008380E18B08800280DD00120CD
+:10CAC000694603E02C190020012800000870306836
+:10CAD000019000216846F9F77AFBB4803C65AC828E
+:10CAE000EC8217B0F0BDFE4B9864184640300173DD
+:10CAF0001A803838D861CDE7F949002049880A07FB
+:10CB000000D501200A06120F01D002221043CA05E7
+:10CB100001D5042210438A0501D51022104349058E
+:10CB200001D520210843EE494031497B002901D03D
+:10CB3000082108437047FFB5A7B00400289816469F
+:10CB40001B9022D00178E6484D0642882292024688
+:10CB500040320092002D14DB8A06920E1E2A0ED05F
+:10CB6000229A5205520E10D13288172A0DD3009AFC
+:10CB7000927B002A09D1DB4D229AAA4205D0CA092C
+:10CB800006D08A06920E122A02D003202BB0F0BDE6
+:10CB9000D348826C0098007B2590C000083810189C
+:10CBA0001F9048060CD40098407B002808D00099BC
+:10CBB00088731F99289808601F9884800220E5E7F1
+:10CBC000002718A90F7069460F72C54902AA0A64A6
+:10CBD000309A4A6410A90F850F861B981D4600786D
+:10CBE00020908106BE4B601F24901A462C32219261
+:10CBF0002898DA691833890E1E93401C0B0006F042
+:10CC000065F81FFDFD11FD1AFD90FDFCFDFBFDFA11
+:10CC1000FDF9FDFCFDF8FDFDFDF7FDF6FDFDFDFD5B
+:10CC2000FDF5FD00032C7BD10320287017226A70CC
+:10CC30000022AA70E0E2052CF5D1417802780902C1
+:10CC40001143A74B10AA19831185C278807812026C
+:10CC500002435A8300297DD091427BD80021184697
+:10CC600081720181491E01841E9800F072FF052027
+:10CC70002870A81C1D900220009021991E9800F099
+:10CC80006BFF002803D047E018A90870F0E2944831
+:10CC90002030807C012803D002206870102002E040
+:10CCA00001206870022022908D48303023900022AD
+:10CCB00020A9239802F06DFD00282AD120A8007831
+:10CCC0002299814225D132880099801C511A8142D3
+:10CCD0001FDB83481D99C08D0870000A48701D989D
+:10CCE00020A9801C1D9000981D9A801C00902398FC
+:10CCF00002F04FFD20A909781D9840181D9000985A
+:10CD0000401880B2009021991E9800F025FF00285D
+:10CD1000CDD0009802288DD10A2018A908706CE2A5
+:10CD20006DE0072C6BD341780378090219436C4BF3
+:10CD30008446198310AB1985C37880781B02184389
+:10CD4000674B0029588305D0814203D8012118463A
+:10CD5000817200E0A4E061464B7909791B020B4324
+:10CD6000038100218173104600F014FD00280FD1CB
+:10CD70005B480121C26991710522C369D2029A8080
+:10CD8000C2699172C26958491181C06900218173D9
+:10CD90005349E01F08841B98C01D48621E9800F08C
+:10CDA000D8FE07202870681C009001201D904C4878
+:10CDB0000021C18530E01D98012815D04848C1697F
+:10CDC000897901292FD000981038C17B807B090216
+:10CDD000014300980170090A41700098801C00907E
+:10CDE0001D98801C80B21D903D4809E013E2BEE111
+:10CDF0007AE1D8E00DE2A0E080E03BE01EE2B6E0A0
+:10CE0000C18D00980170090A41700098801C009043
+:10CE10001D98801C80B21D9021991E9800F09CFEE8
+:10CE2000002802D006E0818DD3E731881D98081ACA
+:10CE30000428C0DA1D98012800D16DE72848C1698F
+:10CE40008979012903D0828D26498A4205D1818DB5
+:10CE500000980170090A417009E000981038C17B00
+:10CE6000827B0802009910430870000A48701D98E0
+:10CE7000801CC1E1072C01D0152C78D141780378B2
+:10CE800009021943164B198310AB1985C3788078B2
+:10CE90001B02034312480029438301D0994201D960
+:10CEA0000120F1E60E480121817200210181817388
+:10CEB000052C07D024981B99C0B2491D02F043FCF1
+:10CEC0000028BAD100200649C04308841B98009668
+:10CED0000195007818AB8006800E1CAA002105E0A1
+:10CEE0002C190020FFFF000001280000FFF7E6FBDF
+:10CEF0000746FE4810A9008B08857EE1032CBCD1B3
+:10CF0000402210A90A86417802780802F7491043A6
+:10CF1000088310A9088520A9009131886B1C491E3F
+:10CF20008AB2002100F080FE18A90870002830D1D4
+:10CF30000B20287020A8008833E0052C9DD180218B
+:10CF400010AB1986014640780B780202E7481A4375
+:10CF50000283CB7889781B021943E44B104619846D
+:10CF600010AB1A85E24A914202D307208CE697E083
+:10CF70003F23DE4A9B021943118421AA0092328882
+:10CF80006B1C521E92B200F04FFE18A908700028C8
+:10CF900003D08328B1D102272FE10D20287020A8CB
+:10CFA0008088401C28E120990C22C9095143C91CE2
+:10CFB0001E91A14204D92098400671D500201BE1A2
+:10CFC000417800780902014310A801851B98007878
+:10CFD00042062898C01C1D90002A62DA05206A4685
+:10CFE00010721B980078C00944D00822684602726B
+:10CFF0008181A01A87B268468782289806901E9879
+:10D00000201A81B26846C1811D980490401805F02D
+:10D010001CFC079006982599C0190890491E08A87D
+:10D02000017102A83099F9F7D2F807460021684645
+:10D030000172002F1BD0022F18D1009808A9007B85
+:10D040000979401E884210DDA848289A836CC900DF
+:10D050005A50816C08A80079C000001D0C5200983D
+:10D060000099407B401C4873C7E00527EAE0062092
+:10D0700069460872002000901E980021201A209016
+:10D0800082B21B9B10A8DB1C008D00F046FC014601
+:10D0900018A80170002268460272832903D003E0B9
+:10D0A00093E00720E4E702271B98007840060ED59E
+:10D0B0008E484188C90506D510AA018B128D914270
+:10D0C00001D100214162002018A9087094E0FF21DD
+:10D0D000013110A80186018D8448018320990184C3
+:10D0E0001D994162132085E0052C6ED341780378A9
+:10D0F0000A021A4310A90A859446092269460A724F
+:10D100000021009101222499D20311438AB2C178EF
+:10D11000807809021B9B01435B1D604600F0FDFB0C
+:10D1200018A90870002269460A720122520210A949
+:10D130000A86832802D0002805D099E06B48098D23
+:10D14000018302277EE06948006D002807D0204651
+:10D150001B99FFF789FB18A9087000284DD12B46B1
+:10D16000324620461B9900F024FB074645E01B98F9
+:10D17000022C4078009064D1002801D0012860D1B1
+:10D180000A2168460172009901731AAA00200099C9
+:10D19000FFF73BFC0146684641730021817302A8FA
+:10D1A0003099F9F714F80746002168460172012109
+:10D1B000890210A80186022F08D04C48006C8079A3
+:10D1C000002807D018A9087020E04BE047490098D4
+:10D1D000088337E0002F03D0812018A9087031E0C0
+:10D1E0001AAA01200099FFF710FC18A9087000285E
+:10D1F00003D119202870012030806846007A002869
+:10D2000004D002A83099F8F7E2FF0746002F2BD090
+:10D2100018E0062038E522993448090711D5012C79
+:10D220000FD10B2269460A72C08888810021042030
+:10D2300002F0B5FF082010A90886BFE62098400636
+:10D2400010D50327294810AA4188128E1143418026
+:10D250005005400E04D01F99289808601F988480BC
+:10D26000384693E404200FE518A8007800280ED073
+:10D27000012028701B980078687010A8008DA87095
+:10D28000000AE87018A80078287105203080174837
+:10D2900010AA4188128E91434180E1E7FFB506460E
+:10D2A0009FB000201B903178012088401149124A1C
+:10D2B000084010A908860D494988914203D00028EA
+:10D2C00004D0080702D5012023B0F0BD219D00271E
+:10D2D0002F7020983C46018810A8018418A8077177
+:10D2E00000F013FB6846077202A907E02C19002022
+:10D2F0000102000009F80000FFFF0000FA48016485
+:10D3000001464031826C1A91097BC90008395718CF
+:10D3100022994164307801282AD0022809D00328B4
+:10D3200079D12878800980011D302870EE48B188B5
+:10D33000C1803078022804D12878800980011B3010
+:10D34000287001A8009010A8008CEB1CC01E82B2AF
+:10D35000B088002100F068FC0028E1D1B188697034
+:10D36000090AA9706946888810A9C01C08842DE1A3
+:10D37000717918A801713079012802D00228CFD123
+:10D38000E6E0D9487F2340881B010246184010ABD5
+:10D390001886802840D006DC102810D020280ED017
+:10D3A00040280AD120E0FF38013859D0FF38013831
+:10D3B0006AD0FF38FF3802387ED0052491E0D006CD
+:10D3C00001D5082000E010201B9004206946087257
+:10D3D0000020888118A800900195318919AB1CAAFA
+:10D3E0001B98FFF76BF977E0BF4B3289188B8242AD
+:10D3F0004FD10A221B92002973D101A9009110A9D3
+:10D40000098C6B1C491E8AB2002100F00DFC18A982
+:10D4100008710B2017E0F6E0B34B3289188B82427B
+:10D4200037D10C221B9200295BD101A9009110A9D0
+:10D43000098C491E8AB21946098C6B1C00F0F4FB5A
+:10D4400018A908710D2028706946888810A9401C09
+:10D450000884042069460872A348008B888140E054
+:10D46000A14A3389108B834213D112231B930029C5
+:10D4700037D1536A002B05D00091128C00F04DFA81
+:10D4800018A9087113205EE097483289038B9A42ED
+:10D4900001D00424E7E016221B92026D002A09D174
+:10D4A000F268002A06D002651A98328A82821A9A95
+:10D4B0000020D082002900E02FE012D1B88839681E
+:10D4C000FFF7D2F918A9087100280AD1B8882B46AD
+:10D4D00018AA396800F06DF90446022818D0042C07
+:10D4E00016D0B88800280FD06846007A002804D0EB
+:10D4F00002A82299F8F76BFE0446012069460872DB
+:10D50000386803900020B880002C5FD0052C7BD0B9
+:10D510006846007A032873D0A5E018201B900029E4
+:10D5200005D071483189018300210165D9E76E4832
+:10D530000246017E18320120FFF767FA18A9087128
+:10D540000028CED119202870012010A90884C8E72E
+:10D550001A98407B002856D0307AC0001358001D1E
+:10D560000193105A1D9000291AD100F0D2F906201B
+:10D5700069460872002000901D980F3882B2019809
+:10D580008178437808021843019B0021DB1C00F0DE
+:10D59000C4F918A90871002269460A72832830D09C
+:10D5A000002118A8017110A80184012168460172A8
+:10D5B000019803901A981A99407B401E48731A9854
+:10D5C000807B002802D01A99401E887310A8008E14
+:10D5D0007F21090102468A431DD04348002200886A
+:10D5E00011468300042002F038FD3F483178017174
+:10D5F00010A94088098E08433B4948800FE003E0AA
+:10D600002BE002242FE00524374810AA4188128E0F
+:10D610009143418027E034494A8882434A806846E2
+:10D62000007A002805D03048416C02A8F8F7CFFDF9
+:10D63000044618A80079002815D01B9868700120AE
+:10D6400028702948008BA870000AE87018A8007993
+:10D650002871052110A8018405E02348416C02A827
+:10D66000F8F7B5FD044600F054F91F48408840051E
+:10D67000400E20D11A98807B00281CD1B888002841
+:10D6800019D0209910AA098811842299009139682B
+:10D6900018AA219BFFF74FFA044602280BD001205D
+:10D6A000694608723868039002A82299F8F78FFD3E
+:10D6B00004460020B88010A8018C209801802046E4
+:10D6C00002E600B50022D243074997B04A800428F9
+:10D6D00007D1022268460270097901710021F8F72A
+:10D6E00076FD17B000BD00002C19002010B5394C94
+:10D6F00003780022216C012B02D0022B44D126E0BA
+:10D700000B78002B01D0042B03D10A71226C03216A
+:10D710001170216C83880A79D200921D8B52216C82
+:10D720000A79D20008328918C2880A80216C0389DC
+:10D730000A79D2000A328B524289206C0179C900E1
+:10D740000C314252216C0879401C087120E00A74A7
+:10D75000226C81889180216CC288CA80226C0189E8
+:10D760001181226C41895181216CC068C860616C53
+:10D77000206CF8F72CFD0146022807D0206C007CB5
+:10D78000002802D1002903D0812010BD832010BDC4
+:10D79000002010BD8178012909D100880521C90226
+:10D7A000884202D0491C884201D1002070470520E0
+:10D7B000704710B51488844201D2052010BD17248B
+:10D7C0001C701080421E491C581C04F0DDFF002014
+:10D7D00010BD00002C19002010B50446FEF759FFBB
+:10D7E0002046FFF76EFF10BD10B58B78002B11D0CF
+:10D7F00082789A4207D10B88002B0BD003E0091DD9
+:10D800008B78002B08D08B789A42F8D103880C884B
+:10D81000A342F4D1002010BD812010BD10B5002915
+:10D8200002D001290DD102E00088000501E0008846
+:10D830008004800F07D001281CD0022809D00328BB
+:10D8400010D0812010BD002901D0032010BD02207E
+:10D8500010BDF6F754F803280CD004280AD000288D
+:10D8600006D009E0F6F74BF8042803D0022803D0CD
+:10D87000052010BD002010BD0F2010BDF3B5C81C41
+:10D8800080080E46800081B0B04201D08620FEBDE7
+:10D89000FE4C354626600198A08000202081E08063
+:10D8A00014E0B807A978800D0843F94904F0E6FFB1
+:10D8B000E088401CE080B80607D42089401880B278
+:10D8C00020810199081A8019A8600C352F887807E3
+:10D8D000E7D40020A072FEBDEC480C22C18800896C
+:10D8E0005143081880B2704770B51346E74A45188F
+:10D8F0009488AC4201D2842070BD126810180A4688
+:10D90000194604F041FF002070BDE04901208872F3
+:10D910007047DE49002088727047FFB589B09704D0
+:10D920000E460546BF0C029200F017FA040021D003
+:10D93000002069460873D548807A012812D0012159
+:10D940002046FFF76BFF002815D12078400609D547
+:10D950000221684601730582218841828682C7823E
+:10D960000C9806900298000407D500273E46012532
+:10D9700001970CE001200DB0F0BD2078A178800760
+:10D98000800D0843C249019004F078FF0D460298CB
+:10D9900040040AD50198A84207D12088E178800583
+:10D9A000800F00020843B04201D3AE4201D90720E4
+:10D9B000E1E7B81980B20290A84201D90D20DAE758
+:10D9C0006846007B002804D003A8F8F7FCFB002879
+:10D9D000D1D10198A8420BD12088032109028843A4
+:10D9E00002998905890F0902084320800298E07096
+:10D9F0001298002800D007800C9800280CD02078BE
+:10DA0000000609D4A0683A4680190C9904F0BCFEBF
+:10DA100020881021884320800020ACE7FFB59B4D73
+:10DA200081B00E46E8882F680C21009048433C18CE
+:10DA30009749039804F022FF0A462889E11B84468F
+:10DA40000C314018318880B28B0601D5002300E0EC
+:10DA500013461818AB8880B2834202D8842005B0E0
+:10DA6000F0BD0098894D401C80B2E88021800D995E
+:10DA7000002900D00C600399A170E2702188039DF9
+:10DA80008908AD058900AD0F294303252D02A9435F
+:10DA90009505AD0F2D0229430425294321800C99BA
+:10DAA000002900D0088001998978A171019909881D
+:10DAB000A1803178890601D50B9905E0734962444C
+:10DAC00092B20A81991AC919A16000212173327892
+:10DAD000920601D50020C2E700910B9B0A9A049997
+:10DAE000FFF71BFFBBE710B5044600F036F900282E
+:10DAF00006D06649641ECC8000210170084610BD26
+:10DB0000012010BD002803D0401E0880002070476F
+:10DB10000120704710B55D490288CB889A4201D335
+:10DB2000822010BD0B680C21514359180B88CC780A
+:10DB30009B059B0F1B02234341608C7904738C88E7
+:10DB40004481C3818968521C0161028002810020E6
+:10DB500010BD012101827047FEB505460020C0437B
+:10DB6000088068680F468178684681706868018817
+:10DB70006846018000218171288A2C88A04200D348
+:10DB800004462C8234E0288A401C2882301D6968B3
+:10DB9000FFF72AFE002829D139883E48814201D169
+:10DBA000601E38806888A04227D33088F1788005CD
+:10DBB000800F0002084302906946301DFFF714FEF3
+:10DBC000002813D12989334881421AD000213046D8
+:10DBD000FFF724FE002809D12A890298824205D144
+:10DBE000E968B06804F0A3FD00280AD0641CA4B260
+:10DBF000204600F0B2F80600C5D1641E2C828220B7
+:10DC0000FEBD7C80B079B871B088B880308838812A
+:10DC100030788007810DB078014379810298B8810E
+:10DC2000B06838610020FEBDFFB585B014460F46D0
+:10DC3000059800F092F8050037D01448BE05807AA8
+:10DC4000B60D012815D000212846FFF7E7FD002872
+:10DC500029D1287840060CD5012168460170059924
+:10DC600081802988C18006814481F8F7ACFA0028B8
+:10DC700019D12888AA788107890D11438005800F62
+:10DC8000EA7800021043BE4211D005E0841900205A
+:10DC900001020000FFFF0000374A914207D3611ED6
+:10DCA000814204DD0B2009B0F0BD0120FBE7864274
+:10DCB00001D90720F7E7801B82B2A24200D9224691
+:10DCC0000E98002800D002800898002804D0A86888
+:10DCD0008119089804F058FD0020E4E770B5144657
+:10DCE0000D4600F03AF800280DD001882980002C5C
+:10DCF0000DD0017880788907890D01431E48814243
+:10DD000003D2012002E0012070BD0020207000201D
+:10DD100070BD70B516460D4600F01FF804000DD01A
+:10DD20002D882580FF2E16D0A807A178800D0843E6
+:10DD3000114904F0A3FD002E06D101E0012070BDC1
+:10DD4000FF31FF31033189B2A170A8088000890535
+:10DD5000890F08432080002070BD0849CA8882428C
+:10DD600007D3002805D00C22096850430C38081846
+:10DD70007047002070470000010200008419002055
+:10DD8000F0B585B00E4605460020694608707078EB
+:10DD9000FE49C00003900C58FD4F002D0ED0022DFF
+:10DDA00073D0002C72D02078801E030004F08EFF08
+:10DDB00009837F7F7F83797F77727F00002C03D177
+:10DDC000F4A16B2004F07DFE2078801E030004F097
+:10DDD0007DFF09065E5E5E19365E50545E00307847
+:10DDE000062803D0EBA1762004F06BFEB8687168BA
+:10DDF000806A032204F0C8FC0120694608700028EC
+:10DE000035D1CEE730780C2803D0E2A1812004F090
+:10DE100058FEE0680078002806D0B8687168C06BCA
+:10DE2000102204F0B1FC28E0B8681021406B04F027
+:10DE300008FDB868C16A406B0A787168F1E730780C
+:10DE40000D2803D0D3A1942004F03BFE04206946A2
+:10DE5000087071684878097800020843B9684A6A0E
+:10DE60005178127809021143484069468880084673
+:10DE700008E0C8A1AF2004F024FE6846007800281E
+:10DE80008FD06846F5F740FD8BE727E01CE0C1A185
+:10DE9000B420F0E7B8686169406CFEF71CF8A1692E
+:10DEA00000E0E168B868406CFEF715F803E0B9A13E
+:10DEB000E32004F006FEB8682146406CFEF70BF83C
+:10DEC000B24A039900205050022D07D0002D05D0F2
+:10DED000012D03D0AFA1EF2004F0F3FD05B0F0BD9C
+:10DEE00010B501780124012902D0022910D112E0D5
+:10DEF0004268A748002182600170A4486C38C1665E
+:10DF0000016741678167928902214C3001F083F9F2
+:10DF10000024204610BDFF209EA11C3004F0D1FD3E
+:10DF2000F7E7F0B505469EA103C997B01491139089
+:10DF3000002108A8017595482A781030944C049067
+:10DF40002078012605903746A068130004F0BEFE35
+:10DF50000CEE073098EFF5EBEAE9E8E8E7EE217020
+:10DF60000124FF2655360D4610A80570457001F0B6
+:10DF700063F90746012803D086A1304604F0A1FDCD
+:10DF800010A93846FFF7FCFE2046641EE4B20028C4
+:10DF9000EAD10A20694608706846029501F02AFA1B
+:10DFA000002803D0FF207BA15E3066E00026E6E279
+:10DFB000006B0078C0072ED06846077001F01AFA8F
+:10DFC000002804D0FF2073A1713004F07AFDA0680E
+:10DFD000406CFDF777FF050004D1FF206DA1743080
+:10DFE00004F06FFD08984078C1006848455006204D
+:10DFF0002870A068016869600069A8606448C01C56
+:10E00000E860284601F0F6F9022804D0FF2061A15B
+:10E010007E3004F056FDA068006B00784007C5D53F
+:10E020006846077001F0E6F9002804D0FF2059A1E6
+:10E03000863004F046FDA068406CFDF743FF050004
+:10E0400004D1FF2053A1893004F03BFD08984078AB
+:10E05000C1004E48455006202870A06801686960DC
+:10E060000069A8604A48401DE860284601F0C2F9EE
+:10E0700002289BD0FF2047A1933004F022FD95E7B2
+:10E08000A8680028684632D001712879012833D069
+:10E09000022804D0FF203FA1AD3004F012FD3B4820
+:10E0A00010221030A96804F06FFB38481030014688
+:10E0B000103148602078C1062DD5EF21084020702E
+:10E0C000032069460870314810300290684601F01C
+:10E0D000B3F80446022808D0002C06D0012C04D046
+:10E0E000FF202CA1BE3004F0ECFC69462AE1077148
+:10E0F000264820304160DDE7244A04986C3AD16715
+:10E1000041608160C1600621A86803F087FA1F4959
+:10E1100010310860C9E720210843207046E758E124
+:10E1200014E1D6E0A3E046E007E000E031E2FF20A2
+:10E1300018A1E73004F0C5FC21E2172269460A72F3
+:10E140000F7089788A08297992008907890F0A4314
+:10E1500069468A70FB210A4029794907C90F89005D
+:10E160000A4369468A70EA888A80826C02A96846F6
+:10E1700001F082F9002804D0FF2006A1F73004F056
+:10E18000A0FC052108A8017568460DE0FC190020D7
+:10E19000A00000207372635C736D2E6300000000AA
+:10E1A00004411A8800A48000017A0187A068002633
+:10E1B000806C0F90E7E16846077001F01BF90028BA
+:10E1C00003D0FD49FD4804F07CFCA068406CFDF7DD
+:10E1D00079FE060004D18320F749800004F071FC29
+:10E1E000A068406CFDF76EFE070004D1F348F249C9
+:10E1F000801D04F066FCF2488068406CFDF762FE0A
+:10E20000040004D1ED48EC49093004F05AFC0898A8
+:10E210004078C100EB4846500A203070287A3071AF
+:10E220006868E74DB060A868806C30611720307373
+:10E2300077613046B46101F0DDF80446022808D069
+:10E24000002C06D0012C04D01120DB49400104F041
+:10E2500038FC2046316AFFF793FD297805220A40F1
+:10E26000042A00D0A2E6FB22114029702AE0059979
+:10E270004908490021708A071CD5FD2211402170F0
+:10E280000F216A46117017211171806C0290684647
+:10E2900000F0D2FF0546022808D0002D06D0012D3F
+:10E2A00004D0C648C4493A3004F00BFC69462846FD
+:10E2B000FFF766FD2078052101400429D2D1FB211A
+:10E2C00008402070072008A90875BD4880780876A6
+:10E2D0006CE66846077001F08DF8002804D0B74856
+:10E2E000B549543004F0EDFBA068406CFDF7EAFD41
+:10E2F000060004D11320B049400104F0E2FBA068FD
+:10E30000406CFDF7DFFD070004D1AC48AA495A3044
+:10E3100004F0D7FB08984078C100AA48465007206F
+:10E320003070A068406870606868F760B060304620
+:10E3300001F060F8040004D0A0489F49653004F063
+:10E34000C0FB316A2046FFF71BFD2FE668460770C9
+:10E3500001F050F8002804D0984897497A3004F02A
+:10E36000B0FB08984778A068406CFDF7ABFD06004D
+:10E3700004D151209049C00004F0A3FBA068406C78
+:10E38000FDF7A0FD040004D18C488B49823004F0D5
+:10E3900098FB8C48F900465008182A694260092009
+:10E3A000307068687060A868B060A889B0818548DE
+:10E3B0006C3830611030B4617061304601F01AF889
+:10E3C000022804D07D487C49903004F07AFB2F75F8
+:10E3D000ECE57C4B00212033197002216A46117054
+:10E3E00001932979002902D0184601709BE07449F5
+:10E3F00003220C314968FB230A708A7800259208B1
+:10E4000092001A408A70027A1207D20F4A706D4A3F
+:10E4100020325560C37ACB70837A13724469537A81
+:10E4200024785B08E4075B00E40F2343537284699C
+:10E43000D460FD242340C4692478E407A40F234357
+:10E440005372036A13614D710D71437A5C4A9C07E4
+:10E450000C32A40F1268012C04D19478A407A40FE5
+:10E46000012C1DD09B089B00437293785B0702D45C
+:10E47000437A5B0728D5037A13AD5B075B0FDC009B
+:10E480005B00E318147864001B19DBB2DC082C5D18
+:10E490005D076D0F06235B1BDC40A3079B0F14E099
+:10E4A000037A54795B065B0F1C404C711379062587
+:10E4B0002B400B71DB002343414C63708B789B082E
+:10E4C0009B005B1C8B70D0E700238C78FB252C40D5
+:10E4D000457A6D07ED0FAD002C438C70047A64070C
+:10E4E000640F0C705178012908D1017A090705D50C
+:10E4F000032108A801750221017614E0022B1ED029
+:10E50000012B21D02F4B00216C3B049AD96751601D
+:10E510009160D16019467C310A4610325160417ACF
+:10E52000FB2211404172684600F086FE040021D0B3
+:10E53000012C20D02049244804F0C3FA1BE003201A
+:10E5400008A908750F76EEE70598000704D5C320E3
+:10E550001949800004F0B5FA1A4C0D211034E01C62
+:10E5600004F06FF9204610304460022008A90875B5
+:10E570000E94D8E7002669462046FFF701FC08A85C
+:10E58000007D002802D00DA8F5F7BEF9304617B07F
+:10E59000F0BDCB2008498000CCE5F0B5054697B02A
+:10E5A0000C460020694608700548064E2F78483E04
+:10E5B000017882680AE0000094E10000090200008E
+:10E5C000A0000020FC1900201F0300003B0004F005
+:10E5D0007DFB0BA8820724394A6977778D9AA800BA
+:10E5E0002B20694608730CA903A8FDF7A1FC00289D
+:10E5F00003D05349534804F064FA53490D9804F08A
+:10E600003DF952480160524869680160AA68426059
+:10E6100001910820694608708CE08A0610D5DF2237
+:10E620001140017003202070484810304168A160FB
+:10E630004068002802D00020207177E00120FBE72D
+:10E64000102256E02B2069460873404903A85C3924
+:10E65000FDF76EFC002804D03A483949293004F00F
+:10E6600030FA04201BE02A206946087303A8102210
+:10E670000230696804F088F807A810220230A968FF
+:10E6800004F082F8314903A85C39FDF751FC0028F9
+:10E6900004D02C482A493A3004F013FA052020709F
+:10E6A000666043E02A79002A02D0012211430170FA
+:10E6B00005206946087028798880A868029039E0AA
+:10E6C000106B4023018819430180106C6968102287
+:10E6D00004F05AF82AE0FB22114001700620694636
+:10E6E0000870A96868680291019023E0CB0703D005
+:10E6F0000222114301704AE70F2020701720207179
+:10E70000906CA06012E0537A9B0706D0126B44789D
+:10E710001388FF3401342343138004221143017012
+:10E7200004E0084806497C3004F0CBF968460078DC
+:10E730000028E0D06846F5F7E7F828E701207047A1
+:10E7400094E100004D03000040420F000C1A00202D
+:10E75000AC00002070B504780D460646230004F096
+:10E76000B5FA0B1C181C1C1C1C07181C1C181C00C0
+:10E770000021052001F013FDB068007805280CD0B9
+:10E78000FA480022008811468300052001F065FC4C
+:10E7900003E00021052001F002FD002D0ED0002035
+:10E7A000287029463046FFF7F8FEF1482978005DC9
+:10E7B000884201D1032070BD022070BD0021304687
+:10E7C000FFF7EBFE002070BD30B5E8494B68497A91
+:10E7D0000A0111460C315C5C032C0CD00446002568
+:10E7E0002034257125725C5CA500AA18641C5C5459
+:10E7F0009850032030BD062030BDF0B504462646B3
+:10E8000020360D463279012008218FB0002A0CD025
+:10E81000012A21D0022A2BD0032A04D12A78052AE2
+:10E8200001D1297000200FB0F0BD01203071606867
+:10E8300000280AD0A0690170616841602169816087
+:10E840006169C160FFF7C0FFEDE70720287020690C
+:10E8500068606069A86009E029780729E3D102208F
+:10E86000307105202870C248203868600320DAE73C
+:10E8700029780529D7D1A08910280AD9103880B263
+:10E88000A081A1681023091803A86A6800F033FE6C
+:10E890002DE0102804D0C1B20BAA1020A76809E00F
+:10E8A00010232269A16817E0491EC9B2401EC0B2F8
+:10E8B0007B5C13540029F7D100280AD0401EC0B257
+:10E8C00080211154002102E0401EC0B211540028E2
+:10E8D000FAD1626910230BA907A800F00CFE1023DF
+:10E8E00007A903A86A6800F006FE0320307160687B
+:10E8F000019003A8029005206946087029466846E1
+:10E90000FFF728FF8FE7F0B5044626460D46203670
+:10E91000317901208DB000290BD0012938D002298E
+:10E9200005D12978052902D10920287000200DB0D1
+:10E93000F0BD217D6846CA07D20F02738807C10F58
+:10E9400068460174012203A905A800F0CCFD04A9C2
+:10E95000012205AF481D00F0C6FD0722B81CE16882
+:10E9600000F0C1FD07A807220130216900F0BBFDBE
+:10E970006068019009A80290102305AAA16800F020
+:10E98000BAFD01203071052168460170294621E059
+:10E9900029780529CBD1062203A8E16900F0A3FD5F
+:10E9A00004A806220230A16900F09DFD042106A8FA
+:10E9B00000F091FD6068019007A80290102303AA5F
+:10E9C000696800F098FD02203071052069460870E2
+:10E9D00029466846FFF7BEFEA9E7F0B5074685B0B1
+:10E9E0000C460020694608703E466248203632795F
+:10E9F0008179133801250078130004F067F9180DA8
+:10EA0000FEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EF9E
+:10EA1000EEEDECEBEAE9E8E7B968039100291BD0D9
+:10EA2000012269460A7003220A710A224A71396971
+:10EA30000291397900297DD0039A1278002A7AD080
+:10EA40000C2A78D2130004F041F90BF009F0354D8F
+:10EA50008498B1F2EEEDF0000020BEE30021062024
+:10EA600001F09DFB3879072866D1424D133D287887
+:10EA7000022802D000287FD101E0002028700398EE
+:10EA80000079C11F0A2901D30A249AE16870394824
+:10EA90000722C01F039900F026FD01203071287065
+:10EAA0000220694608703348801F01903869401C75
+:10EAB00002903BE211293DD12E4D133D0228DAD1BF
+:10EAC00068686978007A884201D9062479E1039957
+:10EAD00026481022491C303800F005FD032028701C
+:10EAE000022046E11129E6D1224C133C0428C2D170
+:10EAF0000520207003991D481022491C203800F081
+:10EB0000F2FC062030717869032101706268516857
+:10EB1000416016492039816021460C31C160C91D10
+:10EB20000161017D537A49084900DB07DB0F194376
+:10EB3000017502E064E34AE387E1D3688361FD2362
+:10EB40001940537A9B07DB0F5B001943017511696C
+:10EB500079E10229AFD1002868D005206946087103
+:10EB60000398407848713869029045E3601A0020A4
+:10EB70004C2D0100C700002073E011299BD1F84CF7
+:10EB800006286ED1A0680399406B1022491C00F042
+:10EB9000AAFC0620694608703869029000200871B6
+:10EBA00001466846FFF7D6FD072058E00B299AD1A9
+:10EBB000EB4C07287ED1A0680399C06A0222491C49
+:10EBC00000F091FCA0680822006B17E00EE10AE358
+:10EBD000F3E2D3E2B9E2AEE28EE265E24FE248E26E
+:10EBE00028E2FDE1E7E1D0E1C6E1BFE1ADE16DE1A1
+:10EBF0004AE12BE1DCE0BFE0B0E076E00399C91C1C
+:10EC000000F071FC0621684601703869029000210D
+:10EC100068460171FFF79EFD20461330417949088F
+:10EC200049003EE041E01DE001E05CE0E2E2112944
+:10EC300090D1CB4C08283DD1A0680399806B10225D
+:10EC4000491C00F050FC06206946087038690290A3
+:10EC50000020087101466846FFF77CFD09202070FE
+:10EC6000BDE227E0082989D1BD49092822D10398AE
+:10EC700042788868C16B0A700399006C0622891C6F
+:10EC800000F031FC062168460170386902900021CD
+:10EC900068460171FFF75EFDB14813304179FD22EE
+:10ECA0001FE041714FE230717EE01129C0D1AC49C3
+:10ECB0000A2801D0082484E088680399406C102257
+:10ECC000491C00F010FC062168460170386902906A
+:10ECD000002168460171FFF73DFDA14813304179DD
+:10ECE000FB221140DDE707246BE0217802297DD16A
+:10ECF0009B490128FBD162684A6014780846002CC1
+:10ED00005DD106216A46117039690291072111719E
+:10ED1000029902240C70CA785207520FCA704B79BC
+:10ED20005B075B0F4B718B795B075B0F8B71D207B6
+:10ED300001D18A714A7105460A794078824200D22F
+:10ED40006A7087480722133000F0CDFB00202C703A
+:10ED5000307101466846FFF7FDFC40E22178042946
+:10ED6000C5D1032871D108227E48616800F0BBFB41
+:10ED7000032030710420E3E121780429B7D1784FD2
+:10ED80000328B4D1774808220830616800F0ABFB53
+:10ED90000420307178684168002907D00321217070
+:10EDA000002121714068A060032531E20320C7E102
+:10EDB000207803289BD1207900281BD00446002C02
+:10EDC00014D0062168460170386902900221684615
+:10EDD0000171029805210170447000216846FFF717
+:10EDE000B9FC012168460170042100E0A2E1017133
+:10EDF000447105E25A49A06849680028486001D179
+:10EE000059484860052030717869032202704A68C9
+:10EE10004260544A8260524A0C32C260D21D026182
+:10EE2000027D4B7A5208DB075200DB0F1A43027552
+:10EE3000CB688361FD231A404B7A9B07DB0F5B0095
+:10EE40001A4302750969C16194E1F2E02178092948
+:10EE500086D14349032891D10420087006206946D1
+:10EE6000087038690290112008710298032101701E
+:10EE7000401C1022616800F036FB00216846FFF755
+:10EE800069FC00203071AAE12178092992D1052876
+:10EE900090D13449626820391020401EC0B20B5C0A
+:10EEA000145CA34203D000200424307189E70028B9
+:10EEB000F3D107203071786904210170284949682D
+:10EEC0004968416027498160103952E120780A2859
+:10EED000BED106216846017038690290112168464A
+:10EEE0000171029804210170401C10221D4900F09C
+:10EEF000FAFA00216846FFF72DFC194810214078E6
+:10EF00006268091AC9B2101800F0E5FA6068019049
+:10EF100013481330C178C9070FD08179002902D175
+:10EF20004079002809D00820307109E1214668465F
+:10EF3000DFE0054601287CD06AE1072069460870B9
+:10EF400000216846FFF706FC4BE120780E289DD192
+:10EF50000348616881604969407808700920A2E629
+:10EF6000B4000020501A00202C2D0100C80701D049
+:10EF70000A20E3E00F2096E620780F2859D1A068F8
+:10EF80003861207938730B20F3E620780428F5D116
+:10EF90006168F84C0822A068C06900F0A4FA0C204F
+:10EFA000307178690722B9690270A268D36843603A
+:10EFB000D2698260DDE020780D28DFD1ED4D6168F7
+:10EFC000A86802230269806900F095FA0D2030716B
+:10EFD000786906210170A9688A68426009695FE062
+:10EFE00020780C28CAD1E34D6168A8686A78006A65
+:10EFF00000F079FA6878AA681021091A126AC9B271
+:10F00000101800F068FA062168460170386902900D
+:10F01000112268460271029810220170A968401CF2
+:10F02000096A00F060FA00216846FFF793FB0E20A2
+:10F030005AE0A2E020780F287CD1062069460870AB
+:10F04000386902900B200871029C0720C94D20707E
+:10F05000A86802228169601C00F045FAA8680822AD
+:10F06000C169E01C00F03FFA00216846FFF772FB1F
+:10F0700080E7880701D5102060E0132013E6207890
+:10F080000F287AD1A0683861207938731120307147
+:10F09000786906210170B7498968C9684160B64935
+:10F0A0008160B549091D64E020780C2865D1B14D17
+:10F0B0006168A8681022406A00F015FA06216846C7
+:10F0C0000170386902901121684601710298082187
+:10F0D0000170A968401C496A102200F004FA00215E
+:10F0E0006846FFF737FB122030710921684601702E
+:10F0F0002146FFF72FFB1CE720780F281AD10621A5
+:10F1000068460170386902900821684601710298CA
+:10F1100009210170974989680A78D207D20F427095
+:10F1200049680622801C00F0DEF900216846FFF7DE
+:10F1300011FBA2E769E0480705D5142030710920CA
+:10F1400069460870F2E61620ADE520780F2853D105
+:10F15000A0683861207938731520307178690621EC
+:10F160000170844989688A684260096981608249BE
+:10F17000891DC160FFF728FBDBE63DE020780C2805
+:10F1800043D161687B4C1022A068806A00F0ABF923
+:10F1900006206946087038690290112008710298AB
+:10F1A0000A210170A168401C896A102200F09BF9B5
+:10F1B00000216846FFF7CEFAC5E76E481330407964
+:10F1C00000280ED0C10703D06A480621017006E06E
+:10F1D000800701D5082000E00A2066490870002554
+:10F1E00016E017205FE56349002805D00020307144
+:10F1F00008700A206946087068460078002804D024
+:10F2000000216846FFF7A6FA00255A480021017040
+:10F21000284605B0F0BD10B5584BFF245C7258600D
+:10F2200019721A80002204E0491EC9B20B010C3386
+:10F23000C2540029F8D110BDF0B5504E0546717A80
+:10F2400001208DB0FF2971D00127727A73681101F6
+:10F250005C180C31595C8900091F64586A70217868
+:10F260000B0003F033FD0B960709272C59818D4ABB
+:10F270004F5492002F7075E0214620310A91097990
+:10F280000120002902D001296DD10EE060680190B3
+:10F2900005A802900D21C01C00F01DF9032205A84D
+:10F2A000A16800F020F90A984EE02978052974D168
+:10F2B000062156E029462046FFF725FB69E0214656
+:10F2C0002031069109790120002902D0012964D159
+:10F2D0000EE06068019007A802900822E16800F043
+:10F2E00002F9082209A8A16800F0FDF806982BE0B1
+:10F2F0002978052951D10A2133E02946204600F01A
+:10F3000005F946E029462046FFF777FA41E029460D
+:10F310002046FFF762FB3CE0214620310591097948
+:10F320000120002903D0012937D116E056E060689A
+:10F33000019007A802900822A16800F0D4F80821E3
+:10F3400009A800F0C8F805986946077105200870FB
+:10F3500029466846FFF7FEF91BE0297805291CD1EC
+:10F360000B212970002018E02946204600F014F9EE
+:10F370000FE00000B4000020242D0100601A0020DE
+:10F380002946204600F038F903E029462046FFF7D9
+:10F39000D5F9002801D001280CD12562717A736853
+:10F3A00009010C315A5C521E1206120E5A5401D039
+:10F3B00003204AE70328FCD0737A726819011D0103
+:10F3C0000D312C46515C7172FF270D3417550C35E9
+:10F3D000545D002C02D0FF2903D173720DB0F0BD33
+:10F3E00021460C010D34145DFF2CF9D109010D31BA
+:10F3F0005354F3E770B5A24C0546607A21460346A4
+:10F400004A6811E0010108460C30105C08E0401E1B
+:10F41000C0B286008E199659AE4201D1042070BD4B
+:10F420000028F4D10D31505CFF28EBD19448002125
+:10F43000007A01E0491CC9B2884204D90E010C3699
+:10F44000965D002EF6D1884201D8052070BD0801D6
+:10F450000D30135461722846FFF7B6F9032806D021
+:10F46000617A626809010D31515C617270BD284694
+:10F470002830FFF7E1FE70BD10B504780123012CA0
+:10F4800014D10C78022C11D30B23137083785B07F3
+:10F490005B0F537002220A708088002805D0830019
+:10F4A00000221146062000F0D8FD0023184610BDAA
+:10F4B0000EB50022012105280AD0062807D168468A
+:10F4C00001700221017142710021FFF766F80EBD43
+:10F4D00068460170F6E7002202E0491EC9B24254B4
+:10F4E0000029FAD1704703E0521ED2B28B5C8354DC
+:10F4F000002AF9D1704730B505E05B1EDBB2CC5C69
+:10F50000D55C6C40C454002BF7D130BD3EB50446E9
+:10F5100020300D4602790121002A02D0012A39D17A
+:10F520000EE06168019157490291012101710520A6
+:10F530006946087029466846FFF70CF9014629E03C
+:10F540002878052826D169681022A06800F087F87D
+:10F550006868C07B000606D54A4AA06810231032AE
+:10F560000146FFF7C8FF1022A168E06800F077F8B5
+:10F57000A068C07B000606D5424AE068102310321E
+:10F580000146FFF7B8FF07202870A0686860E068B0
+:10F590000021A86008463EBDF0B5044626460F4649
+:10F5A00020363179012089B0002909D0012905D1FF
+:10F5B0003978052902D10C203870002009B0F0BD3F
+:10F5C000606803AD01900295022203A8A168FFF7CD
+:10F5D0008AFF0222A81CE168FFF785FF0C21281D85
+:10F5E000FFF779FF01203071052069460870394620
+:10F5F0006846FFF7AFF8E1E710B5034620331C7902
+:10F600000122002C04D0012C10D0022C25D11EE0A8
+:10F6100001211971C16806220A70406848601948C2
+:10F62000801F8860801CC86008460CE00C780C2C99
+:10F6300013D102221A71C268052313704968516000
+:10F64000806890601046FFF7BFF8024605E0087832
+:10F650000B2802D10D2008700022104610BD10B5F5
+:10F66000002409E00B78521E5B0023430370401C0A
+:10F670000B78491CD2B2DC09002AF3D110BD00007E
+:10F68000601A00202C2D010070B50D46040012D028
+:10F69000002D10D02101284603F0D3F81022544940
+:10F6A000284603F071F8524801210838018044804F
+:10F6B0004560002070BD012070BD70B54C4E002427
+:10F6C0000546083E11E0716820014018817BAA7B45
+:10F6D000914209D1C17BEA7B914205D10C22294696
+:10F6E00003F025F8002806D0641C30888442EADB49
+:10F6F0000020C04370BD204670BD70B50D460600A9
+:10F700000AD0002D08D03A4C083C20886188401C63
+:10F71000884203D9042070BD102070BD3046FFF729
+:10F72000CCFF002801DB0F2070BD2088616800013C
+:10F7300040181022314603F027F82088401C208012
+:10F740002870002070BD70B514460D001FD0002C2D
+:10F750001DD00021A170022802D0102817D108E086
+:10F76000687829780002084311D00121A170108027
+:10F770000BE02846FFF7A1FF002808DB401CA07023
+:10F78000687B297B000208432080002070BD012097
+:10F7900070BD70B5054614460E000AD000203070CA
+:10F7A000A878012807D004D9114908390A8890425D
+:10F7B0000BD9012070BD002C04D028782070288837
+:10F7C000000A50700220087010E0002C0CD049682C
+:10F7D0000001411810391022204602F0D5FF287888
+:10F7E00020732888000A607310203070002070BDDC
+:10F7F000D8000020734909680160002070477149F2
+:10F8000008600020704701216F4A704B002803D028
+:10F81000012805D06E48704791630020187001E000
+:10F82000D1631970002070476A4901200860684858
+:10F83000801C70470422684B6649002805D05A6036
+:10F84000086901221043086108E008694008400087
+:10F8500008619A605C490020C031886000207047D0
+:10F860005C490622002808D0012809D002280DD0C2
+:10F8700003280FD05648401C70470869904302E0A7
+:10F8800008699043801C0861002070470869904314
+:10F89000001DF8E708691043F5E74E494A6A02433C
+:10F8A0004A62002070474B494A6A82434A620020FC
+:10F8B00070474849496A0160002070474549CA6954
+:10F8C0000243CA61002070474249CA698243CA6143
+:10F8D000002070473F49C96901600020704730B57A
+:10F8E0000546002072B601463A4A384C4032002D97
+:10F8F00011D00123012D0CD0022D02D0072062B6B9
+:10F9000030BDA3706478002C01D09363F7E7916356
+:10F91000F5E7A170F9E7A170F9E72F4904208860A5
+:10F9200029490020C03188602849012008702B49EE
+:10F930000A688023120A12021A430A6028490860E2
+:10F94000704722480078704770B5EFF31080C50704
+:10F95000ED0F72B61D4C6078401C0006000E607002
+:10F9600003D120A1CC2003F0ACF86078012806D1A7
+:10F97000A078002803D01749012040318863002D6A
+:10F9800000D162B670BD70B5EFF31080C507ED0F02
+:10F9900072B60E4C6078002803D112A1DC2003F06F
+:10F9A00090F86078401E0006000E607006D1A078C6
+:10F9B000002803D00749002040318863002D00D182
+:10F9C00062B670BD0004004040000040E800002026
+:10F9D00004200000000500400003004000E400E0B7
+:10F9E00000E100E07372635C736F635F706F776553
+:10F9F000722E63008107C90E002808DA0007000F85
+:10FA000008388008B94A80008018C06904E080087E
+:10FA1000B74A800080180068C8400006800F704711
+:10FA2000B44948788978884201D3401A02E02122FB
+:10FA3000511A0818C0B27047AE4923314878897806
+:10FA4000884201D3401A02E02122511A0818C0B29C
+:10FA50007047A849463148788978884201D3401ACE
+:10FA600002E02122511A0818C0B27047A04810B510
+:10FA70000C300168FF22120291430122D20311438C
+:10FA800001609C49002023314870887023394870F8
+:10FA90008870463148708870974801F0FCFD9648A0
+:10FAA000401C01F0F8FDF2F723FE00F015F910BD3F
+:10FAB00020207047B4E770B50C4605460026FFF7D6
+:10FAC000AFFF8C49A04214D30A46203A00232046B7
+:10FAD000641EE4B200280BD08878105C2870887807
+:10FAE0006D1C401CC0B288702128F0D18B70EEE7ED
+:10FAF000012600F0F1F8304670BD202070479BE7EA
+:10FB000070B50C4605460026FFF796FF794923316C
+:10FB1000A04214D30A46203A00232046641EE4B2D1
+:10FB200000280BD08878105C287088786D1C401CE9
+:10FB3000C0B288702128F0D18B70EEE7012600F06A
+:10FB4000CBF8304670BD202101700020704710B501
+:10FB50000446FFF77EFF2070002010BD70B50C46F4
+:10FB60000546FFF776FF63494631A04215D30A46A2
+:10FB7000203A00232046641EE4B200280BD0887887
+:10FB8000105C287088786D1C401CC0B288702128D9
+:10FB9000F0D18B70EEE7002400E0584C00F09CF8A8
+:10FBA000204670BD70B50C460546212904D9FF20BA
+:10FBB00053A1473002F085FF4C484068103840B2EE
+:10FBC000FFF718FFC6B20D20FFF714FFC0B2864240
+:10FBD00007D2FF204AA14D3002F073FF01E0F2F797
+:10FBE000C7FD21462846FFF766FF0028F7D070BD05
+:10FBF000F8B5404E07462336B1787078212200F0E0
+:10FC000060F8354623353B4C00280ED0A17860784B
+:10FC1000212200F056F8002814D0A9786878212213
+:10FC200000F04FF800281AD025E032497078C91C3E
+:10FC30000F547078401CC0B2707021281BD1002076
+:10FC4000707018E02B49607820390F546078401CA0
+:10FC5000C0B2607021280ED1002060700BE02549F1
+:10FC6000687826310F546878401CC0B2687021282B
+:10FC700001D100206870B1787078212200F021F85D
+:10FC800000281DD0A1786078212200F01AF8002801
+:10FC900016D0A9786878212200F013F800280FD038
+:10FCA000F2F748FD144801F0FEFC012149038842A7
+:10FCB00003D013A1C12002F004FF0F4801F00BFD97
+:10FCC000F8BD401C884205D0904201D1002901D0E6
+:10FCD000002070470120704710B5074801F0E3FC91
+:10FCE000002801D1F2F715FD10BD000000ED00E085
+:10FCF00000E400E08C1A0020EB0000200720000048
+:10FD00007372635C736F635F72616E642E63000075
+:10FD100010B5284801F0BFFC002803D026A11D2003
+:10FD200002F0CFFE2348401C01F0B5FC002803D0B0
+:10FD300021A1212002F0C5FE10BDF1B5224D6F6852
+:10FD400001261C4801F0AFFC1A4C002803D1002604
+:10FD5000601C01F0C0FC1D4A1D490120506000BF1D
+:10FD600000BF00BF00BF00BF00230B604B60009BC3
+:10FD70006B60106000BF00BF00BF00BF00BF08681D
+:10FD8000002802D148680028F9D048680028E4D14A
+:10FD9000002E04D06F60601C01F085FC07E0601C41
+:10FDA00001F081FC0028D3D1024801F094FC00202E
+:10FDB000F8BDC2E7ED0000207372635C736F635F90
+:10FDC0006563622E6300000000E5004000E0004033
+:10FDD00000E1004030B5EFF31081CC07E40F72B6BC
+:10FDE0001D4A116910230D461D431561002C00D1D9
+:10FDF00062B61A4DC406E40E0120A0402C680442ED
+:10FE00000DD0C8060AD4EFF31080C007C00F72B639
+:10FE1000116999431161002800D162B630BD20BF3D
+:10FE200040BF20BFEAE70E4908784A78401CC0B2BC
+:10FE3000904200D008707047084A094820BF40BF70
+:10FE400020BF4178037843701368002B02D10378F8
+:10FE50008B42F3D00020704700ED00E000E200E0AC
+:10FE6000EF000020FEB5F44C07466068FF213E011C
+:10FE700081552178FF2913D00901083141583246B4
+:10FE8000491E083209020192090A805800F0CBF994
+:10FE9000002802D02478254615E06168207888552E
+:10FEA0002770FEBDE448426801981158280100906F
+:10FEB0000830105800F0B7F9002806D1DE482C466B
+:10FEC000416800980D5CFF2DECD1DB4821014068B2
+:10FED00085554754FEBD70B5D74A04460020157AB3
+:10FEE00053680AE00201561C9E5DA64203D10C3203
+:10FEF0009A588A4204D0401CC0B28542F2D8FF20F2
+:10FF000070BDF8B5CC4F3E7801F042FB0146FF2EA4
+:10FF100071D03401254678680835405900F083F9DE
+:10FF200002280CD97868405901F025FB01F030FB1C
+:10FF300001467868405900F076F902285BD8BE493E
+:10FF40004868025D0A70A11C425C002A0CD0521E57
+:10FF5000425441590122D20589180902090A415126
+:10FF60003046FFF77FFF30E0631CC25C0092221D29
+:10FF700094468258002A10D001239B029A420FD93E
+:10FF80009205920D43595703DB191B021B0A43517B
+:10FF90006346C3589A1A920A09E0FF21C1540AE045
+:10FFA000435952039A181202120A42510022425433
+:10FFB0003046FFF757FFA0480C344168C2680098EC
+:10FFC000095980001258009890479B4C2078FF28D0
+:10FFD00011D0000161680830085801F0CCFA01F036
+:10FFE000D7FA01462078626800010830105800F006
+:10FFF0001AF9022886D3F8BDF8B51C4615460E46F8
+:020000040001F9
+:100000000746FF2B03D38DA1D12002F05AFD8A4869
+:10001000FF21C760456004720674017000224270BF
+:10002000104604E00201521C401CA954C0B2A04278
+:10003000F8D3F8BD70B5804C06466578207C8542C3
+:1000400003D37EA1E42002F03CFDE068A900465005
+:100050006078401C6070284670BDFFB581B01D46B9
+:10006000FF2401F095FA744F064679780198814291
+:1000700003D872A1F22002F024FD6F480021037A18
+:10008000406810E00A019446521C825CFF2A25D089
+:10009000019FBA4205D162460C328758029A9742B4
+:1000A0001ED0491CC9B28B42ECD8FF2C18D02101BC
+:1000B0004A1C019B83540B460C33029AC250039B8B
+:1000C0005D4F0022012B0ED00B1DC25001239B025D
+:1000D0009D4216D9AA05920D08D008E00C46E0E72B
+:1000E000FF2005B0F0BD0B1DC550EFE71A465303C6
+:1000F0009B190E461B0208361B0AAA1A8351920A44
+:1001000009E0002D00D101256B039B191D022D0A6A
+:100110000B460833C550891C42543D463E78204664
+:10012000FFF7A0FE2878B04214D0000169680830BB
+:10013000085801F020FA01F02BFA29786A680901C1
+:10014000083152580146104600F06DF8022801D2DD
+:10015000FFF7D7FE0198C4E770B50C46054601F0DD
+:1001600017FA064621462846FFF7B5FEFF2814D0A9
+:10017000314D04012046696808300858314600F0C6
+:1001800052F80121090340186968A41C095D400B5D
+:10019000002901D08902081870BD002070BDF3B598
+:1001A00081B00F460198FFF796FEFF282AD0224E15
+:1001B0003578726829460C4604E0844205D025460D
+:1001C0002301D45CFF2CF8D11CE0FF2C1AD0A542EF
+:1001D0001CD10801105C3070FF2815D000010830D8
+:1001E000105801F0C8F901F0D3F90146307872686F
+:1001F00000010830105800F016F8022806D2FFF768
+:1002000080FE03E00020FEBD01F0BDF939460198F3
+:10021000FFF7A2FF22017168FF23541C0B558A5C73
+:100220002B01CA54FEBD401A00020121000AC90573
+:10023000884200D900207047D81A00207372635C8E
+:10024000736F635F74696D65722E6300F0B500248F
+:100250001C4A01211C4B0803546018601B4B1C6096
+:100260001B4C20601B480469E443E406E61704695C
+:10027000761C10252C430461174C6160174D2960D2
+:1002800000E020BF1F68002FFBD0002E03D10769BC
+:100290001026B743076190688005906801D5104A21
+:1002A00010436960A160002119600121084A090317
+:1002B0001160F0BD10B50446FFF7C8FF20600020B4
+:1002C00010BD000000C5004080E100E000C100401A
+:1002D00080E200E000ED00E000C3004000C000400C
+:1002E00000FCFFFF70B51F490A68002A17D00023E1
+:1002F0001D4601244A68521C4A60092A00D34D60F9
+:100300000E792246B2400E6816420AD072B60B68C9
+:1003100093430B6062B649680160002070BD052000
+:1003200070BD5B1C092BE5D30FA1362002F0C9FB81
+:10033000F5E701201049800508607047EFF3108150
+:10034000CA07D20F72B601218140064803681943DB
+:100350000160002A00D162B6EBE70248002101608B
+:1003600041607047F40000207372635C736F635FD9
+:100370006576742E6300000000E200E00120810732
+:100380000860704701208107486070471048C068C6
+:10039000C00700D0012070470D488068C00700D01A
+:1003A000012070470A484069C00700D0012070470B
+:1003B0000748C069704706498A69D20306D589692A
+:1003C0008907890F814201D10120704700207047C1
+:1003D00000040040F8B5FE4C607A217A88421BD0B8
+:1003E0000126FC4D0027207A215C14200A46424356
+:1003F0005019037C052B10D0062B19D0072B23D0C6
+:10040000437C012B2BD02120F3A1400102F059FBAA
+:10041000617A207A8142E6D1F8BD0674207A401CC8
+:100420004007400F2072491CC8B2AA58022109E0B7
+:100430000674207A401C4007400F2072491CC8B245
+:10044000AA5803219047E3E70674207A401C40072E
+:10045000400F2072491CC8B2AA580821F2E747741D
+:10046000207A401C4007400F2072491CC8B2AA588D
+:100470000721E7E770B5DB4D05202871DA48002435
+:1004800044700470183044720472D84801F003F9C3
+:10049000D7480474AC71D748611E41606C70847792
+:1004A000C4772C704477D448022104704470D34838
+:1004B000047528300470491EFAD10120F2F7DAF9E8
+:1004C0000020F2F7D7F90120A870F2F765F8CC48C0
+:1004D000F2F774F8CB4C2070CB48F2F76FF86070ED
+:1004E000F2F76CF970BD10B5F2F793F9C54C2078AE
+:1004F000F2F782F86078F2F77FF8BA4CE0780028DB
+:1005000005D0FFF740FAF1F7A8FE0020E07010BD1B
+:1005100070B5B44CA078002805D0FF20AEA1B23051
+:1005200002F0CFFA70BDA079002804D1FF20AAA163
+:10053000953002F0C6FA0125A5700026A671207933
+:10054000042114225043A34AAA4C80180174606805
+:10055000401C04D0481F60600120F2F78BF9002096
+:10056000F2F788F9F2F76CF9F2F773FAF2F7F8FAA2
+:10057000A1480078022804D0032804D1E07F002895
+:1005800001D0A57700E0A677F2F74FFA70BD0346D9
+:1005900090490420142242435218203A127F002A24
+:1005A00004D0401E0006000EF4D1704714224243CE
+:1005B00051180A46403AD362012220390A7770471F
+:1005C000012805D0032805D1002903D10020704758
+:1005D0000029FBD010B4874C00236377864A00289B
+:1005E00090700CD002280AD007291AD20B007B4445
+:1005F0001B79DB189F441505070D0F111300D370ED
+:1006000003E01B2000E03A20D0700120607710BC8E
+:1006100070475820F8E77720F6E79620F4E7B520F2
+:10062000F2E710BC0020704710B573484078F2F72D
+:1006300014FA80B210BD411E1422504310B5654A11
+:100640008418203C032902D8207F002803D162A10E
+:100650006E4802F036FA207F012804D001205EA106
+:10066000400202F02EFA0020207710BD70B55E4CDB
+:1006700060782178884201D1012500E00025F2F759
+:1006800088F9F2F7EAF961782278914201D10121E3
+:1006900000E00021A942EBD170BDF7B58CB0064651
+:1006A0000D98401EC1B20090029114204143494868
+:1006B0000D1828460195007C2D1D07282BD1444F8D
+:1006C00000203C7A797AA14222D03A5D02998A428E
+:1006D00007D1002803D040A14D4802F0F2F90120D3
+:1006E00001E0002804D0611C4907490F795C3955A5
+:1006F000641C6407797A640FA142E6D1002807D010
+:10070000787A002802D0787A401E00E007207872BC
+:100710000199012008740099324C0D9803290FD8D3
+:10072000142148432B4940182038007F002807D067
+:100730000198007C012807D00E98C07A012807D0C4
+:1007400025A1344802F0BDF90E98C07A012839D1AC
+:100750000198204B007C02280FD01D4C607A217A32
+:10076000401C4007400F884203D11BA12A4802F0D9
+:10077000A8F901990120487434E12079029A0146D0
+:10078000904206D0014614277843C018807C9042DE
+:10079000F8D12279824208D1217914225143C91813
+:1007A000897C21710121617107E014224243D21832
+:1007B00014277943927CC9188A7414220521504366
+:1007C000C01881740E98007A06283BD226E00000FB
+:1007D000D41B0020EC1A00207372635C72656D2ECE
+:1007E00063000000001C0020BC1B0020071C002030
+:1007F000C01B0020E01B0020FE000020E81A0020A3
+:1008000003FF0000FC000020D5030100FF010000F1
+:10081000450200004E0200005B02000003007B4422
+:100820001B79DB189F44020C0A08060400200FE025
+:10083000B4200DE073200BE0322009E00A2007E02D
+:10084000062005E0FF20F749443002F03AF9002085
+:1008500003900E98C07A02280E9824D0807A2872CD
+:100860000E9803990068401A28600E99097A0029A9
+:1008700061D00221401A0002000A28600E98016827
+:10088000406808186860C01D0002000A68600E9881
+:100890000627407AA8720E98007A6872FFF776FDF4
+:1008A00000284AD053E04168007A00282DD0022069
+:1008B00009180398C01D09182079052827D0DA489F
+:1008C000039A4078904200D81046801A4218D748C0
+:1008D000921D8446207914235843D54BC018436891
+:1008E00080689B1B801B1B0200021B0A000A9A42A5
+:1008F00004D8CE4A934201D8604508D92079142201
+:100900005043CB4A801880680CE00420D0E7C648EA
+:10091000039A4078904200D81046801A8019801DB2
+:100920000002000A286040180002000A68600020E7
+:1009300028726868A7E704219CE7687A032806D232
+:10094000002804D0039838210F1A32200390B649AA
+:100950000878012801D003280AD1487803998842F1
+:1009600006D9B449C97F002902D10399401AC71991
+:100970002968AE488B1B69681A02891B0591090218
+:10098000120A090A97421ED8074682421BD8B9426A
+:1009900019D82079012205282FD0002001210491A7
+:1009A00021799C46059B14225143A14A89184A6823
+:1009B000921B9A4203D28A68921B62452BD800226E
+:1009C0000AAF3A5430E0019905209B4C0874607AD4
+:1009D000217A401C4007400F884203D197A19A48D2
+:1009E00002F06FF8617A02986054607A401C400708
+:1009F000400F607200200FB0F0BD019802230299F1
+:100A000003742379052B00D02379837421716271DB
+:100A100001200FB0F0BD01220AAF3A548A7BAF7AB1
+:100A2000BA4201D800220492897C401CC0B2052938
+:100A300003D0049A002AB6D1A1E00498002877D008
+:100A400025790520002704900AA8C05D012827D039
+:100A500004951420454376487F1C2818857CFFB2F6
+:100A6000052DF1D1019802230374714F20790528D7
+:100A700053D025790520049001984068811B1420EB
+:100A80006843C0194268921B8A4262D92079A84201
+:100A90004FD1019902980B742279052A42D142E084
+:100AA0002079A8420BD121791420414360480818CD
+:100AB000807C2071012060710020207011E004987A
+:100AC000052803D15DA1614801F0FBFF28461421F0
+:100AD0004843574914234018827C049858434018CF
+:100AE0008274284614214843514906224018027452
+:100AF0005148417A007A491C4907490F814203D184
+:100B00004EA1534801F0DDFF4B48417A4554417AEC
+:100B1000491C4907490F41729BE7227901990298C4
+:100B2000052A00D022798A7420710120607123E0A7
+:100B300025E00498052803D140A1464801F0C1FFF3
+:100B4000049814225043C019029981740198857445
+:100B500012E0807C052807D0049505468FD137A187
+:100B60003D4801F0AEFF21E014214D43E919029800
+:100B7000887401990520887401200FB0F0BD019898
+:100B800005212D4C0174607A217A401C4007400FEA
+:100B9000884203D129A1314801F093FF617A02987C
+:100BA0006054607A401C4007400F607200200FB014
+:100BB000F0BD70B50D460646294900242046891B24
+:100BC000A04103D21DA1274801F07BFF2649002048
+:100BD000491BA04103D219A1244801F072FF244A05
+:100BE00070190021821A8C4101D32249401870BD2E
+:100BF000F8B5401EC0B2142148430D494518687B22
+:100C000006283DD203007B441B79DB189F44023643
+:100C100034080604002067E0B4203AE0732038E08E
+:100C2000322036E0D8070100FE000020FFFF3F0021
+:100C3000EC1A0020E01B0020D41B00207372635CC0
+:100C400072656D2E63000000A3020000DE0200004A
+:100C5000E302000007030000170300001D0300006B
+:100C6000FF7F841E290300000020A1072A03000043
+:100C70000080841E00807BE10A200AE0062008E054
+:100C8000FF20FE49443001F01CFF697B0020002951
+:100C90002AD0022140186968002440180C21000263
+:100CA0006956000A002921DBF1F7D7FEF44A06460F
+:100CB0000C27EF570021101AA14103D2EF49F14848
+:100CC00001F0FFFEF0490020C91BA04103D2EB490F
+:100CD000EE4801F0F6FEEE4AF0190021821A8C412E
+:100CE00001D3EC494018F8BD0421D3E7F1F7B5FE74
+:100CF0000C21695600224018E149091AA241F2D29A
+:100D00004042F8BDF0B5074683B0E3480E46029076
+:100D100000F0C9FCE14C00282ED0E14D287C0028D1
+:100D200003D0E0A1E24801F0CCFE012028742F732B
+:100D3000DB4D30782872707868722A460A3229466C
+:100D40007068F1F794FE0A2028560F2804DD1F383A
+:100D5000A8722868401C28600021B0686A4600918B
+:100D6000117101AA6946F1F782FE6A460420105605
+:100D70000F2846DD012045E060782178401C4007BF
+:100D8000400F884203D1C7A1CA4801F09AFE60789B
+:100D90000101C94809180F73617809010D183078ED
+:100DA0002872707868722A460A3229467068F1F70C
+:100DB0005EFE0A2028560F2804DD1F38A872286816
+:100DC000401C28600021B0686A460091117101AA98
+:100DD0006946F1F74CFE6A46042010560F2801DDE3
+:100DE000012000E00020009940186860307BE87224
+:100DF0006078401C4007400F6070029800F06BFC68
+:100E000005E00020009940186860307BE872607847
+:100E10002178884224D0A9480579052D22D0F1F700
+:100E2000B8FD14214D43A64969180A7C042A17D03D
+:100E3000032A15D04B6889681B1A091A180209027F
+:100E4000A04A000A090A06280AD31346904207D886
+:100E5000994205D860782178884201D0F1F7E5FD04
+:100E600003B0F0BD607821788842F7D103B0F0BDBF
+:100E700010B50020F1F7EBFC10BD10B50120F1F723
+:100E8000E6FC10BDF8B5074602281ED08B4C207931
+:100E9000052803D183A18C4801F013FE0020A07027
+:100EA0000125A571207903211422854E5043801914
+:100EB0000174F1F7BFFD3800844F0BD001281FD01B
+:100EC00003286FD077A1824838E082480078F1F794
+:100ED00099FBF8BD65700020F1F7CCFC7968481CDF
+:100EE00004D0012300221846F1F7FAFC2079217979
+:100EF000401CC0B214225143725801219047F8BDE2
+:100F00000120F1F7B7FC607800280CD07868401C0D
+:100F100009D020792179401CC0B214225143725863
+:100F200006219047F8BD387E01280AD0022812D049
+:100F3000032824D0042836D05AA1674801F0C1FD07
+:100F4000F8BD2078002804D000202070F1F777FD4C
+:100F5000FD77002024E0E078002804D1FEF7F4FCBF
+:100F6000F1F752F9E57020792179401CC0B21422C2
+:100F7000514372580021904700203876F8BD397AE5
+:100F800038680123411A00221846F1F7A9FC20789D
+:100F9000002804D000202070F1F751FDFD770220D9
+:100FA0003876F8BD1AE0397F38680123411A0022EB
+:100FB0001846F1F795FCE078002804D1FEF7C4FC50
+:100FC000F1F722F9E57020792179401CC0B2142292
+:100FD00051437258002190473D76F8BD2079217920
+:100FE000401CC0B214225143725805219047F8BDED
+:100FF00010B5324C2079052803D12AA1374801F0D9
+:1010000060FD20792179401CC0B2142251432C4A42
+:1010100052580421904710BDF0B583B00526F1F772
+:10102000B8FC054629484068401C03D01DA12C4847
+:1010300001F047FD214C21792A480190052956D01D
+:101040002179142041431E480918097C04294ED0F7
+:101050002179142251430818007C03287ED001987E
+:10106000184902684068521B401B12020002120A13
+:10107000000A062A72D30B468A4235E03C0C010076
+:10108000FF7F841E290300000020A1072A0300001F
+:101090000080841E00807BE1071C0020BC1B002018
+:1010A000C01B00207372635C72656D2E63000000CC
+:1010B0006E0300005F0300003C1B0020001C0020AA
+:1010C000EC1A0020FFFF3F00A2030000E01B0020FD
+:1010D000F3030000FC000020E7030000FA03000017
+:1010E0002B040000EC1B002038D8984236D8002092
+:1010F00060702079052808D1F648407F002804D088
+:10110000F548C1784170817801702079052814D0A4
+:10111000207914214843F1494018007C04280CD15F
+:1011200026792279012014235A4352181074227907
+:101130005A435118897C21716071E94F7878397868
+:10114000884215D038780101E6480A183978090133
+:101150000818017B2846FFF7A0FA00E071E1387813
+:10116000401C4007400F3870787839788842E9D1C0
+:10117000DD4F387C002806D0397B3A462846FFF7F9
+:101180008CFA00203874052E1BD0142031464143C0
+:10119000D2480818017C012913D10721D34F0174CB
+:1011A000787A401C0840397A884203D1D0A1D348CC
+:1011B00001F087FC787A3E54787A401C4007400F53
+:1011C0007872207905287DD0607900287BD00020B6
+:1011D0006071217914204143C048BE4F0E18C849A0
+:1011E000B3687268F6688E604B600A60797D00298A
+:1011F00010D0022621791422B84851430818407BA8
+:10120000062815D203007B441B79DB189F44040E8B
+:101210000C0A08060426EDE700200FE0B4200DE0DC
+:1012200073200BE0322009E00A2007E0062005E0E9
+:10123000FF20AFA1443001F044FC00203872797DDA
+:10124000022901D001290FD1F96809184A1B12029D
+:10125000120A382A08D90320787532390802000AA0
+:10126000F860322038720AE0322808D2E07800288C
+:101270000ED1FEF769FBF0F7C7FF012007E0E07829
+:10128000002805D0FEF77FFBF0F7E7FF0020E070B5
+:10129000914A0621507838771278012A01D0032A22
+:1012A00006D1012222703A7A904201D9811A891D11
+:1012B000BA7F002A00D0891C2378002B01D1002A94
+:1012C00061D001E088E098E08C468E490091019958
+:1012D0000B6849685B1B491B09021B02090A1B0AB0
+:1012E00001919C451CD8874DAB4219D8019B0099B0
+:1012F0008B4215D8397A884223D9FB68421A9A1A48
+:101300001202120A101880190002000AFA603860EE
+:10131000002914D0032038760006000E3ED144E0A8
+:1013200000202070B877397A002925D0F868401855
+:1013300080190002000A3860022038762EE0012071
+:10134000E9E781420BD9FA68511889190902090A9B
+:101350003960002801D00420DDE70220DBE7002A05
+:1013600003D163A1684801F0ACFBF8688019000262
+:10137000000A3860002004E0F96889190902090AA6
+:101380003960387611E0387A00281DD0F9680818DD
+:1013900080190002000A386002203876F8680123BC
+:1013A000811900221846F1F79BFA2079142148434D
+:1013B0004A490C2240188256012300203968F1F76F
+:1013C0008FFAF1F7C1FB18E0F86880190002000AF3
+:1013D000386000203876E8E70120F1F74BFA00206A
+:1013E000F1F748FAF1F72CFAE078002805D0FEF77B
+:1013F000CAFAF0F732FF0020E070364DA87F0028CF
+:1014000004D0F1F71CFB0020E877A877687F00285C
+:1014100004D03148C178417081780170207800286B
+:1014200006D000202C49E8770978002900D12070E7
+:101430002E48417A007A814203D034484078F1F74F
+:10144000E1F803B0F0BDF0B5314C0746207983B028
+:10145000052803D126A12F4801F033FB2079142160
+:101460001E4E48438019007C032803D020A12A483F
+:1014700001F027FB174D6868401C03D01CA12748CA
+:1014800001F01FFB20791421484381190C200856D4
+:1014900000216A4600911171C01901AA6946F1F74D
+:1014A000E6FA6A46042010560F2801DD012000E00C
+:1014B000002000994018296840180102090A696053
+:1014C0006078002804D0012300221846F1F708FABA
+:1014D00003B0F0BDE01B0020FE000020EC1A00204D
+:1014E000BC1B00203C1B0020C01B0020D41B002084
+:1014F0007372635C72656D2E630000005C04000013
+:10150000EC1B0020FFFF3F00AE040000FC000020A9
+:10151000001C00200B0500000C0500000D0500005C
+:10152000F8B51D4D0A1A00242346551BA34106D3C6
+:10153000194E431A254600279E1BBD4101D2104675
+:10154000F8BD164E0025B21AA54103D2721C101A1E
+:101550004018F8BD114D0022EB1AA24104D26A1CBA
+:10156000511A08184042F8BD53200DA1000101F0A6
+:10157000A8FA0020F8BD10B5014601230022022080
+:10158000F1F7AEF910BD10B50220F1F773F910BDF7
+:1015900010B5F1F7FEF910BD0020A107FF7F841EF2
+:1015A0007372635C72656D2E6300000010B50146B6
+:1015B00020220A4801F0E8F808490020C8770846C8
+:1015C00010BD0749012048610648074A0168914259
+:1015D00001D100210160704770477047081C00204E
+:1015E0000005004004010020EFBEADDE064A107089
+:1015F0005170704704481C2201784171427001709B
+:101600007047704770477047080100207047704767
+:1016100070477047704770477047704730B5034652
+:10162000002002460DE09C5C2546303D0A2D02D389
+:101630000020C04330BD0A25684330382018521CB2
+:10164000D2B28A42EFD330BD70B50D46144608E0E1
+:101650000A2101F013F92A193031203A641ED1779A
+:10166000E4B2002CF4D170BD10B5002310E0040AE0
+:1016700000020443A0B2CC5C44402006000F60404E
+:101680000407240C44402006C00C60405B1C9BB245
+:101690009342ECD310BD002101700846704701460B
+:1016A000002008707047EFF31081C907C90F72B6A8
+:1016B0000278012A01D0012200E0002201230370F8
+:1016C000002900D162B6002A01D000207047012015
+:1016D00040037047E7E7EFF31081C907C90F72B6FF
+:1016E00000220270002900D162B600207047F2E7A4
+:1016F0000348004703480449024A034B704700006F
+:10170000312B0100481C0020481C002010B5203857
+:101710000C46030001F0DAFA331B1F23272C313764
+:101720003C41474D5054585C606D71656974787CDC
+:101730008084888C9094989C9FA2A6AAAEB2B8BCD4
+:10174000C0C5CACFE9F0F3D3D7E0DBE4F8002068E6
+:10175000FFF7A1FFD6E02068FFF7A5FFD2E02068E1
+:10176000FFF7B9FFCEE0207840B200F0F3F9C9E00E
+:10177000207840B200F011FAC4E02078616840B2ED
+:1017800000F024FABEE0207840B200F034FAB9E06C
+:10179000207840B200F03FFAB4E02078217940B2DE
+:1017A00000F04AFAAEE02078616840B200F074FAC6
+:1017B000A8E000F080FAA5E0206800F084FAA1E03B
+:1017C000207800F099FA9DE02068FEF7BCF999E0D6
+:1017D0002068FEF7BCF995E021792068FEF7BEF994
+:1017E00090E02068FEF706F88CE02068FEF707F826
+:1017F00088E02078FEF707F884E0FEF715F881E02E
+:101800002078FEF717F87DE02078FEF729F879E0D8
+:101810002068FEF742F875E02068FEF744F871E0B2
+:101820002068FEF746F86DE02068FEF747F869E0AB
+:101830002068FEF749F865E02068FEF74BF861E0A4
+:101840002068FEF74CF85DE00846EEF77FFC59E0B3
+:10185000F0F7EDFC56E0F0F71AFD53E02068F0F7E2
+:1018600022FD4FE0206800F079FA4BE0206800F09C
+:101870007BFA47E0206800F07CFA43E02078A26819
+:10188000616800F07BFA3DE0207800F083FA39E0EF
+:10189000207800F08BFA35E02078616800F093FA48
+:1018A00030E02078616800F09AFA2BE02179207806
+:1018B00000F0ACFB26E02068FEF73FFA22E020684B
+:1018C000FEF710FD1EE02068FEF7F4FC1AE020464B
+:1018D00007C800F078FC15E0206800F0C0FC11E0BB
+:1018E0006168206800F0E2FC0CE0206800F04EFE29
+:1018F00008E009E003E0FFE700F061FE02E0206895
+:1019000000F079FE206010BD0120086010BD0000CD
+:1019100010B572B600F0E4F800280BD0EEF7C0FC6A
+:10192000FEF7E1FD00F039FB72490020C8628862D1
+:101930007149086062B6002010BDF3B50025012092
+:101940000007C06A81B0C0430006000E0AD16B4890
+:101950000168491C05D000686949884202D069487D
+:10196000FEBD012572B600F0BBF8002801D062B6BA
+:1019700088E0EEF701FCEEF797FC634C634A002128
+:101980002368CB40DB0720D00346CB40DB0718D1D0
+:101990004BB2002B07DA1E07360F083EB608B6001A
+:1019A000B618F66904E09E08594FB600F619366875
+:1019B0009B07DB0EDE4033069B0F012B05D0032B6C
+:1019C00003D062B64F48401EFEBD491C2029D7D324
+:1019D000019C01204F49230001F078F914222424AE
+:1019E0002424242424240B0D1012142016181A1C4D
+:1019F0001E2F002400E00124C86314E00224FBE74A
+:101A00000324F9E70424F7E70824F5E70924F3E7BA
+:101A10000A24F1E70B24EFE70C24EDE70524EBE7BC
+:101A2000072400E00624D06901210002000AC9074A
+:101A30000843D061002D04D009E062B60120000304
+:101A4000FEBD2C4D3448E862EEF72EFCA8622A4910
+:101A500032480860324902980860EEF725FC2146BA
+:101A600000F082FAFEF706FD00F04CFC00F0FEFAF2
+:101A70000198EEF7E3FB040062B603D0FFF748FFDE
+:101A80002046FEBD0020FEBD10B5044600F028F83B
+:101A9000002800D001202070002010BD21491848E6
+:101AA00008600020704710B50C46102808D0112897
+:101AB0000BD012280CD013280ED00120086010BDC6
+:101AC00061682068FFF739FF08E0FFF721FF05E0B4
+:101AD0002068FFF7D9FF01E0FFF7E0FF206010BDAD
+:101AE00005480E490068884201D101207047002056
+:101AF00070470000000500400401002000100010A5
+:101B0000004001000210000000E100E000ED00E0F4
+:101B100000E400E04000004000200000EFBEADDE29
+:101B200010010020000000208107C90E002808DAFB
+:101B30000007000F08388008814A80008018C069BB
+:101B400004E080087F4A800080180068C8400006D2
+:101B5000800F704710B5044600F0DBF8002813D062
+:101B60002046FFF7E1FFC0B200F0E1F800280DD0F9
+:101B70007549E2060B78D20E01209040002B08D068
+:101B80004A681043486006E0704810BD6F48401C2A
+:101B900010BD6F490860002010BD10B5044600F06C
+:101BA000B8F800280BD06849E2060B78D20E012065
+:101BB0009040002B05D04A6882434A6004E06348A5
+:101BC00010BD634980310860002010BD70B50D461E
+:101BD000044600F09EF800280BD05E480068E2063C
+:101BE000D20E01219140084000D001202860002041
+:101BF00070BD564870BD10B5044600F08AF8002844
+:101C000007D0E106C90E0120884052490860002033
+:101C100010BD4E4810BD10B5044600F07AF80028FB
+:101C200008D0E106C90E012088404A498031086089
+:101C3000002010BD454810BD70B50D46044600F0AB
+:101C400068F8002819D0284600F071F8002816D04E
+:101C5000A007C20EFF209040A907090E9140002C5A
+:101C600010DA2207120F083A9308354A9B009B1896
+:101C7000DA6982430A43DA610CE0344870BD3348C4
+:101C8000401C70BDA3082F4A9B009B181A68824312
+:101C90000A431A60002070BD70B50C46054600F07E
+:101CA00038F8002805D02846FFF73EFF20700020B6
+:101CB00070BD264870BDBFF34F8F21492648C860CC
+:101CC000BFF34F8FFEE770B51F4C0546217801200A
+:101CD00000290ED1207072B600F06EF91C4E8036CD
+:101CE00031688143616000F067F9C043306062B6DB
+:101CF00000202870002070BD13490A78002A06D001
+:101D0000002804D1124A48681060002008700020A2
+:101D1000704710B50446202805DA00F04DF901217E
+:101D2000A140084201D0002010BD012010BD0128B3
+:101D300003D0032801D00020704701207047000025
+:101D400000ED00E000E400E01401002001200000AC
+:101D500000E100E000E200E00400FA05364909680D
+:101D6000C9B20160002070473349C0B2486000200A
+:101D700070473149C0B2886000207047082801D3FD
+:101D80002E4870472C4BC0001033C01801604260D1
+:101D900000207047022802D32848401C7047284979
+:101DA000C00040180121016000207047022802D3C2
+:101DB0002248401C70472249C000091D40180121DB
+:101DC000016000207047022802D31C48401C704765
+:101DD0001C4A80008018C9B20160002070470228A8
+:101DE00002D31648401C7047164A800080180068CD
+:101DF000C0B208600020704710B5FF200E49C043F4
+:101E000088600D4B082210330021D000C0180160FB
+:101E10004160521C102AF8D30A4B00208200D218CD
+:101E2000022801D3116002E01468E4B21460401C7F
+:101E30000428F3D310BD000000F501400820000085
+:101E400000F0014000F80140F8B504468007002585
+:101E50000126002804DA5A48C563C6630220844379
+:101E6000E00404D55748C563C6638014844360000A
+:101E700003D55548456080058443E00504D55348A3
+:101E8000C563C66380158443A00404D55048C56368
+:101E9000C6634014844360042704C00FF90F8842CE
+:101EA00003D04CA1612000F00CFEB80F0AD04E49BF
+:101EB000CD634E48C563C563CE63C663C663032066
+:101EC0008003844320050AD5494FFD632F20EEF798
+:101ED0006BF9FE632F20EEF767F9F8148443002CAA
+:101EE00003DAFFF789FF640064084248044203D024
+:101EF00038A1902000F0E5FDF8BDF0B500210A46BC
+:101F0000FF230446CC40E4072AD04CB2E606F60E86
+:101F10000125B540384E3560384E3560002C11DA59
+:101F200025072D0F083DAE08354DB6007619F56929
+:101F3000A407E70E1C46BC40A5431446BC402543FD
+:101F4000F5610DE0A6082F4DB60076193568A40797
+:101F5000E70E1C46BC40A5431446BC4025433560F3
+:101F6000491C2029CDD3F0BD70B5274C0D4620600B
+:101F7000FFF76AFF2068FFF7C0FF2846F0F720FA56
+:101F8000FDF7C6FEFDF772FDFFF736FFFDF7C5FC56
+:101F9000F0F702FB00F06AF870BD10B51A4C20682B
+:101FA000FFF752FF2068FFF7A8FFFFF725FFF0F7C4
+:101FB0008CFA0020206010BD1348006870470000B4
+:101FC000C01F0040C0CF004000E50140C08F00406E
+:101FD000C0DF00407372635C736F635F636F6E6634
+:101FE00069672E6300000000C0EF0040C0FF0040A2
+:101FF000C0BF0040FEFF0FFC80E100E080E200E097
+:1020000000ED00E000E400E01C01002070B50024B9
+:1020100002460D4620462146002A1ED0012A04D041
+:10202000022A04D0032A1ED103E0012002E002208C
+:1020300013E003202B0000F049FE07160507090BEB
+:102040000D0F1600012108E0022106E0032104E043
+:10205000042102E0052100E00621FEF7B1FA002884
+:1020600001D0204670BD0724FBE700009B490020FB
+:10207000087088709A490870704770B5974C0E4682
+:102080006178884203D097A15A2000F01AFD0325F9
+:10209000330000F01BFE0953063030535353534AAC
+:1020A00053002078022803D08EA15E2000F009FDA5
+:1020B0002570A078022802D0012804D014E0A0687E
+:1020C00000F004FB10E000250BE0E0680168A06868
+:1020D00000F00DFBA068001DA060E068001D6D1CF5
+:1020E000E06020698542F0D30020A070FEF710FA6E
+:1020F0000420207070BD2078022803D079A17620BA
+:1021000000F0DFFC60687649401C6060032801D85D
+:102110004D7003E0062806D80220487070496078A8
+:10212000FEF7F0FD70BD032003E0A0780028FAD18F
+:102130000220FEF703F900F0C7F870BD69A19E20E8
+:1021400000F0BFFC70BD70B50546644C00206060B7
+:102150002078012803D063A1A52000F0B2FC6049DB
+:10216000022008738D6003224A7020706078FEF7A9
+:10217000C9FD70BD10B5594CA078002802D1207857
+:10218000002801D0112010BD5A48FEF700FA6070F7
+:102190006078002803D001202070002010BD0320AB
+:1021A00010BD10B50124020B64040121524BA04262
+:1021B00002D29140186802E0203A586891400840E5
+:1021C00000D0012010BDF8B50E46910005464F190C
+:1021D00014463F1F009100F09CFA00998002891973
+:1021E000091FB14201D2012200E00022002C03D0DD
+:1021F000FF2101318C4201D90920F8BD3F498D42B0
+:1022000019D3AF4217D3854205D2874203D228465D
+:102210003043800701D01020F8BD8E420BD3002A36
+:1022200009D12846FFF7BDFF002804D13846FFF743
+:10223000B8FF002801D00F20F8BDFFF79BFF002852
+:10224000FAD126480121C66085600461817020466C
+:10225000312148431430FFF776FF0020F8BD10B558
+:1022600004462648800A84420BD300F052FAA0426A
+:1022700001D8102010BDA0020446FFF792FF0028ED
+:1022800001D00F2010BDFFF775FF0028FAD11348C9
+:102290000221846081701A48FFF755FF002010BDAD
+:1022A0001648010B01208840401E704700B50B46C0
+:1022B0000246FFF7F5FF104201D00F2000BD0E4887
+:1022C00002604360002000BD10B5044C6078FEF74A
+:1022D000B2F900202070A07010BD00002001002085
+:1022E000281C00207372635C736F635F666C61739C
+:1022F000682E63007B2001000006004000400100C2
+:1023000010540000E349002048700870887048604D
+:10231000E1490873704710B5E048826A81158A4325
+:10232000DC498B691A438262826A0223C9699A4333
+:102330000A438262FEF7ECF810BD002814D0417801
+:10234000002901D001290ED18168D54A6439914212
+:1023500009D24068D349884205D8CE494978012935
+:1023600003D1002801D0002070470120704770B5CC
+:102370000446FEF782FD0068002803D0CAA1802031
+:1023800000F09FFB0126C34D002C06D020780028CA
+:102390002BD0012827D0022801D0EE7023E0287826
+:1023A000002820D16068FFF7C8FF0028F5D06068DA
+:1023B0000078002800D00220B74E30706068806836
+:1023C0009630B06060684168E868FEF7F2FB7060C4
+:1023D000606803244078002808D07470AE49A8785B
+:1023E000FEF790FC6C70FFF796FF70BD02207070D6
+:1023F000F4E7F8B5A74C0D46A178884203D0AAA10E
+:10240000BF2000F05EFB284600270526A24D0300F2
+:1024100000F05CFC09061135587F8997B8A2B80016
+:102420006078032806D06078022803D09EA1C320DC
+:1024300000F047FBF8BD6078032806D060780228DA
+:1024400003D099A1C72000F03CFB04206070E77026
+:102450002078002802D0FEF75BF8F8BDA86896380F
+:10246000FEF7F1FF6868E0608C48816A82151140D0
+:10247000A161806A02210840E06100205CE0607890
+:10248000032806D06078022803D087A1E22000F05C
+:1024900018FB2078002802D000F0EFF8F8BD607833
+:1024A000032802D02069410020E004202DE07A4971
+:1024B000A078FEF727FCF8BD0420FDF73FFF0120C0
+:1024C0006070F8BD6078032807D06078022804D0D7
+:1024D000FF2075A1043000F0F4FA20780028DBD149
+:1024E0006078032810D06868A06076492161A068F0
+:1024F000FEF75FFB686069686069FFF711F868497B
+:1025000063318842D8DCD2E70520FDF717FF6670FB
+:10251000F8BD6078042804D0FF2063A1263000F0C5
+:10252000D0FA022008E06078042804D0FF205EA1E1
+:102530002B3000F0C6FA012061688847FFF717FFCB
+:10254000F8BD6078042804D0FF2057A1303000F097
+:10255000B8FAFFF7E0FEF8BD6078042804D0FF2049
+:1025600051A1353000F0ADFA2078002894D1E07800
+:10257000002805D00620FDF7E1FE6670E770F8BD83
+:102580000720C2E7FF2048A14B3051E770B5050096
+:1025900005D0404C6078002803D0112070BD102079
+:1025A00070BD4948FDF7F3FFA070A078002804D063
+:1025B000656001206070002070BD032070BD10B503
+:1025C00034480178002901D0112010BD417800293C
+:1025D0000BD0417805290AD04178012907D0012183
+:1025E00001704078052802D003E00F2010BD00F0F4
+:1025F00044F8002010BD70B5264C064660780528CA
+:1026000004D06078012801D00F2070BD002E25D0A5
+:102610003046FFF792FE002822D060781E4D012838
+:1026200020D07168E068FEF7C4FA6860B068963040
+:10263000A8603078002800D0032028707078002827
+:1026400017D0032068706078052814D002206070CD
+:102650001149A078FEF756FB002070BD102070BD18
+:10266000072070BDFEF702F86061A0601549216186
+:10267000D9E70220E6E70320E9E710B5054CA0788A
+:10268000FDF7D9FF0820FDF759FE0020607020708B
+:1026900010BD000034010020381C0020000500405F
+:1026A0003D860100FF1FA1077372635C736F635F58
+:1026B000726164696F5F74696D65736C6F742E63AA
+:1026C0000000000024080000F3230100134A022147
+:1026D000516013490B68002BFCD0906008680028FB
+:1026E000FCD00020506008680028FCD0704710B56E
+:1026F0000A4B01225A600A4A1468002CFCD001607F
+:1027000010680028FCD00020586010680028FCD019
+:1027100010BD0120000740697047000000E501403E
+:1027200000E40140704770477047704770470346A8
+:1027300010B50B439B070FD1042A0DD308C810C94D
+:10274000121FA342F8D018BA21BA884201D9012039
+:1027500010BD0020C04310BD002A03D0D30703D012
+:10276000521C07E0002010BD03780C78401C491C67
+:102770001B1B07D103780C78401C491C1B1B01D183
+:10278000921EF1D1184610BDF8B5042A2CD3830748
+:1027900012D00B78491C0370401C521E83070BD0CB
+:1027A0000B78491C0370401C521E830704D00B7821
+:1027B000491C0370401C521E8B079B0F05D0C91A81
+:1027C000DF002023DE1B08C90AE0EDF7FDFCF8BDA1
+:1027D0001D4608C9FD401C46B4402C4310C0121FC2
+:1027E000042AF5D2F308C91A521EF0D40B78491CFA
+:1027F0000370401C521EEAD40B78491C0370401C25
+:10280000521EE4D409780170F8BD01E004C0091F2C
+:102810000429FBD28B0701D50280801CC90700D098
+:102820000270704700290BD0C30702D00270401C11
+:10283000491E022904D3830702D50280801C891E09
+:10284000E3E70022EEE70022DFE70378C2781946CB
+:10285000437812061B0219438378C0781B0419437E
+:1028600011430902090A000608437047020A08706A
+:102870004A70020C8A70020ECA7070470022030967
+:102880008B4273D3030A8B4258D3030B8B423CD346
+:10289000030C8B4221D312E003460B437FD400226A
+:1028A00043088B4274D303098B425FD3030A8B42E4
+:1028B00044D3030B8B4228D3030C8B420DD3FF224E
+:1028C000090212BA030C8B4202D31212090265D01C
+:1028D000030B8B4219D300E0090AC30B8B4201D3CF
+:1028E000CB03C01A5241830B8B4201D38B03C01A16
+:1028F0005241430B8B4201D34B03C01A5241030B8D
+:102900008B4201D30B03C01A5241C30A8B4201D33D
+:10291000CB02C01A5241830A8B4201D38B02C01AE8
+:102920005241430A8B4201D34B02C01A5241030A5F
+:102930008B4201D30B02C01A5241CDD2C3098B4244
+:1029400001D3CB01C01A524183098B4201D38B01C1
+:10295000C01A524143098B4201D34B01C01A524164
+:1029600003098B4201D30B01C01A5241C3088B42A9
+:1029700001D3CB00C01A524183088B4201D38B0094
+:10298000C01A524143088B4201D34B00C01A524136
+:10299000411A00D201465241104670475DE0CA0F0D
+:1029A00000D04942031000D34042534000229C46CD
+:1029B00003098B422DD3030A8B4212D3FC228901D7
+:1029C00012BA030A8B420CD3890192118B4208D3AD
+:1029D000890192118B4204D389013AD0921100E00F
+:1029E0008909C3098B4201D3CB01C01A5241830923
+:1029F0008B4201D38B01C01A524143098B4201D350
+:102A00004B01C01A524103098B4201D30B01C01A7A
+:102A10005241C3088B4201D3CB00C01A52418308F4
+:102A20008B4201D38B00C01A5241D9D243088B424A
+:102A300001D34B00C01A5241411A00D201466346ED
+:102A400052415B10104601D34042002B00D5494251
+:102A5000704763465B1000D3404201B50020C0467A
+:102A6000C04602BD704770477047704710B500F010
+:102A700077F810BD30B58C180278401C13071B0F77
+:102A800001D10378401C120906D10278401C03E0F2
+:102A90000578401C0D70491C5B1EF9D101E00B70DC
+:102AA000491C521EFBD1A142E6D3002030BD0000DC
+:102AB00001231B68134B1860134B1960134B1A60EA
+:102AC0007047134A134B13607246053AF0E7114AF8
+:102AD0000F4B1B689A420ED10D4B002018600198D5
+:102AE0000D4B04B598470CBC9E46024602980099CF
+:102AF0000A4B1B68184706980599094B1B68DB6849
+:102B0000184700005C0100206001002064010020E3
+:102B100054010020EFBEADDEAD1501001001002014
+:102B2000000000200B4A12680B4B9A420AD1004762
+:102B3000084A1268084B9A4204D101B5FDF773F9AF
+:102B400003BC8E4605490968EFF305808000014407
+:102B50000968084704010020EFBEADDE0000002038
+:102B60001C481D497047FFF7FBFFEDF7E7FA00BD72
+:102B700001200007C06AC0B2FF2804D117481849D5
+:102B80000968884202D0174817490160174A136044
+:102B90005B68184720BFFDE7154B1B680F4999423A
+:102BA00002D018688842F5D004D1124B18680B493E
+:102BB0008842EFD080F308880F49884204DD0F482F
+:102BC000026802210A4302600D4880470D48804791
+:102BD0000D480047481C0020481C0020FFFFFFFF55
+:102BE000001000102C050040040000000000002030
+:102BF00014100010004001000020002024050040B7
+:102C0000C3150100712B0100B12A01001248704563
+:102C100002D1EFF3098101E0EFF3088188690238FE
+:102C20000078102812DB20280EDB0C4A12680C4BAF
+:102C30009A4203D1602804DB0A4A10470220086048
+:102C40007047094A10470000084A1047084A1268AE
+:102C50002C32126810470000FDFFFFFF0401002026
+:102C6000EFBEADDEAD0200000D170100A71A010096
+:102C7000000000200A480B4908470B48094908474B
+:102C80000A48084908470A480649084709480549C3
+:102C9000084709480349084708480249084700000F
+:102CA000E1230000252B0100412B0000EB2900004F
+:102CB000992900004D270000A72A000043260000A4
+:102CC00003B40148019001BD0500002030B47446F2
+:102CD000641E2578641CAB4200D21D46635D5B0018
+:102CE000E31830BC1847000002490020C8612039B1
+:102CF00008727047A003002000020206FFFFFFFFDA
+:102D00000000FFFF0102040810204080555555D6F1
+:102D1000BE898E00F401FA00960064004B00320078
+:102D20001E0014000100030000000100000000006C
+:102D3000000000000000000000000000870000000C
+:102D4000000000000000000000000000000002037E
+:102D5000040500000E0F0000882D01000400002073
+:102D60001000000004010000982D01001400002054
+:102D700054010000742A0100C02D010068010020E8
+:102D8000E01A0000200100000249022208681042F7
+:102D9000FCD0704700E200E0A1074E56FF9900CD3D
+:102DA00029023501022B013601000100D83720FB32
+:102DB000349B5F8074800010027001E4B52A01002A
+:020000041000EA
+:1010000000400100FFFFFFFFFFFFFFFFFFFFFFFFAB
+:041010004900FFFF95
+:04000005000000C136
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo_wanted.bin b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo_wanted.bin
new file mode 100644
index 0000000..b7e4cf7
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo_wanted.bin
Binary files differ
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foobar_wanted.bin b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foobar_wanted.bin
new file mode 100644
index 0000000..06b77f5
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foobar_wanted.bin
Binary files differ
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/pca10028_nrf51422_xxac_blinky.bin b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/pca10028_nrf51422_xxac_blinky.bin
new file mode 100644
index 0000000..b745f0d
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/pca10028_nrf51422_xxac_blinky.bin
Binary files differ
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s130_nrf51_mini.hex b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s130_nrf51_mini.hex
new file mode 100644
index 0000000..6e27ce8
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s130_nrf51_mini.hex
@@ -0,0 +1,894 @@
+:020000040000FA
+:10000000C0070000D1060000D1000000B1060000CA
+:1000100000000000000000000000000000000000E0
+:100020000000000000000000000000005107000078
+:100030000000000000000000DB000000E500000000
+:10004000EF000000F9000000030100000D010000B6
+:1000500017010000210100002B0100003501000004
+:100060003F01000049010000530100005D01000054
+:1000700067010000710100007B01000085010000A4
+:100080008F01000099010000A3010000AD010000F4
+:10009000B7010000C1010000CB010000D501000044
+:1000A000DF010000E9010000F3010000FD01000094
+:1000B00007020000110200001B02000025020000E0
+:1000C0001FB5C046C04600F0EFFA04B00FB41FBD24
+:1000D00008205A49096809580847382057490968CB
+:1000E000095808473C2055490968095808474020E5
+:1000F0005249096809580847442050490968095875
+:10010000084748204D490968095808474C204B4981
+:10011000096809580847502048490968095808479C
+:100120005420464909680958084758204349096836
+:10013000095808475C204149096809580847602068
+:100140003E4909680958084764203C49096809582C
+:100150000847682039490968095808476C20374919
+:100160000968095808477020344909680958084740
+:100170007420324909680958084778202F490968CE
+:10018000095808477C202D490968095808478020EC
+:100190002A490968095808478420284909680958E4
+:1001A0000847882025490968095808478C202349B1
+:1001B00009680958084790202049096809580847E4
+:1001C00094201E4909680958084798201B49096866
+:1001D000095808479C201949096809580847A02070
+:1001E0001649096809580847A4201449096809589C
+:1001F0000847A8201149096809580847AC200F4949
+:10020000096809580847B0200C4909680958084787
+:10021000B4200A49096809580847B82007490968FD
+:1002200009580847BC2005490968095808470000D3
+:1002300003480449024A034B7047000000000020B5
+:10024000C0070000C00700000122D84B5A6000BF61
+:10025000D74A1268002AFBD0016000BFD44A126856
+:10026000002AFBD00022D14B5A6000BFD04A12684E
+:10027000002AFBD07047F0B505460E46174600240D
+:1002800006E0A200B158A2005019FFF7DDFF641C80
+:10029000BC42F6D30020F0BD0120C043C549086030
+:1002A000401048607047014601229204086890425D
+:1002B00001D9102070470020FCE7F0B505460C4638
+:1002C0001646002706E028462168FFF7BDFF2D1DD2
+:1002D000241D7F1CB742F6D3F0BD70B505460C4611
+:1002E0002E460BE0304600F075F9FF2C01D80024B3
+:1002F00001E0FF3C013C012080023618002CF1D1C6
+:1003000070BD0146012212044868904201D90920BB
+:100310007047A9484069401C01D10F20F8E7002030
+:10032000F6E7FEB504462068030000F037FA05043E
+:100330002B4249598B00201DFFF7E3FF0546002D96
+:1003400001D02846FEBDFFF7A7FF0120C00200F044
+:1003500041F9042221469948FFF78DFF002801D07A
+:100360000320EFE708222146944800F06DF90028A9
+:1003700006D1002192480068FFF766FF00F00CF9F3
+:100380000320DFE7A768E6686068019031463846D9
+:10039000FFF7A3FF324638460199FFF78EFFB20000
+:1003A0003846019900F050F9002800D1CAE703202F
+:1003B000C8E700F0E3F9834800688349086041E03A
+:1003C00060680190E668A0680090B200009901980A
+:1003D00000F03AF90746002F00D1B3E70E20B1E74D
+:1003E000201DFFF760FF0546002D01D02846A9E734
+:1003F0006068002807D1FFF74FFF0320800200F05C
+:10040000E9F800F0C9F8FFF747FF0120C00200F04B
+:10041000E1F8042221466948FFF72DFF002801D0AA
+:1004200003208FE708222146644800F00DF90028D8
+:1004300006D1002162480068FFF706FF00F0ACF823
+:1004400003207FE700BF00207CE770B505460C461F
+:10045000182D04D12068FFF764FF206002E001201E
+:10046000206000BF00BF70BDF0B589B05248406940
+:1004700003905248806881000398081802900398FE
+:10048000000B01900121090302984018401E000B47
+:1004900000900124002520462946019A00F0C4F866
+:1004A0000022401E91410791069001260027304608
+:1004B0003946009A00F0B8F80022401E914105919B
+:1004C0000490049BDB43059AD2430698184307998E
+:1004D00011430791069037490698086007984860CD
+:1004E00009B0F0BD70B53448446934488568466841
+:1004F000AA003146204600F0A7F8002801D00020CD
+:1005000070BD0120FCE72D484068002801D0012083
+:1005100000E000200546FFF7E5FF002807D0FFF7C1
+:10052000BBFE0320800200F055F800F035F8FFF71D
+:100530009BFF002D0ED020484669204884684768FC
+:1005400021463046FFF7C9FE224639463046FFF7BE
+:10055000B4FE00BF00F020F810B5184844681A48EF
+:100560000460204600F0DCF810BD15480068006803
+:10057000401C01D100BFFEE710480068002802D0EF
+:10058000042806D101E0FFF7BEFFFFF7E5FF00BF3B
+:10059000FEE700BF00BFFEE7BFF34F8F0B480C49DB
+:1005A000C860BFF34F8F00BFFEE7000000E50140C9
+:1005B00000E40140000600400010001000080000A8
+:1005C000B8070000BC070000000000200400FA0586
+:1005D00000ED00E010B50146104B1A6808460223F2
+:1005E0000F4C636000BF0F4B1B68002BFBD0531CEC
+:1005F00004D0904202D20A4B186101E0084B986087
+:1006000000BF084B1B68002BFBD00023044C636029
+:1006100000BF044B1B68002BFBD010BD0010001066
+:1006200000E5014000E4014010B5202A04DB01464A
+:10063000203A9140002010BD914020239C1A03468F
+:10064000E3401943904010BD034610B50B439B0790
+:100650000FD1042A0DD308C810C9121FA342F8D025
+:1006600018BA21BA884201D9012010BD0020C04328
+:1006700010BD002A03D0D30703D0521C07E000208E
+:1006800010BD03780C78401C491C1B1B07D1037854
+:100690000C78401C491C1B1B01D1921EF1D118463D
+:1006A00010BD70477047704710B500F007F810BDD7
+:1006B000014B1B68DB6818470000002019481A49E5
+:1006C0007047FFF7FBFFFFF7FBFC00BD20BFFDE716
+:1006D0001649174C24688C420BD1164B1B68994263
+:1006E0000CD1154B154A1360186810498842EDD09B
+:1006F0000AE0134880F30888124B18470F4A13602A
+:1007000018680A498842E1D080F308880E49884277
+:1007100004DD0E48026802210A4302605B68184744
+:100720000346DFE7C0070000C0070000FFFFFFFF30
+:10073000000C000014100010001000000000002049
+:10074000000400206B05000000200020240500406C
+:100750000D48704502D1EFF3098101E0EFF3088104
+:10076000886902380078182802D1C046074A104725
+:10077000074A12682C3212681047000000B5054B7A
+:10078000054A9B58984700BDFDFFFFFF4B04000042
+:1007900000000020001000000400000030B4744687
+:1007A000641E2578641CAB4204D3635D5B00E318D0
+:1007B00030BC18471D46F8E7000C00000010000090
+:10100000F0210020FDB101005D22000063B101006C
+:1010100000000000000000000000000000000000D0
+:101020000000000000000000000000006DB20100A0
+:1010300000000000000000005D2200005D220000B2
+:10104000D9B20100DFB201005D2200005D22000084
+:101050005D2200005D2200005D2200005D22000094
+:10106000E5B201005D2200005D220000EBB201004C
+:101070005D220000F1B20100F7B20100FDB20100F3
+:101080005D2200005D2200005D2200005D22000064
+:101090005D2200005D2200005D2200005D22000054
+:1010A00003B3010009B301005D2200005D220000CE
+:1010B0005D2200005D2200005D2200005D22000034
+:1010C00000F002F81AF07BF80CA030C80838241899
+:1010D0002D18A246671EAB4654465D46AC4201D170
+:1010E0001AF06DF87E460F3E0FCCB646012633420D
+:1010F00000D0FB1AA246AB46334318477CA301003D
+:10110000ACA30100103A02D378C878C1FAD85207CC
+:1011100001D330C830C101D504680C6070470000AD
+:101120000023002400250026103A01D378C1FBD803
+:10113000520700D330C100D50B6070471FB5C046C1
+:10114000C04619F0DEFF04B00FB41FBDF0B4404636
+:10115000494652465B460FB402A0013001B506482D
+:10116000004700BF01BC86460FBC804689469246B8
+:101170009B46F0BC70470000C11000008269024924
+:101180008161024810447047911100000100000085
+:1011900001B41EB400B501F000FF01B40198864609
+:1011A00001BC01B01EBD0000401E00BF00BF00BF5B
+:1011B00000BF00BF00BF00BF00BF00BF00BF00BF37
+:1011C00000BFF1D17047000070B505460C461646C9
+:1011D00002E00FCC0FC5103E102EFAD2082E02D31B
+:1011E00003CC03C5083E042E07D301CC01C5361F2E
+:1011F00003E021782970641C6D1C761EF9D270BD45
+:101200008307FF22DB0E9A408907090E99400028C8
+:101210000BDA0007000F0838830828489B001818CD
+:10122000C36993430B43C3617047830824489B0001
+:101230001B181868904308431860704710B504469F
+:1012400000210120FFF7DCFF00211820FFF7D8FF65
+:1012500000210B20FFF7D4FF02211920FFF7D0FF58
+:1012600002210D20FFF7CCFF02210E20FFF7C8FF5F
+:1012700002210F20FFF7C4FF0221C81FFFF7C0FFA4
+:1012800003211620FFF7BCFF03211520FFF7B8FF4D
+:10129000204600F019F8002010BD6721018070473A
+:1012A00010B500F020F810BD0648704710B500F0EA
+:1012B00022F810BD704770477047000000ED00E055
+:1012C00000E400E003F9004370B505462D4C08200A
+:1012D0002070A01CFFF7E1FF5920A080294620467E
+:1012E00000F0B3FB70BD10B500F0B8FB254900203D
+:1012F000891E087010BDF8B5224E0446B61E30781F
+:1013000001270D46002807D0204660380B2808D852
+:10131000204600F059FF2BE0602CF9D01A480860F5
+:10132000F8BD20466C38032803D8204600F08DFF16
+:101330001EE0204670381F2803D8204600F047F9E9
+:1013400016E0204690380F2803D8204600F0EAF82F
+:101350000EE02046A0380F2803D8204600F076F88B
+:1013600006E02046B0380F2804D8204600F0E2F905
+:10137000286000E02F60602CD2D128680028CFD1EF
+:101380003770F8BD1A000020013000000120254907
+:10139000C003086024490020087007202349C005C5
+:1013A0008860704770B5204D04462878A04207D069
+:1013B000002C05D0002803D01DA14D2019F0CBFE34
+:1013C0002878A0420ED000211E4A18482C70002C0C
+:1013D0001BD01D4B012C06D0022C0DD014A168206F
+:1013E00019F0B9FE70BD1160022111605361032133
+:1013F00009068160416070BD116003211160536175
+:101400000121C9058160416070BD11601160072133
+:10141000C905816070BD10B505A1712019F09BFE52
+:1014200010BD000080E100E02000002000F5014038
+:101430007372635C68616C5F63636D5F6161722E80
+:101440006300000000F500408401002010B5A038C2
+:10145000030019F0A1FF0B070E172028313A414B6A
+:10146000525C65004B6808788A68194603F0D9F920
+:1014700010BD88888A6883B20888194680B203F054
+:10148000DFF910BD08884C68CB688A6880B22146B5
+:1014900003F0DAF910BD08884B688A6880B21946F3
+:1014A00003F0EEF910BD88888A6883B2088819466F
+:1014B00080B203F0FAF910BD88888A6883B2088880
+:1014C000194680B203F034FA10BD08884A6880B229
+:1014D000114603F073FA10BD088982B2888883B27E
+:1014E0000888194680B203F074FA10BD08884A686B
+:1014F00080B2114603F091FA10BD08894C6882B29F
+:101500000888CB6880B2214603F00AFB10BD08882A
+:101510004C68CB688A6880B2214603F01BFC10BD82
+:10152000012010BD10B59038030019F035FF0906F1
+:101530000F161D242C363F464E0088888A6883B2D9
+:101540000888194680B204F01DF910BD08884A6861
+:1015500080B2114604F051F910BD08884A6880B283
+:10156000114604F056F910BD08884A6880B2114649
+:1015700004F05CF910BD08884B688A6880B219468F
+:1015800004F067F910BD088982B2888883B20888A0
+:10159000194680B204F066F910BD08894B6882B222
+:1015A0000888194680B204F07CF910BD08884A68A2
+:1015B00080B2114604F087F910BD888882B208888D
+:1015C000114680B204F0DBF910BD012010BD10B54A
+:1015D0007038030019F0E0FE1B0F15192125282F84
+:1015E000363B4044484C53585F68707881889095EA
+:1015F000999CA2A5AC004A680878114607F019FC2E
+:1016000010BD086807F066FC10BD0C790B7B8A687A
+:101610000868214607F06FFC10BD086807F000FD60
+:1016200010BD07F08CF910BD08884A6880B21146D9
+:1016300007F034FE10BD0A790888114680B207F021
+:10164000C4FE10BD087840B207F0CDFE10BD08887A
+:1016500080B207F0E1FE10BD086807F0EFFE10BD94
+:10166000086801F0ECFB10BD086801F016FC10BD25
+:10167000088982B209C9194607F0F8FE10BD05C9EC
+:10168000114607F042FF10BD08884A6880B2114633
+:1016900009F0FAF910BD0C790888CB688A6880B225
+:1016A000214609F0CDFA10BD0B7908888A6880B20E
+:1016B000194609F07DFC10BD08884B688A6880B225
+:1016C000194609F0EEFC10BD08884C68CB688A68A2
+:1016D00080B2214609F053FD10BD08884A6880B2E7
+:1016E000114609F08CFD10BD0B7908880A7A80B28A
+:1016F000194607F02DFF10BD088880B207F02DFFB6
+:1017000010BD086807F030FF10BD07F0FCF810BDF1
+:101710008A6809C9194607F08CFF10BD07F0DCF88C
+:1017200010BD08884A6880B2114608F05BF810BD09
+:10173000012010BD10B5B02805D0B12808D0B228BE
+:101740000BD0012010BD088880B20AF056F910BDF8
+:10175000088880B20AF070F910BD08884B688A6862
+:1017600080B219460AF079F910BD000010B50300E7
+:1017700019F012FE0A0609060C0C0F0F06060612D7
+:1017800007F005F910BD09F027FF10BD01F042FA7E
+:1017900010BD06F075FA10BDFAA1FE4819F0DBFC89
+:1017A00010BD7FB5FC49054603C901900291132085
+:1017B000800169468881F94A0F2310460A2128389A
+:1017C0000AF043FE0024F6480AF05DFE641CE4B211
+:1017D0000A2CF8D304200090F04801231A4603A9EC
+:1017E000F0300AF05DFA002804D0FF20E5A1533064
+:1017F00019F0B1FC686800F024FC00211E220846A4
+:1018000004F040F907F0C6FA02222421E54801F06D
+:101810007FFBE44801222C214C3001F079FBE149A7
+:101820000B20B03901F000FA002804D0FF20D5A128
+:10183000673019F090FC09F09FFE02F075F901ABDA
+:1018400000220821D8A007F085F9002804D0FF2045
+:10185000CCA16D3019F07FFC284602F0C2FC0028B4
+:1018600004D0FF20C7A16F3019F075FCDB2189007F
+:10187000D04819F045FBCF48012141710221817107
+:101880000621C1717FBD10B5CA4CA078092804D3C8
+:10189000FF20BCA1A73019F05EFC207860214843EE
+:1018A000001900210173417BF722C908C900C91C36
+:1018B0001140EF22114041730121E1700C3010BD45
+:1018C00070B50E4600211C4619801546030019F01C
+:1018D00063FD0723050B1711231D2300224629460C
+:1018E000304609F096FE70BD22462946304606F085
+:1018F00098FE70BD22462946304601F0C2FF70BDF9
+:1019000022462946304603F0C0FD70BD22462946D6
+:10191000304600F010FC70BD9E489AA1D53819F0F1
+:101920001AFC032070BD70B5A24CE078002818D0D6
+:101930002078602148430019407B00254007400F74
+:1019400001190879401E08712078401CC0B220702F
+:10195000092800D12570A078401CA0700AF01DFF56
+:10196000E57070BD9348C079002800D08BE77047C0
+:1019700070B5904DA86800280CD0FFF7F3FF002841
+:1019800062D06022A968FFF71FFCFFF7CCFF0020A0
+:10199000A860EFE76879002856D0FFF774FF044687
+:1019A00080484C3001F0C4FA6060002804D1C9209E
+:1019B00074A1800019F0CFFB60680AF0EAF80028F3
+:1019C0000DD0204606F011FD6078010703D5C00850
+:1019D000C000401C2BE0734861684C302DE071481A
+:1019E00061684C3001F0ADFA00F05AFB00282BD1B1
+:1019F000FFF749FF04466B4801F09AFA606000283F
+:101A000004D164485FA16D3019F0A5FB60680AF04D
+:101A1000C4F8002814D0606800886080204609F06F
+:101A20002BFE6078010706D5C008C000801C6070DE
+:101A3000FFF779FF9EE75B48616801F082FA99E75A
+:101A40005848616801F07DFA70BD10B55A4CE160EC
+:101A5000A0605A4800F034FC607010BD5649002068
+:101A60000870704770B5564E0546706A94B00C46C3
+:101A7000401C04D1B06AC0430004000C0BD0306A93
+:101A8000C007C00F2870706A19F03CFAB06A207164
+:101A9000000A607114E02B206946087009A96846A5
+:101AA0000AF04BF8002804D0972036A1800019F0E6
+:101AB00052FB0120287006220AA9204619F0C1F91C
+:101AC0002878002803D06079C0210843607114B0E1
+:101AD00070BDF0B53A4C0646206895B00D463746C5
+:101AE0000837401C08D16068401C05D1A068401C24
+:101AF00002D1E068401C11D02068314619F002FA8A
+:101B00006068311D19F0FEF9A068394619F0FAF93C
+:101B1000E06831460C3119F0F5F925E02B206946D3
+:101B2000087009A968460AF008F8002804D0194886
+:101B300014A1553819F00FFB08220AA9304619F0F4
+:101B400080F92B206946087009A9684609F0F5FF5D
+:101B5000002804D0A3200BA1800019F0FCFA082271
+:101B60000AA9384619F06DF920692E460836401C3E
+:101B700029D16069401C26D1A069401C23D1E069AD
+:101B8000401C1FE07372635C686F73745F636F72F5
+:101B9000652E6300DA020000B4B30100D801002012
+:101BA0006D170000A40B00206E52463531383232DA
+:101BB00000000000880700202400002071190000A8
+:101BC0008000001012D02069294619F09BF9606945
+:101BD000291D19F097F9A069314619F093F9E069C8
+:101BE00029460C3119F08EF915B0F0BD2B2468464A
+:101BF000047009A909F0A1FF002803D0F649F748AD
+:101C000019F0A9FA082209AF28460AA919F019F90A
+:101C10006846047009A909F090FF002804D0EF4835
+:101C2000ED49C01D19F097FA0822391D304619F008
+:101C300008F9D9E770B5EA4C0546A068002804D039
+:101C40000320E549000219F086FAA56070BD10B5C1
+:101C50000146E44801F075F9E1498879401CC0B2B9
+:101C60008871012803D1E048407800F04DFB10BD99
+:101C700070B50446DD4816460D46814204D1D7486A
+:101C8000D549CB3019F067FA012E05D0E120D249B1
+:101C9000800019F060FA70BD66202070002020726C
+:101CA000A5810120A07370BD70B515460C4606468F
+:101CB000FFF758FE00280CD06621017046800121F4
+:101CC000017221680161A18881820573FFF72BFEF3
+:101CD00070BD1321304607F078FB70BDC2494968DA
+:101CE000884201D210207047032101700020704704
+:101CF00070B5BD4C05462078002694B0002801D070
+:101D00000820E4E6BA4A6260954201D21020DEE67D
+:101D10006868002809D00921D82804D3C31C9B086F
+:101D20009B00834205D00846D1E60320400268604C
+:101D30000EE0012109074B6B896B4B43AD49511AEA
+:101D40000122591AD202891A814201D20421EAE7FA
+:101D500000F052FF6178A0680CF04EFBE068401E76
+:101D600007280BD8302269460A70887068460DF043
+:101D700088FF002802D009A80CF0FBFC2846FFF7DA
+:101D800010FD012020703046A1E6F8B504469648C3
+:101D90000F464068814208D3002C01D0844204D30E
+:101DA000E01C80088000A04201D01020F8BD8C48C3
+:101DB0008178002911D039880091417860225143FF
+:101DC0000D18287B0C350007000F3B4600222946E2
+:101DD000FFF776FD060004D015E0002038800520CE
+:101DE000F8BD002C13D039880098814201D90C2607
+:101DF0000DE028783B460007000F22462946FFF7F2
+:101E00005FFD060005D00C2E01D000203880304642
+:101E1000F8BD734C6078401CC0B26070092801D1D5
+:101E200000206070A078401EA07068784107490FBC
+:101E300001290ED0022906D003291AD066496E481E
+:101E400019F089F9E3E7C006E1D46868FFF7FFFEFF
+:101E5000DDE7644869684C3001F073F86079401C34
+:101E6000C0B260710128D2D15F48407800F04CFACE
+:101E7000CDE7E079401CE071C9E7604A10B59042B7
+:101E800009D3594A0124A4045268A04201D39042C4
+:101E900001D3914201D2102010BD00F0FEFE10BD12
+:101EA000564B10B5994209D34F4B0124A4045B68EB
+:101EB000A14201D3994201D39A4201D2102010BD10
+:101EC000022803D0102801D0092010BD00F00BFF1C
+:101ED0000028FAD0052010BD484B10B598420DD30C
+:101EE000414B0124A4045B68A04201D3984205D36E
+:101EF000994203D3002A03D09A4201D2102010BD88
+:101F000000F017FF0028FAD0072010BD10B50446D6
+:101F1000354894B04068844202D2102014B010BDFD
+:101F20000F2008A9087369460BA809F006FE0028CF
+:101F3000F4D16846007A207068464089608068461F
+:101F40008089A0800020E9E710B500290BD0264A3F
+:101F50005268914202D30B68934201D2102010BD07
+:101F60008A88002A02D001F037FE10BD092010BD7A
+:101F700010B5224A94B091420ED31B4A01239B0410
+:101F80005268994201D3914206D3441E1E2C41D877
+:101F9000994203D3914201D21020BFE7012837D1E3
+:101FA00008780024C007C00F002803D0032069462A
+:101FB000887001E06846847038206946087009A975
+:101FC000684609F0BAFD002804D004480CA18B38FB
+:101FD00019F0C1F82046A1E7841B0000AA02000006
+:101FE00088070020A40B002024000020FFFF000031
+:101FF00000220020000000202104000000C0010099
+:102000007372635C686F73745F636F72652E6300D5
+:10201000072083E70246203A1F2AF9D806F001FE7E
+:102020007CE710B5604A5268914201D2102010BD81
+:102030000246203A1F2A02D806F068FE10BD07208B
+:1020400010BD70B50546594C002020702046461939
+:1020500055484660E01C80088000A04204D0FF2064
+:102060005349293019F077F801200007C06AC043AE
+:102070000006000E03D14F480068401C03D04E48B4
+:102080004E49301AC862A8B20422214604F00DF964
+:10209000002804D0FF204649393019F05CF870BDA3
+:1020A000F0B595B03B2008A9087369460BA809F064
+:1020B00044FD002804D0FF203D49813019F04BF841
+:1020C0003F4E00246D4630E02F19B87DC10706D081
+:1020D000400704D460004019C08809F0E9FB394882
+:1020E000807900281FD0B87D80071CD5600040197A
+:1020F000C0880022062109F0F7FB002813D03C21FC
+:1021000008A8017360004019C1886846C185694606
+:102110000BA809F012FD06000BD0FF2024499630D1
+:1021200019F019F805E0641CE4B268460079A04291
+:10213000CAD8304658E5F7B50546007800270009AB
+:102140000C463E46062804D0FF201949BF3019F03E
+:1021500002F8287A00280ED0012814D0FF20144954
+:10216000E03018F0F8FF0298002C068001D027809C
+:1021700066800020FEBD02270926002C10D0A88909
+:10218000A080A87B0AE003271426002C08D06888CA
+:10219000A0802869E060A88A2082287B2072E2E77C
+:1021A00002980680E5E700002400002000220020BD
+:1021B000002000000010001000000020000500407A
+:1021C000043000008807002010B56038030019F0C3
+:1021D000E3F80A060A0F13181F252930353A086854
+:1021E000FFF786FD10BD05C91146FFF7CEFD10BDF6
+:1021F0000868FFF773FD10BD05C91146FFF73DFEE6
+:1022000010BD4B6808788A681946FFF749FE10BD73
+:102210008A6809C91946FFF75FFE10BD0868FFF715
+:1022200075FE10BD08884A6880B21146FFF78CFE23
+:1022300010BD05C91146FFF79BFE10BD05C911462B
+:10224000FFF7EFFE10BD012010BD01207047000018
+:102250000E4A12680C498A420AD118470B4A126882
+:10226000094B9A4204D101B500F08EFE03BC8E46A4
+:10227000074909680958084706480749054A064BAF
+:102280007047000000000000BEBAFECA64000020D3
+:1022900004000020F0210020F021002001203F490F
+:1022A000400608603E4908603E490A68FF231B0259
+:1022B0009A4383121A430A6038498039086070478C
+:1022C00010B502460420384904E0C3005B181B79AE
+:1022D000002B0AD00346401EC0B2002BF5D133A11B
+:1022E000432018F038FFFF2010BDC300CA50002261
+:1022F00059184A718A7101220A7110BD2A4A0021B7
+:10230000C00080180171704710B50446042803D33B
+:1023100026A1522018F01FFF2348E1000C18207955
+:10232000012803D021A1532018F015FF6079A1796D
+:10233000401CC0B2814200D06071012017494006A4
+:102340008031086010BD70B5164804250068164E2F
+:102350000004800F1B4C02281AD014A1692018F029
+:10236000FAFE15E02078C10088190279012A07D108
+:10237000427983799A4203D04279827170588047BA
+:102380002078401CC0B22070042801D300202070A7
+:1023900028466D1EEDB20028E4D170BD80E100E05A
+:1023A00080E200E018E400E0200C00207372635C1F
+:1023B000736F635F7369676E616C6C696E672E63C0
+:1023C000000000003400002010B5EFF31080C407B7
+:1023D000E40F72B6D2484178491C41704078012818
+:1023E00001D10AF0FFF9002C00D162B610BD70B522
+:1023F000CB4CE07800280AD10125E570FFF7E4FF17
+:102400000AF0F8F9002804D000200AF0CBF90020E7
+:1024100070BDC44865714560F9E770B5EFF3108091
+:10242000C507ED0F72B6BE4C6078002803D1BEA17F
+:102430008F2018F090FE6078401E60706078002851
+:1024400001D10AF0D3F9002D00D162B670BD10B5EC
+:10245000B348C178002904D000214171C170FFF751
+:10246000DCFF002010BD10B504460AF0C3F9AC49EA
+:10247000C978084000D001202060002010BDF8B5C8
+:102480000246A74C0026A67108200421012510272A
+:10249000130018F081FF0D080A0C0E101214161EFE
+:1024A000262123252800257122E0022001E0217148
+:1024B0001EE020711CE027711AE02020F9E70126B8
+:1024C00016E0FFF781FF0AF095F90028FBD00226FD
+:1024D0000EE02171A5710BE02771FBE7202000E0E1
+:1024E00040202071F6E7FF208FA1763018F033FEF0
+:1024F0000AF08CF9002809D00AF08EF9B04205D113
+:1025000030460AF08CF90028FAD02CE00120800730
+:10251000C560894900224A60884A9661814B02223F
+:102520005A60856086480269D243D206D51702698F
+:1025300010231A4302610F466D1C00E020BF78682B
+:102540000028FBD030460AF06AF90028FAD0002DA6
+:1025500004D17B48026910218A430261714902203B
+:10256000886000207860A07900280CD00AF042F939
+:1025700005460AF09FF8734A002D02D0A260E06081
+:1025800001E0E260A060002E01D100F0A5F8F8BDE6
+:1025900010B504460AF034F9002805D0604901203E
+:1025A000C8704A78521C4A702046FFF768FF10BD79
+:1025B000F8B5614DA8680026012802D1AE600AF086
+:1025C000F1F86868012800D16E6028680127544C32
+:1025D000012812D12E606079002803D000200AF073
+:1025E000E1F866712078002807D00AF003F9002886
+:1025F00003D0012080070761A770286901282AD12C
+:102600002E6100F05FF8012080074761A079002863
+:1026100015D00AF0EFF800900AF04CF80099002964
+:1026200001D0E16800E0A168411A022901DA8A1CA0
+:1026300011DC0099002901D0E06000E0A060FFF704
+:10264000C3FE0AF0D7F8002804D0012080070761F4
+:10265000A77000E02770E868012812D100F032F876
+:1026600000F030F800F02EF8A078002804D1FF2008
+:102670002DA1033018F06FFDEE60A6702670FFF7F5
+:10268000CCFEF8BD10B5264CE078002801D10AF048
+:10269000ADF801208107886100F014F8A0780028C7
+:1026A0000BD0254CE068002803D10AF0B8F80028C8
+:1026B000F8D10020E06000F005F800201949C0437F
+:1026C000886010BD08B55020694608806A461088A9
+:1026D000411E1180FAD208BDF8B51248192787604B
+:1026E000154900200860C8600AF084F8BE0701247C
+:1026F0000B4D002802D03461AC7000E02C70FFF765
+:1027000063FE084847600D4928798863FFF7DAFFC0
+:10271000B461FFF7D7FF0849002008617461F8BD74
+:1027200038000020000300407372635C736F635FC6
+:10273000636C6F636B2E6300000100400005004076
+:1027400000ED00E0FFFFFF7F8107C90E002808DAD7
+:102750000007000F083880082E4A80008018C069E2
+:1027600004E080082C4A800080180068C8400006F9
+:10277000800F704710B50D20FFF7E6FFC4B20420AC
+:10278000C043FFF7E1FFC0B2844203D023A11A2067
+:1027900018F0E1FC26490120486010BD0121254ABE
+:1027A00048031060244B00221A60244A5160244AD6
+:1027B0001060244A11601F49803908607047012168
+:1027C0001C4A480310601F4A51601B4A00211160D7
+:1027D0001B490860704710B517490868012804D0E4
+:1027E0000EA1572018F0B7FC10BD114880680022D8
+:1027F000C0B20A6009F0BEFC10BD10B50E480168F9
+:102800000029FCD0FFF7E7FF01200D4940030860D5
+:1028100010BD000000ED00E000E400E07372635CB6
+:10282000736F635F68616C5F726E672E6300000098
+:1028300000D5004080E100E000D1004000D300401E
+:1028400080E200E000D0004030B40121BC48C90261
+:102850000160CD1005604A030260BA4803681B029C
+:102860001B0A036004680023240A24020460B6489B
+:102870000468240A24020460B4480124446084608B
+:10288000B34C23606360A360B24B19601D601A6093
+:10289000B14B19601A600121016030BC704710B45F
+:1028A0000121A748CA0202600B0203600C06046003
+:1028B000A64841608160A94841680029FCD1A4492B
+:1028C0000020086048608860A248026003600460DD
+:1028D00010BC704701219F48C9020160C910016006
+:1028E0007047002805D0012805D0022805D19C4852
+:1028F00070479C4870479C48704710B59BA18B203F
+:1029000018F029FC002010BD70B500219E4C9F4D91
+:102910009F4A8F4B002808D001281DD0022822D0C2
+:1029200092A1B32018F017FC70BD01200004A06034
+:10293000A86011601960974BC2039A60964A906034
+:102940007F4A0012106095480160864801609448F3
+:1029500001609448017070BD01204004A060A8602F
+:102960005160596070BD01208004A060A860916032
+:10297000996070BDF8B59446834A8B4F834D00240F
+:102980000126002808D0012832D0022840D077A1A3
+:10299000E82018F0E0FBF8BD891E0902090A0120B1
+:1029A000000490603C6468606C4A1164012B1DD087
+:1029B00000217C4A7D4B51706146DC63DE637C4BB9
+:1029C0005C6002249C6004241C61744B3D311960DE
+:1029D00073490E605F4B891519606F4B58605E48F4
+:1029E00001606C49C00548601670F8BD0121E0E740
+:1029F0000120704E4004704F012B04D134645060AC
+:102A000068603964F8BD9060346468603964F8BD0A
+:102A100001206A4E80046A4F012BF4D1EEE74F4843
+:102A20004068704770B54A4D28680026564C01280A
+:102A300006D1A068C00303D501200004A0602E6069
+:102A40006868012809D1A068800306D501204004E8
+:102A5000A0606E6001200AF0B9FEA868012809D1C3
+:102A6000A068400306D501208004A060AE6002206B
+:102A70000AF0ACFE70BD10B54A490878002818D09D
+:102A80000120444AC0079060434AC00B90602C4A22
+:102A900000121060414A00201060324A1060404A23
+:102AA000106008704A78002A02D048700AF08EFE42
+:102AB00010BD0320FAE70120424900060860704774
+:102AC0000120244900060860704701203D49400567
+:102AD0000860704701201F4940050860704733496E
+:102AE0000020C86388151B4908607047410A364AB0
+:102AF000C005C00D5043801C5143400A0818704760
+:102B000010B4324C430B63431B0C5C020C602E4C24
+:102B10006343C31A2E485C0258432B4B400D43437A
+:102B2000E31A0124DB0324041B191B1613700A6823
+:102B30001018086010BC704710B50AF01BFF10BDDC
+:102B400080E100E008E400E018E400E000B00040AC
+:102B500040B1004080E200E000E100E000B500404C
+:102B600048B100404081004044B100407372635C52
+:102B700072656D5F68616C5F6576656E745F7469C0
+:102B80006D65722E6300000000B3004040B300404A
+:102B900040B5004000F50140008300404085004002
+:102BA000008200404800002000B10040C08F00407B
+:102BB0000085004004B1004004B5004008B1004069
+:102BC00008B5004000E200E0093D00003786000043
+:102BD0006F0C010010B50AF0B9FE10BD00200449C9
+:102BE000C863012001218140024A116000BF704783
+:102BF000C01F004080E200E010B50DF05DF909F063
+:102C0000F7F9FEF7C3FB0FF0F5FA0DF08FFF0DF0AB
+:102C10001BFF10BD70B50C46054603F0A7FA214610
+:102C200028460EF0C2FF70BD70B50D46040012D0EC
+:102C3000002D10D02101284618F060F910225449C7
+:102C4000284618F0FEF852480121083801804480D7
+:102C50004560002070BD012070BD70B54C4E002451
+:102C60000546083E11E0716820014018817BAA7B6F
+:102C7000914209D1C17BEA7B914205D10C222946C0
+:102C800018F0B2F8002806D0641C30888442EADBD1
+:102C90000020C04370BD204670BD70B50D460600D3
+:102CA0000AD0002D08D03A4C083C20886188401C8E
+:102CB000884203D9042070BD102070BD3046FFF754
+:102CC000CCFF002801DB401C0AE02088616800017D
+:102CD00040181022314618F0B4F82088401C20809B
+:102CE0002870002070BD70B514460D001FD0002C58
+:102CF0001DD00021A170022802D0102817D108E0B1
+:102D0000687829780002084311D00121A170108051
+:102D10000BE02846FFF7A1FF002808DB401CA0704D
+:102D2000687B297B000208432080002070BD0120C1
+:102D300070BD70B5054614460E000AD000203070F4
+:102D4000A878012807D004D9114908390A88904287
+:102D50000BD9012070BD002C04D028782070288861
+:102D6000000A50700220087010E0002C0CD0496856
+:102D70000001411810222046103918F062F8287816
+:102D800020732888000A607310203070002070BD06
+:102D9000540000205A4910B5884207D30121890404
+:102DA000884205D357490968884201D2102010BDD6
+:102DB0000146012005F0CBF810BD30B5044693B0B4
+:102DC00000200D46079014210BA818F099F81C213B
+:102DD000684618F095F86A46112010770020507761
+:102DE000107802210843107007A80C90012008AA4F
+:102DF000907245486A4610850AA80B902088108476
+:102E000060885084A0889084E088D084907FF921E5
+:102E10000840801C4008400090770820908610876A
+:102E200008A80F9010AA0BA9684600F05CFF0028C4
+:102E300003D110A800882880002013B030BD3EB513
+:102E400004460820694608802D48844207D30120A3
+:102E50008004844205D32B480068844201D21020AC
+:102E60003EBD2146012005F072F80028F8D12088E7
+:102E7000694688806088C880A0880881E088488189
+:102E800005F065FE01AB6A46002101F0BBFB694617
+:102E900009880829E4D003203EBD1FB50446002060
+:102EA000029008206946088115480391844207D39F
+:102EB00001208004844206D312480068844202D272
+:102EC000102004B010BD05F042FE014602AA0F48D2
+:102ED00001F02EFD0028F4D169460989082901D0A6
+:102EE0000320EEE7694609882180694649886180A8
+:102EF00069468988A1806946C988E180E1E70000C8
+:102F000000C0010028000020042A0000FFFF00008C
+:102F100010B5031D03600020521E04E05C181C6005
+:102F2000401C2346C0B29042F8DB0020186010BD60
+:102F300001460A680020002A02D0104612680A6082
+:102F4000704702680A6001607047000010B50146D2
+:102F50002022094817F075FF07490020C877084666
+:102F600010BD0649012048610548064A01689142A2
+:102F700001D1002101607047B00E00200005004023
+:102F800064000020BEBAFECA0C4908784A78401C8A
+:102F9000C0B2904200D008707047094A074820BF6D
+:102FA00040BF20BF4178037843701368002B02D1E3
+:102FB00003788B42F3D00020704700006B000020A4
+:102FC00000E200E00A4A022151600A490B68002B26
+:102FD000FCD0906008680028FCD000205060086891
+:102FE0000028FCD0704701200007406970470000AE
+:102FF00000E5014000E401407047704770477047AA
+:1030000010FFFFFFDBE5B15100C001006700FFFFCB
+:1030100003B40148019001BD09000020002803D03D
+:103020008178012939D101E0102070470188FE4ADA
+:10303000881A914233D01BDCFC4A881A91422ED068
+:103040000BDC00292BD00320C002081A27D001284E
+:1030500025D001210903401A07E001281FD00228CA
+:103060001DD0FF281BD0FF380138002815D116E0ED
+:10307000FF220132811A904211D008DC01280ED0C3
+:1030800002280CD0FE280AD0FF2806D107E001292B
+:1030900005D0022903D0032901D0002070470F205A
+:1030A000704700B50B2826D009DC030018F074F92E
+:1030B0000B1D2125251B25292325271F1B00112832
+:1030C0001BD008DC0C2816D00D281CD00F2814D0DB
+:1030D000102808D10FE0822809D084280FD0852835
+:1030E0000FD0872811D0032000BD002000BD05208F
+:1030F00000BDCF4800BD072000BD0F2000BD04204B
+:1031000000BD062000BD0C2000BD0D20800200BDCA
+:1031100070B500290BD0CB1FFA3B81241E46CDB2DF
+:10312000112B1BD2012805D0022806D009E000206F
+:1031300010701DE0FF20043001E0FF2003308142C9
+:1031400018D0330018F028F9111613131613161699
+:103150001316161613131313161316000846FF380A
+:1031600081381F2803D9FF39FE39022902D815708A
+:10317000002070BD1470072070BD00B5030018F06A
+:103180000BF9060406040C080A0C002000BD1120EF
+:1031900000BD072000BD082000BD032000BD007851
+:1031A0000207120F04D0012A05D0022A0AD10EE02C
+:1031B000000907D108E00009012805D0022803D042
+:1031C000032801D0072070470870002070470620B0
+:1031D0007047002807D0012807D0022807D003280D
+:1031E00007D007207047002004E0112002E02120D2
+:1031F00000E0312008700020704738B50C4605000B
+:103200004FD06946FFF7CBFF002822D12088032149
+:1032100089028843694609788907090D0843208097
+:103220006946681CFFF7BBFF002812D121880320E4
+:1032300000038143684600788007800C01432180A9
+:10324000A8784007820F2020012A03D0022A03D049
+:10325000072038BD814300E00143218088B2010589
+:10326000890F08D0012189038843A9780907C90F6C
+:1032700089030843208080B28104890F0AD0A9788D
+:103280004004C906C90F400CC903084320808004CC
+:10329000800F02D12088400403D5208840210843B4
+:1032A0002080002038BD70B50446002008801546F7
+:1032B0006068FFF7A2FF002815D12189A08981420B
+:1032C00010D861688978C90708D00121490288426D
+:1032D00008D8491C17F01EFE298009E0FF21FF31A4
+:1032E000884201D90C2070BDFF30FF3003302880A8
+:1032F000002070BD10B5137804785B08E4075B000C
+:10330000E40F23431370FD2423400478A407E40F43
+:10331000640023431370FB24234004786407E40F04
+:10332000A40023431370F724234004782407E40FF8
+:10333000E40023431370EF2423400478E406E40FF1
+:10334000240123431370DF2423400478A406E40FF0
+:103350006401234313700078BF244006C00F23404C
+:10336000800103431370002906D00878C10701D1FA
+:10337000800701D5012000E00020C0015906490E58
+:103380000843107010BD30B50A8803239B020488DF
+:103390009A4323059D0F02D1A3049C0F01D09B0FDC
+:1033A00000E001239B021A4303230A801B039A4374
+:1033B00003889804840F02D11805830F01D0800F71
+:1033C00000E00120000302430A8030BDF3B593B052
+:1033D0000D000FD0139800280FD01221284617F0A7
+:1033E0008DFD03AAFF21012003F0D5F80024264615
+:1033F00037467AE0102015B0F0BD0720FBE768469D
+:10340000807D01280BD16846818A0520C002081AF8
+:1034100010D0012810D0022812D0032812D0042C7A
+:1034200014D0052C15D113E002290000012800005A
+:1034300003300000012400E002246846468A08E0C8
+:10344000032406E068460424478A02E0052400E0DD
+:1034500006246846418A1398814246D12C74002E76
+:1034600041D00DAA0EA905200292019100901023CF
+:103470000022FF21304603F02FF9002823D16846AF
+:10348000808E2A46C0B20EA9FFF72DFC00281AD163
+:10349000AE81002F27D00DA9052008AE0291009023
+:1034A000132300220196FF21384603F015F9002866
+:1034B00009D16846808EF11CC01EC0B22A1DFFF7DC
+:1034C00012FC002801D0032095E708A881784278F3
+:1034D00008021043E881062C05D16846807DA87259
+:1034E0006846808A2881002085E703A803F05CF8FD
+:1034F000002884D0FFF7D5FD7DE7002805D0FE4ADF
+:10350000012903D0022903D003207047518800E02D
+:103510009188814201D1002070470720704770B523
+:103520000C4605461C21204617F0E8FC00202080B0
+:10353000002D08D0012D04D0F0A1F54817F00BFEA6
+:1035400070BD062000E00520A07070BD70B592B07F
+:103550001546064601206A461071107453740846D9
+:1035600008300395029048889082FEF7FBF904002A
+:1035700019D06580172069468883203600940AABED
+:103580007178023307AA01A80EF017F90646607891
+:10359000000701D5FEF7C7F9002E0AD03046FFF725
+:1035A000ECFD12B070BD1321284605F00EFF03207C
+:1035B000F7E708A800906846838B0422012128467B
+:1035C00007F0B3FEEDE770B506468AB000200D4661
+:1035D00007900590069003A90490052402460291E5
+:1035E0000190102300942946304603F075F8002816
+:1035F0000DD108A804A9009102900194684683891E
+:1036000000222946304602F083FE002801D0FFF751
+:1036100048FD0AB070BD10B50EF0D5FA10BDF0B57A
+:1036200089B000260546059600780C460827030059
+:1036300017F0B2FE0CFD070C390B75759BBEFCD361
+:10364000E3FD68680A38FEF702FB07E1A88800225C
+:1036500080B20421009008F067FB0290002C04D097
+:10366000AB48A6A16E3017F076FD0298002804D171
+:10367000A748A2A16F3017F06EFD0298009908309C
+:103680000DF0D0FCFEF76EF9040007D060783843E7
+:10369000607000986080FEF746F9E1E01321009821
+:1036A00005F093FEEAE0002C04D1BD2093A1800038
+:1036B00017F051FD60880022042108F035FB0090CE
+:1036C000002804D192488DA1883017F044FD00995C
+:1036D000002008802A7994461EE0C3005B199B688D
+:1036E00007936B469B8B1A0708D5DA0606D560460A
+:1036F000C20050194038C08F088006E05B0409D52D
+:103700000871C2005019C0884880607838436070E2
+:103710000226A3E0401CC0B28445DED89EE0E888C3
+:10372000694608800090002C04D1794873A1983034
+:1037300017F011FD2878062813D10098C00B10D07F
+:1037400060880022042108F0EFFA060004D17048D6
+:103750006AA1A23017F0FFFC00203071A8887080A9
+:1037600039E060783843607078E0002C04D1684814
+:1037700062A1B43017F0EFFC60880022042108F049
+:10378000D3FA0090002804D161485CA1B73017F04B
+:10379000E2FC009808300EF068FA0121484002D19E
+:1037A000E888C00B5AD0009861880226C180D8E70B
+:1037B000002C04D1564851A1D03017F0CCFC6088C1
+:1037C0000022042108F0B0FA002804D150484BA18F
+:1037D000D33017F0C0FC0226C3E7002C04D14C48BC
+:1037E00046A1DC3017F0B7FC022661880122204692
+:1037F000FEF73EFA01200590B3E7A889002280B2C7
+:103800000421009008F090FA0746002C04D04048AC
+:103810003AA1EE3017F09FFC002F04D13C4837A1AD
+:10382000EF3017F098FC6868029001E009E010E0C2
+:10383000288969468881012202A90098FEF734FA96
+:103840000CE0002C8DD16D202CA1C00017F083FC62
+:1038500087E72F4829A1FE3017F07DFC002C0DD002
+:10386000607800070AD50598002807D184202070C9
+:103870002046582229460830FDF7A6FC304609B0FC
+:10388000F0BDF7B50C460546007A224688B00A32EC
+:103890000492921C01920027811E16323E4602922B
+:1038A0000B0017F079FD08F405F348488ED0F2F3C9
+:1038B00068880022042108F037FA0190002803D11B
+:1038C0000EA1144817F047FC01980088002802D088
+:1038D0005227072600E151271E26002C70D0688849
+:1038E000A0800120A071019804990079C0004019BE
+:1038F000C089FFF76BFD0FE0400C00207372635C22
+:1039000067617474735F636F72652E6300000000FB
+:103910006F0200008603000000287DD10198007925
+:10392000C0004019C089208101980079C000401969
+:10393000408AA083F0E0698A0091062820D1E889B6
+:10394000C00B1DD008462230512786B2002CC5D0AE
+:10395000A8890199FFF73AFD002872D16888A080F4
+:103960000220A071A88920810120A072288AE0830A
+:10397000009820846969009A029817F062FACBE0F7
+:1039800008462030502786B2002CA7D0A889049979
+:10399000FFF71CFD002854D16888A080A889E0802A
+:1039A000287A06280AD002202072288AA08300984C
+:1039B000E083204669692030009ADEE70120F3E7C2
+:1039C0008FE068880022042108F0AEF90690688A2A
+:1039D00000900698002803D1FD49FE4817F0BBFB74
+:1039E000069808300EF041F90121484002D1E889DB
+:1039F000C00B25D000985127223086B2002C7AD0F7
+:103A00006888A080A8890199FFF7E0FC002818D1F8
+:103A10000220A071A88900E013E020810420A07298
+:103A2000288AE083009820846969009A029817F038
+:103A300008FA0699002008710698A98941806BE070
+:103A400003200BB0F0BD688804F0DDF900906888B1
+:103A50000022042108F068F901900098002804D1A0
+:103A6000DC48DB492C3017F076FB0198002804D1A4
+:103A7000D848D7492D3017F06EFB0198D649C08839
+:103A8000884205D05127222604E01EE03FE035E0C1
+:103A900050272026002C2ED06888A080502F07D0D9
+:103AA0000220A0712146287B0831FFF738FD33E062
+:103AB000287BA11DFFF733FD6A8800230199009838
+:103AC000FFF744FD0028BCD126E0C449A889C98875
+:103AD000814207D154270626002C0CD06888A0808C
+:103AE0001AE008E053270826002C04D06888A0803C
+:103AF000A889E08010E00A98068013E05527072681
+:103B0000002CF8D0A889A0800020A07104E08D20AE
+:103B1000AF49C00017F01FFB0A98002C068001D0A7
+:103B20002780668000208CE7AC4900200870704731
+:103B300030B585B00C4601F0DBF90546FF2804D10D
+:103B4000A448A349953017F006FB0020208020717F
+:103B50006080401EE0802046294608300DF056FA6D
+:103B60006A462946012002F016FD102412E068463C
+:103B7000808800070ED56846C0882946FFF723FDD8
+:103B800068468188FF2321438180C0882946019AA5
+:103B900002F02CFE684602F007FD0028E7D005B0D1
+:103BA00030BD0A46014610B5104608300DF042FA05
+:103BB00010BD70B505460022042108F0B5F80400D8
+:103BC00004D184488249B73017F0C5FA2046294607
+:103BD00008300DF027FA70BDF0B591B00C460746DD
+:103BE00004F011F9050005D02878222804D2082015
+:103BF00011B0F0BD7A48FBE700220421384608F0F6
+:103C000093F80646002C02D0A08800280CD0012092
+:103C1000694608710220087400204874002C05D001
+:103C2000A0880883206802E00920E1E70883059066
+:103C30003046083003970290FDF794FE040018D038
+:103C40006780172069468883203500940AAB69781D
+:103C5000023307AA01A80DF0B0FD05466078000701
+:103C600001D5FDF760FE002D09D02846FFF785FA43
+:103C7000BEE71321384605F0A8FB0320B8E708A8E3
+:103C800000906846838B04220121384607F04DFBE3
+:103C90000021C943F180ABE7FFB585B00E9E778860
+:103CA000384604F0B0F8054600220421384608F0F2
+:103CB0003BF80446002D03D145494A4817F04BFA1A
+:103CC000002C04D147484249401C17F044FA0834FC
+:103CD000089869460394C1C105A80DC820356978C4
+:103CE0000DF0DAF9CBE5F0B50446002099B00D46A9
+:103CF00001460D9010A88181164601818180374AC6
+:103D000068469180018510A80180684601878185F9
+:103D100081841078012808D0022806D0032804D016
+:103D2000042802D0082019B0F0BD2F4A944273D362
+:103D30002E4F0121890438688C4201D3844278D304
+:103D4000294A954275D3012189048D4201D38542C8
+:103D50006FD36168002913D0234A914269D30122AD
+:103D60009204914201D3814263D3608921898842C0
+:103D700003D801225202914201D90C20D3E70D90C1
+:103D800016AA0EA92846FFF78EFA0028CBD168683C
+:103D900080784007800F02280AD16846008F80048F
+:103DA000800F05D02869002802D03968884240D3A6
+:103DB0000AA92069FFF721FA0028B4D12069002858
+:103DC0001CD0607880076846008D14D580040FE011
+:103DD000FC380000EE030000FFFF0000400C002054
+:103DE000023000000C05000000C001002800002087
+:103DF000800F68D002E08004800F64D16846008D97
+:103E0000810618D58004800F606806D0002812D083
+:103E1000396888420DD302E00BE000280BD0FE4940
+:103E2000884206D301218904884204D33968884234
+:103E300001D2102077E709A96069FFF7DEF90028B1
+:103E40009CD16069002808D06846808C0105890FE4
+:103E5000012938D18004800F35D00BA9A069FFF764
+:103E6000CCF900288AD16846808C80062BD468461D
+:103E7000808D810627D4A169002906D00105890F0C
+:103E8000012920D18004800F1DD0E068002804D0D3
+:103E90000078002817D01C2815D204AA611C2046DF
+:103EA000FFF728FA0121890210A80180012768463E
+:103EB0008773DA49818104AA033217A92868FEF7BB
+:103EC00038FF002801D007202DE710A8007F15A992
+:103ED000C01CC2B200200C920190FF320090034639
+:103EE0000291FF3203A80332109902F0ACFA0028C5
+:103EF00026D110A9888A0F902A892969C84801917A
+:103F00000092029010A90A8B6B8928680E9902F022
+:103F10009AFA01007ED1C2480025001F81886846B8
+:103F20004174090A8174052104A86A4623C210A8B5
+:103F30002A46FF21808A0C9B02F0EAF9002802D071
+:103F4000FFF7AFF8EFE66846007C0322C1090020C6
+:103F5000920290430122920280181490002928D0E6
+:103F6000014610A8018068462921877309028181D2
+:103F7000058608A8007C0023410860784900C00736
+:103F8000C00F014308A80174FD2001406078A54AD4
+:103F90008007C00F4000014308A801740CA902204B
+:103FA00001910090029503A8109902F04CFA0100CB
+:103FB00030D16068002828D0206900280DD10AA9D6
+:103FC0000EA8FFF7E0F96078800706D46946088DEF
+:103FD0000321090388436946088590496846877329
+:103FE000FE3181818F492089891E16F093FF626816
+:103FF0000D9811AB0192009002930A46002303A88A
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s132_nrf52_mini.hex b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s132_nrf52_mini.hex
new file mode 100644
index 0000000..825af2f
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/s132_nrf52_mini.hex
@@ -0,0 +1,910 @@
+:020000040000FA
+:10000000C0080000DD0700000D050000BD0700006E
+:1000100017050000210500002B050000000000006E
+:100020000000000000000000000000006108000067
+:100030000000000000000000350500003F05000042
+:1000400049050000530500005D050000670500003C
+:10005000710500007B050000850500008F0500008C
+:1000600099050000A3050000AD050000B7050000DC
+:10007000C1050000CB050000D5050000DF0500002C
+:10008000E9050000F3050000FD050000070600007B
+:10009000110600001B060000250600002F060000C8
+:1000A00039060000430600004D0600005706000018
+:1000B000610600006B060000750600007F06000068
+:1000C00089060000930600009D060000A7060000B8
+:1000D000B1060000BB060000C5060000CF06000008
+:1000E000D9060000E3060000ED060000F706000058
+:1000F000010700000B070000150700001F070000A4
+:100100002B070000370700001FB500F003F88DE84B
+:100110000F001FBD00F058BB2DE9F04105460E460B
+:100120001746002406E056F8241005EB840000F082
+:10013000D9F9641CBC42F6D30020BDE8F081014629
+:100140000868B0F5002F01D3102070470020FCE7AD
+:100150002DE9F04105460C461646002706E02846E4
+:10016000216800F0BFF92D1D241D7F1CB742F6D376
+:10017000BDE8F08170B505460C462E460BE03046D2
+:1001800000F09EF9B4F5806F01D2002401E0A4F5DF
+:10019000806406F58056002CF1D170BD0146D1E98E
+:1001A000000200EB8200B0F5002F09D84FF01020BC
+:1001B000406904234A6803FB0200B0F5002F01D90F
+:1001C000092070474FF010204069401C08B90F20EB
+:1001D000F7E70020F5E72DE9F041044620680528FF
+:1001E00047D2DFE800F0032A40475700201DFFF701
+:1001F000D5FF054615B12846BDE8F08100F044F969
+:1002000000BF4FF4805000F05BF900BF042221468C
+:100210009148FFF781FF08B10320EDE7082221464E
+:100220008D4800F09BFA30B900218C48006800F03E
+:1002300059F900F002F90320DEE7A668E56867686F
+:1002400029463046FFF796FF2A4639463046FFF7E3
+:100250007FFFAA003946304600F080FA08B9002036
+:10026000CAE70320C8E700F013FB4FF440507C4975
+:10027000086041E06568E668A768B200394628462C
+:1002800000F06CFA8046B8F1000F01D10020B3E70E
+:100290000E20B1E7201DFFF752FF05460DB128469D
+:1002A000AAE7606848B900F0EFF800BF4FF40050CB
+:1002B00000F006F900BF00F0C0F800F0E5F800BF5C
+:1002C0004FF4805000F0FCF800BF04222146624841
+:1002D000FFF722FF08B103208EE7082221465E487F
+:1002E00000F03CFA30B900215C48006800F0FAF8F0
+:1002F00000F0A3F803207FE700BF00207CE770B583
+:1003000005460C46182D04D12068FFF764FF2060D5
+:1003100002E00120206000BF00BF70BD2DE9FF4159
+:100320004FF0102044694C48806804EB8005260B90
+:1003300005F6FF70070B00200090019002900390DB
+:1003400000BF0BE041095DF8211000F01F030122FE
+:100350009A40114342094DF82210401CB042F1D39B
+:1003600038460BE041095DF8211000F01F0301221F
+:100370009A40114342094DF82210401C8028F1D3C5
+:10038000684600F073F8BDE8FF8170B54FF01020AB
+:100390004469314885684668AA003146204600F025
+:1003A000DDF908B1002070BD0120FCE72A48406853
+:1003B00008B1012000E000200546FFF7E6FF48B144
+:1003C00000F062F800BF4FF4005000F079F800BF71
+:1003D00000F033F8FFF7A2FF7DB14FF0102046691F
+:1003E0001D488468476821463046FFF7C3FE224611
+:1003F00039463046FFF7ACFE00BF00F01EF810B5DE
+:100400001548446816480460204600F015FA10BDEF
+:10041000124800680068401C08B900BFFEE70E489B
+:10042000006810B1042806D101E0FFF7BFFFFFF715
+:10043000E6FF00BFFEE700BFFEE7BFF34F8F0948AE
+:10044000006800F4E06008490843001D05490860A1
+:10045000BFF34F8F00BFFEE700100000B40800009C
+:10046000000000200CED00E00000FA050F4A0168D2
+:100470001160121D416811600C4A103281681160D0
+:10048000121DC168116070476FF0060007490860CF
+:10049000C010064914310860091F08600349091D8E
+:1004A000086070470249086070470000000600407D
+:1004B00008E5014000BF134800680028FBD07047E2
+:1004C00010B50446022010490860FFF7F3FF2046EC
+:1004D000FFF7E8FFFFF7EEFF00200B490860FFF78A
+:1004E000E9FF10BD00B502460120074B1860FFF779
+:1004F000E1FF1160FFF7DEFF0020034B1860FFF7FC
+:10050000D9FF00BD00E4014004E501400820904906
+:1005100009680958084710208D4909680958084793
+:1005200014208B4909680958084718208849096828
+:1005300009580847382086490968095808473C2067
+:1005400083490968095808474020814909680958C2
+:10055000084744207E4909680958084748207C49D3
+:100560000968095808474C2079490968095808471B
+:100570005020774909680958084754207449096888
+:1005800009580847582072490968095808475C20EB
+:100590006F4909680958084760206D49096809587A
+:1005A000084764206A49096809580847682068496B
+:1005B0000968095808476C206549096809580847BF
+:1005C0007020634909680958084774206049096820
+:1005D0000958084778205E490968095808477C206F
+:1005E0005B49096809580847802059490968095832
+:1005F0000847842056490968095808478820544903
+:100600000968095808478C20514909680958084762
+:1006100090204F4909680958084794204C490968B7
+:100620000958084798204A490968095808479C20F2
+:100630004749096809580847A020454909680958E9
+:100640000847A4204249096809580847A82040499A
+:10065000096809580847AC203D4909680958084706
+:10066000B0203B49096809580847B420384909684F
+:1006700009580847B8203649096809580847BC2076
+:100680003349096809580847C020314909680958A1
+:100690000847C4202E49096809580847C8202C4932
+:1006A000096809580847CC202949096809580847AA
+:1006B000D0202749096809580847D82024490968E3
+:1006C00009580847DC202249096809580847E020F2
+:1006D0001F49096809580847E4201D490968095855
+:1006E0000847E8201A49096809580847EC201849C2
+:1006F000096809580847F02015490968095808474A
+:10070000F4201349096809580847F8201049096876
+:1007100009580847FC200E490968095808475FF442
+:1007200080700B490968095808475FF482700849CE
+:100730000968095808475FF4847005490968095831
+:100740000847000003480449024A034B7047000071
+:1007500000000020C0080000C008000040EA0103BB
+:1007600010B59B070FD1042A0DD310C808C9121F5A
+:100770009C42F8D020BA19BA884201D9012010BD94
+:100780004FF0FF3010BD1AB1D30703D0521C07E061
+:10079000002010BD10F8013B11F8014B1B1B07D1C5
+:1007A00010F8013B11F8014B1B1B01D1921EF1D136
+:1007B000184610BD7047704770470000014B1B681A
+:1007C000DB681847000000201C481D497047FFF7F0
+:1007D000FBFFFFF799FC00BD20BFFDE74FF0FF31A5
+:1007E000184C24688C420DD1174B1B6899420ED1CE
+:1007F000164B1B68164A136018684FF0FF31884289
+:10080000EAD00BE0134880F30888134B1847104ACE
+:10081000136018684FF0FF318842DDD080F30888FC
+:100820004FF02021884204DD0C48026802210A436F
+:1008300002605B68184700000346DBE7C008000061
+:10084000C00800000020000014100010B0080000D4
+:1008500000000020000400201104000024050040D6
+:100860006FF00200704502D1EFF3098101E0EFF370
+:100870000881886902380078182803D100E0000058
+:10088000074A1047074A12682C32126810470000C6
+:1008900000B5054B1B68054A9B58984700BD0000F2
+:1008A000FF02000000000020B0080000040000006B
+:0C08B00000300000002000000024F400D4
+:10300000F0210020C1D50100E14100001FD50100E1
+:10301000E1410000E1410000E1410000000000004A
+:1030200000000000000000000000000025D60100A4
+:10303000E141000000000000E1410000E14100002A
+:103040008DD6010093D60100E1410000E14100006E
+:10305000E1410000E1410000E1410000E1410000E8
+:1030600099D60100E1410000E14100009FD6010036
+:10307000E1410000A5D60100ABD60100B1D60100A8
+:10308000E1410000E1410000E1410000E1410000B8
+:10309000E1410000E1410000E1410000E1410000A8
+:1030A000B7D60100BDD60100E1410000E1410000BA
+:1030B000E1410000E1410000E1410000E141000088
+:1030C000E1410000E1410000E1410000E141000078
+:1030D000E1410000E1410000E1410000E141000068
+:1030E000E1410000E1410000E1410000E141000058
+:1030F000E1410000E1410000E1410000E141000048
+:10310000E1410000E141000000F002F81AF035FA58
+:103110000AA090E8000C82448344AAF10107DA4532
+:1031200001D11AF02AFAAFF2090EBAE80F0013F033
+:10313000010F18BFFB1A43F00103184788A60100CE
+:10314000B8A601000A4410F8014B14F00F0508BF9F
+:1031500010F8015B240908BF10F8014B6D1E05D063
+:1031600010F8013B6D1E01F8013BF9D1641E03D03C
+:10317000641E01F8015BFBD19142E4D3704700006B
+:10318000103A24BF78C878C1FAD8520724BF30C893
+:1031900030C144BF04680C60704700000023002465
+:1031A00000250026103A28BF78C1FBD8520728BF57
+:1031B00030C148BF0B6070471FB51AF09CFA00F091
+:1031C00031F88DE80F001FBDF0B440464946524625
+:1031D0005B460FB402A0013001B50648004700BFAE
+:1031E00001BC86460FBC8046894692469B46F0BC91
+:1031F00070470000093100008269034981614FF086
+:1032000001001044704700000D32000001B41EB4EC
+:1032100000B501F0E0FE01B40198864601BC01B0A2
+:103220001EBD00001AF0A6B910B504460021012009
+:1032300000F034F80021182000F030F800210B20B5
+:1032400000F02CF80221192000F028F802210D20AE
+:1032500000F024F802210E2000F020F802210F20B7
+:1032600000F01CF80221C81F00F018F803211620F6
+:1032700000F014F80321152000F010F8204600F0AB
+:103280001FF8002010BD68210180704700F028B8A9
+:103290000A48704700F02CB8704770474907090E7C
+:1032A000002806DA00F00F0000F1E02080F8141D7D
+:1032B000704700F1E02080F80014704703F90043E4
+:1032C00070B5304C054608202070A01CFFF7DBFFCE
+:1032D0005920A08029462046BDE8704000F0C5BBBB
+:1032E00010B500F0CCFB27490020891E087010BDE6
+:1032F0002DE9F041234E0446B61E0D4630780127D5
+:1033000038B1A4F160000B280AD8204600F024FF51
+:103310002DE0602CF9D043F201000860BDE8F08197
+:10332000A4F16C00032803D8204600F050FF1EE0F3
+:10333000A4F170001F2803D8204600F041F916E0E0
+:10334000A4F190000F2803D8204600F0EEF80EE01C
+:10335000A4F1A0000F2803D8204600F079F806E079
+:10336000A4F1B0000F2804D8204600F0E2F928604C
+:1033700000E02F60602CD1D128680028CED13770B2
+:10338000CCE700001A0000204FF0E0214FF400408D
+:10339000C1F8800124490020087024494FF0607072
+:1033A0000860704770B5204D04462878A0421CBFC5
+:1033B000002C002803D01EA14C201AF0AAF828786F
+:1033C000A04208BF70BD2C701E49184A00200CB3E3
+:1033D0001D4DDFF878C0131F012C07D0022C0FD031
+:1033E000BDE8704012A167201AF093B8086002206F
+:1033F0000860CCF800504FF040701060186070BD4D
+:10340000086003200860CCF800504FF40000106002
+:10341000186070BD086008604FF06070106070BD8B
+:1034200003A170201AF075B82000002008F50140B3
+:103430007372635C68616C5F63636D5F6161722E60
+:103440006300000000F500408801002014F50040F2
+:1034500030B4A0380B2865D2DFE800F0060D161F47
+:10346000273039404A515B00D1E90132087830BC3D
+:10347000194603F06CB988888A6883B2088830BC22
+:1034800080B2194603F073B9D1E9022308884C6869
+:1034900080B2214630BC03F06BB9D1E90132088813
+:1034A00030BC80B2194603F07EB988888A6883B23E
+:1034B000088830BC80B2194603F08AB988888A68C7
+:1034C00083B2088830BC80B2194603F0C8B90888B6
+:1034D0004A6830BC80B2114603F00DBA088982B246
+:1034E000888883B2088830BC80B2194603F00DBAD0
+:1034F00008884A6830BC80B2114603F02CBA0889AB
+:103500004C6882B20888CB68214630BC80B203F098
+:1035100090BAD1E9022308884C6880B2214630BCB9
+:1035200003F08DBB30BC012070479038092845D28C
+:10353000DFE800F0050D13191F262F373D0088889E
+:103540008A6883B20888194680B204F0B3B8088844
+:103550004A6880B2114604F0F0B808884A6880B220
+:10356000114604F0F8B808884A6880B2114604F0A1
+:1035700000B9D1E901320888194680B204F00EB9C9
+:10358000088982B2888883B20888194680B204F01C
+:103590000AB908894B6882B20888194680B204F0DB
+:1035A00023B908884A6880B2114604F02EB9888889
+:1035B00082B20888114680B204F088B901207047B1
+:1035C00030B470381B287DD2DFE800F00E141820CC
+:1035D00024272E353A3F43474B535960697179840C
+:1035E0008B93989C9FA6A90008784A6830BC114626
+:1035F00007F025BC086830BC07F070BC0C790B7B69
+:103600008A680868214630BC07F078BC086830BC7E
+:1036100007F009BD30BC07F056B908884A6830BCCD
+:1036200080B2114607F027BE08880A7930BC80B204
+:10363000114607F0BEBE087830BC40B207F0C9BEE4
+:10364000088830BC80B207F0DFBE086830BC07F0E5
+:10365000EDBE086830BC01F011BC086830BC01F058
+:103660003DBC088982B2D1E9000330BC194607F09D
+:10367000FFBED1E9000230BC114607F04ABF0888FE
+:103680004A6830BC80B2114609F011BAD1E9022370
+:103690000C790888214630BC80B209F0D0BA08887D
+:1036A0000B798A6830BC80B2194609F07BBCD1E93D
+:1036B0000132088830BC80B2194609F0EBBCD1E970
+:1036C000022300E032E008884C6880B2214630BC1A
+:1036D00009F046BD08884A6830BC80B2114609F03E
+:1036E0007ABD08880A7A0B7930BC80B2194607F097
+:1036F00031BF088830BC80B207F02FBF086830BCEB
+:1037000007F030BF30BC07F0BFB8D1E900038A68CA
+:1037100030BC194607F08EBF30BC07F09EB8088851
+:103720004A6830BC80B2114608F055B830BC012060
+:103730007047B02805D0B12807D0B22809D00120A1
+:103740007047088880B20AF035B9088880B20AF05C
+:1037500050B9D1E901320888194680B20AF05AB945
+:103760000A280ED2DFE800F005070509090B0B0552
+:10377000050507F0D0B809F0FFBE01F060BA06F009
+:103780002DBAFEA140F2E22019F0C3BE7FB5FF4979
+:103790000646FF4AD1E90001CDE901014FF49860E6
+:1037A000ADF80C000F230A21A2F128000AF02FFE29
+:1037B0000024AFF253000AF04BFE641CE4B20A2C62
+:1037C000F7D304200090F24801231A4603A9F030F1
+:1037D0000AF031FA20B1E9A14FF4AD7019F099FE69
+:1037E000EC4C002075682070EB4920462844486066
+:1037F000E01C20F00300A04204D0E8A14FF4977031
+:1038000019F087FEA8B20422214604F09CFC20B1E6
+:10381000E2A14FF4A07019F07CFE00211E220846A0
+:1038200004F0A0F807F0CCFA02222421DF4801F0CE
+:103830008DFBDE4801222C214C3001F087FBDB4957
+:103840000B20B03901F006FA20B1CCA14FF4B770CB
+:1038500019F05FFE09F062FE02F045F901AB0022AB
+:103860000821D3A007F06AF920B1C4A14FF4BA70BF
+:1038700019F04FFE304602F06EFC20B1BFA14FF4AC
+:10388000BB7019F046FE4FF45B71CC4819F00DFE89
+:10389000CA4801214171022181710621C1717FBD98
+:1038A00010B5C64CA078092804D3B4A14FF4D77042
+:1038B00019F02FFE207800EB400004EB401010F8C8
+:1038C0000C1F21F0FF010170417821F00701C91C94
+:1038D00021F0180141700121E17010BD70B50D4655
+:1038E000002114461980072828D2DFE800F02704B9
+:1038F0000B191227200021462846BDE870401A46C1
+:1039000009F05BBE21462846BDE870401A4606F025
+:1039100041BE21462846BDE870401A4601F08CBFE2
+:1039200021462846BDE870401A4603F003BD2146F3
+:103930002846BDE870401A4600F0D1BB8FA140F286
+:103940000D2019F0E6FD032070BD70B59B4CE078AA
+:10395000002819D02078002500EB400004EB40102F
+:10396000407B00F0070001190879401E087120789B
+:10397000401CC0B22070092800D12570A078401CDE
+:10398000A0700AF015FFE57070BD8C48C079002862
+:1039900000D085E7704770B5884DA86860B1FFF723
+:1039A000F4FF002860D06022A96819F02AFDFFF713
+:1039B000CCFF0020A860F0E76879002854D0FFF71A
+:1039C0006FFF044679484C3001F0D0FA606020B9AE
+:1039D0006AA14FF44B7019F09CFD60680AF0AAF8D8
+:1039E00068B1204606F0AEFC6078010703D520F0F0
+:1039F0000700401C29E06D4861684C302BE06B48A3
+:103A000061684C3001F0BBFA00F01EFB00282BD19E
+:103A1000FFF746FF0446654801F0A8FA606020B948
+:103A200056A140F24F3019F074FD60680AF084F836
+:103A3000A0B1606800886080204609F0F3FD6078DE
+:103A4000010706D520F00700801C6070FFF77DFF9E
+:103A5000A3E75648616801F092FA9EE76168BDE805
+:103A60007040524801F08BBA70BD10B54A4CC4E9A1
+:103A70000201AFF2DD0000F0E2FB607010BD4649CC
+:103A800000200870704730B505464FF080500C4656
+:103A9000D0F8A41095B0491C05D1D0F8A810C9439E
+:103AA0000904090C08D050F8A01F01F00101297089
+:103AB00041682160806812E02B208DF8000009A980
+:103AC00068460AF00FF820B12CA14FF4197019F0D4
+:103AD00020FD012028700A982060BDF82C00A080ED
+:103AE0002878002803D0607940F0C000607115B0DC
+:103AF00030BDF0B54FF080540746D4F8800095B043
+:103B00000D462B26401C0BD1D4F88400401C07D155
+:103B1000D4F88800401C03D1D4F88C00401C0BD092
+:103B2000D4F880003860D4F884007860D4F8880035
+:103B3000B860D4F88C001EE08DF82C6069460BA8A4
+:103B400009F0D0FF20B10DA140F28D2019F0E1FC69
+:103B500001983860029878608DF82C6069460BA84F
+:103B600009F0C0FF20B105A14FF4257019F0D1FC78
+:103B70000198B8600298F86022E000007372635CFC
+:103B8000686F73745F636F72652E630000D7010006
+:103B9000DC01002000220020240000207372635CFE
+:103BA000686F73745F636F72652E6300A80B0020EB
+:103BB0006E52463531383232000000008C0700204A
+:103BC000D4F89000401C0BD1D4F89400401C07D1CD
+:103BD000D4F89800401C03D1D4F89C00401C08D0B5
+:103BE00054F8900F286060686860A068A860E0687A
+:103BF00020E08DF8006009A9684609F073FF28B13C
+:103C0000AFF2880140F2B22019F083FC0A982860D4
+:103C10000B9868608DF8006009A9684609F062FF9A
+:103C200028B1AFF2A80140F2B92019F072FC0A984D
+:103C3000A8600B98E86015B0F0BD70B5F84C05466B
+:103C4000A06828B1AFF2CC014FF4427019F061FCCA
+:103C5000A56070BD10B50146F24801F090F9F04939
+:103C60008879401CC0B28871012805D1EE4840789F
+:103C7000BDE8104000F005BB10BD70B50446A1F5CD
+:103C80007F4016460D46FF3805D1AFF2101140F2C5
+:103C90007D3019F03EFC012E07D0AFF22011BDE8B7
+:103CA00070404FF4637019F034BC207820F00F009E
+:103CB000801D20F0F0006030207000202072A5816F
+:103CC0000120A07370BD70B515460C460646FFF77F
+:103CD0005CFE90B1017821F00F01891D21F0F00107
+:103CE0006031017046800121017221680161A18863
+:103CF00081820573BDE8704027E63046BDE870401C
+:103D0000132107F056BBC8494968884201D21020E8
+:103D10007047032101700020704770B5C24C054602
+:103D200094B02078002610B1082014B070BDBF4AAE
+:103D30006260954201D21020F7E7686848B1092116
+:103D4000D82804D3C31C23F00303834205D00846BC
+:103D5000EBE74FF4C06068600DE0B549891A4FF099
+:103D60008052D2F80C2101EB8221A1F50061814241
+:103D700001D20421EBE700F053FF6178A0680CF05A
+:103D800048FCE068401E07280BD830218DF8001051
+:103D90008DF8020068460EF018F810B109A80CF072
+:103DA000F3FD2846FFF7F2FC012020703046BCE707
+:103DB0002DE9F05FDFF870B204460F46DBF804002F
+:103DC000814207D30CB1844204D3E01C20F00300ED
+:103DD000A04202D01020BDE8F09F91484FF00008AB
+:103DE000817899B14178824601EB410100EB4115A0
+:103DF000B7F8009015F80C0F3B4600F00F000022BA
+:103E00002946FFF76BFD060004D013E0A7F80080F9
+:103E10000520E0E794B13988494501D90C260DE029
+:103E200028783B4600F00F0022462946FFF756FD52
+:103E3000060005D00C2E01D0A7F800803046CAE756
+:103E40009AF801005446401CC0B28AF801000928C3
+:103E500001D184F80180A078401EA070687800F03D
+:103E60000701012910D0022908D003291CD0AFF284
+:103E7000F42140F2294019F04CFBDFE7C006DDD405
+:103E80006868FFF7E7FED9E7664869684C3001F0DB
+:103E900076F86079401CC0B260710128CED19BF8E1
+:103EA000010000F0EEF9C9E7E079401C8AF807004C
+:103EB000C4E7604A904208D35B4AB0F5802F52684D
+:103EC00001D3904201D3914201D21020704700F0FB
+:103ED000F8BE584B10B5994208D3534BB1F5802F1B
+:103EE0005B6801D3994201D39A4201D2102010BDE0
+:103EF000022803D0102801D0092010BD00F006FFD1
+:103F00000028FAD0052010BD4A4B10B598420BD3BB
+:103F1000454BB0F5802F5B6801D3984204D399429A
+:103F200002D31AB19A4201D2102010BD00F00DFF49
+:103F30000028FAD0072010BD10B504463A4894B0C6
+:103F40004068844202D2102014B010BD0F208DF8BA
+:103F5000000009A9684609F0C5FD0028F4D19DF8C4
+:103F60002C002070BDF82E006080BDF83000A080CD
+:103F70000020E9E751B12C4A5268914202D30B6804
+:103F8000934201D2102070478A880AB101F008BE1E
+:103F90000920704710B5274A94B091420ED3224AA7
+:103FA0004FF480239942526801D3914206D3441EB4
+:103FB0001E2C25D8994203D3914201D21020C3E789
+:103FC00001281BD108784FF0000410F0010F03D036
+:103FD00003208DF8020001E08DF8024038208DF8B2
+:103FE000000009A9684609F07DFD28B1AFF25441EF
+:103FF00040F2272019F08DFA2046A5E70720A3E715
+:10400000A0F120021F2AF9D814B0BDE8104006F034
+:1040100019BE054A526891420ED210207047000026
+:104020008C070020A80B0020240000200022002084
+:104030000000002000F00100A0F120021F2A01D89A
+:1040400006F07ABE0720E9E7F0B595B03B208DF881
+:104050002C0069460BA809F045FD28B1AFF2C44118
+:104060004FF4C47019F055FA43F2040600246D466B
+:104070002FE02F19B87DC10706D0400704D405EB07
+:104080004400C08809F0F3FB32488079F8B1B87D6C
+:1040900080071CD505EB44000022C088062109F0EA
+:1040A00003FCA0B13C208DF82C0005EB44006946D0
+:1040B000C088ADF82E000BA809F014FD06000CD046
+:1040C000AFF2285140F29D1019F023FA05E0641C6C
+:1040D000E4B29DF80400A042CBD83046ABE52DE910
+:1040E000F04105460C4600270078062190463E46E2
+:1040F000B1EB101F05D0AFF25C514FF4E37019F033
+:1041000008FA287A80B1012815D0AFF2705140F238
+:10411000E71019F0FEF900BFA8F800600CB1278085
+:1041200066800020BDE8F081022709267CB1A889BD
+:10413000A080A87B09E00327142644B16888A080EA
+:104140002869E060A88A2082287B2072E4E7A8F82A
+:104150000060E6E78C07002060380A2835D2DFE8E7
+:1041600000F005080D10151B21242A2F0868FFF701
+:10417000D4BDD1E900021146FFF71ABE0868FFF767
+:10418000C2BDD1E900021146FFF793BED1E9013269
+:1041900008781946FFF79DBED1E900038A681946E1
+:1041A000FFF7B2BE0868FFF7C7BE08884A6880B24A
+:1041B0001146FFF7DFBED1E900021146FFF7EABE64
+:1041C000D1E900021146FFF724BF0120704701200A
+:1041D000704700000E4A12680C498A420AD11847FB
+:1041E0000B4A1268094B9A4204D101B500F0EAFE6D
+:1041F00003BC8E460749096809580847064807491D
+:10420000054A064B7047000000000000BEBAFECA17
+:104210006400002004000020F0210020F021002094
+:104220004FF0E0214FF00070C1F88001C1F880022A
+:10423000394B402283F80024C1F80001704710B5C3
+:1042400002460420354903E001EBC0031B7943B16A
+:10425000401EC0B2F8D232A1432019F05AF9FF2013
+:1042600010BD41F8302001EBC00100224A718A7173
+:1042700001220A7110BD294A002102EBC000017120
+:10428000704710B50446042803D325A1522019F025
+:1042900040F9224800EBC4042079012803D020A172
+:1042A000532019F036F96079A179401CC0B28142DF
+:1042B00000D060714FF0E0214FF00070C1F80002B3
+:1042C00010BD70B51448042590F80004134E400941
+:1042D000194C02281BD012A1692019F01AF916E016
+:1042E000217806EBC1000279012A08D1427983794D
+:1042F0009A4204D04279827156F831008047207882
+:10430000401CC0B22070042801D3002020706D1E14
+:10431000EDB2E5D270BD000019E000E0240C0020F1
+:104320007372635C736F635F7369676E616C6C69F2
+:104330006E672E63000000003400002010B5EFF31C
+:10434000108000F0010472B6D0484178491C4170D9
+:104350004078012801D10AF053FA002C00D162B64E
+:1043600010BD70B5C94CE07848B90125E570FFF77C
+:10437000E5FF0AF04DFA20B100200AF020FA0020F3
+:1043800070BD4FF08040A571C0F80453F7E770B5D9
+:10439000EFF3108000F0010572B6BC4C607818B9DC
+:1043A000BBA1912019F0B5F86078401E607060786C
+:1043B00008B90AF029FA002D00D162B670BDB348E1
+:1043C00010B5C17821B100218171C170FFF7DFFF05
+:1043D000002010BD10B504460AF01AFAAB49C9789E
+:1043E000084000D001202060002010BD2DE9F05FC2
+:1043F0000026A64C08210422102320270125B046C0
+:10440000E6714FF0020A0D282CD2DFE800F0070910
+:104410000C0E101214161F2124262800657126E0A8
+:1044200084F805A023E0627121E061711FE06371EF
+:104430001DE067711BE0012619E0FFF77FFF00BF59
+:104440000AF0E6F90028FBD0022610E0627100E0D5
+:104450006171E5710BE06371FBE76771F9E740207B
+:104460006071F6E78AA140F2651019F052F80AF07F
+:10447000DCF948B10AF0E0F9B04205D130460AF063
+:10448000DFF90028FAD032E04FF08047FD60C7F82E
+:10449000048183490E60C7F804A3BD60C7F810818A
+:1044A000DFF800B2DBF80010C94341F3001101F15D
+:1044B0000109DBF8001041F01001CBF8001000E01A
+:1044C00020BFD7F804010028FAD030460AF0B8F926
+:1044D0000028FAD0B9F1000F05D1DBF8001021F067
+:1044E0001001CBF80010C7F808A3C7F80481E079E1
+:1044F00060B10AF08DF907460AF0DAF86FF0004172
+:1045000017B1C4E9021001E0C4E902011EB184F848
+:104510000480BDE8F09F2571BDE8F05F00F094B81D
+:1045200010B504460AF07AF928B158490120C8703C
+:104530004A78521C4A702046BDE8104056E72DE9E3
+:10454000F0414FF08045D5F808010026012803D13D
+:10455000C5F808610AF033F9D5F80401012801D142
+:10456000C5F80461D5F800010127484C01280ED197
+:10457000C5F80061A07918B100200AF020F9A671F1
+:10458000207820B10AF044F908B12F61A770207992
+:1045900030B3D5F81001012824D1C5F810616F613E
+:1045A000E079B0B10AF034F980460AF081F8B8F148
+:1045B000000F01D0E16800E0A168411A022902DA87
+:1045C00011F1020F0EDCB8F1000F01D0E06000E045
+:1045D000A060FFF7B3FE0AF01BF910B12F61A770BE
+:1045E00000E02770D5F80C0101280ED1A07818B989
+:1045F00027A1F12018F08DFFC5F80C612A4800684A
+:10460000A6702670BDE8F041C1E6BDE8F08170B546
+:104610001E4DE87808B90AF0F7F801208407A06178
+:10462000A87850B1D4F80C0120B900200AF008F99C
+:104630000028F7D10020C4F80C014FF0FF30C4F877
+:1046400008031A48006870BD2DE9F0411927BC071E
+:10465000C4F808734FF00008C4F80081C4F80C8156
+:104660000AF0D6F8094E012510B12561B57000E0B9
+:104670003570FFF763FEC4F804730949707920317F
+:104680000860A561C4F810816561BEE738000020AC
+:104690007372635C736F635F636C6F636B2E630035
+:1046A0001805004010ED00E00C0100400803004038
+:1046B00010B50D2000F06DF8C4B26FF0040000F0EA
+:1046C00068F8C0B2844203D039A11B2018F021FF42
+:1046D0003C490120086010BD70B50D2000F043F882
+:1046E000394C0020C4F800010125C4F804530D2002
+:1046F00000F044F825604FF0E0216014C1F800019B
+:1047000070BD10B50D2000F02EF82F48012141603A
+:104710000021C0F800112D480068BDE810400D20B0
+:1047200000F02CB82849D1F80001012803D020A1BD
+:104730005E2018F0EEBE2348001D00680022C0B2C3
+:10474000C1F800212149096809F0C3BC10B51E4811
+:10475000D0F800110029FBD0FFF7E4FFBDE81040BE
+:104760000D2000F00BB800F01F020121914040091C
+:10477000800000F1E020C0F88011704700F01F02B7
+:10478000012191404009800000F1E020C0F8801232
+:104790007047002806DA00F00F0000F1E02090F8E2
+:1047A000140D03E000F1E02090F800044009704788
+:1047B0007372635C736F635F68616C5F726E672EA8
+:1047C0006300000004D5004000D0004000D100404C
+:1047D00030B44FF0E0204FF400644FF0010C0021A2
+:1047E000C0F88041E510C0F880516303C0F8803103
+:1047F000E34A82F80014D21E82F80014E14A82F8DB
+:104800000014E14AC2F804C0C2F808C0C2F840115E
+:10481000C2F84411C2F84811DC490968C0F8804266
+:10482000C0F88052C0F88032C0F80041C0F80031B2
+:10483000C2F800C030BC704770B401204FF0E023D4
+:10484000C6024FF0000CC3F880610402C3F8804137
+:104850000506C3F88051CC4A50609060CC4801688E
+:104860000029FCD1C2F840C1C2F844C1C2F848C115
+:10487000C6480068C3F88062C3F88042C3F880521B
+:1048800070BC70474FF0E0204FF40061C0F8801218
+:10489000C910C0F880127047002804BFBD48704797
+:1048A000012804BFBC487047022804BFB7487047BE
+:1048B00010B59120B9A118F02CFE002010BDB2490E
+:1048C000002238B1012825D002282FD0B3A1BF2063
+:1048D00018F01FBE4FF48030C1F80803C1F8480338
+:1048E000B54B1A60C1F84021B4490968B44BC10303
+:1048F0001960B449C1F808034FF0E0230012C3F86F
+:104900008001B1480260C1F84021C1F80022AF48DF
+:10491000027070474FF40030C1F80803C1F8480333
+:10492000AB480260C1F844219B480AE04FF4802064
+:10493000C1F80803C1F84803A6480260C1F848213D
+:10494000924800687047F0B4DFF83CC204260025A6
+:10495000012440B101283FD0022857D0F0BC8FA1DC
+:10496000F42018F0D6BD881E20F07F414FF480302F
+:10497000CCF80803CCF84051CCF84403CCF84015EF
+:10498000012B14BF00210121904B59708D494C60BF
+:10499000CC60DFF844C2CCF80050904D4FF0020CD0
+:1049A000C5F800C0DFF838C2CCF80060DFF818C2E4
+:1049B0003D32CCF80020C1F800424FF0E02C8A15BF
+:1049C000CCF88022C1F80403CCF800210804854902
+:1049D00008601C70F0BC704783484FF40032012B14
+:1049E0000AD100BFC0F84051CCF80423CCF84423CE
+:1049F000C0F84015F0BC7047CCF80823C0F840510F
+:104A0000CCF84423C0F84015F0BC704777484FF409
+:104A10008022012BF0D1E5E75D480068704770B552
+:104A2000594CD4F84001002501280AD1D4F80803D4
+:104A300010F4803F05D04FF48030C4F80803C4F868
+:104A40004051D4F8440101280DD1D4F8080310F4E2
+:104A5000003F08D04FF40030C4F80803C4F84451B4
+:104A600001200AF0CCFFD4F8480101280DD1D4F878
+:104A7000080310F4802F08D04FF48020C4F80803F6
+:104A8000C4F8485102200AF0BAFF4048006870BDDF
+:104A90004E490878E0B14A4A4FF000401060494A58
+:104AA000C00BC2F8080303124FF0E02C0020CCF832
+:104AB0008031454B1860C2F84001C2F8000208700E
+:104AC0004A78002A08BF7047487000200AF097BF54
+:104AD00003200AF094BF4FF0E0214FF08070C1F83E
+:104AE000000270474FF0E0214FF08070C1F8800263
+:104AF00070474FF0E0214FF40010C1F800027047FA
+:104B00004FF0E0214FF40010C1F8800270472D48AB
+:104B100001214160C1604FF0E0218015C1F88002A1
+:104B20007047410A43F609525143C0F3080010FB95
+:104B300002F000F5807001EB50207047430B48F203
+:104B4000376C03FB0CF31B0C4FEA432CC1F800C07D
+:104B5000DFF89CC003FB0C0326484CF2F72C5843AB
+:104B6000400D10FB0CFC0CEB432303F580735B1230
+:104B700013700A681044086070470BF045B80000D5
+:104B80000BE000E018E000E000B0004048B1004059
+:104B900004B500404081004044B100407372635C42
+:104BA00072656D5F68616C5F6576656E745F746970
+:104BB0006D65722E6300000040B5004040B10040BA
+:104BC00008F501400080004040850040480000207A
+:104BD00044B5004048B500400485004008850040C9
+:104BE0001085004004F5014004B0004008B00040CA
+:104BF000F7C2FFFF6F0C010010B50AF0EAFF10BD0D
+:104C0000002005490860012001218140034A430931
+:104C100042F8231000BF7047FC1F004080E200E014
+:104C200010B50DF0EDF909F094F9FEF7ADFB0FF0BA
+:104C30004FFB0EF0ADF8BDE810400EF02FB870B588
+:104C40000C46054603F0E2F921462846BDE87040CF
+:104C50000FF06FB870B50D46040011D085B1210179
+:104C6000284618F000FC10224F49284618F084FB13
+:104C70004D4801210838018044804560002070BD06
+:104C8000012070BD70B5484E00240546083E10E076
+:104C90007068AA7B00EB0410817B914208D1C17B34
+:104CA000EA7B914204D10C22294618F039FB30B13D
+:104CB000641C30888442EBDB4FF0FF3070BD20462F
+:104CC00070BD70B50D46060009D045B1364C083CA4
+:104CD00020886188401C884203D9042070BD1020C0
+:104CE00070BD3046FFF7CEFF002801DB401C0AE014
+:104CF00021886068102200EB0110314618F03CFB5F
+:104D00002088401C20802870002070BD70B514469B
+:104D10000D0018D0BCB10021A170022802D01028CB
+:104D200011D105E0288870B10121A170108008E040
+:104D30002846FFF7A7FF002805DB401CA070A889C4
+:104D40002080002070BD012070BD70B5054614465E
+:104D50000E000BD000203070A878012808D005D9AB
+:104D60001149A1F108010A8890420AD9012070BDB9
+:104D700024B1287820702888000A5070022008701A
+:104D80000FE064B14968102201EB00112046103990
+:104D900018F0F2FA287820732888000A607310202F
+:104DA0003070002070BD000054000020654988422A
+:104DB00006D3B0F5802F05D363490968884201D234
+:104DC000102070470146012005F074B830B593B04B
+:104DD000044600200D460090142101A818F065FB40
+:104DE0001C2108A818F061FB9DF80000CDF808D040
+:104DF00020F00F00401C20F0F00010308DF8000073
+:104E00009DF8010006AA20F0FF008DF801009DF832
+:104E1000200001A940F002008DF8200001208DF84B
+:104E2000460042F60420ADF8440011A80190208805
+:104E3000ADF83C006088ADF83E00A088ADF84000B9
+:104E4000E088ADF842009DF8020020F00600801CCA
+:104E500020F001008DF802000820ADF80C00ADF83C
+:104E600010000FA8059008A800F02AFF002803D121
+:104E7000BDF818002880002013B030BD3EB50446B0
+:104E80000820ADF800002F48844206D3B4F5802FE7
+:104E900005D32D480068844201D210203EBD214632
+:104EA000012005F007F80028F8D12088ADF80400AB
+:104EB0006088ADF80600A088ADF80800E088ADF87D
+:104EC0000A0005F038FE01AB6A46002101F03CFB08
+:104ED000BDF800100829E1D003203EBD1FB50446EF
+:104EE000002002900820ADF808001648CDF80CD03C
+:104EF000844206D3B4F5802F06D313480068844259
+:104F000002D2102004B010BD05F015FE014602AA21
+:104F10004FF6FF7001F0A3FC0028F3D1BDF8081094
+:104F2000082901D00320EDE7BDF800102180BDF86D
+:104F300002106180BDF80410A180BDF80610E18068
+:104F4000E0E7000000F001002800002010B5031D7C
+:104F500003600020521E04E05C181C60401C2346C5
+:104F6000C0B29042F8DB0020186010BD024600205D
+:104F70001168002902D0084609681160704702686C
+:104F80000A6001607047000010B501462022094800
+:104F900018F0F2F907490020C877084610BD064905
+:104FA000012008600548064A0168914201D10021AC
+:104FB00001607047B40E002014050040640000201A
+:104FC000BEBAFECA0C4908784A78401CC0B290426A
+:104FD00000D00870704708484FF0E02220BF40BF63
+:104FE00020BF417803784370D2F8003213B90378B8
+:104FF0008B42F3D0002070476B0000207047704751
+:1050000010FFFFFFDBE5B15100F001006800FFFF7A
+:1050100040F2090CC2F2000C6047000018B1817820
+:1050200001293CD101E010207047018842F60213AB
+:10503000C81A4FF48072994233D01CDC42F6010347
+:10504000A1EB030099422CD00CDCF9B1B1F5C05FA3
+:1050500027D06FF4C050081823D0A0F57060FF3837
+:105060001DD11EE001281CD002281AD0FF2818D01C
+:10507000904214D115E0904213D008DC012810D0E2
+:1050800002280ED0FE280CD0FF2808D109E0A0F598
+:105090008070013805D0012803D0022801D00020FB
+:1050A00070470F2070470B2826D008DC1BD2DFE8A2
+:1050B00000F01C2025251A25292325271E0011284C
+:1050C0001CD008DC0C2817D00D281DD00F2815D0B7
+:1050D000102808D110E0822809D0842810D0852813
+:1050E00010D0872812D00320704700207047052079
+:1050F000704743F203007047072070470F20704746
+:1051000004207047062070470C2070474FF4505021
+:10511000704730B551B1A1F201158123CCB2112DE8
+:105120001CD2012805D0022808D00AE00020107007
+:105130001DE0A1F5807003381BD002E0B1F5817F3E
+:1051400017D0112D15D2DFE805F014111114111428
+:10515000141114141411111111141100A1F5C070BF
+:105160001F2803D9A1F2FD11022902D814700020D2
+:1051700030BD1370072030BD06280CD2DFE800F0E8
+:105180000305030B07090020704711207047072013
+:1051900070470820704703207047007810F00F0216
+:1051A00004D0012A05D0022A0AD10EE0000907D155
+:1051B00008E00009012805D0022803D0032801D007
+:1051C000072070470870002070470620704738B1EC
+:1051D000012809D002280FD0032815D007207047D6
+:1051E000087820F0FF0016E0087820F00F00401C3F
+:1051F00020F0F00010300EE0087820F00F00401C86
+:1052000020F0F000203006E0087820F00F00401C6D
+:1052100020F0F000303008700020704738B50C46A0
+:10522000050041D06946FFF7B8FF002819D19DF865
+:105230000010208861F38B2020806946681CFFF7EE
+:10524000ACFF00280DD19DF80010208861F30D30CF
+:105250002080A978C1F34101012903D0022904D09B
+:10526000072038BD20F0200001E040F02000208021
+:1052700080B210F4406F04D0A978C90861F38E3071
+:10528000208080B210F4405F07D0A978090961F34B
+:10529000CF30208010F4405F02D12088400403D535
+:1052A000208840F040002080002038BD70B50446C2
+:1052B0000020088015466068FFF7B0FF002816D16F
+:1052C0002089A189884211D860688078C0070AD0F7
+:1052D000B1F5007F0AD840F20120B1FBF0F200FBEB
+:1052E0001210288007E0B1F5FF7F01D90C2070BDB6
+:1052F00001F201212980002070BD10B504781378D7
+:1053000064F3000313700478640864F341031370BA
+:105310000478A40864F3820313700478E40864F347
+:10532000C30313700478240964F30413137004781E
+:10533000640964F3451313700078800960F38613E1
+:10534000137031B10878C10701D1800701D5012060
+:1053500000E0002060F3C713137010BD028812F440
+:10536000406F02D0C2F3812306E012F4405F02D006
+:10537000C2F3013300E001230A8863F38B220A8021
+:10538000008810F4405F02D0C0F3013006E010F452
+:10539000406F02D0C0F3812000E0012060F30D32A5
+:1053A0000A8070472DE9F04792B00D00804613D077
+:1053B000B8F1000F14D01221284618F054F803AAAF
+:1053C000FF21012003F04BF80024264637464FF416
+:1053D00020596FF4205A6DE0102012B0BDE8F0871C
+:1053E0000720FAE79DF8160001280AD1BDF814003D
+:1053F00048450BD010EB0A000AD001280CD0022837
+:105400000CD0042C0ED0052C0FD10DE0012400E0AF
+:105410000224BDF8126008E0032406E00424BDF86D
+:10542000127002E0052400E00624BDF81210414588
+:1054300040D12C7486B34FF005090DF134080EAA43
+:10544000CDF80090CDE9012810230022FF2130463D
+:1054500003F0A1F8F0B9BDF834002A46C0B20EA995
+:10546000FFF754FCB0B9AE81B7B108AECDF80090EB
+:10547000CDE9016813230022FF21384603F08BF8A1
+:1054800040B9BDF83400F11CC01EC0B22A1DFFF7A0
+:105490003DFC10B10320A0E70AE0BDF82100E8813F
+:1054A000062C05D19DF81600A872BDF814002881BD
+:1054B000002092E703A802F0DAFF002892D0FFF75D
+:1054C000F2FD8AE7002805D0FE4A012903D002290F
+:1054D00003D003207047518800E09188814201D1B8
+:1054E000002070470720704770B50C4605461C2108
+:1054F000204617F0B8FF0020208055B1012D06D0BE
+:10550000BDE87040F0A140F26F2018F002B806200C
+:1055100000E00520A07070BD70B592B00646012075
+:105520008DF814008DF808008DF8153001F1080091
+:10553000CDE9030248881546ADF81800FEF725FAB4
+:10554000040018D065801720ADF80400009496F888
+:1055500021100DF12A0301AA02A80EF004FA064652
+:105560006078000701D5FEF7F0F956B13046FFF735
+:1055700003FE12B070BD1321284605F01AFF032068
+:10558000F7E708A80090BDF804300422012128465E
+:1055900007F0ABFEEDE770B506468AB000200D4679
+:1055A000059005240490069003A900940790CDE986
+:1055B0000101024610232946304602F0ECFF68B98B
+:1055C00004A9009108A8CDE90140BDF80C300022E3
+:1055D0002946304602F0F0FD002801D0FFF763FDB8
+:1055E0000AB070BD0EF0B3BB2DE9FC47054600279D
+:1055F00000780C46B846B9460C286FD2DFE800F0B8
+:10560000FF060B360A6F6F95B5F7C8D768680A387A
+:10561000FEF720FBF8E0A888002280B28146042132
+:1056200008F04CFB064624B1A7A140F2DD2017F09C
+:1056300070FF26B9A4A140F2DE2017F06AFF4946A8
+:1056400006F108000DF019FEFEF79FF9040008D0DE
+:10565000607840F008006070A4F80290FEF775F9D9
+:10566000D3E01321484605F0A4FEE2E024B996A158
+:105670004FF43D7017F04DFF60880022042108F0C0
+:105680001DFB060004D190A140F2F72017F041FF66
+:10569000A6F80090002029791DE000BF05EBC002AC
+:1056A000128992B2130707D5D30605D505EBC100C1
+:1056B00030F8020C308006E052040AD5307105EB58
+:1056C000C000C08870806078022740F008006070D9
+:1056D0009AE0401CC0B28142E0D895E08FE0E888B3
+:1056E000ADF8000024B978A140F2073017F011FF9F
+:1056F0002878062814D1BDF80000000410D5608871
+:105700000022042108F0DAFA060004D16EA140F26A
+:10571000113017F0FEFE86F80490A888708035E0FE
+:10572000607840F0080060706EE024B966A140F235
+:10573000233017F0EEFE60880022042108F0BEFA44
+:10574000060004D160A140F2263017F0E2FE06F117
+:1057500008000EF050FB90F0010F02D1E888000421
+:1057600052D560880227F080DAE724B956A140F2CA
+:105770003F3017F0CEFE60880022042108F09EFA28
+:1057800020B951A140F2423017F0C3FE0227C7E70B
+:1057900024B94DA140F24B3017F0BBFE02276188BF
+:1057A00001222046FEF769FA4FF00108B8E7A88900
+:1057B000002280B28146042108F080FA064624B116
+:1057C00041A140F25D3017F0A4FE26B93EA140F29F
+:1057D0005E3017F09EFE686800902889ADF80400DE
+:1057E000012269464846FEF76EFA0DE0FFE7002CFD
+:1057F00096D135A14FF45A7017F08BFE90E732A185
+:1058000040F26D3017F085FE9CB16078000710D52E
+:10581000B8F1000F0DD12078582220F00F00001DA4
+:1058200020F0F00080302070294604F1080017F0C5
+:10583000E8FD3846BDE8FC872DE9FE4F05460C46DD
+:10584000007A0A31029104F10C010191904600277F
+:105850001631821E3E464FF0020B4FF0010A0091B6
+:10586000082A7DD2DFE802F0F5047C43438CCFF4B4
+:1058700068880022042108F021FA5FEA000904D1B7
+:1058800011A140F2863017F044FEB9F8000010B1C3
+:105890005227072601E151271E26002C6FD0688869
+:1058A000A08084F806A099F80400029905EBC000D6
+:1058B000C089FFF777FD00287DD199F8040005EB3A
+:1058C000C0000BE0440C00207372635C6761747469
+:1058D000735F636F72652E6300000000C0892081D2
+:1058E00099F8040005EBC000408AA083F4E0B5F805
+:1058F0001290062821D1E88900041ED5512709F10C
+:10590000220086B2002CC9D0A8890199FFF74AFD70
+:10591000002876D16888A08084F806B0A889208104
+:1059200084F80AA0288AE083A4F820904A4669698E
+:10593000DDF8000017F020FDCEE0502709F120002F
+:1059400086B2002CAAD0A8890299FFF72BFD002867
+:1059500057D16888A080A889E080287A062800E0CE
+:10596000B4E00AD002202072288AA083A4F81E90F6
+:105970004A4604F120006969DCE70120F3E790E082
+:1059800068880022042108F099F9B5F812A05FEAAE
+:10599000000905D1AFF2D00140F2EE3017F0B9FDA9
+:1059A00009F108000EF027FA90F0010F02D1E88902
+:1059B000000425D500E024E00AF12200512786B238
+:1059C000002C77D06888A080A8890199FFF7EAFCAD
+:1059D000002816D184F806B0A88920810420A0727E
+:1059E000288AE083A4F820A052466969009817F03D
+:1059F000C3FC002089F80400A989A9F802106BE013
+:105A00000320BDE8FE8F688804F0AEF982466888FE
+:105A10000022042108F052F98146BAF1000F05D1A5
+:105A2000AFF25C1140F21A4017F073FDB9F1000FAC
+:105A300005D1AFF26C1140F21B4017F06AFDB9F8C6
+:105A40000600A0F57F41FF3904D05127222603E04C
+:105A50001CE032E0502720261CB36888A080502F1D
+:105A600007D084F806B0287B04F10801FFF73CFD5D
+:105A700032E0287BA11DFFF737FD6A8800234946E5
+:105A80005046FFF749FD0028BBD125E0FE49A88913
+:105A9000C988814206D15427062614B16888A0809F
+:105AA0001AE007E05327082624B16888A080A88957
+:105AB000E08011E0A8F8006013E055270726002CCD
+:105AC000F8D0A889A0800020A07105E0AFF20821DD
+:105AD0004FF48D6017F01DFDA8F800600CB1278011
+:105AE000668000208DE7E84900200870704730B5D7
+:105AF00085B00C4601F079F90546FF2805D1AFF2D3
+:105B0000382140F2834017F004FD002020802071EE
+:105B100060804FF6FF70E080294604F108000DF028
+:105B2000A0FB6A462946012002F099FC16E000BF5E
+:105B3000BDF80400000711D5BDF806002946FFF79F
+:105B40002AFDBDF80400FF2340F01000ADF804006A
+:105B5000BDF806002946019A02F0B2FD684602F03F
+:105B600086FC0028E4D005B030BD0A46014602F1AB
+:105B700008000DF088BB70B505460022042108F02E
+:105B80009DF8040005D1AFF2C02140F2A54017F006
+:105B9000C0FC294604F10800BDE870400DF06DBB63
+:105BA000F0B591B00C46074604F0DEF8050005D0CC
+:105BB0002878222805D2082011B0F0BD43F2020057
+:105BC000FAE700220421384608F078F806460CB1BE
+:105BD000A08870B101208DF8040002208DF810001B
+:105BE00000208DF8110034B1A088ADF818002068AD
+:105BF00003E00920E0E7ADF81800059006F1080081
+:105C0000CDE90207FDF7C1FE040017D06780172019
+:105C1000ADF81C00009495F821100DF12A0307AA95
+:105C200001A80DF0A0FE05466078000701D5FDF73C
+:105C30008CFE4DB12846FFF79FFABDE71321384689
+:105C400005F0B7FB0320B7E708A80090BDF81C30AB
+:105C500004220121384607F048FB4FF6FF71F1801E
+:105C6000AAE72DE9FF5F83460E9E98469146778806
+:105C70008A46384604F078F8054600220421384662
+:105C800008F01CF804462DB9AFF2C43140F20C50B4
+:105C900017F03FFC2CB9AFF2D03140F20D5017F0A5
+:105CA00038FC0834CDE90274CDE9008695F821105E
+:105CB0004B46524658460DF013FB04B0BDE8F09F2A
+:105CC0002DE9F04F9BB00D464FF000096E49ADF83D
+:105CD0001490ADF81890ADF81C90A1F80490ADF8B0
+:105CE0000C90ADF810900446ADF82490ADF82090DB
+:105CF00008781646CB46012809D0022807D0032889
+:105D000005D0042803D008201BB0BDE8F08F5F4801
+:105D100084425FD35E4F4FF480229442396801D3AE
+:105D20008C4257D38046454554D39246554501D3BE
+:105D30008D424FD3606878B140454BD3504501D375
+:105D4000884247D360892189884202D8B1F5007F13
+:105D500001D90C20D8E781460CAA04A92846FFF7F0
+:105D6000A5FA0028D0D168688078C0F341000228E5
+:105D700009D1BDF8100010F4405F04D0286910B1BB
+:105D80003968884226D303A92069FFF747FA00281B
+:105D9000BAD1206948B160788007BDF80C0000F4E2
+:105DA000405001D5F0B300E0E0BBBDF80C00810627
+:105DB00012D510F4405F606804D068B13968884239
+:105DC00008D300E040B1404504D3504504D33968BE
+:105DD000884201D2102097E708A96069FFF71EFAF0
+:105DE000002891D1606940B1BDF82000C0F3812145
+:105DF000012937D110F4405F34D009A9A069FFF719
+:105E00000DFA002880D1BDF8200080062AD4BDF804
+:105E10002400810626D4A16941B1C0F38121012962
+:105E200020D100E01EE010F4405F1BD0E06818B104
+:105E30000078B8B11C2815D20DAA611C2046FFF7C6
+:105E40005CFA01278DF84A7042F60300DA46ADF895
+:105E500048004FF4806B0DF1370215A92868FEF752
+:105E600074FF08B107204FE79DF8540014A9C01C27
+:105E7000CDF800A0CDE901A100F0FF08002308F251
+:105E80000122594612A805E0440C002000F0010050
+:105E90002800002002F02DFA30BBBDF850000A9017
+:105EA000FD492A8928690092CDE901016B89BDF875
+:105EB00030202868049902F01CFA01007ED1DFF836
+:105EC000D8B35546ABF1040B0521BBF80400ADF87F
+:105ED00035000DA88DE8230043460022FF21BDF8C0
+:105EE000500002F069F910B1FFF7DDF80CE79DF8FA
+:105EF00034004FF0020A01064FF48060804622D53C
+:105F000001468DF84A704FF42450ADF84800ADF8C2
+:105F10004C5062789DF84C00002362F300008DF82D
+:105F20004C006278CDF800A0520862F341008DF871
+:105F30004C0013AACDE9012540F2032212A802F079
+:105F4000D8F901003AD1606840B3206960B903A96B
+:105F500004A8FFF703FA6078800705D4BDF80C00A9
+:105F600020F44050ADF80C008DF84A7042F6011054
+:105F7000ADF84800208940F20121B0FBF1F201FBAD
+:105F80001202606807ABCDF80090CDE90103002351
+:105F900012A8039902F0ADF901000FD12078C106D3
+:105FA00001D480062CD5ADF82C50606968B908A9D9
+:105FB00004A8FFF7D3F9BDF8200000E077E020F453
+:105FC000406000F58060ADF82000BDF8200006A913
+:105FD00040F0C800ADF820008DF84A7042F602107B
+:105FE000ADF848000BAACDF800A0CDE901210023AF
+:105FF00040F2032212A8089902F07BF9010056D161
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/key.pem b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/key.pem
new file mode 100644
index 0000000..84fdffc
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEID2WUBCe/4kLhl5ekJ+O8PtprcahUNFE3RIm5htQzDedoAoGCCqGSM49
+AwEHoUQDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF7IoFubVru6oX9GCQm67NrXIm
+wgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA==
+-----END EC PRIVATE KEY-----
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_dfu_transport_serial.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_dfu_transport_serial.py
new file mode 100644
index 0000000..2f9c4e8
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_dfu_transport_serial.py
@@ -0,0 +1,136 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import os
+import unittest
+
+# Nordic Semiconductor imports
+import sys
+from nordicsemi.dfu.dfu_transport import DfuEvent
+from nordicsemi.dfu import crc16
+from nordicsemi.dfu.init_packet import PacketField, Packet
+from nordicsemi.dfu.model import HexType
+from nordicsemi.dfu.dfu_transport_serial import DfuTransportSerial
+
+
+def setup_logging():
+ root = logging.getLogger()
+ root.setLevel(logging.DEBUG)
+
+ ch = logging.StreamHandler(sys.stdout)
+ ch.setLevel(logging.DEBUG)
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ ch.setFormatter(formatter)
+ root.addHandler(ch)
+
+
+@unittest.skip('Ignoring these tests since they take too much time to run.')
+class TestDfuTransportSerial(unittest.TestCase):
+ DEVKEY_PORT = "NORDICSEMI_PCA10028_1_PORT"
+
+ def setUp(self):
+ setup_logging()
+
+ # Assert that environment variables are setUp before starting tests.
+ # TODO: create generic functionality for fetching environment variables that map
+ # TODO: communication ports to PCA versions
+ # TODO: setup target nRF5X device to a given state (bootloader+sd+application)
+ if self.DEVKEY_PORT not in os.environ:
+ self.fail("Environment variable {0} not found. "
+ "Must specify serial port with development kit connected."
+ .format(self.DEVKEY_PORT))
+
+ self.transport = DfuTransportSerial(os.environ[self.DEVKEY_PORT],
+ baud_rate=38400,
+ flow_control=True)
+
+ def tearDown(self):
+ if self.transport and self.transport.is_open():
+ self.transport.close()
+
+ def test_open_close(self):
+ self.transport.open()
+ self.assertTrue(self.transport.is_open())
+ self.transport.close()
+ self.assertFalse(self.transport.is_open())
+
+ def test_dfu_methods(self):
+ def timeout_callback(log_message):
+ logging.debug("timeout_callback. Message: %s", log_message)
+
+ def progress_callback(progress, log_message, done):
+ logging.debug("Log message: %s, Progress: %d, done: %s", log_message, progress, done)
+
+ def error_callback(log_message=""):
+ logging.error("Log message: %s", log_message)
+
+ self.transport.register_events_callback(DfuEvent.TIMEOUT_EVENT, timeout_callback)
+ self.transport.register_events_callback(DfuEvent.PROGRESS_EVENT, progress_callback)
+ self.transport.register_events_callback(DfuEvent.ERROR_EVENT, error_callback())
+
+ firmware = ''
+ test_firmware_path = os.path.join("firmwares", "pca10028_nrf51422_xxac_blinky.bin")
+
+ with open(test_firmware_path, 'rb') as f:
+ while True:
+ data = f.read()
+
+ if data:
+ firmware += data
+ else:
+ break
+
+ crc = crc16.calc_crc16(firmware, 0xffff)
+
+ self.transport.open()
+
+ # Sending start DFU command to target
+ self.transport.send_start_dfu(HexType.APPLICATION,
+ app_size=len(firmware),
+ softdevice_size=0,
+ bootloader_size=0)
+
+ # Sending DFU init packet to target
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 0xfffa,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [0x005a],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: crc
+ }
+ pkt = Packet(init_packet_vars)
+ self.transport.send_init_packet(pkt.generate_packet())
+
+ # Sending firmware to target
+ self.transport.send_firmware(firmware)
+
+ # Validating firmware
+ self.transport.send_validate_firmware()
+ self.transport.send_activate_firmware()
+ self.transport.close()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_init_packet.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_init_packet.py
new file mode 100644
index 0000000..eaef3ec
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_init_packet.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+from nordicsemi.dfu.init_packet import *
+
+
+class TestInitPacket(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def test_generate_packet_a(self):
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 3,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [1111, 2222, 3333, 4444],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 2,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e",
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ '1\xd7B8\x129\xaa\xc3\xe6\x8b\xe2\x01\xd11\x17\x01\x00\xae\x1e\x04\xf9~q\xcd\xbfv"\xdan\xc0f2\xd49' +
+ '\xdc\xc7\xf8\xae\x16VV\x17\x90\xa3\x96\xadxPa\x0bs\xfe\xbdi]\xb2\x95\x81\x99\xe4\xb0\xcf\xe9\xda'
+ }
+
+ ip = Packet(init_packet_vars)
+ data = ip.generate_packet()
+ self.assertEqual(data, ("\x01\x00" # Device type
+ "\x02\x00" # Device revision
+ "\x03\x00\x00\x00" # App version
+ "\x04\x00" # Softdevice array length
+ "\x57\x04" # Softdevice entry #1
+ "\xae\x08" # Softdevice entry #2
+ "\x05\x0d" # Softdevice entry #3
+ "\x5c\x11" # Softdevice entry #4
+ "\x02\x00\x00\x00" # ext packet id
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12" # Firmware hash, part one
+ "\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e" # Firmware hash, part two
+ '1\xd7B8\x129\xaa\xc3\xe6\x8b\xe2\x01\xd11\x17\x01' # Init packet ECDS, part 1
+ '\x00\xae\x1e\x04\xf9~q\xcd\xbfv"\xdan\xc0f2\xd49' # Init packet ECDS, part 2
+ '\xdc\xc7\xf8\xae\x16VV\x17\x90\xa3\x96\xadxPa\x0b' # Init packet ECDS, part 3
+ 's\xfe\xbdi]\xb2\x95\x81\x99\xe4\xb0\xcf\xe9\xda' # Init packet ECDS, part 4
+ )
+ )
+
+ def test_generate_packet_b(self):
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 0xffeeffee,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [1111, 2222, 3333],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 1,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e"
+ }
+
+ ip = Packet(init_packet_vars)
+ data = ip.generate_packet()
+ self.assertEqual(data, ("\x01\x00" # Device type
+ "\x02\x00" # Device revision
+ "\xee\xff\xee\xff" # App version
+ "\x03\x00" # Softdevice array length
+ "\x57\x04" # Softdevice entry #1
+ "\xae\x08" # Softdevice entry #2
+ "\x05\x0d" # Softdevice entry #3
+ "\x01\x00\x00\x00" # ext packet id
+ "\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12" # Firmware hash, part one
+ "\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e" # Firmware hash, part two
+ )
+ )
+
+ def test_generate_packet_c(self):
+ init_packet_vars = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 0xffeeffee,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [1111, 2222, 3333],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 0,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: 0xfaae
+ }
+
+ ip = Packet(init_packet_vars)
+ data = ip.generate_packet()
+ self.assertEqual(data, ("\x01\x00" # Device type
+ "\x02\x00" # Device revision
+ "\xee\xff\xee\xff" # App version
+ "\x03\x00" # Softdevice array length
+ "\x57\x04" # Softdevice entry #1
+ "\xae\x08" # Softdevice entry #2
+ "\x05\x0d" # Softdevice entry #3
+ "\x00\x00\x00\x00" # ext packet id
+ "\xae\xfa" # CRC-16 checksum for firmware
+ )
+ )
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_manifest.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_manifest.py
new file mode 100644
index 0000000..f2755fe
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_manifest.py
@@ -0,0 +1,201 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import copy
+import json
+import unittest
+
+from nordicsemi.dfu.init_packet import PacketField
+from nordicsemi.dfu.manifest import ManifestGenerator, Manifest
+from nordicsemi.dfu.model import HexType
+from nordicsemi.dfu.package import FirmwareKeys
+
+
+class TestManifest(unittest.TestCase):
+ def setUp(self):
+ self.firmwares_data_a = {}
+
+ init_packet_data_a = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 1000,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [22, 11],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 2,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH: 1234,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ '\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e',
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS:
+ '1\xd7B8\x129\xaa\xc3\xe6\x8b\xe2\x01\xd11\x17\x01\x00\xae\x1e\x04\xf9~q\xcd\xbfv"\xdan\xc0f2\xd49' +
+ '\xdc\xc7\xf8\xae\x16VV\x17\x90\xa3\x96\xadxPa\x0bs\xfe\xbdi]\xb2\x95\x81\x99\xe4\xb0\xcf\xe9\xda'
+ }
+
+ self.firmwares_data_a[HexType.APPLICATION] = {
+ FirmwareKeys.BIN_FILENAME: "app_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "app_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data_a,
+ FirmwareKeys.ENCRYPT: False}
+
+ self.firmwares_data_a[HexType.SD_BL] = {
+ FirmwareKeys.BIN_FILENAME: "sd_bl_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "sd_bl_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: copy.copy(init_packet_data_a), # Fake the hash
+ FirmwareKeys.BL_SIZE: 50,
+ FirmwareKeys.SD_SIZE: 90
+ }
+
+ self.firmwares_data_b = {}
+
+ init_packet_data_b = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 1000,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [22, 11],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: 0xfaae
+ }
+
+ self.firmwares_data_b[HexType.APPLICATION] = {
+ FirmwareKeys.BIN_FILENAME: "app_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "app_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data_b
+ }
+
+ self.firmwares_data_b[HexType.BOOTLOADER] = {
+ FirmwareKeys.BIN_FILENAME: "bootloader_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "bootloader_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: copy.copy(init_packet_data_b), # Fake the hash
+ }
+
+ self.firmwares_data_c = {}
+
+ init_packet_data_c = {
+ PacketField.DEVICE_TYPE: 1,
+ PacketField.DEVICE_REVISION: 2,
+ PacketField.APP_VERSION: 1000,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [22, 11],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_CRC16: 0xfaae
+ }
+
+ self.firmwares_data_c[HexType.SOFTDEVICE] = {
+ FirmwareKeys.BIN_FILENAME: "softdevice_fw.bin",
+ FirmwareKeys.DAT_FILENAME: "softdevice_fw.dat",
+ FirmwareKeys.INIT_PACKET_DATA: init_packet_data_c
+ }
+
+ def test_generate_manifest(self):
+ r = ManifestGenerator(0.5, self.firmwares_data_a)
+
+ _json = json.loads(r.generate_manifest())
+
+ # Test for presence of attributes in document
+ self.assertIn('manifest', _json)
+
+ manifest = _json['manifest']
+ self.assertIn('application', manifest)
+
+ application = manifest['application']
+ self.assertIn('init_packet_data', application)
+ self.assertIn('dat_file', application)
+ self.assertIn('bin_file', application)
+
+ init_packet_data = application['init_packet_data']
+ self.assertIn('firmware_hash', init_packet_data)
+ self.assertIn('softdevice_req', init_packet_data)
+ self.assertIn('device_revision', init_packet_data)
+ self.assertIn('device_type', init_packet_data)
+ self.assertIn('application_version', init_packet_data)
+
+ # Test for values in document
+ self.assertEqual("app_fw.bin", application['bin_file'])
+ self.assertEqual("app_fw.dat", application['dat_file'])
+
+ self.assertEqual(2, init_packet_data['ext_packet_id'])
+ self.assertEqual(1234, init_packet_data['firmware_length'])
+ self.assertEqual('c9d3bf69f21e88a0311e0dd242536112f842579bef265a24bd0255fd443f759e',
+ init_packet_data['firmware_hash'])
+ self.assertEqual('31d742381239aac3e68be201d131170100ae1e04f97e71cdbf7622da6ec06632d439dcc7f8ae1656561790a396ad7850610b73febd695db2958199e4b0cfe9da',
+ init_packet_data['init_packet_ecds'])
+ self.assertEqual(1000, init_packet_data['application_version'])
+ self.assertEqual(1, init_packet_data['device_type'])
+ self.assertEqual(2, init_packet_data['device_revision'])
+ self.assertEqual([22, 11], init_packet_data['softdevice_req'])
+
+ # Test softdevice_bootloader
+ bl_sd = manifest['softdevice_bootloader']
+ self.assertIsNotNone(bl_sd)
+ self.assertEqual(90, bl_sd['sd_size'])
+ self.assertEqual(50, bl_sd['bl_size'])
+
+ # Test for values in document
+ self.assertEqual("sd_bl_fw.bin", bl_sd['bin_file'])
+ self.assertEqual("sd_bl_fw.dat", bl_sd['dat_file'])
+
+ def test_manifest_a(self):
+ r = ManifestGenerator(0.5, self.firmwares_data_a)
+ m = Manifest.from_json(r.generate_manifest())
+ self.assertIsNotNone(m)
+ self.assertIsNotNone(m.application)
+ self.assertEqual("app_fw.bin", m.application.bin_file)
+ self.assertEqual("app_fw.dat", m.application.dat_file)
+ self.assertIsNone(m.bootloader)
+ self.assertIsNone(m.softdevice)
+ self.assertIsNotNone(m.softdevice_bootloader)
+ self.assertEqual(90, m.softdevice_bootloader.sd_size)
+ self.assertEqual(50, m.softdevice_bootloader.bl_size)
+ self.assertEqual("sd_bl_fw.bin", m.softdevice_bootloader.bin_file)
+ self.assertEqual("sd_bl_fw.dat", m.softdevice_bootloader.dat_file)
+
+ def test_manifest_b(self):
+ r = ManifestGenerator("0.5", self.firmwares_data_b)
+ m = Manifest.from_json(r.generate_manifest())
+ self.assertIsNotNone(m)
+ self.assertIsNotNone(m.application)
+ self.assertEqual("app_fw.bin", m.application.bin_file)
+ self.assertEqual("app_fw.dat", m.application.dat_file)
+ self.assertIsNotNone(m.bootloader)
+ self.assertEqual("bootloader_fw.bin", m.bootloader.bin_file)
+ self.assertEqual("bootloader_fw.dat", m.bootloader.dat_file)
+ self.assertIsNone(m.softdevice)
+ self.assertIsNone(m.softdevice_bootloader)
+ self.assertEqual(0xfaae, m.application.init_packet_data.firmware_crc16)
+ self.assertEqual(0xfaae, m.bootloader.init_packet_data.firmware_crc16)
+
+
+ def test_manifest_c(self):
+ r = ManifestGenerator("0.5", self.firmwares_data_c)
+ m = Manifest.from_json(r.generate_manifest())
+ self.assertIsNotNone(m)
+ self.assertIsNone(m.application)
+ self.assertIsNone(m.bootloader)
+ self.assertIsNotNone(m.softdevice)
+ self.assertEqual('softdevice_fw.bin', m.softdevice.bin_file)
+ self.assertEqual('softdevice_fw.dat', m.softdevice.dat_file)
+ self.assertIsNone(m.softdevice_bootloader)
+ self.assertEqual(0xfaae, m.softdevice.init_packet_data.firmware_crc16)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_nrfhex.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_nrfhex.py
new file mode 100644
index 0000000..e2f2f2d
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_nrfhex.py
@@ -0,0 +1,134 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+
+import unittest
+import nordicsemi.dfu.nrfhex as nrfhex
+import nordicsemi.dfu.intelhex as intelhex
+
+
+class TestnRFHex(unittest.TestCase):
+ def setUp(self):
+ script_abspath = os.path.abspath(__file__)
+ script_dirname = os.path.dirname(script_abspath)
+ os.chdir(script_dirname)
+
+ def comparefiles(self, actual, wanted):
+ actualfile = intelhex.IntelHex()
+ actualfile.loadfile(actual, format="bin")
+
+ wantedfile = intelhex.IntelHex()
+ wantedfile.loadfile(wanted, format="bin")
+
+ self.assertEqual(actualfile.minaddr(), wantedfile.minaddr())
+ self.assertEqual(actualfile.maxaddr(), wantedfile.maxaddr())
+
+ minaddress = actualfile.minaddr()
+ maxaddress = actualfile.maxaddr()
+
+ length = maxaddress - minaddress
+
+ actualfile_data = actualfile.gets(minaddress, length)
+ wantedfile_data = wantedfile.gets(minaddress, length)
+
+ self.assertEqual(actualfile_data, wantedfile_data)
+
+ def test_tobinfile_single_file_without_uicr_content(self):
+ nrf = nrfhex.nRFHex("firmwares/bar.hex")
+ nrf.tobinfile("firmwares/bar.bin")
+
+ self.comparefiles("firmwares/bar.bin", "firmwares/bar_wanted.bin")
+
+ def test_tobinfile_single_file_with_uicr_content(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex")
+ nrf.tobinfile("firmwares/foo.bin")
+
+ self.comparefiles("firmwares/foo.bin", "firmwares/foo_wanted.bin")
+
+ def test_tobinfile_single_bin_file(self):
+ nrf = nrfhex.nRFHex("firmwares/bar_wanted.bin")
+ nrf.tobinfile("firmwares/bar.bin")
+
+ self.comparefiles("firmwares/bar.bin", "firmwares/bar_wanted.bin")
+
+ def test_tobinfile_two_hex_files(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar.hex")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_tobinfile_one_hex_one_bin(self):
+ nrf = nrfhex.nRFHex("firmwares/foo_wanted.bin", "firmwares/bar.hex")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_tobinfile_one_bin_one_hex(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar_wanted.bin")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_tobinfile_two_bin(self):
+ nrf = nrfhex.nRFHex("firmwares/foo_wanted.bin", "firmwares/bar_wanted.bin")
+ nrf.tobinfile("firmwares/foobar.bin")
+
+ self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin")
+
+ def test_sizes(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar.hex")
+
+ self.assertEqual(nrf.get_mbr_end_address(), 0x1000)
+ self.assertEqual(nrf.minaddr(), 0x1000)
+ self.assertEqual(nrf.size(), 73152)
+ self.assertEqual(nrf.bootloadersize(), 13192)
+
+ nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex")
+
+ self.assertEqual(nrf.get_mbr_end_address(), 0x3000)
+ self.assertEqual(nrf.minaddr(), 0x3000)
+ self.assertEqual(nrf.size(), 12288)
+ self.assertEqual(nrf.bootloadersize(), 0)
+
+ def test_get_softdevice_variant(self):
+ nrf = nrfhex.nRFHex("firmwares/foo.hex")
+
+ self.assertEqual(nrf.get_softdevice_variant(), "unknown")
+
+ nrf = nrfhex.nRFHex("firmwares/s130_nrf51_mini.hex")
+
+ self.assertEqual(nrf.get_softdevice_variant(), "s1x0")
+
+ nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex")
+
+ self.assertEqual(nrf.get_softdevice_variant(), "s132")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_package.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_package.py
new file mode 100644
index 0000000..36dbda0
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_package.py
@@ -0,0 +1,164 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json
+import os
+import tempfile
+import unittest
+from zipfile import ZipFile
+import shutil
+
+from nordicsemi.dfu.package import Package
+
+
+class TestPackage(unittest.TestCase):
+ def setUp(self):
+ self.work_directory = tempfile.mkdtemp(prefix="nrf_dfu_tests_")
+
+ def tearDown(self):
+ shutil.rmtree(self.work_directory, ignore_errors=True)
+
+ def test_generate_package_application(self):
+ self.p = Package(
+ dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xfffe],
+ app_fw="firmwares/bar.hex"
+ )
+
+ pkg_name = "mypackage.zip"
+
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+ expected_zip_content = ["manifest.json", "bar.bin", "bar.dat"]
+
+ with ZipFile(pkg_name, 'r') as pkg:
+ infolist = pkg.infolist()
+
+ for file_information in infolist:
+ self.assertTrue(file_information.filename in expected_zip_content)
+ self.assertGreater(file_information.file_size, 0)
+
+ # Extract all and load json document to see if it is correct regarding to paths
+ pkg.extractall(self.work_directory)
+
+ with open(os.path.join(self.work_directory, 'manifest.json'), 'r') as f:
+ _json = json.load(f)
+ self.assertEqual(u'bar.bin', _json['manifest']['application']['bin_file'])
+ self.assertEqual(u'bar.dat', _json['manifest']['application']['dat_file'])
+ self.assertTrue(u'softdevice' not in _json['manifest'])
+ self.assertTrue(u'softdevice_bootloader' not in _json['manifest'])
+ self.assertTrue(u'bootloader' not in _json['manifest'])
+
+ def test_generate_package_sd_bl(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xfffe],
+ softdevice_fw="firmwares/foo.hex",
+ bootloader_fw="firmwares/bar.hex")
+
+ pkg_name = "mypackage.zip"
+
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ expected_zip_content = ["manifest.json", "sd_bl.bin", "sd_bl.dat"]
+
+ with ZipFile(pkg_name, 'r') as pkg:
+ infolist = pkg.infolist()
+
+ for file_information in infolist:
+ self.assertTrue(file_information.filename in expected_zip_content)
+ self.assertGreater(file_information.file_size, 0)
+
+ # Extract all and load json document to see if it is correct regarding to paths
+ pkg.extractall(self.work_directory)
+
+ with open(os.path.join(self.work_directory, 'manifest.json'), 'r') as f:
+ _json = json.load(f)
+ self.assertEqual(u'sd_bl.bin', _json['manifest']['softdevice_bootloader']['bin_file'])
+ self.assertEqual(u'sd_bl.dat', _json['manifest']['softdevice_bootloader']['dat_file'])
+
+ def test_unpack_package_a(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xffff],
+ softdevice_fw="firmwares/bar.hex",
+ dfu_ver=0.6)
+ pkg_name = os.path.join(self.work_directory, "mypackage.zip")
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ unpacked_dir = os.path.join(self.work_directory, "unpacked")
+ manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir)
+ self.assertIsNotNone(manifest)
+ self.assertEqual(u'bar.bin', manifest.softdevice.bin_file)
+ self.assertEqual(0, manifest.softdevice.init_packet_data.ext_packet_id)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.firmware_crc16)
+
+ def test_unpack_package_b(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xffff],
+ softdevice_fw="firmwares/bar.hex",
+ dfu_ver=0.7)
+ pkg_name = os.path.join(self.work_directory, "mypackage.zip")
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ unpacked_dir = os.path.join(self.work_directory, "unpacked")
+ manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir)
+ self.assertIsNotNone(manifest)
+ self.assertEqual(u'bar.bin', manifest.softdevice.bin_file)
+ self.assertEqual(1, manifest.softdevice.init_packet_data.ext_packet_id)
+ self.assertIsNone(manifest.softdevice.init_packet_data.firmware_crc16)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.firmware_hash)
+
+ def test_unpack_package_c(self):
+ self.p = Package(dev_type=1,
+ dev_rev=2,
+ app_version=100,
+ sd_req=[0x1000, 0xffff],
+ softdevice_fw="firmwares/bar.hex",
+ key_file="key.pem")
+ pkg_name = os.path.join(self.work_directory, "mypackage.zip")
+ self.p.generate_package(pkg_name, preserve_work_directory=False)
+
+ unpacked_dir = os.path.join(self.work_directory, "unpacked")
+ manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir)
+ self.assertIsNotNone(manifest)
+ self.assertEqual(u'bar.bin', manifest.softdevice.bin_file)
+ self.assertEqual(2, manifest.softdevice.init_packet_data.ext_packet_id)
+ self.assertIsNone(manifest.softdevice.init_packet_data.firmware_crc16)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.firmware_hash)
+ self.assertIsNotNone(manifest.softdevice.init_packet_data.init_packet_ecds)
+ self.assertEqual(manifest.dfu_version, 0.8)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_signing.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_signing.py
new file mode 100644
index 0000000..3b19fb0
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/test_signing.py
@@ -0,0 +1,155 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import binascii
+import os
+import shutil
+import tempfile
+import unittest
+
+from nordicsemi.dfu.signing import Signing
+from nordicsemi.dfu.init_packet import Packet, PacketField
+
+
+class TestSinging(unittest.TestCase):
+ def setUp(self):
+ script_abspath = os.path.abspath(__file__)
+ script_dirname = os.path.dirname(script_abspath)
+ os.chdir(script_dirname)
+
+ def test_gen_key(self):
+ self.work_directory = tempfile.mkdtemp(prefix="nrf_signing_tests_")
+
+ key_file_name = 'key.pem'
+ key_file_path = os.path.join(self.work_directory, key_file_name)
+
+ signing = Signing()
+ signing.gen_key(key_file_path)
+
+ self.assertTrue(os.path.exists(key_file_path))
+
+ shutil.rmtree(self.work_directory, ignore_errors=True)
+
+ def test_load_key(self):
+ key_file_name = 'key.pem'
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ self.assertEqual(64, len(binascii.hexlify(signing.sk.to_string())))
+
+ def test_sign_and_verify(self):
+ key_file_name = 'key.pem'
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ init_packet_fields = {
+ PacketField.DEVICE_TYPE: 0xFFFF,
+ PacketField.DEVICE_REVISION: 0xFFFF,
+ PacketField.APP_VERSION: 0xFFFFFFFF,
+ PacketField.REQUIRED_SOFTDEVICES_ARRAY: [0xFFFE],
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 2,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH: 1234,
+ PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
+ '\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e',
+ }
+ init_packet = Packet(init_packet_fields)
+ init_packet_data = init_packet.generate_packet()
+
+ signature = signing.sign(init_packet_data)
+
+ self.assertTrue(signing.verify(init_packet_data, signature))
+
+ init_packet_fields[PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS] = signature
+
+ init_packet = Packet(init_packet_fields)
+ init_packet_data = init_packet.generate_packet()
+
+ self.assertFalse(signing.verify(init_packet_data, signature))
+
+ def test_get_vk(self):
+ key_file_name = 'key.pem'
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_str = signing.get_vk('hex')
+ vk_hex = signing.get_vk_hex()
+ self.assertEqual(vk_hex, vk_str)
+
+ vk_str = signing.get_vk('code')
+ vk_code = signing.get_vk_code()
+ self.assertEqual(vk_code, vk_str)
+
+ vk_str = signing.get_vk('pem')
+ vk_pem = signing.get_vk_pem()
+ self.assertEqual(vk_pem, vk_str)
+
+ def test_get_vk_hex(self):
+ key_file_name = 'key.pem'
+ expected_vk_hex = "Verification key Qx: 658da2eddb981f697dae7220d68217abed3fb87005ec8a05b9b56bbbaa17f460\n" \
+ "Verification key Qy: 909baecdad7226c204b612b662ff4fccbd1b0c90841090d83a59cdad6c981d4c"
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_hex = signing.get_vk_hex()
+
+ self.assertEqual(expected_vk_hex, vk_hex)
+
+ def test_get_vk_code(self):
+ key_file_name = 'key.pem'
+
+ expected_vk_code = "static uint8_t Qx[] = { 0x65, 0x8d, 0xa2, 0xed, 0xdb, 0x98, 0x1f, 0x69, 0x7d, " \
+ "0xae, 0x72, 0x20, 0xd6, 0x82, 0x17, 0xab, 0xed, 0x3f, 0xb8, 0x70, 0x05, 0xec, " \
+ "0x8a, 0x05, 0xb9, 0xb5, 0x6b, 0xbb, 0xaa, 0x17, 0xf4, 0x60 };\n" \
+ "static uint8_t Qy[] = { 0x90, 0x9b, 0xae, 0xcd, 0xad, 0x72, 0x26, 0xc2, 0x04, " \
+ "0xb6, 0x12, 0xb6, 0x62, 0xff, 0x4f, 0xcc, 0xbd, 0x1b, 0x0c, 0x90, 0x84, 0x10, " \
+ "0x90, 0xd8, 0x3a, 0x59, 0xcd, 0xad, 0x6c, 0x98, 0x1d, 0x4c };"
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_code = signing.get_vk_code()
+
+ self.assertEqual(expected_vk_code, vk_code)
+
+ def test_get_vk_pem(self):
+ key_file_name = 'key.pem'
+ expected_vk_pem = "-----BEGIN PUBLIC KEY-----\n" \
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF\n" \
+ "7IoFubVru6oX9GCQm67NrXImwgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA==\n" \
+ "-----END PUBLIC KEY-----\n"
+
+ signing = Signing()
+ signing.load_key(key_file_name)
+
+ vk_pem = signing.get_vk_pem()
+
+ self.assertEqual(expected_vk_pem, vk_pem)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/util.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/util.py
new file mode 100644
index 0000000..a7040fb
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/util.py
@@ -0,0 +1,179 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Nordic libraries
+from nordicsemi.exceptions import NordicSemiException
+
+
+# TODO: Create query function that maps query-result strings with functions
+def query_func(question, default=False):
+ """
+ Ask a string question
+ No input defaults to "no" which results in False
+ """
+ valid = {"yes": True, "y": True, "no": False, "n": False}
+ if default is True:
+ prompt = " [Y/n]"
+ else:
+ prompt = " [y/N]"
+
+ while True:
+ print "%s %s" % (question, prompt)
+ choice = raw_input().lower()
+ if choice == '':
+ return default
+ elif choice in valid:
+ return valid[choice]
+ else:
+ print "Please respond with y/n"
+
+
+def convert_uint16_to_array(value):
+ """
+ Converts a int to an array of 2 bytes (little endian)
+
+ :param int value: int value to convert to list
+ :return list[int]: list with 2 bytes
+ """
+ byte0 = value & 0xFF
+ byte1 = (value >> 8) & 0xFF
+ return [byte0, byte1]
+
+
+def convert_uint32_to_array(value):
+ """
+ Converts a int to an array of 4 bytes (little endian)
+
+ :param int value: int value to convert to list
+ :return list[int]: list with 4 bytes
+ """
+ byte0 = value & 0xFF
+ byte1 = (value >> 8) & 0xFF
+ byte2 = (value >> 16) & 0xFF
+ byte3 = (value >> 24) & 0xFF
+ return [byte0, byte1, byte2, byte3]
+
+
+def slip_parts_to_four_bytes(seq, dip, rp, pkt_type, pkt_len):
+ """
+ Creates a SLIP header.
+
+ For a description of the SLIP header go to:
+ http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00093.html
+
+ :param int seq: Packet sequence number
+ :param int dip: Data integrity check
+ :param int rp: Reliable packet
+ :param pkt_type: Payload packet
+ :param pkt_len: Packet length
+ :return: str with SLIP header
+ """
+ ints = [0, 0, 0, 0]
+ ints[0] = seq | (((seq + 1) % 8) << 3) | (dip << 6) | (rp << 7)
+ ints[1] = pkt_type | ((pkt_len & 0x000F) << 4)
+ ints[2] = (pkt_len & 0x0FF0) >> 4
+ ints[3] = (~(sum(ints[0:3])) + 1) & 0xFF
+
+ return ''.join(chr(b) for b in ints)
+
+
+def int32_to_bytes(value):
+ """
+ Converts a int to a str with 4 bytes
+
+ :param value: int value to convert
+ :return: str with 4 bytes
+ """
+ ints = [0, 0, 0, 0]
+ ints[0] = (value & 0x000000FF)
+ ints[1] = (value & 0x0000FF00) >> 8
+ ints[2] = (value & 0x00FF0000) >> 16
+ ints[3] = (value & 0xFF000000) >> 24
+ return ''.join(chr(b) for b in ints)
+
+
+def int16_to_bytes(value):
+ """
+ Converts a int to a str with 4 bytes
+
+ :param value: int value to convert
+ :return: str with 4 bytes
+ """
+
+ ints = [0, 0]
+ ints[0] = (value & 0x00FF)
+ ints[1] = (value & 0xFF00) >> 8
+ return ''.join(chr(b) for b in ints)
+
+
+def slip_decode_esc_chars(data):
+ """Decode esc characters in a SLIP package.
+
+ Replaces 0xDBDC with 0xCO and 0xDBDD with 0xDB.
+
+ :return: str decoded data
+ :type str data: data to decode
+ """
+ result = []
+ while len(data):
+ char = data.pop(0)
+ if char == 0xDB:
+ char2 = data.pop(0)
+ if char2 == 0xDC:
+ result.append(0xC0)
+ elif char2 == 0xDD:
+ result.append(0xDB)
+ else:
+ raise NordicSemiException('Char 0xDB NOT followed by 0xDC or 0xDD')
+ else:
+ result.append(char)
+ return result
+
+
+def slip_encode_esc_chars(data_in):
+ """Encode esc characters in a SLIP package.
+
+ Replace 0xCO with 0xDBDC and 0xDB with 0xDBDD.
+
+ :type str data_in: str to encode
+ :return: str with encoded packet
+ """
+ result = []
+ data = []
+ for i in data_in:
+ data.append(ord(i))
+
+ while len(data):
+ char = data.pop(0)
+ if char == 0xC0:
+ result.extend([0xDB, 0xDC])
+ elif char == 0xDB:
+ result.extend([0xDB, 0xDD])
+ else:
+ result.append(char)
+ return ''.join(chr(i) for i in result)
diff --git a/circuitpython/lib/nrfutil/nordicsemi/exceptions.py b/circuitpython/lib/nrfutil/nordicsemi/exceptions.py
new file mode 100644
index 0000000..d2ad206
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/exceptions.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+class NordicSemiException(Exception):
+ """
+ Exception used as based exception for other exceptions defined in this package.
+ """
+ pass
+
+
+class NotImplementedException(NordicSemiException):
+ """
+ Exception used when functionality has not been implemented yet.
+ """
+ pass
+
+
+class InvalidArgumentException(NordicSemiException):
+ """"
+ Exception used when a argument is of wrong type
+ """
+ pass
+
+class MissingArgumentException(NordicSemiException):
+ """"
+ Exception used when a argument is missing
+ """
+ pass
+
+
+class IllegalStateException(NordicSemiException):
+ """"
+ Exception used when program is in an illegal state
+ """
+ pass
diff --git a/circuitpython/lib/nrfutil/nordicsemi/utility/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/utility/__init__.py
new file mode 100644
index 0000000..58c0272
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/utility/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.s
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/utility/target_registry.py b/circuitpython/lib/nrfutil/nordicsemi/utility/target_registry.py
new file mode 100644
index 0000000..f87e006
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/utility/target_registry.py
@@ -0,0 +1,121 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import re
+import os
+import json
+from abc import ABCMeta, abstractmethod
+
+
+class TargetDatabase(object):
+ __metaclass__ = ABCMeta
+
+ @abstractmethod
+ def get_targets(self):
+ pass
+
+ @abstractmethod
+ def get_target(self, target_id):
+ pass
+
+ @abstractmethod
+ def refresh(self):
+ pass
+
+ @staticmethod
+ def find_target(targets, target_id):
+ for target in targets:
+ if target["id"] == target_id:
+ return target
+
+ return None
+
+
+class EnvTargetDatabase(TargetDatabase):
+ def __init__(self):
+ self.targets = None
+
+ def get_targets(self):
+ if self.targets is None:
+ self.targets = []
+
+ for key, value in os.environ.iteritems():
+ match = re.match("NORDICSEMI_TARGET_(?P<target>\d+)_(?P<key>[a-zA-Z_]+)", key)
+
+ if match:
+ key_value = match.groupdict()
+ if "key" in key_value and "target" in key_value:
+ target_id = int(key_value["target"])
+
+ target = self.find_target(self.targets, target_id)
+
+ if target is None:
+ target = {"id": int(target_id)}
+ self.targets.append(target)
+
+ target[key_value["key"].lower()] = value
+
+ return self.targets
+
+ def refresh(self):
+ self.targets = None
+
+ def get_target(self, target_id):
+ return self.find_target(self.get_targets(), target_id)
+
+
+class FileTargetDatabase(TargetDatabase):
+ def __init__(self, filename):
+ self.filename = filename
+ self.targets = None
+
+ def get_targets(self):
+ if not self.targets:
+ self.targets = json.load(open(self.filename, "r"))["targets"]
+
+ return self.targets
+
+ def get_target(self, target_id):
+ return self.find_target(self.get_targets(), target_id)
+
+ def refresh(self):
+ self.targets = None
+
+
+class TargetRegistry(object):
+ def __init__(self, target_db=EnvTargetDatabase()):
+ self.target_db = target_db
+
+ def find_one(self, target_id=None):
+ if target_id:
+ return self.target_db.get_target(target_id)
+ else:
+ return None
+
+ def get_all(self):
+ return self.target_db.get_targets()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/utility/tests/__init__.py b/circuitpython/lib/nrfutil/nordicsemi/utility/tests/__init__.py
new file mode 100644
index 0000000..8f8006e
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/utility/tests/__init__.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Package marker file."""
diff --git a/circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_target_registry.py b/circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_target_registry.py
new file mode 100644
index 0000000..1d6df65
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_target_registry.py
@@ -0,0 +1,90 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import unittest
+from nordicsemi.utility.target_registry import TargetRegistry, EnvTargetDatabase
+from nordicsemi.utility.target_registry import FileTargetDatabase
+
+
+class TestTargetRegistry(unittest.TestCase):
+ def setUp(self):
+ script_abspath = os.path.abspath(__file__)
+ script_dirname = os.path.dirname(script_abspath)
+ os.chdir(script_dirname)
+
+ # Setup the environment variables
+ os.environ["NORDICSEMI_TARGET_1_SERIAL_PORT"] = "COM1"
+ os.environ["NORDICSEMI_TARGET_1_PCA"] = "PCA10028"
+ os.environ["NORDICSEMI_TARGET_1_DRIVE"] = "D:\\"
+ os.environ["NORDICSEMI_TARGET_1_SEGGER_SN"] = "1231233333"
+
+ os.environ["NORDICSEMI_TARGET_2_SERIAL_PORT"] = "COM2"
+ os.environ["NORDICSEMI_TARGET_2_PCA"] = "PCA10028"
+ os.environ["NORDICSEMI_TARGET_2_DRIVE"] = "E:\\"
+ os.environ["NORDICSEMI_TARGET_2_SEGGER_SN"] = "3332222111"
+
+ def test_get_targets_from_file(self):
+ target_database = FileTargetDatabase("test_targets.json")
+ target_repository = TargetRegistry(target_db=target_database)
+
+ target = target_repository.find_one(target_id=1)
+ assert target is not None
+ assert target["drive"] == "d:\\"
+ assert target["serial_port"] == "COM7"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "123123123123"
+
+ target = target_repository.find_one(target_id=2)
+ assert target is not None
+ assert target["drive"] == "e:\\"
+ assert target["serial_port"] == "COM8"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "321321321312"
+
+ def test_get_targets_from_environment(self):
+ target_database = EnvTargetDatabase()
+ target_repository = TargetRegistry(target_db=target_database)
+
+ target = target_repository.find_one(target_id=1)
+ assert target is not None
+ assert target["drive"] == "D:\\"
+ assert target["serial_port"] == "COM1"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "1231233333"
+
+ target = target_repository.find_one(target_id=2)
+ assert target is not None
+ assert target["drive"] == "E:\\"
+ assert target["serial_port"] == "COM2"
+ assert target["pca"] == "PCA10028"
+ assert target["segger_sn"] == "3332222111"
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_targets.json b/circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_targets.json
new file mode 100644
index 0000000..2e1ab30
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/utility/tests/test_targets.json
@@ -0,0 +1,17 @@
+{
+ "targets":
+ [{
+ "id": 1,
+ "drive": "d:\\",
+ "serial_port": "COM7",
+ "pca": "PCA10028",
+ "segger_sn": "123123123123"
+ },
+ {
+ "id": 2,
+ "drive": "e:\\",
+ "serial_port": "COM8",
+ "pca": "PCA10028",
+ "segger_sn": "321321321312"
+ }]
+} \ No newline at end of file
diff --git a/circuitpython/lib/nrfutil/nordicsemi/version.py b/circuitpython/lib/nrfutil/nordicsemi/version.py
new file mode 100644
index 0000000..9eec5c2
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/version.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+""" Version definition for nrfutil. """
+
+NRFUTIL_VERSION = "0.5.2d"
diff --git a/circuitpython/lib/nrfutil/nordicsemi/version.pyc b/circuitpython/lib/nrfutil/nordicsemi/version.pyc
new file mode 100644
index 0000000..126f353
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/version.pyc
Binary files differ
diff --git a/circuitpython/lib/nrfutil/nrfutil.egg-info/PKG-INFO b/circuitpython/lib/nrfutil/nrfutil.egg-info/PKG-INFO
new file mode 100644
index 0000000..e1fcafa
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nrfutil.egg-info/PKG-INFO
@@ -0,0 +1,11 @@
+Metadata-Version: 1.1
+Name: nrfutil
+Version: 0.5.2d
+Summary: Nordic Semiconductor nrfutil utility and Python library
+Home-page: https://github.com/NordicSemiconductor/pc-nrfutil
+Author: UNKNOWN
+Author-email: UNKNOWN
+License: Nordic Semicondictor proprietary license
+Description: A Python package that includes the nrfutil utility and the nordicsemi library
+Platform: UNKNOWN
+Classifier: Programming Language :: Python :: 2.7
diff --git a/circuitpython/lib/nrfutil/nrfutil.egg-info/SOURCES.txt b/circuitpython/lib/nrfutil/nrfutil.egg-info/SOURCES.txt
new file mode 100644
index 0000000..f19d8a8
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nrfutil.egg-info/SOURCES.txt
@@ -0,0 +1,43 @@
+setup.py
+nordicsemi/__init__.py
+nordicsemi/__main__.py
+nordicsemi/exceptions.py
+nordicsemi/version.py
+nordicsemi/bluetooth/__init__.py
+nordicsemi/bluetooth/hci/__init__.py
+nordicsemi/bluetooth/hci/codec.py
+nordicsemi/bluetooth/hci/slip.py
+nordicsemi/bluetooth/hci/tests/__init__.py
+nordicsemi/bluetooth/hci/tests/test_codec.py
+nordicsemi/dfu/__init__.py
+nordicsemi/dfu/crc16.py
+nordicsemi/dfu/dfu.py
+nordicsemi/dfu/dfu_transport.py
+nordicsemi/dfu/dfu_transport_ble.py
+nordicsemi/dfu/dfu_transport_serial.py
+nordicsemi/dfu/init_packet.py
+nordicsemi/dfu/manifest.py
+nordicsemi/dfu/model.py
+nordicsemi/dfu/nrfhex.py
+nordicsemi/dfu/package.py
+nordicsemi/dfu/signing.py
+nordicsemi/dfu/util.py
+nordicsemi/dfu/intelhex/__init__.py
+nordicsemi/dfu/intelhex/compat.py
+nordicsemi/dfu/tests/__init__.py
+nordicsemi/dfu/tests/test_dfu_transport_serial.py
+nordicsemi/dfu/tests/test_init_packet.py
+nordicsemi/dfu/tests/test_manifest.py
+nordicsemi/dfu/tests/test_nrfhex.py
+nordicsemi/dfu/tests/test_package.py
+nordicsemi/dfu/tests/test_signing.py
+nordicsemi/utility/__init__.py
+nordicsemi/utility/target_registry.py
+nordicsemi/utility/tests/__init__.py
+nordicsemi/utility/tests/test_target_registry.py
+nrfutil.egg-info/PKG-INFO
+nrfutil.egg-info/SOURCES.txt
+nrfutil.egg-info/dependency_links.txt
+nrfutil.egg-info/entry_points.txt
+nrfutil.egg-info/not-zip-safe
+nrfutil.egg-info/top_level.txt \ No newline at end of file
diff --git a/circuitpython/lib/nrfutil/nrfutil.egg-info/dependency_links.txt b/circuitpython/lib/nrfutil/nrfutil.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nrfutil.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/circuitpython/lib/nrfutil/nrfutil.egg-info/entry_points.txt b/circuitpython/lib/nrfutil/nrfutil.egg-info/entry_points.txt
new file mode 100644
index 0000000..80da469
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nrfutil.egg-info/entry_points.txt
@@ -0,0 +1,4 @@
+
+ [console_scripts]
+ nrfutil = nordicsemi.__main__:cli
+ \ No newline at end of file
diff --git a/circuitpython/lib/nrfutil/nrfutil.egg-info/not-zip-safe b/circuitpython/lib/nrfutil/nrfutil.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nrfutil.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/circuitpython/lib/nrfutil/nrfutil.egg-info/top_level.txt b/circuitpython/lib/nrfutil/nrfutil.egg-info/top_level.txt
new file mode 100644
index 0000000..83c6e6f
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nrfutil.egg-info/top_level.txt
@@ -0,0 +1 @@
+nordicsemi
diff --git a/circuitpython/lib/nrfutil/requirements.txt b/circuitpython/lib/nrfutil/requirements.txt
new file mode 100644
index 0000000..c34bcc9
--- /dev/null
+++ b/circuitpython/lib/nrfutil/requirements.txt
@@ -0,0 +1,5 @@
+ pyserial >= 2.7
+ enum34 >= 1.0.4
+ click == 5.1
+ ecdsa >= 0.13
+ behave
diff --git a/circuitpython/lib/nrfutil/setup.py b/circuitpython/lib/nrfutil/setup.py
new file mode 100644
index 0000000..1b577d2
--- /dev/null
+++ b/circuitpython/lib/nrfutil/setup.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+Setup script for nrfutil.
+
+USAGE:
+ python setup.py install
+ python setup.py py2exe
+
+"""
+import os
+import platform
+
+from setuptools import setup, find_packages
+from setuptools.command.test import test as TestCommand
+#from setuptools_behave import behave_test
+
+from nordicsemi import version
+
+if platform.system() == 'Windows':
+ import py2exe # Required even if it is not used in this file. This import adds py2exe to distutils.
+
+excludes = ["Tkconstants",
+ "Tkinter",
+ "tcl",
+ "pickle",
+ "unittest",
+ "pyreadline"]
+
+# DFU component cli interface
+includes = ["nordicsemi.dfu.dfu"]
+
+packages = []
+
+dll_excludes = [
+ "w9xpopen.exe",
+ "OLEAUT32.DLL",
+ "OLE32.DLL",
+ "USER32.DLL",
+ "SHELL32.DLL",
+ "ADVAPI32.DLL",
+ "KERNEL32.DLL",
+ "WS2_32.DLL",
+ "GDI32.DLL"]
+
+build_dir = os.environ.get("NRFUTIL_BUILD_DIR", "./{}".format(version.NRFUTIL_VERSION))
+description = """A Python package that includes the nrfutil utility and the nordicsemi library"""
+
+
+class NoseTestCommand(TestCommand):
+ def finalize_options(self):
+ TestCommand.finalize_options(self)
+ self.test_args = []
+ self.test_suite = True
+
+ def run_tests(self):
+ import nose
+ nose.run_exit(argv=['nosetests', '--with-xunit', '--xunit-file=test-reports/unittests.xml'])
+
+common_requirements=[]
+
+setup(
+ name="nrfutil",
+ version=version.NRFUTIL_VERSION,
+ license="Nordic Semicondictor proprietary license",
+ url="https://github.com/NordicSemiconductor/pc-nrfutil",
+ description="Nordic Semiconductor nrfutil utility and Python library",
+ long_description=description,
+ packages=find_packages(exclude=["tests.*", "tests"]),
+ include_package_data=False,
+ install_requires=common_requirements,
+ setup_requires=common_requirements,
+ zipfile=None,
+ tests_require=[
+ "nose >= 1.3.4",
+ "behave"
+ ],
+ zip_safe=False,
+ classifiers=[
+ "Programming Language :: Python :: 2.7",
+ ],
+ cmdclass={
+ 'test': NoseTestCommand
+ # 'bdd_test': behave_test
+ },
+ entry_points='''
+ [console_scripts]
+ nrfutil = nordicsemi.__main__:cli
+ ''',
+ console=[{
+ "script": "./nordicsemi/__main__.py",
+ "dest_base": "nrfutil"
+ }],
+ options={
+ "py2exe": {
+ "includes": includes,
+ "excludes": excludes,
+ "ascii": False,
+ "bundle_files": 1, # 1 for bunding into exe, 3 for to distdir
+ "dist_dir": build_dir,
+ "verbose": True,
+ "dll_excludes": dll_excludes
+ }
+ }
+)
diff --git a/circuitpython/lib/nrfutil/tests/bdd/environment.py b/circuitpython/lib/nrfutil/tests/bdd/environment.py
new file mode 100644
index 0000000..dc66699
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/bdd/environment.py
@@ -0,0 +1,37 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+
+logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
+ datefmt='%m-%d %H:%M:%S ', level=logging.DEBUG)
+
+
+def before_all(context):
+ pass
diff --git a/circuitpython/lib/nrfutil/tests/bdd/genpkg_generate_dfu_package.feature b/circuitpython/lib/nrfutil/tests/bdd/genpkg_generate_dfu_package.feature
new file mode 100644
index 0000000..7fec533
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/bdd/genpkg_generate_dfu_package.feature
@@ -0,0 +1,673 @@
+# Notice:
+# It can be smart to use the function util.generate_options_table_for_cucumber() to generate entries in Examples for
+# the options. It will save you a lot of time :-)
+
+Feature: Generate DFU package
+ Scenario Outline: package generation
+ Given the user wants to generate a DFU package with application <application>, bootloader <bootloader> and SoftDevice <softdevice> with name <package>
+ And with option --application-version <app_ver>
+ And with option --dev-revision <dev_rev>
+ And with option --dev-type <dev_type>
+ And with option --dfu-ver <dfu_ver>
+ And with option --sd-req <sd_req>
+ And with option --key-file <pem_file>
+ When user press enter
+ Then the generated DFU package <package> contains correct data
+
+ Examples:
+ | application | bootloader | softdevice | app_ver | dev_rev | dev_type | dfu_ver | sd_req | pem_file | package |
+ | blinky.bin | dfu_test_bootloader_b.hex | dfu_test_softdevice_b.hex | none | none | none | not_set | none | not_set | 111_000000.zip |
+ | blinky.bin | dfu_test_bootloader_b.hex | not_set | none | none | none | not_set | none | not_set | 110_000000.zip |
+ | blinky.bin | not_set | dfu_test_softdevice_b.hex | none | none | none | not_set | none | not_set | 101_000000.zip |
+ | blinky.bin | not_set | not_set | none | none | none | not_set | none | not_set | 100_000000.zip |
+ | not_set | dfu_test_bootloader_b.hex | dfu_test_softdevice_b.hex | none | none | none | not_set | none | not_set | 011_000000.zip |
+ | not_set | dfu_test_bootloader_b.hex | not_set | none | none | none | not_set | none | not_set | 010_000000.zip |
+ | not_set | not_set | dfu_test_softdevice_b.hex | none | none | none | not_set | none | not_set | 001_000000.zip |
+ | blinky.bin | not_set | not_set | none | none | none | not_set | none | not_set | 100_000000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | not_set | none | not_set | 100_000001.zip |
+ | blinky.bin | not_set | not_set | 0xd3 | none | none | not_set | none | not_set | 100_000002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | not_set | none | not_set | 100_000010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | not_set | none | not_set | 100_000011.zip |
+ | blinky.bin | not_set | not_set | 0xcb | not_set | none | not_set | none | not_set | 100_000012.zip |
+ | blinky.bin | not_set | not_set | none | 0x4c | none | not_set | none | not_set | 100_000020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xb6 | none | not_set | none | not_set | 100_000021.zip |
+ | blinky.bin | not_set | not_set | 0x07 | 0x22 | none | not_set | none | not_set | 100_000022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | not_set | none | not_set | 100_000100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | not_set | none | not_set | 100_000101.zip |
+ | blinky.bin | not_set | not_set | 0xdd | none | not_set | not_set | none | not_set | 100_000102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | not_set | none | not_set | 100_000110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | not_set | none | not_set | 100_000111.zip |
+ | blinky.bin | not_set | not_set | 0x19 | not_set | not_set | not_set | none | not_set | 100_000112.zip |
+ | blinky.bin | not_set | not_set | none | 0x19 | not_set | not_set | none | not_set | 100_000120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x92 | not_set | not_set | none | not_set | 100_000121.zip |
+ | blinky.bin | not_set | not_set | 0x28 | 0xe6 | not_set | not_set | none | not_set | 100_000122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xe9 | not_set | none | not_set | 100_000200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x26 | not_set | none | not_set | 100_000201.zip |
+ | blinky.bin | not_set | not_set | 0xea | none | 0xcf | not_set | none | not_set | 100_000202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x57 | not_set | none | not_set | 100_000210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x53 | not_set | none | not_set | 100_000211.zip |
+ | blinky.bin | not_set | not_set | 0xbb | not_set | 0x36 | not_set | none | not_set | 100_000212.zip |
+ | blinky.bin | not_set | not_set | none | 0x01 | 0x1a | not_set | none | not_set | 100_000220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x39 | 0x0e | not_set | none | not_set | 100_000221.zip |
+ | blinky.bin | not_set | not_set | 0x29 | 0x6d | 0x7b | not_set | none | not_set | 100_000222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.5 | none | not_set | 100_001000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.5 | none | not_set | 100_001001.zip |
+ | blinky.bin | not_set | not_set | 0x70 | none | none | 0.5 | none | not_set | 100_001002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.5 | none | not_set | 100_001010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.5 | none | not_set | 100_001011.zip |
+ | blinky.bin | not_set | not_set | 0x57 | not_set | none | 0.5 | none | not_set | 100_001012.zip |
+ | blinky.bin | not_set | not_set | none | 0x2f | none | 0.5 | none | not_set | 100_001020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xc9 | none | 0.5 | none | not_set | 100_001021.zip |
+ | blinky.bin | not_set | not_set | 0x7c | 0x05 | none | 0.5 | none | not_set | 100_001022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.5 | none | not_set | 100_001100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.5 | none | not_set | 100_001101.zip |
+ | blinky.bin | not_set | not_set | 0x18 | none | not_set | 0.5 | none | not_set | 100_001102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.5 | none | not_set | 100_001110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.5 | none | not_set | 100_001111.zip |
+ | blinky.bin | not_set | not_set | 0xec | not_set | not_set | 0.5 | none | not_set | 100_001112.zip |
+ | blinky.bin | not_set | not_set | none | 0x4d | not_set | 0.5 | none | not_set | 100_001120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xa1 | not_set | 0.5 | none | not_set | 100_001121.zip |
+ | blinky.bin | not_set | not_set | 0xb1 | 0xb1 | not_set | 0.5 | none | not_set | 100_001122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x0f | 0.5 | none | not_set | 100_001200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x1f | 0.5 | none | not_set | 100_001201.zip |
+ | blinky.bin | not_set | not_set | 0x75 | none | 0xf4 | 0.5 | none | not_set | 100_001202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x72 | 0.5 | none | not_set | 100_001210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x37 | 0.5 | none | not_set | 100_001211.zip |
+ | blinky.bin | not_set | not_set | 0x41 | not_set | 0x02 | 0.5 | none | not_set | 100_001212.zip |
+ | blinky.bin | not_set | not_set | none | 0xb6 | 0x96 | 0.5 | none | not_set | 100_001220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xaf | 0x38 | 0.5 | none | not_set | 100_001221.zip |
+ | blinky.bin | not_set | not_set | 0xbe | 0x81 | 0x37 | 0.5 | none | not_set | 100_001222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.6 | none | not_set | 100_002000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.6 | none | not_set | 100_002001.zip |
+ | blinky.bin | not_set | not_set | 0x7f | none | none | 0.6 | none | not_set | 100_002002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.6 | none | not_set | 100_002010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.6 | none | not_set | 100_002011.zip |
+ | blinky.bin | not_set | not_set | 0x15 | not_set | none | 0.6 | none | not_set | 100_002012.zip |
+ | blinky.bin | not_set | not_set | none | 0xb8 | none | 0.6 | none | not_set | 100_002020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x92 | none | 0.6 | none | not_set | 100_002021.zip |
+ | blinky.bin | not_set | not_set | 0x6f | 0xf6 | none | 0.6 | none | not_set | 100_002022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.6 | none | not_set | 100_002100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.6 | none | not_set | 100_002101.zip |
+ | blinky.bin | not_set | not_set | 0xfd | none | not_set | 0.6 | none | not_set | 100_002102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.6 | none | not_set | 100_002110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.6 | none | not_set | 100_002111.zip |
+ | blinky.bin | not_set | not_set | 0x19 | not_set | not_set | 0.6 | none | not_set | 100_002112.zip |
+ | blinky.bin | not_set | not_set | none | 0xfc | not_set | 0.6 | none | not_set | 100_002120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xf3 | not_set | 0.6 | none | not_set | 100_002121.zip |
+ | blinky.bin | not_set | not_set | 0x2c | 0x97 | not_set | 0.6 | none | not_set | 100_002122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x54 | 0.6 | none | not_set | 100_002200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xe7 | 0.6 | none | not_set | 100_002201.zip |
+ | blinky.bin | not_set | not_set | 0x71 | none | 0x8c | 0.6 | none | not_set | 100_002202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x74 | 0.6 | none | not_set | 100_002210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x4b | 0.6 | none | not_set | 100_002211.zip |
+ | blinky.bin | not_set | not_set | 0x40 | not_set | 0xd0 | 0.6 | none | not_set | 100_002212.zip |
+ | blinky.bin | not_set | not_set | none | 0x72 | 0x5c | 0.6 | none | not_set | 100_002220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x5f | 0x85 | 0.6 | none | not_set | 100_002221.zip |
+ | blinky.bin | not_set | not_set | 0x6b | 0x9b | 0xaf | 0.6 | none | not_set | 100_002222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.7 | none | not_set | 100_003000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.7 | none | not_set | 100_003001.zip |
+ | blinky.bin | not_set | not_set | 0x0d | none | none | 0.7 | none | not_set | 100_003002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.7 | none | not_set | 100_003010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.7 | none | not_set | 100_003011.zip |
+ | blinky.bin | not_set | not_set | 0x54 | not_set | none | 0.7 | none | not_set | 100_003012.zip |
+ | blinky.bin | not_set | not_set | none | 0xfc | none | 0.7 | none | not_set | 100_003020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x79 | none | 0.7 | none | not_set | 100_003021.zip |
+ | blinky.bin | not_set | not_set | 0xb8 | 0x20 | none | 0.7 | none | not_set | 100_003022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.7 | none | not_set | 100_003100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.7 | none | not_set | 100_003101.zip |
+ | blinky.bin | not_set | not_set | 0xd0 | none | not_set | 0.7 | none | not_set | 100_003102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.7 | none | not_set | 100_003110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.7 | none | not_set | 100_003111.zip |
+ | blinky.bin | not_set | not_set | 0x69 | not_set | not_set | 0.7 | none | not_set | 100_003112.zip |
+ | blinky.bin | not_set | not_set | none | 0x65 | not_set | 0.7 | none | not_set | 100_003120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xd2 | not_set | 0.7 | none | not_set | 100_003121.zip |
+ | blinky.bin | not_set | not_set | 0x48 | 0x65 | not_set | 0.7 | none | not_set | 100_003122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x19 | 0.7 | none | not_set | 100_003200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xe7 | 0.7 | none | not_set | 100_003201.zip |
+ | blinky.bin | not_set | not_set | 0x34 | none | 0x65 | 0.7 | none | not_set | 100_003202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x21 | 0.7 | none | not_set | 100_003210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x3b | 0.7 | none | not_set | 100_003211.zip |
+ | blinky.bin | not_set | not_set | 0x5c | not_set | 0x1f | 0.7 | none | not_set | 100_003212.zip |
+ | blinky.bin | not_set | not_set | none | 0x88 | 0xb3 | 0.7 | none | not_set | 100_003220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xe1 | 0xb5 | 0.7 | none | not_set | 100_003221.zip |
+ | blinky.bin | not_set | not_set | 0x4c | 0xeb | 0x4d | 0.7 | none | not_set | 100_003222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | not_set | not_set | not_set | 100_010000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | not_set | not_set | not_set | 100_010001.zip |
+ | blinky.bin | not_set | not_set | 0x33 | none | none | not_set | not_set | not_set | 100_010002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | not_set | not_set | not_set | 100_010010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | not_set | not_set | not_set | 100_010011.zip |
+ | blinky.bin | not_set | not_set | 0x78 | not_set | none | not_set | not_set | not_set | 100_010012.zip |
+ | blinky.bin | not_set | not_set | none | 0xf7 | none | not_set | not_set | not_set | 100_010020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x23 | none | not_set | not_set | not_set | 100_010021.zip |
+ | blinky.bin | not_set | not_set | 0x06 | 0xf5 | none | not_set | not_set | not_set | 100_010022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | not_set | not_set | not_set | 100_010100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | not_set | not_set | not_set | 100_010101.zip |
+ | blinky.bin | not_set | not_set | 0x88 | none | not_set | not_set | not_set | not_set | 100_010102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | not_set | not_set | not_set | 100_010110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | not_set | not_set | not_set | 100_010111.zip |
+ | blinky.bin | not_set | not_set | 0x15 | not_set | not_set | not_set | not_set | not_set | 100_010112.zip |
+ | blinky.bin | not_set | not_set | none | 0x52 | not_set | not_set | not_set | not_set | 100_010120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x0b | not_set | not_set | not_set | not_set | 100_010121.zip |
+ | blinky.bin | not_set | not_set | 0x49 | 0x52 | not_set | not_set | not_set | not_set | 100_010122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x66 | not_set | not_set | not_set | 100_010200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x62 | not_set | not_set | not_set | 100_010201.zip |
+ | blinky.bin | not_set | not_set | 0x1f | none | 0xdf | not_set | not_set | not_set | 100_010202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x23 | not_set | not_set | not_set | 100_010210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x98 | not_set | not_set | not_set | 100_010211.zip |
+ | blinky.bin | not_set | not_set | 0x28 | not_set | 0x8f | not_set | not_set | not_set | 100_010212.zip |
+ | blinky.bin | not_set | not_set | none | 0xce | 0x5a | not_set | not_set | not_set | 100_010220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x8d | 0x50 | not_set | not_set | not_set | 100_010221.zip |
+ | blinky.bin | not_set | not_set | 0x44 | 0xb3 | 0x8f | not_set | not_set | not_set | 100_010222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.5 | not_set | not_set | 100_011000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.5 | not_set | not_set | 100_011001.zip |
+ | blinky.bin | not_set | not_set | 0x54 | none | none | 0.5 | not_set | not_set | 100_011002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.5 | not_set | not_set | 100_011010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.5 | not_set | not_set | 100_011011.zip |
+ | blinky.bin | not_set | not_set | 0xbe | not_set | none | 0.5 | not_set | not_set | 100_011012.zip |
+ | blinky.bin | not_set | not_set | none | 0xaa | none | 0.5 | not_set | not_set | 100_011020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xf0 | none | 0.5 | not_set | not_set | 100_011021.zip |
+ | blinky.bin | not_set | not_set | 0x19 | 0x4a | none | 0.5 | not_set | not_set | 100_011022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.5 | not_set | not_set | 100_011100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.5 | not_set | not_set | 100_011101.zip |
+ | blinky.bin | not_set | not_set | 0x74 | none | not_set | 0.5 | not_set | not_set | 100_011102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.5 | not_set | not_set | 100_011110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.5 | not_set | not_set | 100_011111.zip |
+ | blinky.bin | not_set | not_set | 0x8b | not_set | not_set | 0.5 | not_set | not_set | 100_011112.zip |
+ | blinky.bin | not_set | not_set | none | 0xc7 | not_set | 0.5 | not_set | not_set | 100_011120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x02 | not_set | 0.5 | not_set | not_set | 100_011121.zip |
+ | blinky.bin | not_set | not_set | 0x98 | 0xb1 | not_set | 0.5 | not_set | not_set | 100_011122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xe5 | 0.5 | not_set | not_set | 100_011200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xad | 0.5 | not_set | not_set | 100_011201.zip |
+ | blinky.bin | not_set | not_set | 0x30 | none | 0x8d | 0.5 | not_set | not_set | 100_011202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x1c | 0.5 | not_set | not_set | 100_011210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x74 | 0.5 | not_set | not_set | 100_011211.zip |
+ | blinky.bin | not_set | not_set | 0xf6 | not_set | 0xdb | 0.5 | not_set | not_set | 100_011212.zip |
+ | blinky.bin | not_set | not_set | none | 0xd9 | 0xe4 | 0.5 | not_set | not_set | 100_011220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x84 | 0x1a | 0.5 | not_set | not_set | 100_011221.zip |
+ | blinky.bin | not_set | not_set | 0x8c | 0x4f | 0xe2 | 0.5 | not_set | not_set | 100_011222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.6 | not_set | not_set | 100_012000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.6 | not_set | not_set | 100_012001.zip |
+ | blinky.bin | not_set | not_set | 0x20 | none | none | 0.6 | not_set | not_set | 100_012002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.6 | not_set | not_set | 100_012010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.6 | not_set | not_set | 100_012011.zip |
+ | blinky.bin | not_set | not_set | 0xae | not_set | none | 0.6 | not_set | not_set | 100_012012.zip |
+ | blinky.bin | not_set | not_set | none | 0x1a | none | 0.6 | not_set | not_set | 100_012020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x18 | none | 0.6 | not_set | not_set | 100_012021.zip |
+ | blinky.bin | not_set | not_set | 0x33 | 0x65 | none | 0.6 | not_set | not_set | 100_012022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.6 | not_set | not_set | 100_012100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.6 | not_set | not_set | 100_012101.zip |
+ | blinky.bin | not_set | not_set | 0x38 | none | not_set | 0.6 | not_set | not_set | 100_012102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.6 | not_set | not_set | 100_012110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.6 | not_set | not_set | 100_012111.zip |
+ | blinky.bin | not_set | not_set | 0xe5 | not_set | not_set | 0.6 | not_set | not_set | 100_012112.zip |
+ | blinky.bin | not_set | not_set | none | 0x74 | not_set | 0.6 | not_set | not_set | 100_012120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xc4 | not_set | 0.6 | not_set | not_set | 100_012121.zip |
+ | blinky.bin | not_set | not_set | 0x45 | 0x51 | not_set | 0.6 | not_set | not_set | 100_012122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x64 | 0.6 | not_set | not_set | 100_012200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x80 | 0.6 | not_set | not_set | 100_012201.zip |
+ | blinky.bin | not_set | not_set | 0x0c | none | 0x39 | 0.6 | not_set | not_set | 100_012202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x96 | 0.6 | not_set | not_set | 100_012210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x33 | 0.6 | not_set | not_set | 100_012211.zip |
+ | blinky.bin | not_set | not_set | 0xba | not_set | 0xbb | 0.6 | not_set | not_set | 100_012212.zip |
+ | blinky.bin | not_set | not_set | none | 0x11 | 0x28 | 0.6 | not_set | not_set | 100_012220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x91 | 0x81 | 0.6 | not_set | not_set | 100_012221.zip |
+ | blinky.bin | not_set | not_set | 0x2b | 0x60 | 0x0c | 0.6 | not_set | not_set | 100_012222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.7 | not_set | not_set | 100_013000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.7 | not_set | not_set | 100_013001.zip |
+ | blinky.bin | not_set | not_set | 0xcf | none | none | 0.7 | not_set | not_set | 100_013002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.7 | not_set | not_set | 100_013010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.7 | not_set | not_set | 100_013011.zip |
+ | blinky.bin | not_set | not_set | 0x2f | not_set | none | 0.7 | not_set | not_set | 100_013012.zip |
+ | blinky.bin | not_set | not_set | none | 0xc3 | none | 0.7 | not_set | not_set | 100_013020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x54 | none | 0.7 | not_set | not_set | 100_013021.zip |
+ | blinky.bin | not_set | not_set | 0x2c | 0x67 | none | 0.7 | not_set | not_set | 100_013022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.7 | not_set | not_set | 100_013100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.7 | not_set | not_set | 100_013101.zip |
+ | blinky.bin | not_set | not_set | 0x04 | none | not_set | 0.7 | not_set | not_set | 100_013102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.7 | not_set | not_set | 100_013110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.7 | not_set | not_set | 100_013111.zip |
+ | blinky.bin | not_set | not_set | 0xe6 | not_set | not_set | 0.7 | not_set | not_set | 100_013112.zip |
+ | blinky.bin | not_set | not_set | none | 0x68 | not_set | 0.7 | not_set | not_set | 100_013120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x72 | not_set | 0.7 | not_set | not_set | 100_013121.zip |
+ | blinky.bin | not_set | not_set | 0x84 | 0x81 | not_set | 0.7 | not_set | not_set | 100_013122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xba | 0.7 | not_set | not_set | 100_013200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x7d | 0.7 | not_set | not_set | 100_013201.zip |
+ | blinky.bin | not_set | not_set | 0xb8 | none | 0x1a | 0.7 | not_set | not_set | 100_013202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0xff | 0.7 | not_set | not_set | 100_013210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0xb8 | 0.7 | not_set | not_set | 100_013211.zip |
+ | blinky.bin | not_set | not_set | 0x94 | not_set | 0x9e | 0.7 | not_set | not_set | 100_013212.zip |
+ | blinky.bin | not_set | not_set | none | 0xc7 | 0x4b | 0.7 | not_set | not_set | 100_013220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x80 | 0x20 | 0.7 | not_set | not_set | 100_013221.zip |
+ | blinky.bin | not_set | not_set | 0xb5 | 0x77 | 0xbf | 0.7 | not_set | not_set | 100_013222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | not_set | 0x9eee,0x7e19,0x1f29 | not_set | 100_020000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | not_set | 0x48b3 | not_set | 100_020001.zip |
+ | blinky.bin | not_set | not_set | 0xc5 | none | none | not_set | 0x358c,0x21ba | not_set | 100_020002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | not_set | 0xd4a1,0x0744 | not_set | 100_020010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | not_set | 0xcdc3 | not_set | 100_020011.zip |
+ | blinky.bin | not_set | not_set | 0xa4 | not_set | none | not_set | 0x65ea,0x9a9e,0x167d | not_set | 100_020012.zip |
+ | blinky.bin | not_set | not_set | none | 0x11 | none | not_set | 0x6b24,0xf50d | not_set | 100_020020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x8c | none | not_set | 0x7f3f,0x14df | not_set | 100_020021.zip |
+ | blinky.bin | not_set | not_set | 0x94 | 0x0e | none | not_set | 0x36aa,0x5f86 | not_set | 100_020022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | not_set | 0x97fc,0x7d68,0x1350 | not_set | 100_020100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | not_set | 0x4487 | not_set | 100_020101.zip |
+ | blinky.bin | not_set | not_set | 0xa9 | none | not_set | not_set | 0x9abf | not_set | 100_020102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | not_set | 0xe61d,0x394f | not_set | 100_020110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | not_set | 0xf6ab,0x6ed8 | not_set | 100_020111.zip |
+ | blinky.bin | not_set | not_set | 0x07 | not_set | not_set | not_set | 0x7d1d | not_set | 100_020112.zip |
+ | blinky.bin | not_set | not_set | none | 0x85 | not_set | not_set | 0xfde4,0xd40c,0xe81f | not_set | 100_020120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xb0 | not_set | not_set | 0x14fd,0x2dab | not_set | 100_020121.zip |
+ | blinky.bin | not_set | not_set | 0xc5 | 0x16 | not_set | not_set | 0x2d78,0x08da,0x2505 | not_set | 100_020122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xe6 | not_set | 0xbb52 | not_set | 100_020200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x2d | not_set | 0x748c | not_set | 100_020201.zip |
+ | blinky.bin | not_set | not_set | 0xdc | none | 0x54 | not_set | 0xc7c2,0xd360,0xad5b,0x1b87 | not_set | 100_020202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x81 | not_set | 0x6b14,0x534f | not_set | 100_020210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x47 | not_set | 0x9bf0,0x5d81,0xe2dd,0x02b2 | not_set | 100_020211.zip |
+ | blinky.bin | not_set | not_set | 0x53 | not_set | 0x96 | not_set | 0x8d27,0x1c8d | not_set | 100_020212.zip |
+ | blinky.bin | not_set | not_set | none | 0x0b | 0x0f | not_set | 0x0f66,0xae4b,0xe10e,0x5687 | not_set | 100_020220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xf5 | 0x9f | not_set | 0xee32,0x81dd | not_set | 100_020221.zip |
+ | blinky.bin | not_set | not_set | 0xce | 0x39 | 0x77 | not_set | 0xe3fc | not_set | 100_020222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.5 | 0x6c13,0xc805 | not_set | 100_021000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.5 | 0xa3ef,0xd077,0xa2f5,0x00e7 | not_set | 100_021001.zip |
+ | blinky.bin | not_set | not_set | 0xcf | none | none | 0.5 | 0xff23,0x5981,0xbedf,0xb817 | not_set | 100_021002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.5 | 0x238d | not_set | 100_021010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.5 | 0xac00,0xaffa,0xb51c,0x8049 | not_set | 100_021011.zip |
+ | blinky.bin | not_set | not_set | 0xcb | not_set | none | 0.5 | 0xf549,0x0cb6,0xa55b | not_set | 100_021012.zip |
+ | blinky.bin | not_set | not_set | none | 0x8b | none | 0.5 | 0xa774,0x2904,0x44ed | not_set | 100_021020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x0f | none | 0.5 | 0x4f42,0x959d,0x1802,0x7ab4 | not_set | 100_021021.zip |
+ | blinky.bin | not_set | not_set | 0x2e | 0xc7 | none | 0.5 | 0x8dd8,0xc966,0xba0a | not_set | 100_021022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.5 | 0x9ae1,0xec05 | not_set | 100_021100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.5 | 0xe650 | not_set | 100_021101.zip |
+ | blinky.bin | not_set | not_set | 0x18 | none | not_set | 0.5 | 0x0d63,0x8d8a | not_set | 100_021102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.5 | 0x8400,0x49e3 | not_set | 100_021110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.5 | 0x2ae0,0x08ed,0xb09e,0xdd0c | not_set | 100_021111.zip |
+ | blinky.bin | not_set | not_set | 0xab | not_set | not_set | 0.5 | 0x86f8,0xb4ff,0x6ff7 | not_set | 100_021112.zip |
+ | blinky.bin | not_set | not_set | none | 0xa8 | not_set | 0.5 | 0xbb0e,0x2ffd | not_set | 100_021120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x57 | not_set | 0.5 | 0xe2ad,0xfdda,0x3d3b | not_set | 100_021121.zip |
+ | blinky.bin | not_set | not_set | 0x66 | 0x49 | not_set | 0.5 | 0x8ed0 | not_set | 100_021122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x96 | 0.5 | 0x85e9 | not_set | 100_021200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x53 | 0.5 | 0x7434 | not_set | 100_021201.zip |
+ | blinky.bin | not_set | not_set | 0x5f | none | 0xa9 | 0.5 | 0xdeab,0xccda,0x7ee3,0x2c2f | not_set | 100_021202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x8a | 0.5 | 0xb7ac,0xc007,0xad41,0xfe30 | not_set | 100_021210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x28 | 0.5 | 0x0942 | not_set | 100_021211.zip |
+ | blinky.bin | not_set | not_set | 0xcd | not_set | 0x3c | 0.5 | 0x590d,0x49e9 | not_set | 100_021212.zip |
+ | blinky.bin | not_set | not_set | none | 0x08 | 0xe1 | 0.5 | 0xb01e,0xe190,0x4825 | not_set | 100_021220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x27 | 0x7e | 0.5 | 0x2fbb | not_set | 100_021221.zip |
+ | blinky.bin | not_set | not_set | 0xf2 | 0x15 | 0xba | 0.5 | 0x3b61,0x8636 | not_set | 100_021222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.6 | 0xfc23,0x3777 | not_set | 100_022000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.6 | 0x7930,0xbc19 | not_set | 100_022001.zip |
+ | blinky.bin | not_set | not_set | 0x87 | none | none | 0.6 | 0x51ee,0x9228 | not_set | 100_022002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.6 | 0x583c,0x8601 | not_set | 100_022010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.6 | 0x2a67,0x0283,0xdc4b | not_set | 100_022011.zip |
+ | blinky.bin | not_set | not_set | 0xcb | not_set | none | 0.6 | 0xa044 | not_set | 100_022012.zip |
+ | blinky.bin | not_set | not_set | none | 0x50 | none | 0.6 | 0x3afc,0xd36a,0x68c8,0xf66b | not_set | 100_022020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xa6 | none | 0.6 | 0xb26b | not_set | 100_022021.zip |
+ | blinky.bin | not_set | not_set | 0x24 | 0x26 | none | 0.6 | 0x23c6 | not_set | 100_022022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.6 | 0xe825 | not_set | 100_022100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.6 | 0xbe95 | not_set | 100_022101.zip |
+ | blinky.bin | not_set | not_set | 0x28 | none | not_set | 0.6 | 0x061e,0x1c6d,0xa02d,0xeb9f | not_set | 100_022102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.6 | 0xccc6 | not_set | 100_022110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.6 | 0x2cf4,0x3dbf,0x3015,0x3a11 | not_set | 100_022111.zip |
+ | blinky.bin | not_set | not_set | 0x69 | not_set | not_set | 0.6 | 0x49d8 | not_set | 100_022112.zip |
+ | blinky.bin | not_set | not_set | none | 0x07 | not_set | 0.6 | 0x5816,0xeae2,0x4c5c,0x164b | not_set | 100_022120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x14 | not_set | 0.6 | 0x3513,0x0464 | not_set | 100_022121.zip |
+ | blinky.bin | not_set | not_set | 0xba | 0x44 | not_set | 0.6 | 0x98cb,0x3f0b,0xea9a | not_set | 100_022122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x7f | 0.6 | 0xa301,0xb7c7,0x8baa,0xf91a | not_set | 100_022200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xf6 | 0.6 | 0x79f4,0x0a71,0x7153 | not_set | 100_022201.zip |
+ | blinky.bin | not_set | not_set | 0xa1 | none | 0x6e | 0.6 | 0x12d3,0xbd74,0xd1ce,0xf24f | not_set | 100_022202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x12 | 0.6 | 0xa75c,0xc411,0xe043 | not_set | 100_022210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x3f | 0.6 | 0x5e94,0x434e,0xfba2,0x672b | not_set | 100_022211.zip |
+ | blinky.bin | not_set | not_set | 0x84 | not_set | 0xa8 | 0.6 | 0x639e | not_set | 100_022212.zip |
+ | blinky.bin | not_set | not_set | none | 0x57 | 0x8a | 0.6 | 0x7689,0xbecb,0xb70a,0x7aed | not_set | 100_022220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x75 | 0xaf | 0.6 | 0x6f95 | not_set | 100_022221.zip |
+ | blinky.bin | not_set | not_set | 0xdd | 0x35 | 0xe1 | 0.6 | 0x77ee,0xcfcb,0xe477 | not_set | 100_022222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.7 | 0x8d22,0x01b5,0x8215,0xc099 | not_set | 100_023000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.7 | 0x6f64,0x88f7,0xb87e,0xedd2 | not_set | 100_023001.zip |
+ | blinky.bin | not_set | not_set | 0x1c | none | none | 0.7 | 0x22d0 | not_set | 100_023002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.7 | 0xd22b,0x47d4,0xdc8c,0x2e63 | not_set | 100_023010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.7 | 0xfbef | not_set | 100_023011.zip |
+ | blinky.bin | not_set | not_set | 0x04 | not_set | none | 0.7 | 0x4d1b,0x4fd9,0x2909,0x57b6 | not_set | 100_023012.zip |
+ | blinky.bin | not_set | not_set | none | 0x02 | none | 0.7 | 0x0601,0xfadf,0xa309 | not_set | 100_023020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x2e | none | 0.7 | 0xeeb4,0x296c,0xb5d5 | not_set | 100_023021.zip |
+ | blinky.bin | not_set | not_set | 0x1c | 0xa7 | none | 0.7 | 0xf8d5,0x69d5,0x8470 | not_set | 100_023022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.7 | 0x2e79,0x0f64 | not_set | 100_023100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.7 | 0x11a0 | not_set | 100_023101.zip |
+ | blinky.bin | not_set | not_set | 0x5d | none | not_set | 0.7 | 0x4f17 | not_set | 100_023102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.7 | 0x9cda,0x7c3b | not_set | 100_023110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.7 | 0x1770,0x889f | not_set | 100_023111.zip |
+ | blinky.bin | not_set | not_set | 0xd1 | not_set | not_set | 0.7 | 0x0e09,0x2c98 | not_set | 100_023112.zip |
+ | blinky.bin | not_set | not_set | none | 0x20 | not_set | 0.7 | 0x2c87,0x36e8,0xc2aa | not_set | 100_023120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x67 | not_set | 0.7 | 0x12b8,0x60ec,0x39da | not_set | 100_023121.zip |
+ | blinky.bin | not_set | not_set | 0xfe | 0x37 | not_set | 0.7 | 0xe971,0xc49e | not_set | 100_023122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x4a | 0.7 | 0x655d,0x595d | not_set | 100_023200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xed | 0.7 | 0x1bb3,0xcb67,0x4c69 | not_set | 100_023201.zip |
+ | blinky.bin | not_set | not_set | 0x5f | none | 0xe1 | 0.7 | 0x4aca,0xbea2 | not_set | 100_023202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x09 | 0.7 | 0xc4bd,0x086d,0xb12a,0x5218 | not_set | 100_023210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x43 | 0.7 | 0x4336,0x7805 | not_set | 100_023211.zip |
+ | blinky.bin | not_set | not_set | 0x5a | not_set | 0x57 | 0.7 | 0x5d40,0xf31f | not_set | 100_023212.zip |
+ | blinky.bin | not_set | not_set | none | 0x22 | 0xcc | 0.7 | 0xe5c8 | not_set | 100_023220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xc0 | 0x6c | 0.7 | 0xfe83 | not_set | 100_023221.zip |
+ | blinky.bin | not_set | not_set | 0x7d | 0xa2 | 0xe5 | 0.7 | 0xd584,0xbbbb,0x2804 | not_set | 100_023222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | not_set | none | test.pem | 100_100000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | not_set | none | test.pem | 100_100001.zip |
+ | blinky.bin | not_set | not_set | 0x11 | none | none | not_set | none | test.pem | 100_100002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | not_set | none | test.pem | 100_100010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | not_set | none | test.pem | 100_100011.zip |
+ | blinky.bin | not_set | not_set | 0xbe | not_set | none | not_set | none | test.pem | 100_100012.zip |
+ | blinky.bin | not_set | not_set | none | 0x43 | none | not_set | none | test.pem | 100_100020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xa6 | none | not_set | none | test.pem | 100_100021.zip |
+ | blinky.bin | not_set | not_set | 0xd8 | 0x0a | none | not_set | none | test.pem | 100_100022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | not_set | none | test.pem | 100_100100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | not_set | none | test.pem | 100_100101.zip |
+ | blinky.bin | not_set | not_set | 0xae | none | not_set | not_set | none | test.pem | 100_100102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | not_set | none | test.pem | 100_100110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | not_set | none | test.pem | 100_100111.zip |
+ | blinky.bin | not_set | not_set | 0x91 | not_set | not_set | not_set | none | test.pem | 100_100112.zip |
+ | blinky.bin | not_set | not_set | none | 0x35 | not_set | not_set | none | test.pem | 100_100120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xfe | not_set | not_set | none | test.pem | 100_100121.zip |
+ | blinky.bin | not_set | not_set | 0xfc | 0x45 | not_set | not_set | none | test.pem | 100_100122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xf7 | not_set | none | test.pem | 100_100200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x7a | not_set | none | test.pem | 100_100201.zip |
+ | blinky.bin | not_set | not_set | 0x5f | none | 0x93 | not_set | none | test.pem | 100_100202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x51 | not_set | none | test.pem | 100_100210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0xce | not_set | none | test.pem | 100_100211.zip |
+ | blinky.bin | not_set | not_set | 0xe5 | not_set | 0xd1 | not_set | none | test.pem | 100_100212.zip |
+ | blinky.bin | not_set | not_set | none | 0xd4 | 0xc3 | not_set | none | test.pem | 100_100220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xed | 0xa4 | not_set | none | test.pem | 100_100221.zip |
+ | blinky.bin | not_set | not_set | 0xac | 0x6f | 0x9c | not_set | none | test.pem | 100_100222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.5 | none | test.pem | 100_101000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.5 | none | test.pem | 100_101001.zip |
+ | blinky.bin | not_set | not_set | 0x1f | none | none | 0.5 | none | test.pem | 100_101002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.5 | none | test.pem | 100_101010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.5 | none | test.pem | 100_101011.zip |
+ | blinky.bin | not_set | not_set | 0x5d | not_set | none | 0.5 | none | test.pem | 100_101012.zip |
+ | blinky.bin | not_set | not_set | none | 0xec | none | 0.5 | none | test.pem | 100_101020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x6e | none | 0.5 | none | test.pem | 100_101021.zip |
+ | blinky.bin | not_set | not_set | 0x55 | 0x2d | none | 0.5 | none | test.pem | 100_101022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.5 | none | test.pem | 100_101100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.5 | none | test.pem | 100_101101.zip |
+ | blinky.bin | not_set | not_set | 0xfc | none | not_set | 0.5 | none | test.pem | 100_101102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.5 | none | test.pem | 100_101110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.5 | none | test.pem | 100_101111.zip |
+ | blinky.bin | not_set | not_set | 0xdb | not_set | not_set | 0.5 | none | test.pem | 100_101112.zip |
+ | blinky.bin | not_set | not_set | none | 0xb1 | not_set | 0.5 | none | test.pem | 100_101120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x10 | not_set | 0.5 | none | test.pem | 100_101121.zip |
+ | blinky.bin | not_set | not_set | 0xd4 | 0x9a | not_set | 0.5 | none | test.pem | 100_101122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xac | 0.5 | none | test.pem | 100_101200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x2e | 0.5 | none | test.pem | 100_101201.zip |
+ | blinky.bin | not_set | not_set | 0x8d | none | 0x93 | 0.5 | none | test.pem | 100_101202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x4e | 0.5 | none | test.pem | 100_101210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x5e | 0.5 | none | test.pem | 100_101211.zip |
+ | blinky.bin | not_set | not_set | 0x78 | not_set | 0x53 | 0.5 | none | test.pem | 100_101212.zip |
+ | blinky.bin | not_set | not_set | none | 0x76 | 0x7e | 0.5 | none | test.pem | 100_101220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x3b | 0x97 | 0.5 | none | test.pem | 100_101221.zip |
+ | blinky.bin | not_set | not_set | 0x71 | 0xe9 | 0xbc | 0.5 | none | test.pem | 100_101222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.6 | none | test.pem | 100_102000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.6 | none | test.pem | 100_102001.zip |
+ | blinky.bin | not_set | not_set | 0xe9 | none | none | 0.6 | none | test.pem | 100_102002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.6 | none | test.pem | 100_102010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.6 | none | test.pem | 100_102011.zip |
+ | blinky.bin | not_set | not_set | 0xa2 | not_set | none | 0.6 | none | test.pem | 100_102012.zip |
+ | blinky.bin | not_set | not_set | none | 0x26 | none | 0.6 | none | test.pem | 100_102020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x99 | none | 0.6 | none | test.pem | 100_102021.zip |
+ | blinky.bin | not_set | not_set | 0x72 | 0x3e | none | 0.6 | none | test.pem | 100_102022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.6 | none | test.pem | 100_102100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.6 | none | test.pem | 100_102101.zip |
+ | blinky.bin | not_set | not_set | 0x17 | none | not_set | 0.6 | none | test.pem | 100_102102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.6 | none | test.pem | 100_102110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.6 | none | test.pem | 100_102111.zip |
+ | blinky.bin | not_set | not_set | 0x9c | not_set | not_set | 0.6 | none | test.pem | 100_102112.zip |
+ | blinky.bin | not_set | not_set | none | 0xb9 | not_set | 0.6 | none | test.pem | 100_102120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x91 | not_set | 0.6 | none | test.pem | 100_102121.zip |
+ | blinky.bin | not_set | not_set | 0x5a | 0x17 | not_set | 0.6 | none | test.pem | 100_102122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x11 | 0.6 | none | test.pem | 100_102200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x8b | 0.6 | none | test.pem | 100_102201.zip |
+ | blinky.bin | not_set | not_set | 0x61 | none | 0x01 | 0.6 | none | test.pem | 100_102202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0xf4 | 0.6 | none | test.pem | 100_102210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x3e | 0.6 | none | test.pem | 100_102211.zip |
+ | blinky.bin | not_set | not_set | 0xb9 | not_set | 0xe4 | 0.6 | none | test.pem | 100_102212.zip |
+ | blinky.bin | not_set | not_set | none | 0xf3 | 0xcb | 0.6 | none | test.pem | 100_102220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x8d | 0xdd | 0.6 | none | test.pem | 100_102221.zip |
+ | blinky.bin | not_set | not_set | 0x69 | 0xa7 | 0xf3 | 0.6 | none | test.pem | 100_102222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.7 | none | test.pem | 100_103000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.7 | none | test.pem | 100_103001.zip |
+ | blinky.bin | not_set | not_set | 0xfe | none | none | 0.7 | none | test.pem | 100_103002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.7 | none | test.pem | 100_103010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.7 | none | test.pem | 100_103011.zip |
+ | blinky.bin | not_set | not_set | 0xdb | not_set | none | 0.7 | none | test.pem | 100_103012.zip |
+ | blinky.bin | not_set | not_set | none | 0xfa | none | 0.7 | none | test.pem | 100_103020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x3d | none | 0.7 | none | test.pem | 100_103021.zip |
+ | blinky.bin | not_set | not_set | 0xe1 | 0xc7 | none | 0.7 | none | test.pem | 100_103022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.7 | none | test.pem | 100_103100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.7 | none | test.pem | 100_103101.zip |
+ | blinky.bin | not_set | not_set | 0x74 | none | not_set | 0.7 | none | test.pem | 100_103102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.7 | none | test.pem | 100_103110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.7 | none | test.pem | 100_103111.zip |
+ | blinky.bin | not_set | not_set | 0xc2 | not_set | not_set | 0.7 | none | test.pem | 100_103112.zip |
+ | blinky.bin | not_set | not_set | none | 0x0a | not_set | 0.7 | none | test.pem | 100_103120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x3b | not_set | 0.7 | none | test.pem | 100_103121.zip |
+ | blinky.bin | not_set | not_set | 0x64 | 0xda | not_set | 0.7 | none | test.pem | 100_103122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x22 | 0.7 | none | test.pem | 100_103200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x32 | 0.7 | none | test.pem | 100_103201.zip |
+ | blinky.bin | not_set | not_set | 0xc8 | none | 0x2a | 0.7 | none | test.pem | 100_103202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x46 | 0.7 | none | test.pem | 100_103210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0xf5 | 0.7 | none | test.pem | 100_103211.zip |
+ | blinky.bin | not_set | not_set | 0xb6 | not_set | 0x5e | 0.7 | none | test.pem | 100_103212.zip |
+ | blinky.bin | not_set | not_set | none | 0x75 | 0xf6 | 0.7 | none | test.pem | 100_103220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xd7 | 0xc6 | 0.7 | none | test.pem | 100_103221.zip |
+ | blinky.bin | not_set | not_set | 0xe0 | 0xe5 | 0xb2 | 0.7 | none | test.pem | 100_103222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | not_set | not_set | test.pem | 100_110000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | not_set | not_set | test.pem | 100_110001.zip |
+ | blinky.bin | not_set | not_set | 0xd4 | none | none | not_set | not_set | test.pem | 100_110002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | not_set | not_set | test.pem | 100_110010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | not_set | not_set | test.pem | 100_110011.zip |
+ | blinky.bin | not_set | not_set | 0x15 | not_set | none | not_set | not_set | test.pem | 100_110012.zip |
+ | blinky.bin | not_set | not_set | none | 0x5d | none | not_set | not_set | test.pem | 100_110020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x0e | none | not_set | not_set | test.pem | 100_110021.zip |
+ | blinky.bin | not_set | not_set | 0x08 | 0x5e | none | not_set | not_set | test.pem | 100_110022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | not_set | not_set | test.pem | 100_110100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | not_set | not_set | test.pem | 100_110101.zip |
+ | blinky.bin | not_set | not_set | 0xf9 | none | not_set | not_set | not_set | test.pem | 100_110102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | not_set | not_set | test.pem | 100_110110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | not_set | not_set | test.pem | 100_110111.zip |
+ | blinky.bin | not_set | not_set | 0x38 | not_set | not_set | not_set | not_set | test.pem | 100_110112.zip |
+ | blinky.bin | not_set | not_set | none | 0xb6 | not_set | not_set | not_set | test.pem | 100_110120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x19 | not_set | not_set | not_set | test.pem | 100_110121.zip |
+ | blinky.bin | not_set | not_set | 0x9d | 0xae | not_set | not_set | not_set | test.pem | 100_110122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xaf | not_set | not_set | test.pem | 100_110200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xdc | not_set | not_set | test.pem | 100_110201.zip |
+ | blinky.bin | not_set | not_set | 0xfa | none | 0x14 | not_set | not_set | test.pem | 100_110202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0xc5 | not_set | not_set | test.pem | 100_110210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x1a | not_set | not_set | test.pem | 100_110211.zip |
+ | blinky.bin | not_set | not_set | 0x7f | not_set | 0xd9 | not_set | not_set | test.pem | 100_110212.zip |
+ | blinky.bin | not_set | not_set | none | 0xc1 | 0x25 | not_set | not_set | test.pem | 100_110220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x88 | 0xb9 | not_set | not_set | test.pem | 100_110221.zip |
+ | blinky.bin | not_set | not_set | 0x7f | 0x12 | 0x58 | not_set | not_set | test.pem | 100_110222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.5 | not_set | test.pem | 100_111000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.5 | not_set | test.pem | 100_111001.zip |
+ | blinky.bin | not_set | not_set | 0x15 | none | none | 0.5 | not_set | test.pem | 100_111002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.5 | not_set | test.pem | 100_111010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.5 | not_set | test.pem | 100_111011.zip |
+ | blinky.bin | not_set | not_set | 0x15 | not_set | none | 0.5 | not_set | test.pem | 100_111012.zip |
+ | blinky.bin | not_set | not_set | none | 0x47 | none | 0.5 | not_set | test.pem | 100_111020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xfa | none | 0.5 | not_set | test.pem | 100_111021.zip |
+ | blinky.bin | not_set | not_set | 0x2b | 0x25 | none | 0.5 | not_set | test.pem | 100_111022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.5 | not_set | test.pem | 100_111100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.5 | not_set | test.pem | 100_111101.zip |
+ | blinky.bin | not_set | not_set | 0x39 | none | not_set | 0.5 | not_set | test.pem | 100_111102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.5 | not_set | test.pem | 100_111110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.5 | not_set | test.pem | 100_111111.zip |
+ | blinky.bin | not_set | not_set | 0x33 | not_set | not_set | 0.5 | not_set | test.pem | 100_111112.zip |
+ | blinky.bin | not_set | not_set | none | 0x87 | not_set | 0.5 | not_set | test.pem | 100_111120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xe1 | not_set | 0.5 | not_set | test.pem | 100_111121.zip |
+ | blinky.bin | not_set | not_set | 0x53 | 0x4a | not_set | 0.5 | not_set | test.pem | 100_111122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x9b | 0.5 | not_set | test.pem | 100_111200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x06 | 0.5 | not_set | test.pem | 100_111201.zip |
+ | blinky.bin | not_set | not_set | 0xa5 | none | 0x3f | 0.5 | not_set | test.pem | 100_111202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x01 | 0.5 | not_set | test.pem | 100_111210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0xc7 | 0.5 | not_set | test.pem | 100_111211.zip |
+ | blinky.bin | not_set | not_set | 0xd7 | not_set | 0x80 | 0.5 | not_set | test.pem | 100_111212.zip |
+ | blinky.bin | not_set | not_set | none | 0x5d | 0x3f | 0.5 | not_set | test.pem | 100_111220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x91 | 0x15 | 0.5 | not_set | test.pem | 100_111221.zip |
+ | blinky.bin | not_set | not_set | 0xfd | 0x1a | 0xb6 | 0.5 | not_set | test.pem | 100_111222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.6 | not_set | test.pem | 100_112000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.6 | not_set | test.pem | 100_112001.zip |
+ | blinky.bin | not_set | not_set | 0x7f | none | none | 0.6 | not_set | test.pem | 100_112002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.6 | not_set | test.pem | 100_112010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.6 | not_set | test.pem | 100_112011.zip |
+ | blinky.bin | not_set | not_set | 0x72 | not_set | none | 0.6 | not_set | test.pem | 100_112012.zip |
+ | blinky.bin | not_set | not_set | none | 0x3d | none | 0.6 | not_set | test.pem | 100_112020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xbb | none | 0.6 | not_set | test.pem | 100_112021.zip |
+ | blinky.bin | not_set | not_set | 0xf7 | 0x20 | none | 0.6 | not_set | test.pem | 100_112022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.6 | not_set | test.pem | 100_112100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.6 | not_set | test.pem | 100_112101.zip |
+ | blinky.bin | not_set | not_set | 0x3d | none | not_set | 0.6 | not_set | test.pem | 100_112102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.6 | not_set | test.pem | 100_112110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.6 | not_set | test.pem | 100_112111.zip |
+ | blinky.bin | not_set | not_set | 0x2a | not_set | not_set | 0.6 | not_set | test.pem | 100_112112.zip |
+ | blinky.bin | not_set | not_set | none | 0x3d | not_set | 0.6 | not_set | test.pem | 100_112120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xdf | not_set | 0.6 | not_set | test.pem | 100_112121.zip |
+ | blinky.bin | not_set | not_set | 0x7a | 0x58 | not_set | 0.6 | not_set | test.pem | 100_112122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x80 | 0.6 | not_set | test.pem | 100_112200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x9f | 0.6 | not_set | test.pem | 100_112201.zip |
+ | blinky.bin | not_set | not_set | 0xd5 | none | 0x12 | 0.6 | not_set | test.pem | 100_112202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0xea | 0.6 | not_set | test.pem | 100_112210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x87 | 0.6 | not_set | test.pem | 100_112211.zip |
+ | blinky.bin | not_set | not_set | 0x39 | not_set | 0x84 | 0.6 | not_set | test.pem | 100_112212.zip |
+ | blinky.bin | not_set | not_set | none | 0x7f | 0x82 | 0.6 | not_set | test.pem | 100_112220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x6b | 0x66 | 0.6 | not_set | test.pem | 100_112221.zip |
+ | blinky.bin | not_set | not_set | 0x53 | 0xce | 0xe5 | 0.6 | not_set | test.pem | 100_112222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.7 | not_set | test.pem | 100_113000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.7 | not_set | test.pem | 100_113001.zip |
+ | blinky.bin | not_set | not_set | 0xed | none | none | 0.7 | not_set | test.pem | 100_113002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.7 | not_set | test.pem | 100_113010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.7 | not_set | test.pem | 100_113011.zip |
+ | blinky.bin | not_set | not_set | 0x4c | not_set | none | 0.7 | not_set | test.pem | 100_113012.zip |
+ | blinky.bin | not_set | not_set | none | 0x7d | none | 0.7 | not_set | test.pem | 100_113020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x7a | none | 0.7 | not_set | test.pem | 100_113021.zip |
+ | blinky.bin | not_set | not_set | 0x59 | 0x4a | none | 0.7 | not_set | test.pem | 100_113022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.7 | not_set | test.pem | 100_113100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.7 | not_set | test.pem | 100_113101.zip |
+ | blinky.bin | not_set | not_set | 0x3f | none | not_set | 0.7 | not_set | test.pem | 100_113102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.7 | not_set | test.pem | 100_113110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.7 | not_set | test.pem | 100_113111.zip |
+ | blinky.bin | not_set | not_set | 0x71 | not_set | not_set | 0.7 | not_set | test.pem | 100_113112.zip |
+ | blinky.bin | not_set | not_set | none | 0x9e | not_set | 0.7 | not_set | test.pem | 100_113120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xc4 | not_set | 0.7 | not_set | test.pem | 100_113121.zip |
+ | blinky.bin | not_set | not_set | 0xe8 | 0xa5 | not_set | 0.7 | not_set | test.pem | 100_113122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x57 | 0.7 | not_set | test.pem | 100_113200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xae | 0.7 | not_set | test.pem | 100_113201.zip |
+ | blinky.bin | not_set | not_set | 0xb7 | none | 0xd0 | 0.7 | not_set | test.pem | 100_113202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0xe1 | 0.7 | not_set | test.pem | 100_113210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x76 | 0.7 | not_set | test.pem | 100_113211.zip |
+ | blinky.bin | not_set | not_set | 0xa2 | not_set | 0x80 | 0.7 | not_set | test.pem | 100_113212.zip |
+ | blinky.bin | not_set | not_set | none | 0x75 | 0xff | 0.7 | not_set | test.pem | 100_113220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xb1 | 0xc8 | 0.7 | not_set | test.pem | 100_113221.zip |
+ | blinky.bin | not_set | not_set | 0x64 | 0x64 | 0x79 | 0.7 | not_set | test.pem | 100_113222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | not_set | 0xedc8 | test.pem | 100_120000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | not_set | 0x2c1d | test.pem | 100_120001.zip |
+ | blinky.bin | not_set | not_set | 0xe8 | none | none | not_set | 0x3ace,0x2f36 | test.pem | 100_120002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | not_set | 0x81ef,0xab1e | test.pem | 100_120010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | not_set | 0x6be6,0xaa70,0x769d | test.pem | 100_120011.zip |
+ | blinky.bin | not_set | not_set | 0x27 | not_set | none | not_set | 0x4ae0,0x9c9b,0x37ab | test.pem | 100_120012.zip |
+ | blinky.bin | not_set | not_set | none | 0x84 | none | not_set | 0x6387,0x1cbb,0x2307,0x917e | test.pem | 100_120020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x43 | none | not_set | 0x238c,0xedab | test.pem | 100_120021.zip |
+ | blinky.bin | not_set | not_set | 0xb8 | 0x96 | none | not_set | 0xa0e9,0x7477,0x4831,0x675c | test.pem | 100_120022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | not_set | 0x631f,0x300a | test.pem | 100_120100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | not_set | 0x30de | test.pem | 100_120101.zip |
+ | blinky.bin | not_set | not_set | 0x53 | none | not_set | not_set | 0xfb81 | test.pem | 100_120102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | not_set | 0xba05,0xd884,0xf29d,0x42b4 | test.pem | 100_120110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | not_set | 0x7fd8 | test.pem | 100_120111.zip |
+ | blinky.bin | not_set | not_set | 0x79 | not_set | not_set | not_set | 0x5100 | test.pem | 100_120112.zip |
+ | blinky.bin | not_set | not_set | none | 0x0f | not_set | not_set | 0x9246,0x5db5,0x96b6 | test.pem | 100_120120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xae | not_set | not_set | 0x3eff | test.pem | 100_120121.zip |
+ | blinky.bin | not_set | not_set | 0x44 | 0x27 | not_set | not_set | 0xb087,0x70da | test.pem | 100_120122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xe6 | not_set | 0xd3b0 | test.pem | 100_120200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x2c | not_set | 0x9c41,0x953e | test.pem | 100_120201.zip |
+ | blinky.bin | not_set | not_set | 0x78 | none | 0x36 | not_set | 0x6453,0xe79c,0x9a72,0x0054 | test.pem | 100_120202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x70 | not_set | 0xac7a | test.pem | 100_120210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x52 | not_set | 0xebe0,0x77a8,0x2fb2 | test.pem | 100_120211.zip |
+ | blinky.bin | not_set | not_set | 0x58 | not_set | 0x08 | not_set | 0xb475 | test.pem | 100_120212.zip |
+ | blinky.bin | not_set | not_set | none | 0x3b | 0xf2 | not_set | 0xfd44 | test.pem | 100_120220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x7d | 0x6e | not_set | 0x484e,0xa1e1,0xee6e,0x23e6 | test.pem | 100_120221.zip |
+ | blinky.bin | not_set | not_set | 0xc7 | 0x2d | 0xdf | not_set | 0x87c8,0x4c7a | test.pem | 100_120222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.5 | 0xa594,0xd782,0xd2de,0x10a5 | test.pem | 100_121000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.5 | 0x49a7,0xccdb | test.pem | 100_121001.zip |
+ | blinky.bin | not_set | not_set | 0x50 | none | none | 0.5 | 0x4d22,0x7c0a,0x1b8b,0x8ac1 | test.pem | 100_121002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.5 | 0x2486,0x5254,0x4d24,0xf56b | test.pem | 100_121010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.5 | 0x76de | test.pem | 100_121011.zip |
+ | blinky.bin | not_set | not_set | 0x34 | not_set | none | 0.5 | 0x6bbc,0xcea5,0xb74b | test.pem | 100_121012.zip |
+ | blinky.bin | not_set | not_set | none | 0xb8 | none | 0.5 | 0x825c,0x4269 | test.pem | 100_121020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xf7 | none | 0.5 | 0x9bcf | test.pem | 100_121021.zip |
+ | blinky.bin | not_set | not_set | 0xea | 0x46 | none | 0.5 | 0x6cf7 | test.pem | 100_121022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.5 | 0xe7ce,0xba8c,0x9a8c,0x61bf | test.pem | 100_121100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.5 | 0x7926,0xf847 | test.pem | 100_121101.zip |
+ | blinky.bin | not_set | not_set | 0x9b | none | not_set | 0.5 | 0x6f8c | test.pem | 100_121102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.5 | 0x6d71,0xdddd,0x4388 | test.pem | 100_121110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.5 | 0x0daf,0xb6d7 | test.pem | 100_121111.zip |
+ | blinky.bin | not_set | not_set | 0x33 | not_set | not_set | 0.5 | 0x2ec2,0xc08c,0x54cb,0x69f9 | test.pem | 100_121112.zip |
+ | blinky.bin | not_set | not_set | none | 0x57 | not_set | 0.5 | 0x3760 | test.pem | 100_121120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x2d | not_set | 0.5 | 0xba4e,0x93b4,0x1a91 | test.pem | 100_121121.zip |
+ | blinky.bin | not_set | not_set | 0xd4 | 0x7b | not_set | 0.5 | 0x326e,0x5fb1 | test.pem | 100_121122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x07 | 0.5 | 0x6e23,0xd2d5,0x28f0 | test.pem | 100_121200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x74 | 0.5 | 0x5ceb,0x3e76,0x3d4f | test.pem | 100_121201.zip |
+ | blinky.bin | not_set | not_set | 0xe3 | none | 0x24 | 0.5 | 0xccc6,0xd5cc,0x48af,0x26fd | test.pem | 100_121202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x50 | 0.5 | 0x9ed9,0x3d56,0x3464,0x14a0 | test.pem | 100_121210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x8b | 0.5 | 0x8ce3,0xe7ed,0x6a8e,0x2f5e | test.pem | 100_121211.zip |
+ | blinky.bin | not_set | not_set | 0xc0 | not_set | 0x98 | 0.5 | 0x281c,0xde91,0x829d | test.pem | 100_121212.zip |
+ | blinky.bin | not_set | not_set | none | 0xe5 | 0x99 | 0.5 | 0x7bc5,0xd7f9,0x3f17 | test.pem | 100_121220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xf7 | 0x2d | 0.5 | 0xb170,0x2cb4,0x6d74,0xc280 | test.pem | 100_121221.zip |
+ | blinky.bin | not_set | not_set | 0xda | 0x15 | 0x21 | 0.5 | 0xcc28 | test.pem | 100_121222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.6 | 0xbd91,0xb19f | test.pem | 100_122000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.6 | 0xe15e,0xb1a8,0xb30f | test.pem | 100_122001.zip |
+ | blinky.bin | not_set | not_set | 0x15 | none | none | 0.6 | 0x1cb4,0xe663,0x990c | test.pem | 100_122002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.6 | 0xd0c7,0xd442,0x4b54,0xe00a | test.pem | 100_122010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.6 | 0x4589,0x2a0f,0x2dad | test.pem | 100_122011.zip |
+ | blinky.bin | not_set | not_set | 0x46 | not_set | none | 0.6 | 0xc3d8,0xbfb4,0xb477,0x44fb | test.pem | 100_122012.zip |
+ | blinky.bin | not_set | not_set | none | 0x2e | none | 0.6 | 0xc508,0x6ad9 | test.pem | 100_122020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xff | none | 0.6 | 0x37bf,0x3db0,0x53c5 | test.pem | 100_122021.zip |
+ | blinky.bin | not_set | not_set | 0x1f | 0x00 | none | 0.6 | 0xf7e7 | test.pem | 100_122022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.6 | 0x768d,0x6506,0x49b0,0xe4f4 | test.pem | 100_122100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.6 | 0xb2ce | test.pem | 100_122101.zip |
+ | blinky.bin | not_set | not_set | 0x57 | none | not_set | 0.6 | 0x9f32,0x1aec,0x0c11,0xe22a | test.pem | 100_122102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.6 | 0x002a,0x56ea,0xa835,0x4ff8 | test.pem | 100_122110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.6 | 0x5d36 | test.pem | 100_122111.zip |
+ | blinky.bin | not_set | not_set | 0x3a | not_set | not_set | 0.6 | 0x860a,0x335c,0xd037 | test.pem | 100_122112.zip |
+ | blinky.bin | not_set | not_set | none | 0xab | not_set | 0.6 | 0x46a7 | test.pem | 100_122120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x7f | not_set | 0.6 | 0xbf23,0x00d4 | test.pem | 100_122121.zip |
+ | blinky.bin | not_set | not_set | 0x99 | 0x1b | not_set | 0.6 | 0xfac2 | test.pem | 100_122122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0x47 | 0.6 | 0x7548,0x8a18 | test.pem | 100_122200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0xcb | 0.6 | 0x4f4e | test.pem | 100_122201.zip |
+ | blinky.bin | not_set | not_set | 0xa2 | none | 0xbb | 0.6 | 0x0dac | test.pem | 100_122202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0x70 | 0.6 | 0x9b2d,0x89fa | test.pem | 100_122210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x27 | 0.6 | 0x6353,0x7647 | test.pem | 100_122211.zip |
+ | blinky.bin | not_set | not_set | 0x11 | not_set | 0xff | 0.6 | 0x8ca7,0x2665 | test.pem | 100_122212.zip |
+ | blinky.bin | not_set | not_set | none | 0x39 | 0xb7 | 0.6 | 0x644e,0xc60b,0xbf44 | test.pem | 100_122220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xad | 0x71 | 0.6 | 0x1fa6,0x5cf3,0x430b,0x4fd2 | test.pem | 100_122221.zip |
+ | blinky.bin | not_set | not_set | 0x27 | 0x3d | 0xd8 | 0.6 | 0x3b4a,0x45f0,0xc4c7,0x8af3 | test.pem | 100_122222.zip |
+ | blinky.bin | not_set | not_set | none | none | none | 0.7 | 0xa000,0x4356,0x70dc,0x2304 | test.pem | 100_123000.zip |
+ | blinky.bin | not_set | not_set | not_set | none | none | 0.7 | 0xfe10,0x31db | test.pem | 100_123001.zip |
+ | blinky.bin | not_set | not_set | 0xe4 | none | none | 0.7 | 0xf113,0x84fd | test.pem | 100_123002.zip |
+ | blinky.bin | not_set | not_set | none | not_set | none | 0.7 | 0xdad5,0x5b52,0xb732,0x0445 | test.pem | 100_123010.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | none | 0.7 | 0x2be7,0x9f38 | test.pem | 100_123011.zip |
+ | blinky.bin | not_set | not_set | 0x58 | not_set | none | 0.7 | 0xeb9d | test.pem | 100_123012.zip |
+ | blinky.bin | not_set | not_set | none | 0xbb | none | 0.7 | 0x399c | test.pem | 100_123020.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x5c | none | 0.7 | 0x140d | test.pem | 100_123021.zip |
+ | blinky.bin | not_set | not_set | 0x17 | 0x83 | none | 0.7 | 0x48b7,0xd0a3,0xbec0,0x1b48 | test.pem | 100_123022.zip |
+ | blinky.bin | not_set | not_set | none | none | not_set | 0.7 | 0x2506,0xe218,0x6d03 | test.pem | 100_123100.zip |
+ | blinky.bin | not_set | not_set | not_set | none | not_set | 0.7 | 0x9e42,0x629e | test.pem | 100_123101.zip |
+ | blinky.bin | not_set | not_set | 0xbf | none | not_set | 0.7 | 0x6314 | test.pem | 100_123102.zip |
+ | blinky.bin | not_set | not_set | none | not_set | not_set | 0.7 | 0x7f87,0xbb8e,0xa3d9 | test.pem | 100_123110.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | not_set | 0.7 | 0xb55b | test.pem | 100_123111.zip |
+ | blinky.bin | not_set | not_set | 0x07 | not_set | not_set | 0.7 | 0x855b | test.pem | 100_123112.zip |
+ | blinky.bin | not_set | not_set | none | 0x88 | not_set | 0.7 | 0x661b,0x6082,0x0add,0x5f93 | test.pem | 100_123120.zip |
+ | blinky.bin | not_set | not_set | not_set | 0xfa | not_set | 0.7 | 0x1f06,0x7c8b,0x53dc,0xf342 | test.pem | 100_123121.zip |
+ | blinky.bin | not_set | not_set | 0xf8 | 0xd5 | not_set | 0.7 | 0x8381,0x3cc5,0x1392 | test.pem | 100_123122.zip |
+ | blinky.bin | not_set | not_set | none | none | 0xf3 | 0.7 | 0x46c6,0xa2a9 | test.pem | 100_123200.zip |
+ | blinky.bin | not_set | not_set | not_set | none | 0x00 | 0.7 | 0x5127,0xed30,0x194c,0x8c7a | test.pem | 100_123201.zip |
+ | blinky.bin | not_set | not_set | 0xe4 | none | 0xd3 | 0.7 | 0xd2a4,0xb1a6,0x4cd6,0x2fa5 | test.pem | 100_123202.zip |
+ | blinky.bin | not_set | not_set | none | not_set | 0xd2 | 0.7 | 0x63d4,0x01f2,0x5a63 | test.pem | 100_123210.zip |
+ | blinky.bin | not_set | not_set | not_set | not_set | 0x9b | 0.7 | 0xa64e,0x9586,0xc0b5 | test.pem | 100_123211.zip |
+ | blinky.bin | not_set | not_set | 0x6f | not_set | 0x0e | 0.7 | 0x4b13 | test.pem | 100_123212.zip |
+ | blinky.bin | not_set | not_set | none | 0xf8 | 0xcc | 0.7 | 0xa27a,0x1aab,0x7677 | test.pem | 100_123220.zip |
+ | blinky.bin | not_set | not_set | not_set | 0x89 | 0x00 | 0.7 | 0x1595,0x01e3,0x5b1b | test.pem | 100_123221.zip |
+ | blinky.bin | not_set | not_set | 0x2c | 0x2b | 0xc8 | 0.7 | 0xba47,0x8a49 | test.pem | 100_123222.zip |
diff --git a/circuitpython/lib/nrfutil/tests/bdd/genpkg_help_information.feature b/circuitpython/lib/nrfutil/tests/bdd/genpkg_help_information.feature
new file mode 100644
index 0000000..01d62d5
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/bdd/genpkg_help_information.feature
@@ -0,0 +1,10 @@
+Feature: Help information
+ Scenario: User types --help
+ Given user types 'nrfutil dfu genpkg --help'
+ When user press enter
+ Then output contains 'Generate a zipfile package for distribution to Apps supporting Nordic DFU' and exit code is 0
+
+ Scenario: User does not type mandatory arguments
+ Given user types 'nrfutil dfu genpkg'
+ When user press enter
+ Then output contains 'Error: Missing argument "zipfile".' and exit code is 2
diff --git a/circuitpython/lib/nrfutil/tests/bdd/steps/common_steps.py b/circuitpython/lib/nrfutil/tests/bdd/steps/common_steps.py
new file mode 100644
index 0000000..ffe7459
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/bdd/steps/common_steps.py
@@ -0,0 +1,84 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from Queue import Queue
+import logging
+import os
+import subprocess
+from threading import Thread
+from util import process_pipe, ON_POSIX
+
+logger = logging.getLogger(__file__)
+
+
+class Exec(object):
+ def __init__(self, exec_path):
+ self.path = exec_path
+ self.name = os.path.basename(self.path)
+ self.dir = os.path.dirname(self.path)
+ self.out_queue = Queue()
+ self.stdout_thread = None
+ self.stderr_thread = None
+ self.process = None
+
+ def execute(self, args, working_directory):
+ args = args
+ shell = False
+
+ args.insert(0, self.path)
+
+ self.process = subprocess.Popen(args=args,
+ bufsize=0,
+ cwd=working_directory,
+ executable=self.path,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ close_fds=ON_POSIX,
+ universal_newlines=True,
+ shell=shell)
+
+ if self.process.poll() is not None:
+ raise Exception("Error starting {} application {}, return code is {}".format(
+ self.path,
+ self.process.poll()))
+
+ self.stdout_thread = Thread(target=process_pipe, args=(self.process.stdout, self.out_queue))
+ self.stdout_thread.start()
+
+ self.stderr_thread = Thread(target=process_pipe, args=(self.process.stderr, self.out_queue))
+ self.stderr_thread.start()
+
+ def kill(self):
+ if self.process is not None:
+ self.process.kill()
+ self.process.stdin.close()
+
+
+def get_resources_path():
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "resources")
diff --git a/circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_generate_dfu_package_steps.py b/circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_generate_dfu_package_steps.py
new file mode 100644
index 0000000..9cab77a
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_generate_dfu_package_steps.py
@@ -0,0 +1,250 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json
+import logging
+import os
+from zipfile import ZipFile
+from behave import given, then, when
+from click.testing import CliRunner
+from nordicsemi.__main__ import cli, int_as_text_to_int
+from common_steps import get_resources_path
+
+
+logger = logging.getLogger(__file__)
+
+
+@given(u'the user wants to generate a DFU package with application {application}, bootloader {bootloader} and SoftDevice {softdevice} with name {package}')
+def step_impl(context, application, bootloader, softdevice, package):
+ runner = CliRunner()
+ context.runner = runner
+ args = ['dfu', 'genpkg']
+
+ if application != u'not_set':
+ args.extend(['--application', os.path.join(get_resources_path(), application)])
+ context.application = application
+ else:
+ context.application = None
+
+ if bootloader != u'not_set':
+ args.extend(['--bootloader', os.path.join(get_resources_path(), bootloader)])
+ context.bootloader = bootloader
+ else:
+ context.bootloader = None
+
+ if softdevice != u'not_set':
+ args.extend(['--softdevice', os.path.join(get_resources_path(), softdevice)])
+ context.softdevice = softdevice
+ else:
+ context.softdevice = None
+
+ args.append(package)
+
+ context.args = args
+
+
+@given(u'with option --application-version {app_ver}')
+def step_impl(context, app_ver):
+ context.application_version = None
+
+ if app_ver == u'not_set':
+ context.application_version = 0xFFFFFFFF
+ elif app_ver == u'none':
+ context.args.extend(['--application-version', 'None'])
+ else:
+ context.args.extend(['--application-version', app_ver])
+ context.application_version = int_as_text_to_int(app_ver)
+
+
+@given(u'with option --dev-revision {dev_rev}')
+def step_impl(context, dev_rev):
+ context.dev_revision = None
+
+ if dev_rev == u'not_set':
+ context.dev_revision = 0xFFFF
+ elif dev_rev == u'none':
+ context.args.extend(['--dev-revision', 'None'])
+ else:
+ context.args.extend(['--dev-revision', dev_rev])
+ context.dev_revision = int_as_text_to_int(dev_rev)
+
+
+@given(u'with option --dev-type {dev_type}')
+def step_impl(context, dev_type):
+ context.dev_type = None
+
+ if dev_type == u'not_set':
+ context.dev_type = 0xFFFF
+ elif dev_type == u'none':
+ context.args.extend(['--dev-type', 'None'])
+ else:
+ context.args.extend(['--dev-type', dev_type])
+ context.dev_type = int_as_text_to_int(dev_type)
+
+
+@given(u'with option --dfu-ver {dfu_ver}')
+def step_impl(context, dfu_ver):
+ context.firmware_hash = None
+ context.ext_packet_id = None
+ context.init_packet_ecds = None
+
+ if dfu_ver == u'not_set':
+ context.dfu_ver = 0.5
+ context.ext_packet_id = 0
+ else:
+ if dfu_ver == 0.5:
+ pass
+ elif dfu_ver == 0.6:
+ context.ext_packet_id = 0
+ elif dfu_ver == 0.7:
+ context.ext_packet_id = 1
+ context.firmware_hash = 'exists'
+ elif dfu_ver == 0.8:
+ context.ext_packet_id = 2
+ context.firmware_hash = 'exists'
+ context.init_packet_ecds = 'exists'
+
+ context.args.extend(['--dfu-ver', dfu_ver])
+ context.dfu_ver = float(dfu_ver)
+
+
+@given(u'with option --sd-req {sd_reqs}')
+def step_impl(context, sd_reqs):
+ context.sd_req = None
+
+ if sd_reqs == u'not_set':
+ context.sd_req = [0xFFFE]
+ elif sd_reqs == u'none':
+ context.args.extend(['--sd-req', 'None'])
+ else:
+ context.args.extend(['--sd-req', sd_reqs])
+
+ sd_reqs = sd_reqs.split(",")
+ sd_reqs_value = []
+
+ for sd_req in sd_reqs:
+ sd_reqs_value.append(int_as_text_to_int(sd_req))
+
+ context.sd_req = sd_reqs_value
+
+
+@given(u'with option --key-file {pem_file}')
+def step_impl(context, pem_file):
+ if pem_file != u'not_set':
+ context.args.extend(['--key-file', os.path.join(get_resources_path(), pem_file)])
+ context.dfu_ver = 0.8
+
+
+@when(u'user press enter')
+def step_impl(context):
+ pass
+
+
+@then(u'the generated DFU package {package} contains correct data')
+def step_impl(context, package):
+ with context.runner.isolated_filesystem():
+ pkg_full_name = os.path.join(os.getcwd(), package)
+ logger.debug("Package full name %s", pkg_full_name)
+
+ result = context.runner.invoke(cli, context.args)
+ logger.debug("exit_code: %s, output: \'%s\'", result.exit_code, result.output)
+ assert result.exit_code == 0
+
+ with ZipFile(pkg_full_name, 'r') as pkg:
+ infolist = pkg.infolist()
+
+ expected_zip_content = ["manifest.json"]
+
+ if context.bootloader and context.softdevice:
+ expected_zip_content.append("sd_bl.bin")
+ expected_zip_content.append("sd_bl.dat")
+ elif context.bootloader:
+ expected_zip_content.append(context.bootloader.split(".")[0] + ".bin")
+ expected_zip_content.append(context.bootloader.split(".")[0] + ".dat")
+ elif context.softdevice:
+ expected_zip_content.append(context.softdevice.split(".")[0] + ".bin")
+ expected_zip_content.append(context.softdevice.split(".")[0] + ".dat")
+
+ if context.application:
+ expected_zip_content.append(context.application.split(".")[0] + '.bin')
+ expected_zip_content.append(context.application.split(".")[0] + '.dat')
+
+ for file_information in infolist:
+ assert file_information.filename in expected_zip_content
+ assert file_information.file_size > 0
+
+ # Extract all and load json document to see if it is correct regarding to paths
+ pkg.extractall()
+
+ with open('manifest.json', 'r') as f:
+ _json = json.load(f)
+
+ if context.dfu_ver:
+ assert 'dfu_version' in _json['manifest']
+ assert _json['manifest']['dfu_version'] == context.dfu_ver
+
+ if context.bootloader and context.softdevice:
+ data = _json['manifest']['softdevice_bootloader']['init_packet_data']
+ assert_init_packet_data(context, data)
+ elif context.bootloader:
+ data = _json['manifest']['bootloader']['init_packet_data']
+ assert_init_packet_data(context, data)
+ elif context.softdevice:
+ data = _json['manifest']['softdevice']['init_packet_data']
+ assert_init_packet_data(context, data)
+ if context.application:
+ data = _json['manifest']['application']['init_packet_data']
+ assert_init_packet_data(context, data)
+
+
+def assert_init_packet_data(context, data):
+ if context.application_version:
+ assert 'application_version' in data
+ assert data['application_version'] == context.application_version
+
+ if context.dev_revision:
+ assert 'device_revision' in data
+ assert data['device_revision'] == context.dev_revision
+
+ if context.dev_type:
+ assert 'device_type' in data
+ assert data['device_type'] == context.dev_type
+
+ if context.sd_req:
+ assert 'softdevice_req' in data
+ assert data['softdevice_req'] == context.sd_req
+
+ if context.ext_packet_id:
+ assert 'ext_packet_id' in data
+ assert data['ext_packet_id'] == context.ext_packet_id
+
+ if context.firmware_hash:
+ assert 'firmware_hash' in data
+
+ if context.init_packet_ecds:
+ assert 'init_packet_ecds' in data
diff --git a/circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_help_information_steps.py b/circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_help_information_steps.py
new file mode 100644
index 0000000..7ea98b5
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/bdd/steps/genpkg_help_information_steps.py
@@ -0,0 +1,64 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from Queue import Empty
+import logging
+import os
+import time
+import sys
+
+from click.testing import CliRunner
+from behave import then, given, when
+
+from nordicsemi.__main__ import cli, int_as_text_to_int
+
+
+logger = logging.getLogger(__file__)
+
+STDOUT_TEXT_WAIT_TIME = 50 # Number of seconds to wait for expected output from stdout
+
+
+@given(u'user types \'{command}\'')
+def step_impl(context, command):
+ args = command.split(' ')
+ assert args[0] == 'nrfutil'
+
+ exec_args = args[1:]
+
+ runner = CliRunner()
+ context.runner = runner
+ context.args = exec_args
+
+
+@then(u'output contains \'{stdout_text}\' and exit code is {exit_code}')
+def step_impl(context, stdout_text, exit_code):
+ result = context.runner.invoke(cli, context.args)
+ logger.debug("exit_code: %s, output: \'%s\'", result.exit_code, result.output)
+ assert result.exit_code == int_as_text_to_int(exit_code)
+ assert result.output != None
+ assert result.output.find(stdout_text) >= 0
diff --git a/circuitpython/lib/nrfutil/tests/bdd/steps/util.py b/circuitpython/lib/nrfutil/tests/bdd/steps/util.py
new file mode 100644
index 0000000..ba46075
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/bdd/steps/util.py
@@ -0,0 +1,154 @@
+# Copyright (c) 2015, Nordic Semiconductor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Nordic Semiconductor ASA nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from random import randint
+import time
+import sys
+import math
+
+ON_POSIX = 'posix' in sys.builtin_module_names
+
+
+def process_pipe(pipe, queue):
+ for line in iter(pipe.readline, b''):
+ queue.put({'type': 'output', 'data': line})
+
+ pipe.close()
+ queue.put({'type': 'output_terminated'})
+
+
+def kill_process(target):
+ if 'proc' in target:
+ target['proc'].kill()
+
+ # Close file descriptors
+ target['proc'].stdin.close()
+ time.sleep(1) # Let the application terminate before proceeding
+
+
+def kill_processes(context):
+ targets = context.target_registry.get_all()
+
+ for target in targets:
+ kill_process(target)
+
+
+def generate_options_table_for_cucumber():
+ retval = ""
+
+ number_of_2_option_options = 1
+ number_of_3_option_options = 4
+ number_of_4_option_options = 1
+
+ number_of_optional_option_permutations = 1
+ number_of_optional_option_permutations *= int(math.pow(2, number_of_2_option_options))
+ number_of_optional_option_permutations *= int(math.pow(3, number_of_3_option_options))
+ number_of_optional_option_permutations *= int(math.pow(4, number_of_4_option_options))
+
+ for x in xrange(0, number_of_optional_option_permutations):
+ retval += "{0:<8}".format(" ")
+ retval += "| {0:<12}| {1:<29}| {2:<29}|".format("blinky.bin", "not_set", "not_set")
+
+ permutation_name = ""
+ options_factor = 1
+
+ option = int(x / options_factor % 3)
+ options_factor *= 3
+ permutation_name = str(option) + permutation_name
+
+ if option == 0:
+ retval += " {0:<8}|".format("none")
+ if option == 1:
+ retval += " {0:<8}|".format("not_set")
+ if option == 2:
+ retval += " {0:<8}|".format("0x{0:02x}".format(randint(0, 255)))
+
+ option = int(x / options_factor % 3)
+ options_factor *= 3
+ permutation_name = str(option) + permutation_name
+
+ if option == 0:
+ retval += " {0:<8}|".format("none")
+ if option == 1:
+ retval += " {0:<8}|".format("not_set")
+ if option == 2:
+ retval += " {0:<8}|".format("0x{0:02x}".format(randint(0, 255)))
+
+ option = int(x / options_factor % 3)
+ options_factor *= 3
+ permutation_name = str(option) + permutation_name
+
+ if option == 0:
+ retval += " {0:<9}|".format("none")
+ if option == 1:
+ retval += " {0:<9}|".format("not_set")
+ if option == 2:
+ retval += " {0:<9}|".format("0x{0:02x}".format(randint(0, 255)))
+
+
+ option = int(x / options_factor % 4)
+ options_factor *= 4
+ permutation_name = str(option) + permutation_name
+
+ if option == 0:
+ retval += " {0:<8}|".format("not_set")
+ if option == 1:
+ retval += " {0:<8}|".format("0.5")
+ if option == 2:
+ retval += " {0:<8}|".format("0.6")
+ if option == 3:
+ retval += " {0:<8}|".format("0.7")
+
+ option = int(x / options_factor % 3)
+ options_factor *= 3
+ permutation_name = str(option) + permutation_name
+
+ if option == 0:
+ retval += " {0:<28}|".format("none")
+ if option == 1:
+ retval += " {0:<28}|".format("not_set")
+ if option == 2:
+ sd_reqs = []
+
+ for i in xrange(0, randint(1, 4)):
+ sd_reqs.append("0x{0:04x}".format(randint(0, 65535)))
+
+ retval += " {0:<28}|".format(",".join(sd_reqs))
+
+ option = int(x / options_factor % 2)
+ permutation_name = str(option) + permutation_name
+
+ if option == 0:
+ retval += " {0:<9}|".format("not_set")
+ if option == 1:
+ retval += " {0:<9}|".format("test.pem")
+
+ retval += " {0:<15}|".format("100_{0:0>6}.zip".format(permutation_name))
+ retval += "\n"
+
+ return retval
diff --git a/circuitpython/lib/nrfutil/tests/resources/blinky.bin b/circuitpython/lib/nrfutil/tests/resources/blinky.bin
new file mode 100644
index 0000000..b745f0d
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/resources/blinky.bin
Binary files differ
diff --git a/circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s110.hex b/circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s110.hex
new file mode 100644
index 0000000..7270637
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s110.hex
@@ -0,0 +1,1229 @@
+:020000040001F9
+:108000005031002059810100738101007581010008
+:108010000000000000000000000000000000000060
+:108020000000000000000000000000007781010057
+:108030000000000000000000798101007B81010048
+:108040007D8101007D810100918401007D8101001D
+:108050007D81010000000000A98201007D810100F6
+:108060007D8101007D8101007D8101007D81010014
+:108070007D8101007D8101007D8101007D81010004
+:108080007D810100A58301007D8101007D810100CA
+:10809000C58301007D810100198401007D810100FB
+:1080A0007D8101007D8101000000000000000000D2
+:1080B00000000000000000000000000000000000C0
+:1080C0000348854600F0C0F800480047C5B80100E5
+:1080D00050310020401E00BF00BF00BF00BF00BFE6
+:1080E00000BF00BF00BF00BF00BF00BF00BFF1D195
+:1080F00070470000401E00BF00BF00BF00BF00BFB0
+:1081000000BF00BF00BF00BF00BF00BF00BFF1D174
+:1081100070470000056885F3088846680A4AEFF34F
+:1081200005839A42304602D1084CA6463047074C98
+:10813000064D0646064FF0B4034C034D024E024F67
+:10814000F0B404480047000000000000FFFFFFFFFC
+:1081500000000021F9FFFFFF0321094802680A43DC
+:108160000260084802680A430260074880470748DF
+:108170000047FEE7FEE7FEE7FEE7FEE7FEE700005A
+:1081800024050040540500403D840100C1800100E9
+:1081900030B50B46014600202022012409E00D469F
+:1081A000D5409D4205D31D469540491B2546954027
+:1081B00040191546521E002DF1DC30BD10B5431A92
+:1081C000934209D28318881803E0401E01785B1E91
+:1081D0001970521EF9D210BD03460B439B0703D002
+:1081E00009E008C9121F08C0042AFAD203E00B787C
+:1081F0000370401C491C521EF9D210BDD2B201E0DE
+:108200000270401C491EFBD270470022F6E710B5F1
+:1082100013460A4604461946FFF7F0FF204610BDF4
+:10822000421C0178401C0029FBD1801A704730B5F0
+:1082300004460020034600E05B1C934203D2E05C4E
+:10824000CD5C401BF8D030BD064C0125064E05E044
+:10825000E36807CC2B430C3C98471034B442F7D367
+:10826000FFF732FF50CC010070CC010030B58C1804
+:108270000278401C13071B0F01D10378401C120920
+:1082800006D10278401C03E005780D70401C491CA3
+:108290005B1EF9D101E00B70491C521EFBD1A142BB
+:1082A000E6D3002030BD0000F0B52A4885B004694F
+:1082B00029480021C1630E46284F45E01420796803
+:1082C000704345180120B968B04008423AD00020F8
+:1082D00000900390E8682968C04360400840014668
+:1082E0000290284604F036F81A4800692968604070
+:1082F000084016D0224642400192E868C0435040F0
+:10830000084001460090284604F024F8019A00989D
+:10831000A9689043014003910098696802401140A8
+:1083200000910298A968A04301400398029A014372
+:10833000686822401040009A104302460A4301D068
+:108340002A699047761CF6B278788642B6D305B093
+:10835000F0BD0000000500504061004038210020C1
+:108360008307FF22DB0E9A408907090E99400028F7
+:108370000BDA0007000F0838830808489B0018181C
+:10838000C36993430B43C3617047830804489B0050
+:108390001B181868904308431860704700ED00E010
+:1083A00000E400E010B506490020086048608860DD
+:1083B000C860034940390860486004F09BFA10BD6A
+:1083C00040110140FEB50020C043124D0290686983
+:1083D000019068462E6902F0F5FE074603F0B0F9F9
+:1083E0000446002F08D002AA0199009802F00AFF63
+:1083F000029803F0EFF906E0029803F0EBF9002889
+:1084000001D1002C02D0304601F022FE002068711C
+:10841000FEBD00004421002010B507484068002838
+:1084200007D08047002803D00022114600F03EFA12
+:1084300010BD03F001F910BD7021002010B503F04C
+:1084400049F9002805D00E490C484860C8130D4969
+:1084500088610D48018CC9B201290ED1818C0907B0
+:108460000BD1018D0906090F042906D1808D000664
+:10847000000F02D105490120886010BDDFFF07C051
+:1084800000050040006C0040C00F00F000060040F6
+:108490007CB51B4CA0681B4E0025002818D0A56099
+:1084A00019488069C1B2194800F023FA002805D0A4
+:1084B00001216A4611700190684607E013488168FF
+:1084C000C068401A012803D168460570B168884722
+:1084D000E069002803D0E561032003F075FB606AC2
+:1084E00000280BD0656208498039086808600221BD
+:1084F0006A4611700190B168684688477CBD0000EB
+:108500000021004008210020002500401428002000
+:1085100030B47446641E2578641CAB4200D21D46FC
+:10852000635D5B00E31830BC184702E008C8121F07
+:1085300008C1002AFAD170477047002001E001C14C
+:10854000121F002AFBD1704738B50D4C6078022805
+:1085500002D00C490120886069460B4800F0B8F948
+:10856000002802D000F016F838BD0848802181604C
+:108570006A46074B1278DA6102226270416038BDA8
+:108580000821002000200040242800200023004073
+:10859000002500401CB506490120C8600549487007
+:1085A00003206A4610708968684688471CBD000031
+:1085B00000200040082100200449002048700449A0
+:1085C0000122CA604A600349086070470821002000
+:1085D0000020004000250040F7B582B00025064687
+:1085E000157000781446002805D03046039903F032
+:1085F000F7F9050008D1B07800281ED02078039F35
+:10860000001D1F2802D90C2005B0F0BD684679DF97
+:108610000028F9D121780322481C20707A5421784F
+:108620001922481C20707A542078C11968460088A5
+:1086300004F0EAF92178401820702078039A411C50
+:1086400002232170135420780399471C01222770BC
+:108650000A542078F278471C039927700A547068EE
+:10866000002815D00021415620788C460246C01CB7
+:1086700003991F28C7D8501C20708B5422780A23D6
+:10868000501C20708B5420786246431C23700A547F
+:108690003089002809D03046009406220221083093
+:1086A000039B04F02FFA0500AED1308A002809D0D0
+:1086B00030460094072203211030039B04F022FA75
+:1086C0000500A1D1308B002809D030460094152236
+:1086D00014211830039B04F015FA050094D1306A78
+:1086E000002805D02246039901F004FD05008BD136
+:1086F000706A002805D02246039903F03FF905006F
+:1087000082D12C20805D002806D022463046039975
+:1087100003F0A5FE0500C7D1284675E710B594B053
+:1087200030216846FFF771FD02216846017001247F
+:1087300084700621C1700321018212480590002136
+:10874000684600F097FB002803D00022114600F095
+:10875000ADF820210CA8FFF758FD08A80476FF20EB
+:108760002D300F90B42010900023074A0CA96846C2
+:1087700000F0AEFB002803D00022114600F096F86E
+:1087800014B010BD3820002075BA010004484268BA
+:108790000121C9050B46934383600A40C2607047BC
+:1087A0000005005010B505484168002903D0407805
+:1087B00000F0FCF810BD082010BD000020210020B2
+:1087C000F8B50B46052A01D20720F8BD1349144D10
+:1087D00048600B708A60002101240BE0DA00121857
+:1087E00016789778B600BF0076193760167822465B
+:1087F000B24011431A465B1EDBB2002AEED1074895
+:10880000084B0A46401C00F01BF90028DDD1034844
+:10881000054A00210C3000F04BF9F8BD2021002062
+:108820000007005075B401003DA201003EB50446AA
+:1088300004200190184802906946204601F0DAFFB2
+:10884000002807D01549884203D00022114600F0C5
+:108850002DF83EBD10480C38017BC90716D0104AD0
+:108860000C218088A7DF002810D00E4988420DD047
+:1088700008280BD0891C884208D0112806D00A4944
+:10888000884203D00022114600F010F8204601F083
+:1088900067FF0028D9D13EBD0C2000204080000099
+:1088A000FFFF00000230000001340000BFF34F8FD3
+:1088B00003490248C860BFF34F8FFEE70400FA0582
+:1088C00000ED00E0014B1B6818470000F027002076
+:1088D0008268C36893420AD0826883881A4003681A
+:1088E0009A5C0A708168491C8160002070470520ED
+:1088F00070478268C3689B1A8288934208D8C3680D
+:1089000013400268D154C168491CC16000207047FF
+:108910000420704710B5002903D08A070024002ADC
+:1089200001D0072010BD0F4A0B4651601070142172
+:108930005470414318469460FFF767FC00200A49D1
+:10894000C0438860094840210160094A1068FF233C
+:108950001B0498430B041843106006480160002074
+:1089600010BD0000382100200063004080E200E0DC
+:1089700004E400E000E100E00A4B5A68002A04D059
+:108980005B78984203D30720704708207047142370
+:1089900058438018044A12690068024000200A60A7
+:1089A000704700003821002000050050F0B51F4A34
+:1089B0005168002904D05378984203D30720F0BDB2
+:1089C0000820F0BD1A4B0025DD631A4B1C6997681F
+:1089D000002F02D1184EDB057360012686403E430E
+:1089E0009660142250434218D560002201230D588E
+:1089F00093401D4215D01C4202D003252D0405E0F2
+:108A000001256D044618F7681F43F7600B4B96006D
+:108A1000F3181E6803273F04BE431E601E682E43E2
+:108A20001E60521C202AE1D30020F0BD3821002016
+:108A30004061004000050050006300400007005006
+:108A4000F8B5114F84467D68002D07D0002B07D064
+:108A500078783C78A04205D30420F8BD0820F8BD02
+:108A60000720F8BD0E461424164344432E516419C2
+:108A70002361A260616061460870411C797003F057
+:108A800013F90020F8BD00003821002038B50C464D
+:108A9000A268064B12019D5809786288009202462E
+:108AA000204608302369A84738BD0000002900206F
+:108AB00070B5114CA568002D06D0002A06D00028FC
+:108AC00004D00023247809E0082070BD072070BD81
+:108AD00024265E43AE5D002E04D05B1CA342F7DB70
+:108AE000042070BD242401265C432E556419617056
+:108AF000A2610360002070BD44210020FFB59807EB
+:108B0000002481B01E4615460F4600280BD1002ECA
+:108B100009D003F0FDFB22490A9888610F703246A4
+:108B200000208E6008E0072005B0F0BD24234343F9
+:108B3000D4549B181C75401CB842F7DB24204743D3
+:108B4000BB19032048700F461846CB6019461830F1
+:108B5000002218232E465E43D3005B181C705C7005
+:108B60009D7058603018521C032AF5DB0020C0436A
+:108B70003861BC70FC7001240A482405046003219C
+:108B80001420FFF7EDFB08480460084C0198A06032
+:108B900003211120FFF7E4FB606878610020C3E740
+:108BA0004421002080E200E000E100E000150140E7
+:108BB000FEB504461D48174682680D46002A0CD0B3
+:108BC00001788C4201D2052D01D20720FEBD21463D
+:108BD00024235943535C012B01D00820FEBD881883
+:108BE000407801281DD0002603F050FFC0000F4937
+:108BF0000190C9684018694603F072FF002812D03E
+:108C0000012101700A49446049680830E2C00749FF
+:108C10000198C96841180098487003F0F9FD0020D8
+:108C2000FEBD2E46E0E70420FEBD000044210020EA
+:108C300000150140F8B5144D0446A868002809D075
+:108C400029788C4201D30720F8BD24216143405C80
+:108C5000012801D00820F8BD03F018FFC600E8681D
+:108C60006946301803F03CFF00280AD00221017049
+:108C70004460E86831180098487003F0C9FD00208E
+:108C8000F8BD0420F8BD00004421002010B5184CA8
+:108C90000121002209042069FFF78AFF002803D080
+:108CA00000221146FFF702FE01210022C90360697C
+:108CB000FFF77EFF002803D000221146FFF7F6FDE4
+:108CC00000220C49A069FFF773FF002803D000229F
+:108CD0001146FFF7EBFD05210022C903E069FFF70C
+:108CE00067FF002803D000221146FFF7DFFD10BD0B
+:108CF0000020002066260000F0B50546007D002417
+:108D000093B00E4600280DD0012001466846103170
+:108D100003940173717B4173817BF92001406846A4
+:108D2000891C81731C2104A8FFF76FFA6946087C2F
+:108D300002210843694608742A7DEF21002A02D0E7
+:108D40001022104300E008406A461074059407940E
+:108D50000894287D002800D003A8099001270A94D0
+:108D600010469771304A82800094B27B0270F27B89
+:108D700042708078F9221040F722801C1040EF21C9
+:108D800008404108490068468170317B0172142116
+:108D90000BA8FFF73AFA01A80B9068460C9087865B
+:108DA000C486078702A80F90A888AB1D0BAA04A948
+:108DB000A2DF002835D1B068002830D0684687711E
+:108DC0001A4981800094317C017000200146684678
+:108DD00041708078F9210840F721801C0840EF217C
+:108DE0000840410849006846817011A8B16800F048
+:108DF00060FD064614210BA8FFF707FA01A80B90A7
+:108E000068460C908686C486068711A80F902A466D
+:108E1000E8880E320BA9A3DF002802D100E0EC8124
+:108E2000002013B0F0BD0000192A0000082900003E
+:108E300010B50C490C4803F0F7FAC1B2094868387C
+:108E400000F012FA00280BD0082809D00749884200
+:108E500006D00749884203D000221146FFF726FDBD
+:108E600010BD00005025002020200020043000000C
+:108E70000134000070B50C4692B000216A461170B2
+:108E800007251171002809D0C17849070CD502A91E
+:108E9000FFF7A2FB002808D102AE00E00026002C5C
+:108EA0000ED0E078002802D0284612B070BD01AA8A
+:108EB0000AA92046FFF790FB0028F6D10AAA00E095
+:108EC0000022684603790178304672DFEDE7000042
+:108ED00070B5040012D0002910D04A480025457111
+:108EE0000361C26020224848FFF768F94648C1681C
+:108EF000002905D00169002902D002E00E2070BDD2
+:108F000005728169002902D0C169002900D1057567
+:108F100000F0DCF83C494039084610380160203147
+:108F2000816030213038FFF770F937482178803878
+:108F30000170A1788170E178C170617841706269D7
+:108F4000216942610161E268A168C26081600146F5
+:108F5000E369A269CB618A61616A002917D0014681
+:108F6000A0310246AC3241628A60636A1B880B8082
+:108F7000616A436A898899800021436A04E0656ACE
+:108F8000AD686D5C5554491C9D888D42F7D8A16A27
+:108F900000291CD01C4A583211460C398A60816263
+:108FA000A36A9B888B80A16A836A09881980002143
+:108FB000836A04E0A56AAD686D5C5554491C9D88C0
+:108FC0008D42F7D82C210A5D0F4960390A73216A56
+:108FD000002909D00B4914310162226A52884A8063
+:108FE000216A026A098811806168002904D0054954
+:108FF000C91D416061684160034800218038FFF766
+:1090000039FF70BD642000203026002010B5028892
+:10901000204C102A15D00021112A15D0192A0FD161
+:10902000807900280CD1607901281CD002282DD02D
+:10903000032805D12171E2680846002A00D0904734
+:1090400010BD8088208110BD617013490979A1711C
+:10905000808821898842F6D1012012E02169002907
+:10906000F1D0884710BDA079002809D009481930EF
+:1090700002F0EEFD002803D0A079401EA071EBE7BE
+:10908000022000F02BF80028E8D110BD022020714A
+:109090000320F6E7642000203026002010B50228C7
+:1090A00001D003280ED1084C207800280AD00020D7
+:1090B0002070607900F012F8002803D0216900299F
+:1090C00000D0884710BD00006420002010B50721A3
+:1090D0000148FFF79AF810BD7C200020F0B5604CE5
+:1090E00087B0607106A802F01DFE002879D10698AD
+:1090F0000127002801D02770AFE0FFF7E7FF594DA7
+:1091000000266878002808D06079012816D1E16827
+:10911000002906D0E770072088476079012802D02F
+:109120000CE0E67002E06878002805D04C48193061
+:1091300002F08EFD002801D102206071287A0028FB
+:1091400004D16079022801D103206071287D0028B4
+:1091500004D16079032801D166712671E168002984
+:109160000AD06079022801D0032805D12878002888
+:1091700002D06078002814D0A67018216846FFF746
+:1091800044F86846067001960672039660790128D5
+:109190000BD0344F0426503F02280FD0032850D163
+:1091A0002EE0A77006208847E7E72D481830019089
+:1091B0006846077046820682277145E0288A69461C
+:1091C0004882A88908822748503803F0FFFC00280D
+:1091D00005D02878002802D06078002802D002202C
+:1091E0002EE03BE00220694608721E480397803853
+:1091F000C6700021FFF73EFE00282FD1267120E027
+:10920000288B69460882A88B48821648503803F09C
+:10921000DDFC002805D02878002802D060780028DE
+:1092200001D003200CE00220694608720D48039724
+:109230008038C6700021FFF71DFE00280ED10520E2
+:1092400020716079002803D0684673DF002805D1BB
+:10925000E168002901D020798847002007B0F0BDDF
+:10926000642000203026002073B586B0044669468D
+:10927000227C097F00208A4225D0002501266846ED
+:1092800000950680458007A801902174E188608AD6
+:109290006A46A4DF002816D1608A0D49884214D09E
+:1092A000207D002811D00295039504950595E1884D
+:1092B00068460181867241888181049001980590F9
+:1092C000608A02A9A6DF08B070BD0820FBE7000095
+:1092D000FFFF000038B50446086820600020C04346
+:1092E000608208792075FF200D46207401216846B0
+:1092F000817006490180221D69460120A0DF0028F7
+:1093000003D129462046FFF7F7FC38BD0F180000AF
+:1093100038B50A88102A1AD0112A1AD0502A1BD11F
+:10932000027D002A18D0CA884389891D9A4213D128
+:109330000A8B022A10D10268002A0DD0CB7E8C7EC7
+:1093400019022143C907C90F07D0002106E0898807
+:1093500001E00021C943418238BD01216B461970EB
+:109360006946904738BD000070B5054601461C228D
+:109370000F48FEF723FF0F4C0026267029680029AE
+:1093800007D00822A018FEF719FF204608307ADF20
+:1093900002E0084808307BDF002808D1401E6080CA
+:1093A00004486670044A0021001DFFF781FB70BD70
+:1093B000A82600208420002029CA0100F8B5224CEC
+:1093C000028800271F4DE689102A16D029464968D1
+:1093D000112A21D0122A2DD0502A1CD1C288801DDA
+:1093E000B24218D1028B022A15D1C27E837E1002AE
+:1093F0001843C007C00F0CD112E081886980014674
+:109400001048082216311030FEF7D8FE6F70002E7B
+:1094100001D100F0B7FEF8BD0020C04368806F7036
+:109420000846FFF707FC0028F5D0A1690029F2D013
+:109430008847F8BD811D034808221030FEF7BEFEA4
+:10944000E7E7000084200020A826002010B502488D
+:109450004068FFF7EFFB10BD8420002030B585B0D9
+:109460000D46040039D0002D37D06868002834D06C
+:109470000020C0431A4B20800FCB049301AB07C3DD
+:1094800018486946088001A8811E63DF002822D1A0
+:10949000221D69460120A0DF00281CD16846807883
+:1094A000A071204601F0D2F8002814D1204601F026
+:1094B00089F800280FD12946204601F009F9002833
+:1094C00009D16868A062A868002800D0E062064957
+:1094D00001200870002005B030BD0E20FBE7000021
+:1094E0000CCC0100301500009C2000203EB5002867
+:1094F00028D0002926D0826A002A23D00A88102A80
+:1095000021D0112A30D0502A1FD0512A1AD10A4610
+:109510000446891D0878022814D14888238A984275
+:1095200010D1907A04280DD006280BD0052809D038
+:109530002046891C02F0D4FA002803D0E16A0029F1
+:1095400000D088473EBD898810E0CB8802899342CD
+:10955000F8D108226B461A708A7F1A712031029165
+:10956000826A694690473EBD0021C94301803EBDE5
+:1095700030B585B0002822D00388134CA34220D0F8
+:10958000124B1B78002B1CD0104B10255B1C1D7040
+:109590005970002401259A70032269460A820094BA
+:1095A000019402940394028A0A808D708C8004A92D
+:1095B0000291039300886946A6DF05B030BD0E20F6
+:1095C000FBE70820F9E70000FFFF00009C200020D7
+:1095D0007FB504460121684681714A4981804A4A23
+:1095E00001A90120A0DF00287ED1228825463C3534
+:1095F000002A09D044482B46801C009043486168EB
+:1096000000F00CFC00287BD12289002A0AD03E48B9
+:109610002B460A3000903D48E168401F00F0FEFBF9
+:1096200000286DD1228A002A0AD037482B461230F2
+:10963000009036486169001F00F0F0FB00285FD100
+:10964000228B002A0AD030482B461A3000902F482F
+:10965000E169801E00F0E2FB002851D1228C002A33
+:109660000AD029482B46223000902848616AC01E43
+:1096700000F0D4FB002843D1228D002A0AD02248D2
+:109680002B462A3000902148E16A401E00F0C6FBBC
+:10969000002835D1216B00290ED002A803F08CF8E8
+:1096A00019482B46323000901848082202A9801F22
+:1096B00000F0B4FB002823D1606B00280BD01249C6
+:1096C0002B463A310091027901681048401C00F0A5
+:1096D000A5FB002814D1A16B002910D002A802F02C
+:1096E00001FB0948423000E00AE0009007482B46A1
+:1096F000072202A9273000F091FB002800D10020AA
+:1097000004B070BD0A180000A4200020292A00001F
+:1097100010B5044601F04AF92146114800F07EF8E0
+:109720000F4821461838FFF7F3FD2046FFF746FEA5
+:109730000B4821468030FFF7D9FE208810280BD136
+:10974000072000F011FA002803D000221146FFF78D
+:10975000ADF80449A08888802046FFF757FC10BD6B
+:10976000002500200020002030B50446008C134A5C
+:109770008BB090421FD006AA204601F019FF69461F
+:1097800005460880002001900290039004902289F1
+:109790008A8001228A71088106A803910490208C96
+:1097A00001A9A6DF002804D169460988A94200D092
+:1097B0000C200BB030BD0820FBE70000FFFF0000CD
+:1097C00038B5044608682060087960710020C043FD
+:1097D0000D4620840020222108554C2108530121E8
+:1097E000684681700C490180A21D69460120A0DFF6
+:1097F00000280FD12946204601F082FE002809D119
+:10980000A868002805D02946204600F08DF80028D9
+:1098100000D1002038BD00000D18000038B50A88BE
+:10982000102A17D0112A17D0502A18D1CA88838934
+:10983000891D9A4213D10A8B022A10D10268002A8C
+:109840000DD0CB7E8C7E19022143C907C90F07D0EA
+:10985000002106E0898801E00021C943018438BD68
+:1098600001216B4619706946904738BD70B50546B1
+:1098700004464035A8890E46142807D12622A1188F
+:10988000881EFEF79BFCA889401EA88180B241007B
+:109890000919401CA8818E8470BD203081707047EA
+:1098A00070B504460D460846FEF7BAFC2080656098
+:1098B00070BD0A780270497841700220704700003C
+:1098C0001CB5002348221549082002F0B3FE0028E9
+:1098D00003D000221146FEF7E9FF0020009001901E
+:1098E000012069460870684660DF002803D0002226
+:1098F0001146FEF7DBFF0A4802F092FE002803D073
+:1099000000221146FEF7D2FF064802F0ABFE002807
+:1099100003D000221146FEF7C9FF1CBD8C24002095
+:1099200011970100A9C70100F0B58FB00D4606469A
+:109930001C216846FEF769FC684601780220014355
+:10994000684601700024019403940494059401274F
+:1099500008A8069487701549684601840794E97B36
+:109960000177297C4177807FF9210840F721801C0D
+:109970000840EF21084041084900684681771421DA
+:1099800009A8FEF742FC08A8099007A80A906846B3
+:109990008785C4850786A8680D903346F088103304
+:1099A00009AA6946A2DF0FB0F0BD0000382A000006
+:1099B0001CB5044681786A460C4802F0C7F90028B5
+:1099C00012D160781C21484309491C2340181A46CB
+:1099D000694602F073FA064806494C30807A8000E6
+:1099E0000A582146684690471CBD0000002100200F
+:1099F000A427002030CC0100F8B5054608206946B0
+:109A0000088001236A461D492846AADF1C480068D1
+:109A10008047B12044DF002803D000221146FEF722
+:109A200045FF11DF002803D000221146FEF73EFF5C
+:109A3000144C606913DF002803D000221146FEF7A2
+:109A400035FF284600F062FD01210F4A88051060AD
+:109A50000E4802680D4B002080330D4685401542AC
+:109A600004D0C606F60E0D46B5401D60401C2028E9
+:109A7000F3D3606900F00CF8F8BD00004429002021
+:109A8000682100200010001080E200E000E100E00A
+:109A900010B5FEF73FFB10BD30B4002201290BD1F9
+:109AA0000B49C968002907D00A4B94001C5984420D
+:109AB00004D0521C042AF8D330BC7047042AFBD2CD
+:109AC00003481030805C0028F6D030BC0847000006
+:109AD00044200020DCCB010004280CD2074A126984
+:109AE000074B80001B5C01209840904300D0012070
+:109AF0000870002070470020FAE7000000050050C1
+:109B0000DCCB0100F0B500210F4D01270F4A0323E4
+:109B10001B048C002E593C468C40044207D0B400F4
+:109B2000A41826689E43266026681E4305E0B400FC
+:109B3000A41826689E43266026682660491C0429CE
+:109B4000E7D30020F0BD0000DCCB0100000700508F
+:109B500002460020042A02D2024B99547047072083
+:109B6000704700005420002010B5054A0146127AC3
+:109B70000020D20702D0084600F04AF810BD0000CD
+:109B80004420002070B50E461C4905464E608D608D
+:109B90000020CA60A90717D5002420460B30C1B2A7
+:109BA0002046FFF7D5FF641C042C02D20028F4D015
+:109BB0000AE0002808D1720804211148FEF700FECF
+:109BC000002801D1FEF7EEFDE90706D00F220D496E
+:109BD00052058A600023CB608A6100280DD10748B6
+:109BE000094A00211430FEF763FF002805D103481D
+:109BF000064A01211830FEF75BFF70BD44200020AB
+:109C0000ECCB01000005005029B701008D87010051
+:109C1000FEB5784906464F684B690093BB00FB18B8
+:109C200000200122019352050546734C3300FEF7D4
+:109C30006FFC180D13133749596C828E858E97A1CE
+:109C4000A5A5A5A5A5C3C8CDD4DADA120B22520565
+:109C5000A260E5600D70FEBD05208005A060E56096
+:109C600060680F235B055840800209D5A260E5605B
+:109C7000022E02D1E120C0000AE07D20400107E071
+:109C8000E260A560022E01D1C82001E0FF209130E2
+:109C90000E706421FEF77CFA78430022014646E00C
+:109CA00005208005A060E56060680F235B055840D3
+:109CB000800204D5A260E56019204001E8E7E26077
+:109CC000A560E1E705208005A060E56060680F23DE
+:109CD0005B055840800202D5A260E560CDE7E260F6
+:109CE000A560D3E705208005A060E56060680F23CC
+:109CF0005B055840800202D5A260E56001E0E260A9
+:109D0000A5600E707900002211E005208005A0609A
+:109D1000E56060680F235B055840800202D5A260B1
+:109D2000E56001E0E260A5600E700022394600980F
+:109D3000FEF73EFFFEBD05239B0544E06068012160
+:109D400089050A468243A2600840E06010E061682D
+:109D50000120800502468A43A2600140E160E4E7F9
+:109D600061680120800502468A43A2600140E160EB
+:109D70000199C8E70F214905E1601BE00F4688699A
+:109D8000FEF758FF11218A1B1C4E01D0002802D07B
+:109D9000A660E560FEBD012A0BD91046C8214843E4
+:109DA0006421FEF7F5F9796800224143B869FEF7AE
+:109DB000FFFEE660A560FEBD0F225205A260E560D1
+:109DC00015E007239B05A360E5600EE00D22520518
+:109DD000A260E5600122920507E00322D205A2609D
+:109DE000E560921001E00F225205E260A5600E705E
+:109DF000FEBD00004420002000050050000080004F
+:109E0000012905D0002908D1027843681046184777
+:109E1000037842680121184610477047FFB58FB09C
+:109E20001E4615460F0004D1002211461046FEF7CB
+:109E30003DFD002D04D1002211461046FEF736FDEF
+:109E40001C216846FEF7E1F96846017802200143CB
+:109E50006846017000240194039404940594012140
+:109E600008A80694817068460F9901840794317898
+:109E7000017771784177807FF9210840F721801CB4
+:109E80000840EF21084041084900684681771421C5
+:109E900009A8FEF7BAF908A8099007A80A90684629
+:109EA0008585C485058604480D9709AA69460088FA
+:109EB000189BA2DF13B0F0BDA4200020F8B53B49E9
+:109EC00014230A780F205A43541821792569384EF3
+:109ED000241D02291AD004292ED0052964D101F0AD
+:109EE000AFFF01462846FEF753F9064601F0A8FFEA
+:109EF0000146A08871434019401A870801F0A0FF6D
+:109F0000711C4843A1886288891836E0B0882269AC
+:109F1000800261881318091AA288281810180122D3
+:109F20009202914203D28A08194629DF37E0FF22C4
+:109F30000132194629DF32E0A2681C481101CC30F9
+:109F4000091808894B894968A94203D16188584397
+:109F500088421BD0022A19D001F072FF0146284620
+:109F6000FEF716F9064601F06BFF7043281A8708C2
+:109F700001F066FF711C484361883A464919401A4E
+:109F800083083146204602F079FB08E001F058FFD3
+:109F900001462846FEF7FCF8B188401828DF002863
+:109FA00002D1024901228A70F8BD00003428002045
+:109FB0001421002010B5084900204A78002A09D051
+:109FC0008978002906D1FFF779FF002802D01128EF
+:109FD00000D1002010BD000034280020142250437E
+:109FE000054A002180180171C18001220161C2600F
+:109FF000416101817047000034280020F8B5134CFE
+:10A00000069E65780A2D1FD027787D19EDB20A2D9E
+:10A0100001D30A3DEDB214277D432D19287100208C
+:10A0200068716A6103C92961E860EB802E81A178BB
+:10A030000020002904D1FFF741FF112800D10020A2
+:10A040006178491C6170F8BD0420F8BD34280020F7
+:10A05000F8B5224801694A1C3DD024225143826848
+:10A0600089184E681E494C6847690079E11B0D024A
+:10A070002D0AED1C002814D101201A4A000450605A
+:10A08000184A403A50601849400008601749086073
+:10A090001749012008602F20FEF72CF80F490120F6
+:10A0A0000871B54200D23546E81900020C49000A91
+:10A0B000403108600A494968001B091B0902090A66
+:10A0C0000002000AC91C814204D90120064940044B
+:10A0D00080390860F8BD02F01BF9F8BD442100206A
+:10A0E000001501404013014080E200E000E100E083
+:10A0F00000100140F8B50D4611780646881D14463B
+:10A100001F2801D90C20F8BD33880720062BFAD36D
+:10A110001927FF01BB4202D9164A9342F3D1728834
+:10A12000062AF0D3BA4202D9124FBA42EBD1114FEC
+:10A13000BB4203D0BA4201D09342E4D8481C052266
+:10A1400020706A5420781222411C21702A542078F1
+:10A150004119308802F058FC21784018C0B22070B4
+:10A160004119708802F050FC2178401820700020BE
+:10A17000F8BD0000FFFF000010B500221146FEF7F9
+:10A1800095FB10BDF8B5164801F096FA144D00265F
+:10A19000103D144C002807D0616900291BD0012014
+:10A1A0006A461070684615E02878002805D0616975
+:10A1B000002910D0684606700CE0687800280CD0A2
+:10A1C000A16800226868FEF7F3FC002803D0A169AB
+:10A1D000002900D088472E70F8BD6168F1E70000C3
+:10A1E00094200020A826002070B5094B04469E7AD2
+:10A1F000082000250E4207D00648844202D0188964
+:10A20000A04202D10020156070BD052070BD000085
+:10A21000E4270020FFFF00000C214843064910B549
+:10A22000012240188272911E0181FF21C172072113
+:10A23000FDF7EBFF10BD0000E4270020F8B5184D36
+:10A2400069466878FEF798FB00281DD12F46002448
+:10A250001037012615E06968E000401803783146A0
+:10A260003A6899400A4210D04268002A0DD04178DD
+:10A27000012901D1002100E00121FFF7C1FD641C8B
+:10A28000E4B228788442E6D3F8BD7A680A42F6D070
+:10A2900041680029F3D041780129EDD0EAE70000B8
+:10A2A00020210020FEB50E46044681786A462348E8
+:10A2B00001F04CFD002826D160780C21204F484346
+:10A2C000C019807A40061FD4022E1DD0012E1DD049
+:10A2D0001C4DA0781C2148431B49002341181C2217
+:10A2E0006846A847002813D0022E0CD020780C21F5
+:10A2F000484313490C314018807A144980000A58A9
+:10A30000214668469047FEBD114DE2E7114DE0E75A
+:10A31000022EF8D060780C214843C019817ABF2200
+:10A320001140817260781C21484305494039411829
+:10A330001C231A466846A847D8E7000000210020E1
+:10A34000E427002079C60100E026002020CC01008F
+:10A3500001C2010049C0010070B50546114A12480A
+:10A3600000241C2363431B189B7EFF2B04D0641C1A
+:10A37000072CF6D3104670BD0A78022A09D01C2299
+:10A3800062431018FD22827607221030FDF716FF77
+:10A3900004E01C2161430818FE2181762C70002204
+:10A3A000E8E7000043800000E0260020F7B505251F
+:10A3B0000F4F06460024002E0AD01C206043C0190F
+:10A3C000072231461030FDF732FF002807D00AE09F
+:10A3D0001C206043C019018B0298814203D101986F
+:10A3E0000025046002E0641C072CE4D32846FEBD6F
+:10A3F000E02600207CB5054681B26A46074801F098
+:10A40000A5FC040008D17421684601F0C9FC0400D1
+:10A4100002D1284601F028FC20467CBD0021002006
+:10A4200070B505460C46100003D000221146FEF719
+:10A430003DFA2078152802D12846FEF7F7F90020CA
+:10A4400070BD00001FB501F001FD002803D00022FF
+:10A450001146FEF72BFA03A90120FFF73DFB002868
+:10A4600003D000221146FEF721FA03A800F006FDF2
+:10A47000002803D000221146FEF718FA01A8052192
+:10A480000130FDF7C2FE6946487901221043E121FF
+:10A490000840DF210C300840694648710720887168
+:10A4A0001020C871064800900A71064800F04EFE60
+:10A4B000002803D000221146FEF7F8F91FBD000066
+:10A4C00021A401000220002001B50549684600F0E2
+:10A4D0004DFA002803D000221146FEF7E7F908BD27
+:10A4E0006C21002010B5097800290AD0032201212F
+:10A4F000FFF73EF8002803D000221146FEF7D6F9F8
+:10A5000010BD0088FFF778FA10BD000000B58BB0D1
+:10A5100000210091254900F07FFC002817D101A9F6
+:10A52000224800F023FC002813D021491F4800F0E6
+:10A5300007FD002803D000221146FEF7B7F91C489A
+:10A5400000DF002803D000221146FEF7AFF90BB060
+:10A5500000BD0299072216481031FDF72FFE14485E
+:10A560001022C01D0299FDF729FE11481122183052
+:10A570000199FDF723FE0E4801990A222A30123173
+:10A58000FDF71CFE0A4800DF002803D00022114618
+:10A59000FEF78CF90120009004200890684609908D
+:10A5A00007A9024800F080F9CBE700006C210020E9
+:10A5B0001029002070470000014908607047000022
+:10A5C0006821002030B58FB005461C216846FDF794
+:10A5D0001CFE69460878082108431022104369468A
+:10A5E0000870002401940394049405940694A879B7
+:10A5F00008A98870144869460884601C00070794FD
+:10A60000000F0C7710304877887FF9210840F72138
+:10A61000801C0840104301210843694688771421B3
+:10A6200009A8FDF7F2FD08A8099007A80A90694655
+:10A630008C851720CC8508860D942B46A88810336E
+:10A6400009AAA2DF0FB030BD3115000030B58FB0C0
+:10A6500005461C216846FDF7D8FD694608780421A7
+:10A6600008436946087000240194039404940594F7
+:10A670000694A87908A98870144869460884601C63
+:10A6800000070794000F0C77103048778A7FF92075
+:10A690000240F720921C0240EF20024001200243BA
+:10A6A0008A77142109A8FDF7B0FD08A8099007A82A
+:10A6B0000A9069468C851420CC8508860D942B461B
+:10A6C000A888083309AAA2DF0FB030BD32150000F8
+:10A6D000F0B58FB00F4605461C216846FDF795FD85
+:10A6E00068460178022631430170002401940394E6
+:10A6F000049405940694A97908A8817017496846BE
+:10A700000184601C0107090F684610310794017726
+:10A710000020014668464177817FF9200140F720FB
+:10A72000891C0140EF2001400120014368468177E8
+:10A73000142109A8FDF769FD08A8099007A80A9047
+:10A7400068468685C48506860D972B46A8882033E3
+:10A7500009AA6946A2DF0FB0F0BD00003415000061
+:10A760003EB504461E4801781E48002930D0002C12
+:10A770002FD0217800292BD11B49002509680029F9
+:10A7800026D0A178072927D21C20184A48438018D0
+:10A79000807EFF2820D012486A46103001F0D6FA99
+:10A7A000002815D160230422694602A801F086FB27
+:10A7B0000299491C0CD0602304220D49684601F01F
+:10A7C0001FFD002804D1A178084A89001C3A555081
+:10A7D0003EBD0448801D3EBD024808303EBD00001D
+:10A7E000F020002008800000F0270020E026002054
+:10A7F0001CCC01003EB50C4627490A782749002A9F
+:10A8000030D08A1D002805D0002C03D00278002A01
+:10A8100028D101E010463EBD214A1268002A21D00D
+:10A820008178072920D21C221E4B4A43D218927EDF
+:10A83000FF2A19D01B4AA3681C3A002B17D08900A5
+:10A840005350817814486A46103001F07FFA00288E
+:10A85000E1D160230422694602A801F02FFB002801
+:10A8600009D016E008463EBD0C4808303EBD8900C0
+:10A870005158A160E5E70298401C0AD064231022D9
+:10A880006946A06801F01AFB0028EFD102996160C7
+:10A890003EBD024838303EBDF02000200880000058
+:10A8A000F0270020E0260020FEB5054629480C468A
+:10A8B0000078294900281DD0881D002D19D0002CB2
+:10A8C00017D0A268002A14D02878002812D1234873
+:10A8D000006800280ED0A97807290DD21C20204A34
+:10A8E00048438018807EFF2806D06068042806D27E
+:10A8F0000720FEBD0846FEBD17480830FEBD1548BE
+:10A90000184E6A46103001F021FA0028F6D1602373
+:10A910000422694602A801F0D1FA002803D1029866
+:10A92000401C00D0104E60230422211D6846B04711
+:10A930000028E3D1642310226846A16801F060FC7E
+:10A940000028DBD1AA78064B92001C3BA1689950E5
+:10A95000FEBD0000F020002008800000F02700204D
+:10A96000E026002049C0010001C201000C4A137812
+:10A970000C4A002B11D0931D002905D0002803D0CC
+:10A980000078002809D101E018467047064B1B6883
+:10A99000002B02D00870002070471046704700005E
+:10A9A000F020002008800000F0270020F0B50546C8
+:10A9B00093B000200090FF24E7480E940078002810
+:10A9C0004ED0E64E306800284AD001A800F048FA80
+:10A9D000002803D000221146FDF768FF00200D90EB
+:10A9E000281D05902A2168460183FF2181710021DD
+:10A9F00001710391D94C28880C3C10280ED0A888EE
+:10AA000003AA0221FFF7F0FB002807D103980C21CD
+:10AA100041430919CA7A69468A7148712A88132004
+:10AA2000CF4F172A7ED00FDC102A1BD0112A53D00B
+:10AA3000132A78D0142A13D103980C214843001903
+:10AA4000C07AFF2870D09FE0C649182A6DD01C2A12
+:10AA500063D0522A04D1B07A8000095801A88847EF
+:10AA600013B0F0BDC04E03AA01213046FFF7BCFB76
+:10AA70000028F5D103990C20484302220019827264
+:10AA800011236A4613745171A98801810722A91DF7
+:10AA9000FDF794FB287DC10707D04108AE48083078
+:10AAA000405CFF2808D00E9006E032460EA9A81D93
+:10AAB000FFF77CFC002832D103990C22514309197D
+:10AAC0000E98C8728A7A08231A438A726946887176
+:10AAD00001A8FEF76DFF22E003980C2148430119FD
+:10AAE000887AFD2210408872010706D5C0090DD072
+:10AAF000002101A8FFF7D6FB08E068468079FF280F
+:10AB000004D001F0B1F8FF206946887103980C2247
+:10AB1000504310210019817212206946087404A95B
+:10AB200001A803E08AE03FE011E0DAE00D9AFDF7CA
+:10AB3000C9FE6846007C122892D103980C2141433B
+:10AB40000919897A01298BD0FFF766FB88E7EA8922
+:10AB50000EA90020FFF72AFC00280ED103990C2231
+:10AB6000514309190E98C8728A7A08231A438A72C7
+:10AB70006946887101A8FEF71BFF03980C21484322
+:10AB80000019C07AFF2806D003981C214843734956
+:10AB90004C394018009003981C214843C219A888DA
+:10ABA0000023009982DF5BE769460874039B0C2051
+:10ABB00058430119887A042210438872C87AFF2802
+:10ABC0002ED01620694608742420434363481A2176
+:10ABD000303818180830FDF718FB03980C2148434B
+:10ABE0000019817A40221143817203990C224A4351
+:10ABF00000200A901219D27A1C235A43D2190B92C0
+:10AC0000564A59434C3A89180C900791089009907C
+:10AC1000321DA88807AB00217FDF002896D17EE790
+:10AC20000EA8FFF799FB0028DFD169460E988871BE
+:10AC300003990C2251430919C872D6E7707A0C2186
+:10AC40004008400070720398FB2341438C46091969
+:10AC50008A7A6E461A408A7214233374AB79002BB9
+:10AC600004D0C87AFFF7C6FBA87973E0EB795B07DD
+:10AC7000D5D5B379FF2BD2D0082632438A72EA7A2F
+:10AC8000920706D51C224243D219957E6D086D00AD
+:10AC90009576CA7AFF2AC2D06246A25C022A0FD0F9
+:10ACA0001C204343D81907221030FDF787FA684665
+:10ACB00080791C214843C019817EFD2211400AE0A1
+:10ACC0001C21484325494C394118498AC019018340
+:10ACD000817E490849008176012101A8FFF7E2FA47
+:10ACE0001DE7A8790209012A23D10007000F0128D6
+:10ACF0001FD103980C2242431219927A120718D5D9
+:10AD0000242148431549303940181A210830FDF7ED
+:10AD10007CFA16206946087403980C2148430119EF
+:10AD2000887A602210438872707A02210843707218
+:10AD30000FE003980C2250430019827A80231A43B3
+:10AD4000827215206A461074B07A8000095801A8F2
+:10AD5000884700200D90E2E6F0200020F027002038
+:10AD6000E026002040CC0100FFFF0000F0B50646C1
+:10AD700025480C460078254989B000283FD0881D19
+:10AD8000002E3AD0002C38D03078002837D1204817
+:10AD900000250068002832D0B078072831D21C2165
+:10ADA0001C4F4843C019807EFF282AD0E560B07848
+:10ADB00065614843C01920611548A5600C3060608A
+:10ADC0001148B17807AA103000F0C0FF002814D154
+:10ADD0001C231A4607A9684601F070F800280CD118
+:10ADE0000B49E5600C3165612161B1781C2251434A
+:10ADF000C919A56061606946216009B0F0BD0846C7
+:10AE0000FBE702480830F8E7F02000200880000047
+:10AE1000F0270020E026002030B50446002903D0AA
+:10AE20000878002814D101E00B4830BD0B480023FE
+:10AE3000006800280CD0094AFF2088700C3A158958
+:10AE40000520A542F1D14B70D07A8870002030BD2A
+:10AE50000148801F30BD00000E800000F027002058
+:10AE6000002806D0FF21017041708170C170002060
+:10AE700070470148704700000E800000F0B585B0B3
+:10AE8000040036D0294800250560457285722846A1
+:10AE9000FFF7C2F9254824213038FDF7B6F900261E
+:10AEA000FF27304600F0E0FE21488755761C072E2C
+:10AEB000F7D37421684681800721C1801D481C4951
+:10AEC00000900831684601F04BF800280FD1184E69
+:10AED0000120083E3070207800280CD06946888810
+:10AEE000C988484381B23046103000F059FF05B0A0
+:10AEF000F0BD1148FBE7114F00240D48A1B202AA92
+:10AF0000083000F023FF002809D11C206043C0193D
+:10AF100000231C2202A900F0D1FF002801D03570C7
+:10AF2000E5E7641C072CE8D3E1E70000F0270020E8
+:10AF3000F8200020C1AF01000E800000E0260020B4
+:10AF40000B4610B51A491B4A0978002920D0911DDB
+:10AF5000002805D0002B03D00178002918D101E08A
+:10AF6000084610BD14490968002911D0114A81789A
+:10AF7000D21EFF290ED01C20414310480918887E9C
+:10AF8000800705D4072218461031FDF717F9002273
+:10AF9000104610BD4078FF28FAD00C2148430649DE
+:10AFA0000C394118887A8007F2D507221846ECE759
+:10AFB000F020002008800000F0270020E02600207C
+:10AFC000FFB55D488FB00068189F1E46002875D0F9
+:10AFD000742F73D86846FFF743FF002803D0002280
+:10AFE0001146FDF763FC0024684604700471254691
+:10AFF00005970696A9B20DAA504800F0A7FE0028B2
+:10B0000006D108220DA90F98FDF711F9002817D0D5
+:10B010006D1C072DEED368468578FF2D4ED0109815
+:10B02000042810D046481C21301AFDF7B1F801273A
+:10B0300007281ED204A80290119800280BD011E016
+:10B0400068468570E7E7742F03D040206946087191
+:10B050006CE02020FAE738463849A84010394968A2
+:10B06000084261D0284601F0D5FC202069460871CD
+:10B070004AE031481C214C38301AFDF789F8002885
+:10B080001DD02D4824213038301AFDF781F80100F9
+:10B090002C482CD040216A4611712B498E4245D054
+:10B0A000274AA9001C3A5158B1423DD104A9029146
+:10B0B000C07A854228D16846447025E034E004A86F
+:10B0C000029020216846017144701B480A940C309C
+:10B0D0000B9058380790684680781C2148431849DF
+:10B0E0004018089007A80690182005900CE0302220
+:10B0F00069460A714C70CF70807A800704D4114879
+:10B1000024212438FDF781F810986946032808792E
+:10B1100010D0022108436946087104A8029001A9D1
+:10B120006846119AFDF7CEFB13B0F0BD6946087969
+:10B130000321EFE73843EFE7F0270020002100204C
+:10B14000E0260020E42700201CCC010070B5064654
+:10B1500019480D46007800280ED01849002E0ED050
+:10B16000002D0CD02868002809D0154C2168002932
+:10B1700007D012480A3870BD1048801F70BD0846BD
+:10B1800070BD20600522691D201DFDF717F8287984
+:10B19000A072207A0221400840000843FB210840A9
+:10B1A0002072E07901221043FD2210400840E07136
+:10B1B0000020307070BD0000F02000200E800000E4
+:10B1C000F027002010B50E4900238A78CC78A242DF
+:10B1D00012D0521CD2B28A70022A00D18B708A78A7
+:10B1E000074B92001C339A580260486910180002FD
+:10B1F000000A4861012010BD0360002010BD00005E
+:10B2000044210020F7B5144C0025A76823691EE0EF
+:10B2100024215943C9194E68864202D9301A486020
+:10B2200017E0801B751900264E600E750E699C464E
+:10B230000B6AB646002E0AD0019E76193602360AEF
+:10B240008E607646CE6016680E6261461160591CAB
+:10B25000DED12361FEBD0000442100200EB5112087
+:10B2600069460872072214A102A87CDF002803D0D7
+:10B2700000221146FDF71AFB114878DF002803D0A1
+:10B2800000221146FDF712FB0020FF220090413200
+:10B29000694601900A804122D2004A808880FF20BE
+:10B2A0009130C88068467ADF002803D0002211461A
+:10B2B000FDF7FCFA0EBD00004466755F48524D0074
+:10B2C00041030000002070470020704700207047B5
+:10B2D000F8B506464078242104464C4324490C2204
+:10B2E00050436118224A00254B6824328018AE462C
+:10B2F0002F469C46002B0CD0827A1346D20908D0E8
+:10B300005A0606D40D461A4A614689B217590835BD
+:10B310008E46174C008924343B4672462946A9DFE5
+:10B320000B2819D0002800D01248012F13D17078B3
+:10B330000C214843001900890F4AA7DF00280AD0D2
+:10B340000E49884212D0082810D0891C88420DD09E
+:10B3500011280BD00020F8BD70780C214843012340
+:10B360000019008972462946A9DFE0E70148F8BDC7
+:10B37000C027002041800000FFFF000002300000D5
+:10B3800070B50C46014660782422084D50434019A0
+:10B39000382300F093FD002807D16178242251431F
+:10B3A00049194A68521C00D14A6070BDC02700206C
+:10B3B000F3B589B00D461A206946888368780C2158
+:10B3C00003274843224E3B468019008907AA694655
+:10B3D000AADF002838D1687824214843741A00195C
+:10B3E00069468A8B0830FCF722FF0028687807D06E
+:10B3F000242148430119496800290DD0154E0CE05D
+:10B400000C2141438919897A89071DD42421484395
+:10B410000019FCF7FAFE17E00F4E27506846828BA2
+:10B42000687824214843001942606878484300192D
+:10B4300069460830FCF7C2FE6878242148430119A8
+:10B44000382324220998B04700200BB0F0BD00003B
+:10B45000E427002001C2010049C0010010B5FFF738
+:10B4600037FF10BD10B5FFF78BFF10BD10B5FFF70C
+:10B470009FFF10BD70B5094D04460E46E868FDF704
+:10B48000D9FB002809D128461030066044603443B7
+:10B490002246A968E868FDF78BFB70BD20210020DB
+:10B4A00010B51349134800F0BFFF124C81B2283C7D
+:10B4B000A068401CA0600E486038FEF755F90028CF
+:10B4C0000BD0082809D00C49884206D00B49884285
+:10B4D00003D000221146FDF7E9F90321A068FCF72B
+:10B4E00057FE002901D0012000E00020207010BD8F
+:10B4F00060250020282000200430000001340000D6
+:10B50000F0B5002406460D46601C010795B0090FF2
+:10B5100008A810310C940174297B4174817CF927AF
+:10B520003940891C81741C2105A8FCF76EFE684611
+:10B53000017D10200143684601750CA806940A900D
+:10B540000894099401220B9408A88276174968464A
+:10B5500001870D94697B08A80175A97B4175817DE0
+:10B56000F7203940891C0140EF200140114308A811
+:10B57000817514216846FCF748FE0EA800900DA8BE
+:10B5800001900FAA0021304600F012F801466846EB
+:10B5900001811421448181810FA804903346F088F1
+:10B5A00008336A4605A9A2DF15B0F0BD372A0000AE
+:10B5B000F7B542790025002A00D004252222135C29
+:10B5C0000222002B00D01543CBB2FF2907D901225C
+:10B5D0001543029A090A53709170032602E00299FA
+:10B5E00002264B7004464034A189002901D0102165
+:10B5F0000D43002716E0B11C142909D9A189C91BE4
+:10B600004A007900091824302431FCF7D7FD0CE0FA
+:10B61000029B7A0012189B19928C1A70120A5A70A7
+:10B62000CEB27F1CA189B942E5DCA089C01BA081F4
+:10B63000029805703046FEBDF8B51E4C20780028F3
+:10B6400037D02069002807D00026E068002805D000
+:10B650000025002E04D013E00126F6E70125F8E7C7
+:10B66000684651DF052806D0002806D00022114682
+:10B67000FDF71CF904E0012602E0216900988847E3
+:10B68000002D12D1608869460880A06861DF052816
+:10B6900006D0002806D000221146FDF707F904E085
+:10B6A000012502E0E168A0688847002ED8D0002D6F
+:10B6B000CFD0F8BD70210020418805480288914212
+:10B6C00004D34088814201D8012070470020704790
+:10B6D0008C2000201048018CC9B2012917D1818C1F
+:10B6E000090714D1018D09060A0F03D1828D1206B4
+:10B6F000120F0ED0090F012903D1828D1206120FED
+:10B7000007D0032903D1808D0006000F01D000204F
+:10B710007047012070470000C00F00F0800701D083
+:10B72000002070470120704710B50448017AC9070E
+:10B7300002D00078FEF76CFA10BD00004420002013
+:10B74000F8B5234801690091457833E02048E900C5
+:10B75000C0680E1834782AE0182060437168641CB1
+:10B760000818B178E4B2A14200D10024017802297E
+:10B7700002D003291BD113E0154A406824219268A6
+:10B7800041438F18397D002911D001F07BF800204A
+:10B7900038750CE024277843C0180275006A03E06E
+:10B7A0000B4900228B680869471CF3D10861707847
+:10B7B000A042D1D128466D1EEDB20028C6D1044862
+:10B7C00001690098814201D00120F8BD0020F8BD38
+:10B7D00044210020F8B5044638480027016900914B
+:10B7E00046785CE03548F100C2688D1851E0601C75
+:10B7F00007D0324A24209268604321468018046AA8
+:10B8000024E02878182141436A68401CC0B25218CD
+:10B810002870A978884200D12F70284B51682420C5
+:10B820009B684843C0181378012B34D1037D002B4B
+:10B8300031D193688360D368C3601369036152692F
+:10B84000C2611E4A5279002A00D087601B4B826871
+:10B850005B6996469C46D31A1A02194B120A9A4201
+:10B8600002D2C368D21808E0724663469A1A1202DE
+:10B87000C368120A934202D99A1A426000E04760F4
+:10B8800087600122C7600275921E0262084600F0BE
+:10B89000C7FF601CABD1287869788842A7D13046B1
+:10B8A000761EF6B200289DD10448016900988142B5
+:10B8B00001D00120F8BD0020F8BD00004421002087
+:10B8C000FFFF7F0088B0FDF7FBFF01F053F8274929
+:10B8D0000120FDF71FF8002803D000221146FCF7D5
+:10B8E000E5FF002222490320FEF74CF9002803D08F
+:10B8F00000221146FCF7DAFFFEF7A4FDFFF7AEFCCD
+:10B90000FCF70CFF00F0EAFD00F054FD1C21684636
+:10B91000FCF77BFC0521C90301910F2109040020DC
+:10B9200002910090032269460A7310492C318A89DA
+:10B930006946CA8108740F4805900F48069068460A
+:10B94000FDF712FD002803D000221146FCF7AEFFE0
+:10B95000FDF79CF90220FDF7C1FB48DF0028FCD071
+:10B9600000221146FCF7A2FFF7E70000D4240020D4
+:10B97000CD0C0000BDBA010079A1010070B50546EB
+:10B9800000790E46801C1446C0B21178821C8A18B9
+:10B990001F2A01D90C2070BD0A46491C2170401C89
+:10B9A000B0542078FF22411C217032542078811934
+:10B9B000288801F029F821784018C0B22070AA88A0
+:10B9C000002A09D0A968002908D08019FCF7F6FBE5
+:10B9D0002078297940182070002070BD072070BDA4
+:10B9E000F8B514780746A01C15460E461F2803D844
+:10B9F0007878801C1F2801D90C20F8BD1D20001B61
+:10BA000080B26946864608803019801C7DDF002898
+:10BA1000F3D13878022805D168460088704501D8EE
+:10BA2000092107E078780821002801D0704501D964
+:10BA300068460088421C3255641CE2B2B154297831
+:10BA4000801C081828700020F8BD002070470020D6
+:10BA5000704700207047000031B5054C04E0401EDF
+:10BA600000902046FCF736FB00980028F7D138BD3F
+:10BA7000E703000010B5002809D0022806D1FEF720
+:10BA800073F817E000221146FCF710FF10BD0020EC
+:10BA9000FEF76AF8002803D000221146FCF706FFE3
+:10BAA0000320FEF72FF8002803D000221146FCF7F0
+:10BAB000FDFE3CDF0028E5D110BD000010B5007888
+:10BAC000002809D105483B21808876DF002803D073
+:10BAD00000221146FCF7EAFE10BD00000020002005
+:10BAE000F0B58BB004460227684607730026099616
+:10BAF0008784C68408A80A900D46A18A208809AACE
+:10BB0000A5DF002804D0E16A00291AD0884718E090
+:10BB10006846008CC007C00F13D068460682208894
+:10BB200003A9A8DF002813D1A97E28461B300122D3
+:10BB30000B00FCF7EDFC09460F1C2227292C442E94
+:10BB40004600FF20FE3069460882208803A9A8DF4E
+:10BB50000BB0F0BD6B461E700BE006221EE069467E
+:10BB60000A71029027E0204690470020F0E76B46DC
+:10BB70001A702B8B022BF2D2EFE7684607706946EA
+:10BB8000A26AF0E7032000E00420694612E00520E5
+:10BB9000FBE7298B032905D2032208212046FDF764
+:10BBA000E7FCD5E7417802780802104369468880AF
+:10BBB00003D006200870A26AD5E70720FAE709201B
+:10BBC000E3E70322EAE7000010B51D4A1D49030020
+:10BBD000FCF79EFC05040B31202712004878012851
+:10BBE0001FD0022808D1032005E04878002804D09F
+:10BBF000032801D10220487010BD134B04201860A7
+:10BC0000124B012018609368D2689A42F3D0FCF777
+:10BC10009BFC10BD4878012806D0022804D00328D8
+:10BC2000F7D1FCF7C9FC10BD9068D1688142EED114
+:10BC3000FCF7B0FC10BD48780128E8D010BD00002A
+:10BC4000242800200821002000250040002000407A
+:10BC50000021425C002A01D001207047491C0629BE
+:10BC6000F7D300207047000070B505461C200D4931
+:10BC700068434418204611300621FCF7C6FA2046D6
+:10BC80001021FCF7C2FAFF2121740020A176C043E5
+:10BC90002083284600F0BEFE024A0020A9001C3A7C
+:10BCA000505070BDE0260020F0B50C4A00215368CA
+:10BCB0001422504301240A4D03273F041E582246F4
+:10BCC0008A40164206D08A0052191668BE43166092
+:10BCD00016681660491C2029F0D3F0BD38210020D9
+:10BCE0000007005070B50D00044604D10022114633
+:10BCF0001046FCF7DBFD002C04D100221146104653
+:10BD0000FCF7D4FD2878207069886170090AA17059
+:10BD1000A988E170090A2171E8886071000AA071A0
+:10BD200070BD000007490978002906D0002806D018
+:10BD300005494978016000207047082070470E20AF
+:10BD400070470000142100203428002030B5124B29
+:10BD50001B78002B07D0002807D0002A05D00468E4
+:10BD6000002C12D103E0082030BD0E2030BD0B4B5B
+:10BD70001D68002D09D045681889414369185D89FF
+:10BD8000454358682818884201D8072030BD146000
+:10BD90000020516030BD0000142100200029002047
+:10BDA000F8B505461B480F460078002805D0002D41
+:10BDB00005D02868002820D103E00820F8BD0E2017
+:10BDC000F8BD154C00262068002816D0608921890E
+:10BDD000484361684118686881420ED9FFF79EFCAC
+:10BDE00000280CD029686868090109194A6809897E
+:10BDF000801AFCF7CDF9002903D00720F8BD1020E8
+:10BE0000F8BD3B460022294604200096FEF7F6F8CE
+:10BE1000F8BD0000142100200029002010B50748BB
+:10BE20004469601C06D000F00BF801462046FCF780
+:10BE3000AFF910BD01200007406910BD00100010CF
+:10BE400001200007006980B270470000F8B50024A7
+:10BE5000184D194EAC806C7034707470B4702746F5
+:10BE60003846FEF7BBF87F1C0A2FF9D36C80FFF72A
+:10BE7000D5FF871EFFF7E4FF47430F48AF60AC8054
+:10BE8000CC30046004818481448108206870FFF70D
+:10BE9000D7FF0746FFF7C2FF441EFFF7D1FF6043FD
+:10BEA0003946FCF775F928DF002802D10121B1706D
+:10BEB0002970F8BD1421002034280020FFB5264841
+:10BEC00081B000781F4616460D46002808D0002D88
+:10BED00009D00198002806D02868002818D104E06D
+:10BEE000082005B0F0BD0E20FBE71C4C20680028A0
+:10BEF0000ED0618920896268414389186A6891423D
+:10BF000006D9002E04D0B04202D3F119814201D9E2
+:10BF10000720E6E70198FFF701FC00281AD0384611
+:10BF2000FFF7FCFB002815D06868FFF7F7FB002837
+:10BF300010D068683246C1190198FCF73FF90096A5
+:10BF4000286800220001245803212846019BA047AD
+:10BF50000020C6E71020C4E714210020002900209B
+:10BF6000F8B5374D044628780E4600282ED0002C10
+:10BF70002ED0002E2CD02068002829D0FFF760FF9B
+:10BF80000146A088814228D3102826D3E0880028C3
+:10BF900023D0FFF743FF471EFFF752FF4743E088D8
+:10BFA000A1884843A9684018874216D3FFF748FF85
+:10BFB0000146E088A288504381420BDAFFF740FF38
+:10BFC000A188FCF7E5F8002907D103E00820F8BDB7
+:10BFD0000E20F8BD2079800701D00720F8BD6888C1
+:10BFE00001281BD03060174FA9680201D019716079
+:10BFF00041602168B950A1880181E1884181A08810
+:10C00000E188002648430446761CB6B2FFF718FFC5
+:10C01000A04205D2FFF714FF241A02E00420F8BD65
+:10C020000024FFF70DFFA9684018A860002CEBD191
+:10C0300068880101C9198E81401C68800020F8BD04
+:10C040001421002000290020F8B5044620481E468F
+:10C05000007815460F46002807D0002F07D0002C87
+:10C0600005D02068002817D103E00820F8BD0E2075
+:10C07000F8BD1848016800290ED04289018940683E
+:10C080004A4310186268904206D9002D04D0A94294
+:10C0900002D3A819884201D90720F8BD3846FFF716
+:10C0A0003DFB002811D03046FFF738FB00280CD0AC
+:10C0B0006068FFF733FB002807D02B463A4621463D
+:10C0C00002200096FDF79AFFF8BD1020F8BD000091
+:10C0D0001421002000290020F8B507460020464E14
+:10C0E0008646B07801281ED10020444BB0705A78A3
+:10C0F000082A19D034462578142169430C19022FD7
+:10C1000020D0032F0FD16079401CC0B26071241D74
+:10C1100003286AD0FDF7D2FE002804D0112802D0EF
+:10C120002146FCF7B3FCF8BD022F09D01870FDF7CB
+:10C1300041FF0028F7D0317814225143891959E082
+:10C140005870F4E72D498B885B1C9EB28E80237952
+:10C15000241D022B05D16788B102B94201D3012108
+:10C1600000E000218C46052B01D1072A03D00021D5
+:10C17000042B02D003E00121FAE7072A03D00027AD
+:10C18000042B02D007E00127FAE76488B302A34238
+:10C1900001D3002A27D000223943114362461143BC
+:10C1A00017D0164A1449507090804878401E487045
+:10C1B000681CC0B208700A2801D30A38087014201D
+:10C1C000684341187046091DFCF760FC2846FDF7DE
+:10C1D00005FFFDF7EFFE0028A5D0074914230A78D4
+:10C1E0005A43511806E00122D6E73078142148431B
+:10C1F00081190D20091D94E7342800201421002006
+:10C20000F8B5044620481E46007815460F4600281B
+:10C2100007D0002F07D0002C05D02068002817D1A8
+:10C2200003E00820F8BD0E20F8BD18480168002979
+:10C230000ED04289018940684A43101862689042D2
+:10C2400006D9002D04D0A94202D3A819884201D9E9
+:10C250000720F8BD3846FFF761FA002811D03046B4
+:10C26000FFF75CFA00280CD06068FFF757FA002847
+:10C2700007D02B463A46214605200096FDF7BEFE24
+:10C28000F8BD1020F8BD0000142100200029002076
+:10C2900010B5134813498088884207D0132176DFF0
+:10C2A00005E000221146FCF701FB02E074DF0028E4
+:10C2B000F7D10020FDF758FC002803D000221146DA
+:10C2C000FCF7F4FAFDF7C2F8002803D0002211466B
+:10C2D000FCF7ECFAFF20F530FFF7BEFB10BD0000C5
+:10C2E00000200020FFFF000010B50748007800285C
+:10C2F00009D005480549303000F096F881B203486E
+:10C300007038FDF7B3FA10BD002000207025002022
+:10C3100070B501240B49600408600B494010886027
+:10C32000094940398860094D6C602F20FBF7E2FE17
+:10C33000AC60074D00242F206C61FBF7DBFE2C71F5
+:10C3400070BD000080E100E040130140001001409A
+:10C3500044210020F0B500220123032636041F46A5
+:10C360009740394212D0C5683D4203D1012464048C
+:10C370003D4301E03446BD43C560064D97007D193D
+:10C380002F68B7432F602F6827432F60521C202A45
+:10C39000E5D3F0BD0007005010B5044801224178F4
+:10C3A000514041700248FDF778FA10BD002000208E
+:10C3B0000025002070B514480124512164258460B3
+:10C3C00022C004711049114800F022F80E488C2157
+:10C3D00010300160FF212D3141600A21816000266B
+:10C3E000067301460948083000F012F80648FF219C
+:10C3F00020300560F53184604160067301460348D2
+:10C40000103000F005F870BD5025002020200020DD
+:10C410000A7B002A03D049680160002102E0096814
+:10C42000016001210171704710B504798B680268C1
+:10C43000002C08D049688C1A9C4201D9D11807E019
+:10C440000160002108E00968541A9C4202D9D11AFF
+:10C45000016002E0016001210171006810BDF7B5C3
+:10C4600082B002981446806A0F46002833D00298A2
+:10C4700000252030009028E00298816A0C20684353
+:10C480000E18217830794A1C2270C01C785420780C
+:10C490001622411C21703A542078C119308800F0CE
+:10C4A000B3FA21784018C0B22070B288002A09D0AF
+:10C4B000B16800290FD0C019FBF780FE20783179D0
+:10C4C000401820706D1C0098EDB2007BA842D3D8B4
+:10C4D000002005B0F0BD0720FBE7000030B59FB09D
+:10C4E000032118A80175142110A8FBF78EFE002463
+:10C4F000012510A8109405711DA81290601C010759
+:10C50000090F10A81031017344738473601C010774
+:10C51000090F10A81031C1730020014610A8017442
+:10C5200001463348FDF74CF9002803D0002211469C
+:10C53000FCF7BCF9142115A8FBF767FE01200146A2
+:10C5400018A8103141700120014618A810318170DF
+:10C550000020014618A8C1700120014618A810311A
+:10C56000017110A815940576642118A8179401701C
+:10C570001F4815A91838FCF7ADFE002803D000228B
+:10C580001146FCF793F940216846FBF73EFE19A1DE
+:10C590006846FDF785F90120014608A810310177AA
+:10C5A0000020014608A841776846FDF711F80028E9
+:10C5B00003D000221146FCF779F913481B901A9416
+:10C5C0001C9410A805850A481AA98030FCF746FF7C
+:10C5D000002803D000221146FCF768F90B48FDF74C
+:10C5E000EBFF0B488078FDF76FFF1FB030BD0000F8
+:10C5F000002500204E6F7264696353656D69636F37
+:10C600006E647563746F7200E5A4010091C201004D
+:10C610000020002010B508461146C046C04610BD97
+:10C62000002803D00249C860002070470E207047E0
+:10C630007021002070B5002901D08C0701D007209F
+:10C6400070BD064C0125A16062800549636010DF62
+:10C650000028F5D1257016202EDF70BD7021002036
+:10C6600015C60100002803D0024908610020704768
+:10C670000E2070477021002000207047FFB581B068
+:10C68000484C0E46039F049A0546617803201743E1
+:10C69000002903D1002F0DD001216170039AC9B286
+:10C6A000920000920B00FBF733FF072C071B2E466E
+:10C6B0005D6C2C000221F0E7FFF7C2FB8708FFF753
+:10C6C000BFFB70430546FFF7A9FB461EFFF7B8FB0B
+:10C6D00070433A46294629DF002812D102210FE093
+:10C6E000304628DF00280CD10399002901D003210E
+:10C6F00006E00499002917D12978042950D018E0C0
+:10C70000617005B0F0BDFFF789FB471EFFF798FB8E
+:10C710004743FFF795FB70433946039A29DF00280A
+:10C72000EFD10499002901D00421E9E729780429EF
+:10C7300025D00521E4E7FFF771FB471EFFF780FBDB
+:10C7400047436888391800980F18FFF779FB698804
+:10C75000704341180098049A0818394629DF0028C8
+:10C76000E4D0CEE7FFF76CFB00997043401869886E
+:10C770008A08296929DF0028C3D1002F10D006219B
+:10C78000BEE7FFF75DFB0646FFF748FB451EFFF7D8
+:10C7900057FB68433146FBF7FBFC28DF0028B0D18C
+:10C7A0000721ADE71421002010B50446FFF794FCE3
+:10C7B0002046FCF773FC10BD70B50C00054604D193
+:10C7C000002211461046FCF771F8002D04D100221A
+:10C7D00011461046FCF76AF8207828702088FF215F
+:10C7E00009020840000A6870206809020840000C2D
+:10C7F000A8702068000EE87020792871207A68718E
+:10C800002089000AA871A068000CE87170BD0000C2
+:10C8100001200249000508607047000000E200E0C6
+:10C82000F0B5174F2421BC6841430D1939694A1CE2
+:10C8300009D024224A4316196B687268934204D8BF
+:10C84000D21A726029623861F0BD0A4602E00A46D7
+:10C85000396A9B1B4E1C0BD024264E4337197E6829
+:10C860009E42F4D324264E4336197768FF1A776028
+:10C870006B60296224214A4311190862F0BD00004F
+:10C880004421002070B5194C2269A5681346114651
+:10C8900006E0814207D00A46242671434919096AF5
+:10C8A0004E1CF6D170BD002EFCD08A420CD1242043
+:10C8B00043435819006A2061401C05D10C4B0120EC
+:10C8C0009860002363616071242041434819242348
+:10C8D00041685A43006A52191062421CE2D0242275
+:10C8E0005043401942685118416070BD44210020F6
+:10C8F00000100140F8B51D4C2569681C35D01C4856
+:10C90000002640686169401A07023F0A19E02420A6
+:10C910004543A0682A185068B84214D8A3693F1A42
+:10C920008619156A002B09D0D169906998470028AB
+:10C9300007D000221146FBF7B9FF02E09169D069E8
+:10C940008847681CE3D1A178E078814206D1401C79
+:10C95000C0B2E070022801D10020E0700349000657
+:10C96000800D1C310E50FFF753FFF8BD442100200D
+:10C970000015014008B500201D4B0522082100903C
+:10C98000FCF7BCF8002803D000221146FBF78EFF0D
+:10C99000184A01211848FCF78BF8002803D0002220
+:10C9A0001146FBF783FF1448144A0121001DFCF7D0
+:10C9B0007FF8002803D000221146FBF777FF0E48CE
+:10C9C0000F4A01210830FCF773F8002803D0002239
+:10C9D0001146FBF76BFF08480A4A01210C30FCF7AF
+:10C9E00067F8002803D000221146FBF75FFF08BD5F
+:10C9F00084210020318E010010200020A1B401000C
+:10CA0000E9C2010099C301000870000A48700220C1
+:10CA10007047000001218140024842688A43426019
+:10CA200070470000F020002038B51549154A4888A5
+:10CA300090420FD04A78144C521CD2B24A70237BD9
+:10CA4000934208D3083175DF002803D0A16900297B
+:10CA500000D0884738BD00254D70217C002907D0C3
+:10CA60003B2176DF002803D0A169002900D0884748
+:10CA700061690029EED068460570884738BD00001E
+:10CA800084200020FFFF0000A826002012494868EB
+:10CA9000C005C00D19D0103840B2002807DA0207CF
+:10CAA000120F083A920892005118C96904E08108EF
+:10CAB0000A4A8900891809688007C00EC140080623
+:10CAC000800F012803D0032803D0022070470020E4
+:10CAD000704701207047000000ED00E000E400E036
+:10CAE00042788378521C934200D10022037893420B
+:10CAF00001D1002070470A604168407818225043F5
+:10CB000008187047F8B51546069C1E4607460222CF
+:10CB1000009400F00AF8002806D133461022294676
+:10CB20003846009400F001F8F8BDFFB583B0074621
+:10CB300000200C9C8646267805463AE07868A900D5
+:10CB400041180A88684682804988C1800022694667
+:10CB500001A865DF002810D1684601780598814258
+:10CB600026D17046002801D0002200E00222207861
+:10CB7000891841181F2902D90C2007B0F0BD714651
+:10CB8000002908D1401CC0B2411C069B049A2170A8
+:10CB90001A5401208646217806980A18694601A889
+:10CBA00065DF0028E9D169462078097840182070AF
+:10CBB0006D1C3888A842C1DC7046002804D020785B
+:10CBC0000699801B401E88550020D6E70179002970
+:10CBD00002D1007B002800D0012070471100000026
+:10CBE00012000000130000001400000011000300F8
+:10CBF000999A010012000300999A010013000300A2
+:10CC0000999A010014000300999A010023D1BCEA0B
+:10CC10005F782315DEEF121200000000FFFFFFFF18
+:10CC200053BA0100B1B30100CDB201006DB40100EF
+:10CC30004FBA010081B30100C9B2010065B401001F
+:10CC40004BBA0100D1B20100C5B201005DB40100D0
+:10CC500070CC010000200020840100006C820100E3
+:10CC600094CC010084210020CC0F00003A85010003
+:10CC700042010333FFFF0C1F0D1801000F180100C4
+:10CC80000A1801A324F4039BFFFF026001041AB5F4
+:04CC9000A5010000FA
+:04000005000180C1B5
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s130.hex b/circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s130.hex
new file mode 100644
index 0000000..57c7fb7
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/resources/dfu_test_app_hrm_s130.hex
@@ -0,0 +1,1287 @@
+:020000040001F9
+:10C00000C039002049C1010063C1010065C10100C0
+:10C010000000000000000000000000000000000020
+:10C0200000000000000000000000000067C10100E7
+:10C03000000000000000000069C101006BC10100A8
+:10C040006DC101006DC10100DDC401006DC10100C1
+:10C050006DC101000000000099C201006DC1010026
+:10C060006DC101006DC101006DC101006DC1010014
+:10C070006DC101006DC101006DC101006DC1010004
+:10C080006DC10100F1C301006DC101006DC101006E
+:10C0900011C401006DC1010065C401006DC1010042
+:10C0A0006DC101006DC10100000000000000000032
+:10C0B0000000000000000000000000000000000080
+:10C0C0000348854600F0B8F80048004709FA010027
+:10C0D000C0390020401E00BF00BF00BF00BF00BF2E
+:10C0E00000BF00BF00BF00BF00BF00BF00BFF1D155
+:10C0F00070470000401E00BF00BF00BF00BF00BF70
+:10C1000000BF00BF00BF00BF00BF00BF00BFF1D134
+:10C1100070470000056885F308884068FF2464B212
+:10C12000EFF30585002D01D1A646004725460646BA
+:10C1300021273FBAF0B40024002500260027F0B4E0
+:10C14000F92040B2004700000321094802680A4371
+:10C150000260084802680A430260074880470748AF
+:10C160000047FEE7FEE7FEE7FEE7FEE7FEE700002A
+:10C17000240500405405004089C40100C1C00100ED
+:10C1800030B50B46014600202022012409E00D466F
+:10C19000D5409D4205D31D469540491B25469540F7
+:10C1A00040191546521E002DF1DC30BD10B5431A62
+:10C1B000934209D28318881803E0401E01785B1E61
+:10C1C0001970521EF9D210BD03460B439B0703D0D2
+:10C1D00009E008C9121F08C0042AFAD203E00B784C
+:10C1E0000370401C491C521EF9D210BDD2B201E0AE
+:10C1F0000270401C491EFBD270470022F6E710B5C2
+:10C2000013460A4604461946FFF7F0FF204610BDC4
+:10C21000421C0178401C0029FBD1801A704730B5C0
+:10C2200004460020034600E05B1C934203D2E05C1E
+:10C23000CD5C401BF8D030BD064C0125064E05E014
+:10C24000E36807CC2B430C3C98471034B442F7D337
+:10C25000FFF73AFFE80F02000810020030B58C1813
+:10C260000278401C13071B0F01D10378401C1209F0
+:10C2700006D10278401C03E005780D70401C491C73
+:10C280005B1EF9D101E00B70491C521EFBD1A1428B
+:10C29000E6D3002030BD0000FEB50024FF250135A7
+:10C2A000012726460194284603F0C4FD00280AD041
+:10C2B000374901204968B040014204D03548002187
+:10C2C00028183C4301602D1D7F00761CADB2042E62
+:10C2D000E9D3FF207D3003F0ADFD002807D02E48C4
+:10C2E00000210160400704432C48006901902C4F55
+:10C2F000200713D00126002526420BD02948AA008A
+:10C30000111808690969C004C00E8903890FD21980
+:10C310005268904776006D1C042DEDD3002C34DA62
+:10C3200000241F4F012638194030007B8506AD0ED2
+:10C3300080090090AE40284603F08EFE002821D0F0
+:10C34000284601F0EDFD8000C0194768002F19D084
+:10C350001549A8004018006801998003800F0E421B
+:10C3600002D0022802D00DE003280BD10099032946
+:10C3700005D102280AD00221284603F04BFD2846A9
+:10C380000099B847641C062CCBD3FEBD0321F3E70C
+:10C3900000630040006000407C61004000050050E8
+:10C3A0005030002000650040000700508307FF2246
+:10C3B000DB0E9A408907090E994000280BDA000726
+:10C3C000000F0838830808489B001818C369934376
+:10C3D0000B43C3617047830804489B001B1818680F
+:10C3E000904308431860704700ED00E000E400E06F
+:10C3F00010B506490020086048608860C86003499D
+:10C4000040390860486004F03FFC10BD4011014015
+:10C41000FEB50020C043124D029068690190684645
+:10C420002E6902F061FF074603F02CFA0446002F44
+:10C4300008D002AA0199009802F076FF029803F052
+:10C440006BFA06E0029803F067FA002801D1002C8D
+:10C4500002D0304601F086FE00206871FEBD00006B
+:10C460003C29002010B507484068002807D08047C5
+:10C47000002803D00022114600F028FA10BD03F076
+:10C480007DF910BD6829002010B503F0C5F900281A
+:10C4900005D00E490C484860C8130D4988610D4805
+:10C4A000018CC9B201290ED1818C09070BD1018DF4
+:10C4B0000906090F042906D1808D0006000F02D15C
+:10C4C00005490120886010BDDFFF07C0000500405E
+:10C4D000006C0040C00F00F0000600407CB51B4C13
+:10C4E000A0681B4E0025002818D0A5601948806957
+:10C4F000C1B2194800F00FFA002805D001216A46A0
+:10C5000011700190684607E013488168C068401ABE
+:10C51000012803D16846057071688847E0690028E2
+:10C5200003D0E561032003F027FD606A00280BD0EB
+:10C530006562084980390868086002216A461170FE
+:10C5400001907168684688477CBD0000002100406A
+:10C5500010290020002500403030002030B47446FF
+:10C56000641E2578641CAB4200D21D46635D5B00EF
+:10C57000E31830BC184702E008C8121F08C1002A9F
+:10C58000FAD170477047002001E001C1121F002A54
+:10C59000FBD1704738B50D4C6078022802D00C49A9
+:10C5A0000120886069460B4800F0A4F9002802D0F9
+:10C5B00000F016F838BD0848802181606A46074BB4
+:10C5C0001278DA6102226270416038BD10290020C1
+:10C5D00000200040403000200023004000250040A3
+:10C5E0001CB506490120C8600549487003206A4609
+:10C5F00010704968684688471CBD00000020004054
+:10C600001029002004490020487004490122CA6012
+:10C610004A6003490860704710290020002000404C
+:10C6200000250040F7B582B0002605461670007858
+:10C630001446002805D02846039903F0A7FA0600FF
+:10C6400008D1A87800281ED02078039F001D1F283D
+:10C6500002D90C2005B0F0BD684679DF0028F9D179
+:10C6600021780322481C20707A5421781922481C12
+:10C6700020707A542078C1196846008804F08EFB37
+:10C68000217840182070E8780223002810D0207804
+:10C69000039A411C2170135420780399471C0122EE
+:10C6A00027700A542078EA78471C039927700A54A7
+:10C6B0006868002815D00021415620788C46024633
+:10C6C000C01C03991F28C4D8501C20708B5422789A
+:10C6D0000A23501C20708B5420786246431C237020
+:10C6E0000A542889002809D02846009406220221ED
+:10C6F0000830039B04F0D0FB0600ABD1288A002849
+:10C7000009D028460094072203211030039B04F02F
+:10C71000C3FB06009ED1288B002809D02846009430
+:10C72000152214211830039B04F0B6FB060091D1AA
+:10C73000286A002805D02246039901F065FD06000D
+:10C7400088D1686A002805D02246039903F0ECF9E5
+:10C75000060084D12C20405D002806D022462846C1
+:10C76000039904F02CF80600C7D1304672E710B5E3
+:10C7700001220221002001F001FA00280BD107223A
+:10C780000221012001F0FAF9002804D100210A2237
+:10C79000084601F0F3F910BD044842680121C905BB
+:10C7A0000B46934383600A40C26070470005005007
+:10C7B00070B50024064D06E06968E000085C0121C0
+:10C7C00003F05EFA641C28788442F5D3002070BD23
+:10C7D00024290020F8B515460C460646052A01D244
+:10C7E0000720F8BD03F00EFB002803D103F0E2FAA6
+:10C7F0000028F6D1114900204E600C7008618D6050
+:10C8000048610F4D0DE0E0002968801900918178A2
+:10C810006A46517000780B4A694603F077FA00289F
+:10C82000DFD12046641EE4B20028ECD10348064A5A
+:10C8300000210C3000F092F8F8BD000024290020FF
+:10C84000E40F020099F5010051E301003EB50446F2
+:10C8500004200190184802906946204602F048F8EA
+:10C86000002807D01549884203D00022114600F065
+:10C870002DF83EBD10480C38017BC90716D0104A70
+:10C880000C218088A7DF002810D00E4988420DD0E7
+:10C8900008280BD0891C884208D0112806D00A49E4
+:10C8A000884203D00022114600F010F8204601F023
+:10C8B000D5FF0028D9D13EBD0C28002040800000C3
+:10C8C000FFFF00000230000001340000BFF34F8F73
+:10C8D00004490348C860BFF34F8F00BFFDE7000065
+:10C8E0000400FA0500ED00E0014B1B68184700004A
+:10C8F0000C3000208268C36893420AD08268838823
+:10C900001A4003689A5C0A708168491C81600020A3
+:10C910007047052070478268C3689B1A82889342DB
+:10C9200008D8C36813400268D154C168491CC1606B
+:10C93000002070470420704738B50C46A268064BAB
+:10C9400012019D58097862880092024620460830FC
+:10C950002369A84738BD00007031002070B5114C24
+:10C96000A568002D06D0002A06D0002804D0002398
+:10C97000247809E0082070BD072070BD24265E439E
+:10C98000AE5D002E04D05B1CA342F7DB042070BD1B
+:10C99000242401265C432E5564196170A261036052
+:10C9A000002070BD3C290020FFB59807002481B00D
+:10C9B0001E4615460F4600280BD1002E09D003F065
+:10C9C00079FE22490A9888610F70324600208E60F5
+:10C9D00008E0072005B0F0BD24234343D4549B183E
+:10C9E0001C75401CB842F7DB24204743BB190320C9
+:10C9F00048700F461846CB6019461830002218239D
+:10CA00002E465E43D3005B181C705C709D705860AE
+:10CA10003018521C032AF5DB0020C0433861BC707B
+:10CA2000FC7001240A482405046003211420FFF748
+:10CA3000BDFC08480460084C0198A0600321112047
+:10CA4000FFF7B4FC606878610020C3E73C29002050
+:10CA500080E200E000E100E000150140FEB5044680
+:10CA60001D48174682680D46002A0CD001788C427A
+:10CA700001D2052D01D20720FEBD214624235943B2
+:10CA8000535C012B01D00820FEBD88184078012896
+:10CA90001DD0002604F0C4F9C0000F490190C968F8
+:10CAA0004018694604F0E6F9002812D0012101700F
+:10CAB0000A49446049680830E2C007490198C968DA
+:10CAC00041180098487004F06DF80020FEBD2E4615
+:10CAD000E0E70420FEBD00003C29002000150140D5
+:10CAE000F8B5144D0446A868002809D029788C426E
+:10CAF00001D30720F8BD24216143405C012801D007
+:10CB00000820F8BD04F08CF9C600E86869463018C2
+:10CB100004F0B0F900280AD0022101704460E868EE
+:10CB200031180098487004F03DF80020F8BD04204A
+:10CB3000F8BD00003C29002010B5184C012100224E
+:10CB400009042069FFF78AFF002803D0002211465C
+:10CB5000FFF7BCFE01210022C9036069FFF77EFFD9
+:10CB6000002803D000221146FFF7B0FE00220C4936
+:10CB7000A069FFF773FF002803D000221146FFF7DA
+:10CB8000A5FE05210022C903E069FFF767FF002821
+:10CB900003D000221146FFF799FE10BD00280020A7
+:10CBA00066260000F0B50546007D002493B00E46D1
+:10CBB00000280DD00120014668461031039401730E
+:10CBC000717B4173817BF92001406846891C817328
+:10CBD0001C2104A8FFF711FB6946087C02210843C9
+:10CBE000694608742A7DEF21002A02D010221043E2
+:10CBF00000E008406A461074059407940894287D64
+:10CC0000002800D003A8099001270A9410469771C4
+:10CC1000304A82800094B27B0270F27B427080784E
+:10CC2000F9221040F722801C1040EF2108404108F3
+:10CC3000490068468170317B017214210BA8FFF70F
+:10CC4000DCFA01A80B9068460C908786C48607879B
+:10CC500002A80F90A888AB1D0BAA04A9A2DF002888
+:10CC600035D1B068002830D0684687711A49818074
+:10CC70000094317C01700020014668464170807844
+:10CC8000F9210840F721801C0840EF2108404108A5
+:10CC900049006846817011A8B16800F096FD06460B
+:10CCA00014210BA8FFF7A9FA01A80B9068460C9075
+:10CCB0008686C486068711A80F902A46E8880E3219
+:10CCC0000BA9A3DF002802D100E0EC81002013B003
+:10CCD000F0BD0000192A00000829000010B50C4919
+:10CCE0000C4803F051FDC1B20948683800F03EFA23
+:10CCF00000280BD0082809D00749884206D00749E8
+:10CD0000884203D000221146FFF7E0FD10BD00006D
+:10CD1000602D002020280020043000000134000095
+:10CD200070B50C4692B000216A461170072511714A
+:10CD3000002809D0C17849070CD502A9FFF772FC79
+:10CD4000002808D102AE00E00026002C0ED0E078CA
+:10CD5000002802D0284612B070BD01AA0AA92046B8
+:10CD6000FFF760FC0028F6D10AAA00E0002268461E
+:10CD700003790178304672DFEDE70000F8B50D4623
+:10CD800006991746040013D0002F11D04A480026F8
+:10CD90004671C3600161202239464848FFF706FA10
+:10CDA0004648C168002905D00169002902D002E087
+:10CDB0000E20F8BD06728169002902D0C1690029E0
+:10CDC00000D1067500F0E0F83C49303108461038D3
+:10CDD00001602031816030215038FFF70EFA37486A
+:10CDE000217830380170A1788170E178C170617864
+:10CDF00041706269216942610161E268A168C260B3
+:10CE000081600146E369A269CB618A61616A002998
+:10CE100017D00146A0310246AC3241628A60636A93
+:10CE20001B880B80616A436A898899800021436A64
+:10CE300004E0666AB668765C5654491C9E888E4249
+:10CE4000F7D8A16A00291CD01C4AA83211460C3917
+:10CE50008A608162A36A9B888B80A16A836A098841
+:10CE600019800021836A04E0A66AB668765C56548D
+:10CE7000491C9E888E42F7D82C210A5D0F49103933
+:10CE80000A73216A002909D00B4914310162226A10
+:10CE900052884A80216A026A0988118061680029E3
+:10CEA00004D00549C91D41606168416003482946B5
+:10CEB0003038FFF735FFF8BD6C280020FC2D00202E
+:10CEC00010B50288224C102A15D00021112A18D042
+:10CED000192A0FD1807900280CD1607901281FD040
+:10CEE000022830D0032805D12171E2680846002AC3
+:10CEF00000D0904710BD017D0129FBD180882081A1
+:10CF000010BD617013490979A17180882189884217
+:10CF1000F6D1012012E021690029F1D0884710BD27
+:10CF2000A079002809D00A48193003F069F80028D0
+:10CF300003D0A079401EA071EBE7022000F04CF86E
+:10CF40000028E8D110BD022020710320F6E7000080
+:10CF50006C280020FC2D002010B5022801D00328E9
+:10CF60000ED1084C207800280AD00020207060796B
+:10CF700000F032F8002803D02169002900D088474A
+:10CF800010BD00006C28002010B507210148FFF7F4
+:10CF900034F910BD8428002010B50D480078012810
+:10CFA00014D10C4C6078002810D16079002802D090
+:10CFB00074DF00280BD101206070607900F00CF85C
+:10CFC000002803D02169002900D08847002010BD27
+:10CFD000FC2D00206C280020F0B5624C87B06071F9
+:10CFE000002606A8069603F06FF80127082806D049
+:10CFF000002878D10698002802D02770AFE0069666
+:10D00000FFF7C2FF584D6878002808D060790128E2
+:10D0100016D1E168002906D0E770072088476079BB
+:10D02000012802D00CE0E67002E06878002805D004
+:10D030004C48193002F0E4FF002801D10220607151
+:10D04000287A002804D16079022801D10320607178
+:10D05000287D002804D16079032801D166712671EA
+:10D06000E16800290AD06079022801D0032805D19F
+:10D070002878002802D06078002814D0A6701821E3
+:10D080006846FFF7BAF8684606700196067203967E
+:10D09000607901280BD0344F0426203702280FD0A6
+:10D0A000032850D12EE0A77006208847E7E72D48D7
+:10D0B000183001906846077046820682277145E065
+:10D0C000288A69464882A88908822748203003F0C8
+:10D0D00047FF002805D02878002802D06078002873
+:10D0E00002D002202EE03BE00220694608721E4872
+:10D0F00003973038C6700021FFF712FE00282FD1A9
+:10D10000267120E0288B69460882A88B4882164841
+:10D11000203003F025FF002805D02878002802D011
+:10D120006078002801D003200CE0022069460872D4
+:10D130000D4803973038C6700021FFF7F1FD002835
+:10D140000ED1052020716079002803D0684673DF76
+:10D15000002805D1E168002901D020798847002006
+:10D1600007B0F0BD6C280020FC2D002073B586B000
+:10D1700004466946227C097F00208A4225D000258A
+:10D180000126684600950680458007A80190217415
+:10D19000E188608A6A46A4DF002816D1608A0D49BA
+:10D1A000884214D0207D002811D002950395049563
+:10D1B0000595E188684601818672418881810490E5
+:10D1C00001980590608A02A9A6DF08B070BD08200A
+:10D1D000FBE70000FFFF000038B504460868206048
+:10D1E0000020C043608208792075FF200D4620741E
+:10D1F00001216846817006490180221D694601208F
+:10D20000A0DF002803D129462046FFF7CBFC38BD1C
+:10D210000F18000038B50A88102A1AD0112A1AD01F
+:10D22000502A1BD1027D002A18D0CA884389891D43
+:10D230009A4213D10A8B022A10D10268002A0DD01B
+:10D24000CB7E8C7E19022143C907C90F07D000216C
+:10D2500006E0898801E00021C943418238BD0121EF
+:10D260006B4619706946904738BD000070B5054699
+:10D2700001461C220F48FEF799FF0F4C002626702E
+:10D280002968002907D00822A018FEF78FFF204642
+:10D2900008307ADF02E0084808307BDF002808D138
+:10D2A000401E608004486670044A0021001DFFF79C
+:10D2B00055FB70BDC42E00208C280020BD0D02003F
+:10D2C000F8B5224C028800271F4DE689102A16D097
+:10D2D00029464968112A21D0122A2DD0502A1CD162
+:10D2E000C288801DB24218D1028B022A15D1C27E9B
+:10D2F000837E10021843C007C00F0CD112E0818852
+:10D30000698001461048082216311030FEF74EFFA2
+:10D310006F70002E01D100F0BFFFF8BD0020C043A8
+:10D3200068806F700846FFF7DBFB0028F5D0A16925
+:10D330000029F2D08847F8BD811D0348082210302B
+:10D34000FEF734FFE7E700008C280020C42E002001
+:10D3500010B502484068FFF7C3FB10BD8C280020C1
+:10D3600030B585B00D46040039D0002D37D068683F
+:10D37000002834D00020C0431A4B20800FCB0493E8
+:10D3800001AB07C318486946088001A8811E63DF06
+:10D39000002822D1221D69460120A0DF00281CD1CF
+:10D3A00068468078A071204601F0CEF9002814D19B
+:10D3B000204601F085F900280FD12946204601F0CA
+:10D3C00005FA002809D16868A062A868002800D082
+:10D3D000E062064901200870002005B030BD0E2033
+:10D3E000FBE70000A00F020030150000A428002079
+:10D3F0003EB5002828D0002926D0826A002A23D0F2
+:10D400000A88102A21D0112A30D0502A1FD0512A40
+:10D410001AD10A460446891D0878022814D1488882
+:10D42000238A984210D1907A04280DD006280BD078
+:10D43000052809D02046891C02F02AFD002803D0C7
+:10D44000E16A002900D088473EBD898810E0CB887A
+:10D4500002899342F8D108226B461A708A7F1A71AA
+:10D4600020310291826A694690473EBD0021C9433E
+:10D4700001803EBD30B585B0002822D00388134C12
+:10D48000A34220D0124B1B78002B1CD0104B102530
+:10D490005B1C1D705970002401259A700322694697
+:10D4A0000A820094019402940394028A0A808D7087
+:10D4B0008C8004A90291039300886946A6DF05B019
+:10D4C00030BD0E20FBE70820F9E70000FFFF000059
+:10D4D000A42800207FB504460121684681714A498D
+:10D4E00081804A4A01A90120A0DF00287ED122883C
+:10D4F00025463C35002A09D044482B46801C009024
+:10D500004348616800F014FD00287BD12289002A7D
+:10D510000AD03E482B460A3000903D48E168401F43
+:10D5200000F006FD00286DD1228A002A0AD0374873
+:10D530002B461230009036486169001F00F0F8FC5D
+:10D5400000285FD1228B002A0AD030482B461A309F
+:10D5500000902F48E169801E00F0EAFC002851D1BC
+:10D56000228C002A0AD029482B46223000902848D5
+:10D57000616AC01E00F0DCFC002843D1228D002A25
+:10D580000AD022482B462A3000902148E16A401EEA
+:10D5900000F0CEFC002835D1216B00290ED002A866
+:10D5A00003F0D4FA19482B4632300090184808226C
+:10D5B00002A9801F00F0BCFC002823D1606B00286A
+:10D5C0000BD012492B463A3100910279016810487C
+:10D5D000401C00F0ADFC002814D1A16B002910D034
+:10D5E00002A802F051FD0948423000E00AE0009034
+:10D5F00007482B46072202A9273000F099FC002893
+:10D6000000D1002004B070BD0A180000AC28002032
+:10D61000292A000070B5044601F04EFA214616484A
+:10D6200000F088F8144821461838FFF7F3FD20462B
+:10D63000FFF746FE204600F0E5F90F48214680300E
+:10D64000FFF7D6FE20880D4D102802D011280ED1EC
+:10D650000AE0072000F0B6FA002803D000221146A5
+:10D66000FFF734F9A08801E00020C043A8802046DD
+:10D67000FFF726FC70BD0000102D002000280020C0
+:10D6800030B50446008C134A8BB090421FD006AAD6
+:10D69000204602F02FF869460546088000200190D8
+:10D6A00002900390049022898A8001228A71088165
+:10D6B00006A803910490208C01A9A6DF002804D1BC
+:10D6C00069460988A94200D00C200BB030BD082063
+:10D6D000FBE70000FFFF000038B504460868206043
+:10D6E000087960710020C0430D462084002022216B
+:10D6F00008554C2108530121684681700C4901806E
+:10D70000A21D69460120A0DF00280FD1294620462E
+:10D7100001F098FF002809D1A868002805D0294603
+:10D72000204600F08DF8002800D1002038BD000010
+:10D730000D18000038B50A88102A17D0112A17D002
+:10D74000502A18D1CA888389891D9A4213D10A8B1D
+:10D75000022A10D10268002A0DD0CB7E8C7E1902DD
+:10D760002143C907C90F07D0002106E0898801E0DD
+:10D770000021C943018438BD01216B4619706946F7
+:10D78000904738BD70B5054604464035A8890E4619
+:10D79000142807D12622A118881EFEF707FDA889A4
+:10D7A000401EA88180B241000919401CA8818E84C6
+:10D7B00070BD20308170704770B504460D46084634
+:10D7C000FEF726FD2080656070BD0A7802704978FA
+:10D7D00041700220704700001CB500234822154903
+:10D7E000082003F0F1F8002803D000221146FFF7CB
+:10D7F0006DF800200090019001206946087068468D
+:10D8000060DF002803D000221146FFF75FF80A48C6
+:10D8100003F0D0F8002803D000221146FFF756F895
+:10D82000064803F0E9F8002803D000221146FFF76C
+:10D830004DF81CBDB02C002015D601003D0B020098
+:10D84000F0B58FB00D4606461C216846FEF7D5FCA4
+:10D850006846017802200143684601700024019463
+:10D86000039404940594012708A806948770154929
+:10D87000684601840794E97B0177297C4177807FA2
+:10D88000F9210840F721801C0840EF210840410899
+:10D89000490068468177142109A8FEF7AEFC08A864
+:10D8A000099007A80A9068468785C4850786A868F6
+:10D8B0000D903346F088103309AA6946A2DF0FB0F5
+:10D8C000F0BD0000382A00001CB5044681786A4685
+:10D8D0000C4802F00DFC002812D160781C2148434E
+:10D8E00009491C2340181A46694602F0B9FC06484B
+:10D8F00006494C30807A80000A5821466846904795
+:10D900001CBD000008290020C02F0020C40F020009
+:10D91000F8B5054608206946088001236A461D4976
+:10D920002846AADF1C4800688047B12044DF002851
+:10D9300003D000221146FEF7C9FF11DF002803D0F3
+:10D9400000221146FEF7C2FF144C606913DF002865
+:10D9500003D000221146FEF7B9FF284600F054FE1E
+:10D9600001210F4A880510600E4802680D4B002007
+:10D9700080330D468540154204D0C606F60E0D468E
+:10D98000B5401D60401C2028F3D3606900F00CF8FE
+:10D99000F8BD0000B4310020602900200010001004
+:10D9A00080E200E000E100E010B5FEF7B3FB10BD3F
+:10D9B0007CB5134E00250C463060002918D069460E
+:10D9C000002000F0A7F8002819D101A9012000F0DB
+:10D9D000A1F8002813D1684601790020002901D060
+:10D9E000022004E069460978002900D00B2020704D
+:10D9F0007068002802D1FEF7BAFE054628467CBDB5
+:10DA00006428002010B5184C0188606810290DD0DA
+:10DA100011290AD1401E606007D1FEF7A8FE002838
+:10DA200003D02168002900D0884710BD002817D1F5
+:10DA300000210122084600F0A1F800280AD107229F
+:10DA40000221012000F09AF8002803D104220221CB
+:10DA500000F094F8002803D02168002900D08847FE
+:10DA60006068401C606010BD6428002010B5032071
+:10DA700000F0FEF910BD0000F8B50746002422486A
+:10DA800002E0641C042C19D2A2008258BA42F8D1D8
+:10DA9000042C13D21D4E1E4DF069002928D00129F7
+:10DAA0000DD002290AD16000201840194578002DB8
+:10DAB00004D0F168002901D028468847F8BD6100EC
+:10DAC00062182946AD5C511800914978002909D0A7
+:10DAD00071680A2251430D4A521CFEF7BFFF00280D
+:10DAE00000D1777000988178084810300155DEE742
+:10DAF000FEF7F6FF05486100611810304919005D16
+:10DB00008D78A842D3D0F8BD700F020044280020C1
+:10DB1000C02D002004280CD2074A1269074B800050
+:10DB20001B5C01209840904300D001200870002029
+:10DB300070470020FAE7000000050050700F020057
+:10DB400010B5042806D0072810D00A2801D102F009
+:10DB500011FF10BD08481321808876DF08E00028F7
+:10DB6000F7D000221146FEF7B1FE10BDFFF714FA00
+:10DB70000828F4D110BD00000028002070B5002353
+:10DB8000042811D2440004190D4D012A02D10129A3
+:10DB90000DD0002246008019094E801900290CD0B2
+:10DBA000012906D0022906D00723184670BD0D3082
+:10DBB000C2B22A55F9E74270F7E78270F5E7000034
+:10DBC000C02D002010B5054A0146127A0020D20768
+:10DBD00002D0084600F054F810BD00004428002090
+:10DBE00070B50E46204905464E608D600020CA6023
+:10DBF000A9071ED50024012211462046FFF7BEFFCB
+:10DC0000641C042C02D20028F5D012E0002810D1A8
+:10DC1000720804211548FEF7DDFD002809D1FEF742
+:10DC2000C7FD002805D11048114A00211C30FEF71D
+:10DC300095FEE90706D00F220E4952058A6000239F
+:10DC4000CB608A6100280DD107480B4A00211430AF
+:10DC5000FEF784FE002805D10348084A0121183048
+:10DC6000FEF77CFE70BD000044280020800F0200FB
+:10DC7000ADDE0100000500506DF8010099C70100FC
+:10DC8000FEB5784906464F684B690093BB00FB1808
+:10DC900000200122019352050546734C3300FEF724
+:10DCA0005DFC180D13133749596C828E858E97A130
+:10DCB000A5A5A5A5A5C3C8CDD4DADA120B225205B5
+:10DCC000A260E5600D70FEBD05208005A060E560E6
+:10DCD00060680F235B055840800209D5A260E560AB
+:10DCE000022E02D1E120C0000AE07D20400107E0C1
+:10DCF000E260A560022E01D1C82001E0FF20913032
+:10DD00000E706421FEF73CFA78430022014646E09B
+:10DD100005208005A060E56060680F235B05584022
+:10DD2000800204D5A260E56019204001E8E7E260C6
+:10DD3000A560E1E705208005A060E56060680F232D
+:10DD40005B055840800202D5A260E560CDE7E26045
+:10DD5000A560D3E705208005A060E56060680F231B
+:10DD60005B055840800202D5A260E56001E0E260F8
+:10DD7000A5600E707900002211E005208005A060EA
+:10DD8000E56060680F235B055840800202D5A26001
+:10DD9000E56001E0E260A5600E700022394600985F
+:10DDA000FEF75CFEFEBD05239B0544E06068012193
+:10DDB00089050A468243A2600840E06010E061687D
+:10DDC0000120800502468A43A2600140E160E4E749
+:10DDD00061680120800502468A43A2600140E1603B
+:10DDE0000199C8E70F214905E1601BE00F468869EA
+:10DDF000FEF776FE11218A1B1C4E01D0002802D0AE
+:10DE0000A660E560FEBD012A0BD91046C821484333
+:10DE10006421FEF7B5F9796800224143B869FEF73D
+:10DE20001DFEE660A560FEBD0F225205A260E56002
+:10DE300015E007239B05A360E5600EE00D22520567
+:10DE4000A260E5600122920507E00322D205A260EC
+:10DE5000E560921001E00F225205E260A5600E70AD
+:10DE6000FEBD000044280020000500500000800096
+:10DE7000F0B500210B4C0C4D03273F048A00A2583B
+:10DE800092005619326801238B40034000D00323CF
+:10DE9000BA431B0413433360491C0429EED300200A
+:10DEA000F0BD0000700F02000007005010B50078B0
+:10DEB0000221FFF7E1FD10BD054900228300D24396
+:10DEC0005B185A60042802D3081840300272704769
+:10DED00050300020F0B50025ED43002A02D0002389
+:10DEE000042601E004230A260C4C05E09F003F199C
+:10DEF0007F687F1C04D05B1CB342F7D32846F0BD7B
+:10DF000026185DB2203635739E0036197160002ADE
+:10DF1000F4D1E11840310872F0E7000050300020E1
+:10DF2000024909182C200856704700005030002084
+:10DF3000FFB58FB01E4615460F0004D100221146D2
+:10DF40001046FEF7C3FC002D04D1002211461046F6
+:10DF5000FEF7BCFC1C216846FEF74FF968460178C5
+:10DF60000220014368460170002401940394049444
+:10DF70000594012108A80694817068460F990184D0
+:10DF800007943178017771784177807FF9210840D3
+:10DF9000F721801C0840EF210840410849006846ED
+:10DFA0008177142109A8FEF728F908A8099007A885
+:10DFB0000A9068468585C485058604480D9709AA98
+:10DFC00069460088189BA2DF13B0F0BDAC28002082
+:10DFD000F8B53B4914230A780F205A435418217985
+:10DFE0002569384E241D02291AD004292ED005296E
+:10DFF00064D102F0F7F801462846FEF7C1F806465C
+:10E0000002F0F0F80146A08871434019401A8708D1
+:10E0100002F0E8F8711C4843A1886288891836E04C
+:10E02000B0882269800261881318091AA28828180A
+:10E03000101801229202914203D28A08194629DF60
+:10E0400037E0FF220132194629DF32E0A2681C487E
+:10E050001101CC30091808894B894968A94203D1BC
+:10E060006188584388421BD0022A19D002F0BAF8BE
+:10E0700001462846FEF784F8064602F0B3F87043DE
+:10E08000281A870802F0AEF8711C484361883A46A6
+:10E090004919401A83083146204602F0B9FC08E0CD
+:10E0A00002F0A0F801462846FEF76AF8B188401849
+:10E0B00028DF002802D1024901228A70F8BD000041
+:10E0C000A43000201829002010B5084900204A7803
+:10E0D000002A09D08978002906D1FFF779FF0028A6
+:10E0E00002D0112800D1002010BD0000A430002073
+:10E0F00014225043054A002180180171C180012279
+:10E100000161C2604161018170470000A4300020BC
+:10E11000F8B5134C069E65780A2D1FD027787D1917
+:10E12000EDB20A2D01D30A3DEDB214277D432D191E
+:10E130002871002068716A6103C92961E860EB8079
+:10E140002E81A1780020002904D1FFF741FF11287A
+:10E1500000D100206178491C6170F8BD0420F8BD31
+:10E16000A4300020F8B5224801694A1C3DD0242281
+:10E170005143826889184E681E494C684769007986
+:10E18000E11B0D022D0AED1C002814D101201A4AB2
+:10E1900000045060184A403A506018494000086036
+:10E1A000174908601749012008602F20FDF7A2FFDA
+:10E1B0000F4901200871B54200D23546E819000226
+:10E1C0000C49000A403108600A494968001B091BD4
+:10E1D0000902090A0002000AC91C814204D901206F
+:10E1E0000649400480390860F8BD02F063FAF8BDC2
+:10E1F0003C290020001501404013014080E200E06E
+:10E2000000E100E000100140F8B50D461178064627
+:10E21000881D14461F2801D90C20F8BD338807201B
+:10E22000062BFAD31927FF01BB4202D9164A9342A3
+:10E23000F3D17288062AF0D3BA4202D9124FBA42F9
+:10E24000EBD1114FBB4203D0BA4201D09342E4D884
+:10E25000481C052220706A5420781222411C21702B
+:10E260002A5420784119308802F098FD217840180E
+:10E27000C0B220704119708802F090FD21784018DA
+:10E2800020700020F8BD0000FFFF000010B5002244
+:10E290001146FEF71BFB10BDF8B5164801F0AEFAAB
+:10E2A000144D0026103D144C002807D06169002948
+:10E2B0001BD001206A461070684615E028780028B7
+:10E2C00005D06169002910D0684606700CE06878B6
+:10E2D00000280CD0A16800226868FEF7BFFB002868
+:10E2E00003D0A169002900D088472E70F8BD61686D
+:10E2F000F1E700009C280020C42E002070B5094BD7
+:10E3000004469E7A082000250E4207D00648844223
+:10E3100002D01889A04202D10020156070BD0520EE
+:10E3200070BD000000300020FFFF00000C214843BA
+:10E33000064910B5012240188272911E0181FF2109
+:10E34000C1720721FDF759FF10BD00000030002009
+:10E35000F8B500260124154D23E06968F000471840
+:10E36000387821466A698140114218D08A436A612F
+:10E3700001F016FD3A7821462B6991401940034679
+:10E38000934099420BD17978012901D0012100E015
+:10E3900000217B684140002B01D010469847761C35
+:10E3A000F6B228788642D8D3F8BD00002429002090
+:10E3B000FEB50E46044681786A46234801F098FE71
+:10E3C000002826D160780C21204F4843C019807A5C
+:10E3D00040061FD4022E1DD0012E1DD01C4DA0784A
+:10E3E0001C2148431B49002341181C226846A847AA
+:10E3F000002813D0022E0CD020780C21484313495A
+:10E400000C314018807A144980000A582146684629
+:10E410009047FEBD114DE2E7114DE0E7022EF8D026
+:10E4200060780C214843C019817ABF221140817263
+:10E4300060781C2148430549403941181C231A467D
+:10E440006846A847D8E700000829002000300020CF
+:10E450000D0A0200FC2E0020B40F0200A5050200E8
+:10E46000ED03020070B50546114A124800241C2332
+:10E4700063431B189B7EFF2B04D0641C072CF6D330
+:10E48000104670BD0A78022A09D01C226243101877
+:10E49000FD22827607221030FDF788FE04E01C2161
+:10E4A00061430818FE2181762C700022E8E7000005
+:10E4B00043800000FC2E0020F7B505250F4F0646CF
+:10E4C0000024002E0AD01C206043C01907223146C8
+:10E4D0001030FDF7A4FE002807D00AE01C2060439E
+:10E4E000C019018B0298814203D101980025046074
+:10E4F00002E0641C072CE4D32846FEBDFC2E00205D
+:10E500007CB5054681B26A46074801F0F1FD04007A
+:10E5100008D17421684601F015FE040002D1284696
+:10E5200001F07AFD20467CBD0829002070B5054623
+:10E530000C46100003D000221146FEF7C7F92078E0
+:10E54000152802D12846FEF781F9002070BD000091
+:10E550001FB56946087301F04BFE002803D0002266
+:10E560001146FEF7B3F903A800F01CFD002803D004
+:10E5700000221146FEF7AAF901A805210130FDF796
+:10E580003CFE6946487901221043E1210840DF2121
+:10E590000C30084069464871072088711020C87106
+:10E5A000064800900A71064800F064FE002803D077
+:10E5B00000221146FEF78AF91FBD00002DE501007B
+:10E5C0000228002001B50549684600F055FA0028E8
+:10E5D00003D000221146FEF779F908BD6429002016
+:10E5E00010B5097800290AD003220121FEF742FF65
+:10E5F000002803D000221146FEF768F910BD0088FC
+:10E60000FFF786F910BD000010B58AB00024264936
+:10E61000009400F095FC002817D101A9224800F0D1
+:10E6200037FC002813D021491F4800F01DFD0028A9
+:10E6300003D000221146FEF749F91C4800DF0028EC
+:10E6400003D000221146FEF741F90AB010BD05992A
+:10E65000072216481031FDF7A9FD14481022C01DED
+:10E660000599FDF7A3FD1148112218300199FDF716
+:10E670009DFD0E4801990A222A301231FDF796FDC0
+:10E680000A4800DF002803D000221146FEF71EF9D9
+:10E6900001200090042008906846099007A907947B
+:10E6A000014800F07FF9CAE764290020803100208A
+:10E6B0007047000001490860704700006029002091
+:10E6C00030B58FB005461C216846FDF796FD6946BA
+:10E6D0000878082108431022104369460870002476
+:10E6E00001940394049405940694A87908A9887069
+:10E6F000144869460884601C00070794000F0C77D3
+:10E7000010304877887FF9210840F721801C0840A5
+:10E7100010430121084369468877142109A8FDF7B1
+:10E720006CFD08A8099007A80A9069468C851720F7
+:10E73000CC8508860D942B46A888103309AAA2DF41
+:10E740000FB030BD3115000030B58FB005461C212B
+:10E750006846FDF752FD694608780421084369467A
+:10E760000870002401940394049405940694A879F5
+:10E7700008A98870144869460884601C000707943B
+:10E78000000F0C77103048778A7FF9200240F7207D
+:10E79000921C0240EF200240012002438A7714219C
+:10E7A00009A8FDF72AFD08A8099007A80A9069465C
+:10E7B0008C851420CC8508860D942B46A8880833B8
+:10E7C00009AAA2DF0FB030BD32150000F0B58FB03E
+:10E7D0000F4605461C216846FDF70FFD6846017887
+:10E7E000022631430170002401940394049405949B
+:10E7F0000694A97908A88170174968460184601CAD
+:10E800000107090F6846103107940177002001467F
+:10E8100068464177817FF9200140F720891C01403B
+:10E82000EF2001400120014368468177142109A8A7
+:10E83000FDF7E3FC08A8099007A80A9068468685BA
+:10E84000C48506860D972B46A888203309AA6946F9
+:10E85000A2DF0FB0F0BD0000341500003EB5044645
+:10E860001E4801781E48002930D0002C2FD0217876
+:10E8700000292BD11B4900250968002926D0A17841
+:10E88000072927D21C20184A48438018807EFF2879
+:10E8900020D012486A46103001F02AFC002815D119
+:10E8A00060230422694602A801F0DAFC0299491C9F
+:10E8B0000CD0602304220D49684601F073FE002845
+:10E8C00004D1A178084A89001C3A55503EBD04483D
+:10E8D000801D3EBD024808303EBD0000F8280020E3
+:10E8E000088000000C300020FC2E0020B00F020039
+:10E8F0003EB50C4627490A782749002A30D08A1DA0
+:10E90000002805D0002C03D00278002A28D101E08D
+:10E9100010463EBD214A1268002A21D0817807297D
+:10E9200020D21C221E4B4A43D218927EFF2A19D0B5
+:10E930001B4AA3681C3A002B17D0890053508178DA
+:10E9400014486A46103001F0D3FB0028E1D160235F
+:10E950000422694602A801F083FC002809D016E0D1
+:10E9600008463EBD0C4808303EBD89005158A160A4
+:10E97000E5E70298401C0AD0642310226946A0688B
+:10E9800001F06EFC0028EFD1029961603EBD0248A3
+:10E9900038303EBDF8280020088000000C300020F0
+:10E9A000FC2E0020FEB505462D480C4601782D486A
+:10E9B000002925D0811D002D23D0002C21D0A26854
+:10E9C000002A1ED0297800291AD127490968002970
+:10E9D00016D0A978072916D21C22244B4A43D218F4
+:10E9E000927EFF2A0FD06A780C235A431E4B0C3BB1
+:10E9F000D218927A120703D56068042806D207203D
+:10EA0000FEBD0846FEBD17480830FEBD1448184E2E
+:10EA10006A46103001F06CFB0028F6D16023042216
+:10EA2000694602A801F01CFC002803D10298401C92
+:10EA300000D0104E60230422211D6846B0470028F4
+:10EA4000E3D1642310226846A16801F0ABFD0028E1
+:10EA5000DBD1AA78054B92001C3BA1689950FEBD02
+:10EA6000F8280020088000000C300020FC2E002038
+:10EA7000ED030200A50502000C4A13780C4A002B96
+:10EA800011D0931D002905D0002803D0007800285C
+:10EA900009D101E018467047064B1B68002B02D0D5
+:10EAA000087000207047104670470000F8280020CA
+:10EAB000088000000C300020F0B5054693B000201F
+:10EAC0000290FF24ED480E94007800284BD0EC4FC4
+:10EAD0003868002847D001A800F056FA002803D073
+:10EAE00000221146FDF7F2FE281D05902A206946F6
+:10EAF0000883FF20002688710E710396E04C288859
+:10EB00000C3C10280ED0A88803AA0221FFF7F6FBC0
+:10EB1000002807D103980C2141430919CA7A694694
+:10EB20008A7148712888132217287CD00FDC10289E
+:10EB30001BD0112853D0132876D0142813D1039852
+:10EB40000C2148430019C07AFF2871D08DE0CD49CF
+:10EB500018286BD01C286AD0522804D1B87A8000BB
+:10EB6000095801A8884713B0F0BDC74F03AA012177
+:10EB70003846FFF7C3FB0028F5D103990C20484322
+:10EB800002220019827211236A4613745171A988F6
+:10EB900001810722A91DFDF709FB687DC10707D088
+:10EBA0004108B6480830405CFF2808D00E9006E0C7
+:10EBB0003A460EA9A81DFFF77FFC00280ED1039945
+:10EBC0000C22514309190E98C8728A7A08231A43F5
+:10EBD0008A726946887101A8FEF776FE39E10398CA
+:10EBE0000C2148430119887AFD22104088720107E0
+:10EBF00006D5C0090DD0002101A8FFF7D9FB08E018
+:10EC000068468079FF2804D001F006FAFF206946A3
+:10EC1000887103980C225043102100198172122030
+:10EC20006946087415E17FE030E001E0D5E00EE1CF
+:10EC3000EA890EA90020FFF73FFC00280ED10398B7
+:10EC40000C22504300190E99C172837A0822134393
+:10EC500083726846817101A8FEF736FE03980C2185
+:10EC600048430019C07AFF2806D003981C21484366
+:10EC700083494C394018029003981C21484383492A
+:10EC80004218A8880023029982DF6CE76846027464
+:10EC9000039B0C2058430119887A04221043887280
+:10ECA000C87AFF2830D016206946087424204343D0
+:10ECB00073481A21303818180830FDF79EFA039867
+:10ECC0000C2148430019817A402211438172039933
+:10ECD0000C2200204A430A901219D27A1C235A436C
+:10ECE0006A4B0C90D2180B921C2251431A46C43224
+:10ECF00089180791089009903A1DA88807AB002150
+:10ED00007FDF0028C1D1A4E00EA8FFF7ABFB0028ED
+:10ED100001D00646DBE769460E98887103990C22FC
+:10ED200051430919C872D2E7787A400840007872D6
+:10ED3000039A0C209446424311198B7AFB2003401E
+:10ED40008B7214206F463874A879002804D0C87AD2
+:10ED5000FFF7D6FBAE797CE0E879400779D5B87942
+:10ED6000FF2876D008273B438B72EB7A9B0708D5A8
+:10ED70001C2503466B43454D5B199D7E6D086D0058
+:10ED80009D76CB7AFF2B64D0A25C022A10D01C2285
+:10ED900050433E4D072240191030FDF707FA6846F0
+:10EDA00080791C2148434019817EFD2211400EE0EC
+:10EDB00061461C225143324A4C3A89184A8A1C2126
+:10EDC0004843324940180283817E490849008176D0
+:10EDD000012101A8FFF7ECFA3BE0A8790209012A1A
+:10EDE00023D10007000F01281FD103980C224243B2
+:10EDF0001219927A120718D5242148432049303934
+:10EE000040181A210830FDF7F8F9162069460874F1
+:10EE100003980C2148430119887A602210438872B4
+:10EE2000787A0221084378720FE003980C2250434D
+:10EE30000019827A80231A43827215206A46107460
+:10EE4000B87A8000095801A88847002601E0684682
+:10EE50000274324604A901A8FDF746FD6846007C0D
+:10EE6000122800D07FE603980C2141430919897AC2
+:10EE70000129F7D0FFF75AFA75E60000F8280020BC
+:10EE80000C300020D40F0200FFFF0000FC2E0020F9
+:10EE9000F0B5064626480C460178264889B0002978
+:10EEA0003FD0811D002E3ED0002C3CD0317800296F
+:10EEB00037D1214900250968002932D0B0780728C8
+:10EEC00033D21C211D4F4843C019807EFF282CD00F
+:10EED000E560B07865614843C01920611648A560B7
+:10EEE0000C306060684620601148B17807AA103085
+:10EEF00001F0FEF8002814D11C231A4607A9684621
+:10EF000001F0AEF900280CD1E560B1781C22514324
+:10EF1000C919656121610849A5600C3161606946C4
+:10EF2000216009B0F0BD0846FBE702480830F8E769
+:10EF3000F8280020088000000C300020FC2E002063
+:10EF400030B50446002903D00878002814D101E028
+:10EF50000B4830BD0B480023006800280CD0094A3C
+:10EF6000FF2088700C3A15890520A542F1D14B701D
+:10EF7000D07A8870002030BD0148801F30BD00006D
+:10EF80000E8000000C300020002806D0FF21017008
+:10EF900041708170C17000207047014870470000C7
+:10EFA0000E800000F0B585B0040036D02948002559
+:10EFB0000560457285722846FFF7B8F92548242177
+:10EFC0003038FDF71AF90026FF27304601F024F803
+:10EFD00021488755761C072EF7D374216846818017
+:10EFE0000721C1801D481C4900900831684601F086
+:10EFF00089F900280FD1184E0120083E3070207882
+:10F0000000280CD069468888C988484381B23046B8
+:10F01000103001F097F805B0F0BD1148FBE7114F33
+:10F0200000240D48A1B202AA083001F061F80028BE
+:10F0300009D11C206043C01900231C2202A901F041
+:10F040000FF9002801D03570E5E7641C072CE8D3E0
+:10F05000E1E700000C30002000290020E9F0010069
+:10F060000E800000FC2E00200B4610B51A491B4AEA
+:10F070000978002920D0911D002805D0002B03D04D
+:10F080000178002918D101E0084610BD144909682B
+:10F09000002911D0114A8178D21EFF290ED01C20E0
+:10F0A000414310480918887E800705D40722184676
+:10F0B0001031FDF77BF80022104610BD4078FF2884
+:10F0C000FAD00C21484306490C394118887A800748
+:10F0D000F2D507221846ECE7F82800200880000047
+:10F0E0000C300020FC2E0020FFB55D488FB000687A
+:10F0F000189F1E46002875D0742F73D86846FFF7F6
+:10F1000043FF002803D000221146FDF7DFFB002457
+:10F11000684604700471254605970696A9B20DAAA3
+:10F12000504800F0E5FF002806D108220DA90F98ED
+:10F13000FDF775F8002817D06D1C072DEED3684633
+:10F140008578FF2D4ED01098042810D046481C21F9
+:10F15000301AFDF715F8012707281ED204A80290DF
+:10F16000119800280BD011E068468570E7E7742FEE
+:10F1700003D04020694608716CE02020FAE7384649
+:10F180003849A84010394968084261D0284601F042
+:10F190000BFE2020694608714AE031481C214C389A
+:10F1A000301AFCF7EDFF00281DD02D4824213038FF
+:10F1B000301AFCF7E5FF01002C482CD040216A46AC
+:10F1C00011712B498E4245D0274AA9001C3A51584B
+:10F1D000B1423DD104A90291C07A854228D1684646
+:10F1E000447025E034E004A80290202168460171B3
+:10F1F00044701B480A940C300B90583807906846AE
+:10F2000080781C21484318494018089007A80690A8
+:10F21000182005900CE0302269460A714C70CF70BE
+:10F22000807A800704D4114824212438FCF7E5FFB4
+:10F23000109869460328087910D0022108436946CE
+:10F24000087104A8029001A96846119AFDF74CFBC9
+:10F2500013B0F0BD694608790321EFE73843EFE7C3
+:10F260000C30002008290020FC2E00200030002057
+:10F27000B00F020070B5064618480D460078002809
+:10F280000ED01749002E0ED0002D0CD02868002873
+:10F2900009D0144C2168002907D011480A3870BDE4
+:10F2A0000F48801F70BD084670BD20600522691D93
+:10F2B000201DFCF77BFF2879A072207A02214008EC
+:10F2C00040000843FB2210402072E07901231843DC
+:10F2D00008431040E0710020307070BDF828002015
+:10F2E0000E8000000C30002010B50E4900238A78F3
+:10F2F000CC78A24212D0521CD2B28A70022A00D11B
+:10F300008B708A78074B92001C339A5802604869C8
+:10F3100010180002000A4861012010BD036000209F
+:10F3200010BD00003C290020F7B5144C0025A7684B
+:10F3300023691EE024215943C9194E68864202D927
+:10F34000301A486017E0801B751900264E600E7554
+:10F350000E699C460B6AB646002E0AD0019E7619AD
+:10F360003602360A8E607646CE6016680E626146B8
+:10F370001160591CDED12361FEBD00003C29002034
+:10F380000EB5112069460872072214A102A87CDF7D
+:10F39000002803D000221146FDF798FA114878DFC3
+:10F3A000002803D000221146FDF790FA0020FF222A
+:10F3B00000904132694601900A804122D2004A8081
+:10F3C0008880FF209130C88068467ADF002803D00B
+:10F3D00000221146FDF77AFA0EBD00004466755F03
+:10F3E00048524D0041030000002070470020704744
+:10F3F00000207047F8B506464078242104464C4367
+:10F4000024490C2250436118224A00254B682432BB
+:10F410008018AE462F469C46002B0CD0827A1346AD
+:10F42000D20908D05A0606D40D461A4A614689B256
+:10F43000175908358E46174C008924343B467246CE
+:10F440002946A9DF0B2819D0002800D01248012F27
+:10F4500013D170780C214843001900890F4AA7DFA7
+:10F4600000280AD00E49884212D0082810D0891CE2
+:10F4700088420DD011280BD00020F8BD70780C21E7
+:10F48000484301230019008972462946A9DFE0E7B5
+:10F490000148F8BDDC2F002041800000FFFF000084
+:10F4A0000230000070B50C46014660782422084DF9
+:10F4B00050434019382300F0D3FE002807D161786B
+:10F4C0002422514349194A68521C00D14A6070BD38
+:10F4D000DC2F0020F3B589B00D461A2069468883D9
+:10F4E00068780C2103274843224E3B468019008947
+:10F4F00007AA6946AADF002838D168782421484342
+:10F50000741A001969468A8B0830FCF788FE0028B7
+:10F51000687807D0242148430119496800290DD093
+:10F52000154E0CE00C2141438919897A89071DD4B5
+:10F53000242148430019FCF760FE17E00F4E2750C6
+:10F540006846828B687824214843001942606878B5
+:10F550004843001969460830FCF728FE68782421E2
+:10F5600048430119382324220998B04700200BB0E2
+:10F57000F0BD000000300020A5050200ED030200F0
+:10F5800010B5FFF737FF10BD10B5FFF78BFF10BDAB
+:10F5900010B5FFF79FFF10BD70B50646104C012552
+:10F5A000B540E068FDF79CFA00280CD1616929425A
+:10F5B00007D1304600F0F4FB0028206904D028432E
+:10F5C00003E0A943616170BDA84320616069002226
+:10F5D00028436061A168E068FDF740FA70BD000053
+:10F5E0002429002010B51349134801F0CDF8124C1E
+:10F5F00081B2283CA068401CA0600E486038FEF72D
+:10F600003FF800280BD0082809D00C49884206D0C2
+:10F610000B49884203D000221146FDF757F9032118
+:10F62000A068FCF7ADFD002901D0012000E000201A
+:10F63000207010BD702D002028280020043000000C
+:10F6400001340000F0B5002406460D46601C010799
+:10F6500095B0090F08A810310C940174297B4174EE
+:10F66000817CF9273940891C81741C2105A8FCF78D
+:10F67000C4FD6846017D10200143684601750CA851
+:10F6800006940A900894099401220B9408A88276A3
+:10F690001749684601870D94697B08A80175A97B05
+:10F6A0004175817DF7203940891C0140EF200140E0
+:10F6B000114308A8817514216846FCF79EFD0EA829
+:10F6C00000900DA801900FAA0021304600F012F81A
+:10F6D0000146684601811421448181810FA804906C
+:10F6E0003346F08808336A4605A9A2DF15B0F0BD9D
+:10F6F000372A0000F7B542790025002A00D00425FA
+:10F700002222135C0222002B00D01543CBB2FF292A
+:10F7100007D901221543029A090A537091700326F2
+:10F7200002E0029902264B7004464034A189002968
+:10F7300001D010210D43002716E0B11C142909D96E
+:10F74000A189C91B4A007900091824302431FCF72B
+:10F750002DFD0CE0029B7A0012189B19928C1A70F6
+:10F76000120A5A70CEB27F1CA189B942E5DCA08989
+:10F77000C01BA081029805703046FEBDF8B51E4C36
+:10F780002078002837D02069002807D00026E068BC
+:10F79000002805D00025002E04D013E00126F6E74E
+:10F7A0000125F8E7684651DF052806D0002806D075
+:10F7B00000221146FDF78AF804E0012602E02169E3
+:10F7C00000988847002D12D1608869460880A0689B
+:10F7D00061DF052806D0002806D000221146FDF77B
+:10F7E00075F804E0012502E0E168A0688847002E72
+:10F7F000D8D0002DCFD0F8BD682900204188054819
+:10F800000288914204D34088814201D80120704788
+:10F8100000207047942800201048018CC9B20129AB
+:10F8200017D1818C090714D1018D09060A0F03D164
+:10F83000828D1206120F0ED0090F012903D1828D7D
+:10F840001206120F07D0032903D1808D0006000F86
+:10F8500001D000207047012070470000C00F00F069
+:10F86000800701D0002070470120704710B5044880
+:10F87000017AC90702D00078FEF702FA10BD000035
+:10F8800044280020F8B5234801690091457833E009
+:10F890002048E900C0680E1834782AE01820604338
+:10F8A0007168641C0818B178E4B2A14200D1002448
+:10F8B0000178022902D003291BD113E0154A4068C0
+:10F8C0002421926841438F18397D002911D001F01D
+:10F8D000A3F9002038750CE024277843C01802757E
+:10F8E000006A03E00B4900228B680869471CF3D1CA
+:10F8F00008617078A042D1D128466D1EEDB2002873
+:10F90000C6D1044801690098814201D00120F8BDA8
+:10F910000020F8BD3C290020F8B5044638480027EF
+:10F920000169009146785CE03548F100C2688D18A5
+:10F9300051E0601C07D0324A24209268604321467F
+:10F940008018046A24E02878182141436A68401C22
+:10F95000C0B252182870A978884200D12F70284B65
+:10F96000516824209B684843C0181378012B34D178
+:10F97000037D002B31D193688360D368C360136922
+:10F9800003615269C2611E4A5279002A00D0876021
+:10F990001B4B82685B6996469C46D31A1A02194B28
+:10F9A000120A9A4202D2C368D21808E0724663462D
+:10F9B0009A1A1202C368120A934202D99A1A426032
+:10F9C00000E0476087600122C7600275921E0262F4
+:10F9D000084601F0EFF8601CABD1287869788842BE
+:10F9E000A7D13046761EF6B200289DD104480169A1
+:10F9F0000098814201D00120F8BD0020F8BD000030
+:10FA00003C290020FFFF7F0096B001F07DF93F4ABE
+:10FA10003F490320FEF7E4F8002803D000221146F6
+:10FA2000FCF754FF01A90020FDF7C2FF002803D016
+:10FA300000221146FCF74AFF6846007902285BD095
+:10FA4000002168460170FDF7C7FE68460078FEF7A2
+:10FA50007FFDFFF795FC302101A8FCF7CEFB0221CA
+:10FA600068460171012484710621C17103258582D4
+:10FA70002848069020210DA8FCF7BFFB08A80477B2
+:10FA8000FF202D301090B42000241190224B0DAA9D
+:10FA90002146009401A8FDF771F9002803D0002247
+:10FAA0001146FCF713FF00F0C9FE00F033FE1C21E5
+:10FAB0006846FCF7A2FB0520C00301900F2000045C
+:10FAC0000290009468460573144881896846C18194
+:10FAD000047413480590134806906846FDF7C6FB6A
+:10FAE000002803D000221146FCF7F0FEFDF724F8B1
+:10FAF0000220FDF771FA02E00121A2E748DF0028A9
+:10FB0000FCD000221146FCF7E1FEF7E741DB0100E3
+:10FB1000CD0C00003828002049FE0100102D0020E7
+:10FB20006DFE01008DE2010070B5054600790E46BC
+:10FB3000801C1446C0B21178821C8A181F2A01D971
+:10FB40000C2070BD0A46491C2170401CB05420781E
+:10FB5000FF22411C2170325420788119288801F03D
+:10FB60001DF921784018C0B22070AA88002A09D057
+:10FB7000A968002908D08019FCF718FB207829799A
+:10FB800040182070002070BD072070BDF8B51478B3
+:10FB90000746A01C15460E461F2803D87878801CFF
+:10FBA0001F2801D90C20F8BD1D20001B80B269461A
+:10FBB000864608803019801C7DDF0028F3D1387814
+:10FBC000022805D168460088704501D8092107E060
+:10FBD00078780821002801D0704501D9684600884E
+:10FBE000421C3255641CE2B2B1542978801C0818BA
+:10FBF00028700020F8BD00207047002070470020CA
+:10FC00007047000031B5054C04E0401E00902046CE
+:10FC1000FCF760FA00980028F7D138BDE703000030
+:10FC20008207D30EFF229A408907090E10B599402A
+:10FC300000280BDA03071B0F083B9C080C4BA400A1
+:10FC4000E318DC6994430C43DC6107E08408094B4A
+:10FC5000A400E418236893430B432360C106C90E34
+:10FC600001208840044908600449086010BD000074
+:10FC700000ED00E000E400E080E200E000E100E0F0
+:10FC800070B50D46064600F0E7F90124002830461D
+:10FC900018D0FEF745F91849001F08184030007BBE
+:10FCA0008009032802D0012805D006E01348006926
+:10FCB000B440204201D1022100E00321304600F08F
+:10FCC000A9F870BD00F0D4F90028FAD03046FEF74C
+:10FCD00027F98100CA1D0A4BF932C9180B6992B283
+:10FCE00023430B610749511800220A60002DE8D018
+:10FCF00084400548446070BD50300020000500502D
+:10FD0000006500400060004000630040F8B5204FEF
+:10FD10000D46044638192C2141560026C8171346B3
+:10FD2000401C01D0082630E0EA7819462046FEF74C
+:10FD3000D1F8411C28D0174BAA78A100C918002A75
+:10FD400003D00A6802239A4301E06A7892000A60AD
+:10FD5000E978002910D082000F482978101802692C
+:10FD60000E4B1A400261E206D20C8907890B0A4346
+:10FD700001690A43026108E0381840302A78017AA4
+:10FD800092011143017200E004263046F8BD0000E4
+:10FD9000503000200007005000650040FFE0FCFFED
+:10FDA00003490969C140C807C00F00D0012070474E
+:10FDB0000005005070B5114D2878002801D00820AA
+:10FDC00070BD0020411E2A182032401CC0B21173A1
+:10FDD0002028F8D300242046FEF76EF8641CE4B215
+:10FDE0000A2CF8D301210620FFF71AFF012004494D
+:10FDF000C007486001202870002070BD50300020EE
+:10FE00000063004002480078002800D001207047BD
+:10FE100050300020820006481018026803231B049B
+:10FE20009A430260026809040A43026070470000B6
+:10FE300000070050034940180068012800D0002046
+:10FE4000704700000060004010B500280AD002286A
+:10FE500007D1FDF7B7FE002803D000221146FCF7BA
+:10FE600035FD10BD00F086FD10BD000010B5007816
+:10FE7000002809D105483B21808876DF002803D07F
+:10FE800000221146FCF722FD10BD000000280020D2
+:10FE9000F0B58BB004460227684607730026099622
+:10FEA0008784C68408A80A900D46A18A208809AADA
+:10FEB000A5DF002804D0E16A00291AD0884718E09D
+:10FEC0006846008CC007C00F13D0684606822088A1
+:10FED00003A9A8DF002813D1A97E28461B300122E0
+:10FEE0000B00FCF73BFB09460F1C2227292C442E54
+:10FEF0004600FF20FE3069460882208803A9A8DF5B
+:10FF00000BB0F0BD6B461E700BE006221EE069468A
+:10FF10000A71029027E0204690470020F0E76B46E8
+:10FF20001A702B8B022BF2D2EFE7684607706946F6
+:10FF3000A26AF0E7032000E00420694612E00520F1
+:10FF4000FBE7298B032905D2032208212046FDF770
+:10FF500091FAD5E741780278080210436946888013
+:10FF600003D006200870A26AD5E70720FAE7092027
+:10FF7000E3E70322EAE7000010B51D4A1D4903002C
+:10FF8000FCF7ECFA05040B31202712004878012811
+:10FF90001FD0022808D1032005E04878002804D0AB
+:10FFA000032801D10220487010BD134B04201860B3
+:10FFB000124B012018609368D2689A42F3D0FCF784
+:10FFC000E9FA10BD4878012806D0022804D0032899
+:10FFD000F7D1FCF717FB10BD9068D1688142EED1D4
+:10FFE000FCF7FEFA10BD48780128E8D010BD0000EB
+:10FFF0004030002010290020002500400020004053
+:020000040002F8
+:100000000021425C002A01D001207047491C0629CA
+:10001000F7D300207047000070B505461C200D493D
+:1000200068434418204611300621FCF7E6F82046C4
+:100030001021FCF7E2F8FF2121740020A176C043D3
+:100040002083284600F0B0FE024A0020A9001C3A96
+:10005000505070BDFC2E0020044908182C21415638
+:10006000042901DB01207047002070475030002038
+:10007000044908182C214156042901D20120704757
+:10008000002070475030002070B50D00044604D1A8
+:10009000002211461046FCF719FC002C04D1002266
+:1000A00011461046FCF712FC2878207069886170B0
+:1000B000090AA170A988E170090A2171E8886071B4
+:1000C000000AA07170BD000007490978002906D018
+:1000D000002806D0054949780160002070470820B3
+:1000E00070470E207047000018290020A43000201F
+:1000F00030B5124B1B78002B07D0002807D0002A00
+:1001000005D00468002C12D103E0082030BD0E2079
+:1001100030BD0B4B1D68002D09D04568188941433F
+:1001200069185D89454358682818884201D8072016
+:1001300030BD14600020516030BD0000182900203F
+:1001400070310020F8B505461B480F46007800289E
+:1001500005D0002D05D02868002820D103E0082014
+:10016000F8BD0E20F8BD154C00262068002816D0DA
+:1001700060892189484361684118686881420ED9C5
+:10018000FFF76EFB00280CD029686868090109197F
+:100190004A680989801AFBF7F3FF002903D007207A
+:1001A000F8BD1020F8BD3B460022294604200096E9
+:1001B000FDF7AEFFF8BD00001829002070310020C7
+:1001C00010B507484469601C06D000F00BF80146E2
+:1001D0002046FBF7D5FF10BD01200007406910BD88
+:1001E0000010001001200007006980B27047000075
+:1001F000F8B50024184D194EAC806C7034707470D2
+:10020000B47027463846FDF773FF7F1C0A2FF9D3D9
+:100210006C80FFF7D5FF871EFFF7E4FF47430F48C9
+:10022000AF60AC80CC3004600481848144810820BC
+:100230006870FFF7D7FF0746FFF7C2FF441EFFF7BE
+:10024000D1FF60433946FBF79BFF28DF002802D12E
+:100250000121B1702970F8BD18290020A4300020B8
+:10026000FFB5264881B000781F4616460D46002887
+:1002700008D0002D09D00198002806D02868002851
+:1002800018D104E0082005B0F0BD0E20FBE71C4C9F
+:10029000206800280ED0618920896268414389184E
+:1002A0006A68914206D9002E04D0B04202D3F119F7
+:1002B000814201D90720E6E70198FFF7D1FA00282B
+:1002C0001AD03846FFF7CCFA002815D06868FFF737
+:1002D000C7FA002810D068683246C1190198FBF7A8
+:1002E00065FF009628680022000124580321284653
+:1002F000019BA0470020C6E71020C4E71829002072
+:1003000070310020F8B5374D044628780E46002895
+:100310002ED0002C2ED0002E2CD02068002829D0E2
+:10032000FFF760FF0146A088814228D3102826D31A
+:10033000E088002823D0FFF743FF471EFFF752FF56
+:100340004743E088A1884843A9684018874216D3EC
+:10035000FFF748FF0146E088A288504381420BDA4C
+:10036000FFF740FFA188FBF70BFF002907D103E04F
+:100370000820F8BD0E20F8BD2079800701D00720A5
+:10038000F8BD688801281BD03060174FA9680201AA
+:10039000D019716041602168B950A1880181E1885C
+:1003A0004181A088E188002648430446761CB6B205
+:1003B000FFF718FFA04205D2FFF714FF241A02E04E
+:1003C0000420F8BD0024FFF70DFFA9684018A860BD
+:1003D000002CEBD168880101C9198E81401C68800E
+:1003E0000020F8BD1829002070310020F8B504461F
+:1003F00020481E46007815460F46002807D0002FDB
+:1004000007D0002C05D02068002817D103E0082071
+:10041000F8BD0E20F8BD1848016800290ED04289A9
+:10042000018940684A4310186268904206D9002D3D
+:1004300004D0A94202D3A819884201D90720F8BDE7
+:100440003846FFF70DFA002811D03046FFF708FABA
+:1004500000280CD06068FFF703FA002807D02B466D
+:100460003A46214602200096FDF752FEF8BD1020C4
+:10047000F8BD00001829002070310020F8B50746AB
+:100480000020464E8646B07801281ED10020444BFD
+:10049000B0705A78082A19D0344625781421694357
+:1004A0000C19022F20D0032F0FD16079401CC0B24D
+:1004B0006071241D03286AD0FDF78AFD002804D04E
+:1004C000112802D02146FCF737FAF8BD022F09D0D7
+:1004D0001870FDF7F9FD0028F7D031781422514348
+:1004E000891959E05870F4E72D498B885B1C9EB23E
+:1004F0008E802379241D022B05D16788B102B94271
+:1005000001D3012100E000218C46052B01D1072AEF
+:1005100003D00021042B02D003E00121FAE7072ACF
+:1005200003D00027042B02D007E00127FAE76488F4
+:10053000B302A34201D3002A27D00022394311433A
+:100540006246114317D0164A14495070908048787B
+:10055000401E4870681CC0B208700A2801D30A38CF
+:1005600008701420684341187046091DFCF7E4F92F
+:100570002846FDF7BDFDFDF7A7FD0028A5D00749DA
+:1005800014230A785A43511806E00122D6E730783E
+:100590001421484381190D20091D94E7A43000203F
+:1005A00018290020F8B5044620481E460078154654
+:1005B0000F46002807D0002F07D0002C05D0206858
+:1005C000002817D103E00820F8BD0E20F8BD184818
+:1005D000016800290ED04289018940684A431018F9
+:1005E0006268904206D9002D04D0A94202D3A8190E
+:1005F000884201D90720F8BD3846FFF731F90028B5
+:1006000011D03046FFF72CF900280CD06068FFF7B6
+:1006100027F9002807D02B463A46214605200096A8
+:10062000FDF776FDF8BD1020F8BD00001829002068
+:100630007031002010B5134813498088884207D0D4
+:10064000132176DF05E000221146FCF73FF902E0B6
+:1006500074DF0028F7D10020FDF7B4FA002803D09A
+:1006600000221146FCF732F9FCF772FE002803D095
+:1006700000221146FCF72AF9FF20F530FFF7C2FAF5
+:1006800010BD000000280020FFFF000010B5074843
+:100690000078002809D005480549303000F074F88A
+:1006A00081B203487038FDF76DF810BD00280020B6
+:1006B000802D002070B501240B49600408600B49AF
+:1006C00040108860094940398860094D6C602F20CE
+:1006D000FBF710FDAC60074D00242F206C61FBF789
+:1006E00009FD2C7170BD000080E100E04013014065
+:1006F000001001403C29002010B504480122417837
+:10070000514041700248FDF754F810BD0028002008
+:10071000102D002070B514480124512164258460F7
+:1007200022C004711049114800F022F80E488C21B3
+:1007300010300160FF212D3141600A2181600026C7
+:10074000067301460948083000F012F80648FF21F8
+:1007500020300560F531846041600673014603482E
+:10076000103000F005F870BD602D0020202800201A
+:100770000A7B002A03D049680160002102E0096871
+:10078000016001210171704710B504798B6802681E
+:10079000002C08D049688C1A9C4201D9D11807E076
+:1007A0000160002108E00968541A9C4202D9D11A5C
+:1007B000016002E0016001210171006810BDF7B520
+:1007C00082B002981446806A0F46002833D00298FF
+:1007D00000252030009028E00298816A0C206843B0
+:1007E0000E18217830794A1C2270C01C7854207869
+:1007F0001622411C21703A542078C119308800F02B
+:10080000CDFA21784018C0B22070B288002A09D0F1
+:10081000B16800290FD0C019FBF7C8FC20783179E6
+:10082000401820706D1C0098EDB2007BA842D3D810
+:10083000002005B0F0BD0720FBE7000030B59FB0F9
+:10084000032118A80175142110A8FBF7D6FC002479
+:10085000012510A8109405711DA81290601C0107B5
+:10086000090F10A81031017344738473601C0107D1
+:10087000090F10A81031C1730020014610A801749F
+:1008800001463348FCF728FF002803D00022114618
+:10089000FCF71CF8142115A8FBF7AFFC012001465A
+:1008A00018A8103141700120014618A8103181703C
+:1008B0000020014618A8C1700120014618A8103177
+:1008C000017110A815940576642118A81794017079
+:1008D0001F4815A91838FCF77FFC002803D0002218
+:1008E0001146FBF7F3FF40216846FBF786FC19A190
+:1008F0006846FCF761FF0120014608A81031017726
+:100900000020014608A841776846FCF7E3FD00286F
+:1009100003D000221146FBF7D9FF13481B901A940D
+:100920001C9410A805850A481AA98030FCF718FD08
+:10093000002803D000221146FBF7C8FF0B48FDF743
+:10094000B9FE0B488078FDF73DFE1FB030BD0000BA
+:10095000102D00204E6F7264696353656D69636F7B
+:100960006E647563746F7200E1E501003506020084
+:100970000028002010B50020FDF724F9002803D03E
+:1009800000221146FBF7A2FFFDF770F8002803D004
+:1009900000221146FBF79AFF3CDF002803D000221B
+:1009A0001146FBF793FF10BD10B508461146C0462F
+:1009B000C04610BD002803D00249C860002070471F
+:1009C0000E2070476829002070B5002901D08C07DF
+:1009D00001D0072070BD064C0125A1606280054949
+:1009E000636010DF0028F5D1257016202EDF70BD62
+:1009F00068290020A9090200002803D002490861E3
+:100A0000002070470E2070476829002000207047A2
+:100A1000FFB581B0484C0E46039F049A05466178A5
+:100A200003201743002903D1002F0DD0012161704D
+:100A3000039AC9B2920000920B00FBF78FFD072CBE
+:100A4000071B2E465D6C2C000221F0E7FFF7CAFB66
+:100A50008708FFF7C7FB70430546FFF7B1FB461E4B
+:100A6000FFF7C0FB70433A46294629DF002812D120
+:100A700002210FE0304628DF00280CD1039900291D
+:100A800001D0032106E00499002917D1297804290F
+:100A900050D018E0617005B0F0BDFFF791FB471E24
+:100AA000FFF7A0FB4743FFF79DFB70433946039ACE
+:100AB00029DF0028EFD10499002901D00421E9E7BA
+:100AC0002978042925D00521E4E7FFF779FB471EA3
+:100AD000FFF788FB47436888391800980F18FFF71D
+:100AE00081FB6988704341180098049A08183946B8
+:100AF00029DF0028E4D0CEE7FFF774FB00997043AC
+:100B0000401869888A08296929DF0028C3D1002F85
+:100B100010D00621BEE7FFF765FB0646FFF750FB46
+:100B2000451EFFF75FFB68433146FBF729FB28DFD3
+:100B30000028B0D10721ADE71829002010B50446E0
+:100B4000FFF79CFC2046FCF707FA10BD70B50C00BF
+:100B5000054604D1002211461046FBF7B7FE002DD2
+:100B600004D1002211461046FBF7B0FE2078287011
+:100B70002088FF2109020840000A687020680902E5
+:100B80000840000CA8702068000EE87020792871D9
+:100B9000207A68712089000AA871A068000CE871A9
+:100BA00070BD000001200249000508607047000088
+:100BB00000E200E0F0B5174F2421BC6841430D1955
+:100BC00039694A1C09D024224A4316196B68726895
+:100BD000934204D8D21A726029623861F0BD0A4685
+:100BE00002E00A46396A9B1B4E1C0BD024264E435A
+:100BF00037197E689E42F4D324264E43361977680F
+:100C0000FF1A77606B60296224214A431119086238
+:100C1000F0BD00003C29002070B5194C2269A56880
+:100C20001346114606E0814207D00A462426714346
+:100C30004919096A4E1CF6D170BD002EFCD08A42BB
+:100C40000CD1242043435819006A2061401C05D16F
+:100C50000C4B0120986000236361607124204143A4
+:100C60004819242341685A43006A52191062421CF1
+:100C7000E2D024225043401942685118416070BDAF
+:100C80003C29002000100140F8B51D4C2569681C66
+:100C900035D01C48002640686169401A07023F0AA7
+:100CA00019E024204543A0682A185068B84214D897
+:100CB000A3693F1A8619156A002B09D0D16990697A
+:100CC0009847002807D000221146FBF7FFFD02E0FD
+:100CD0009169D0698847681CE3D1A178E0788142A6
+:100CE00006D1401CC0B2E070022801D10020E070A3
+:100CF00003490006800D1C310E50FFF753FFF8BD6D
+:100D00003C2900200015014008B500201D4B05229C
+:100D100009210090FBF748FE002803D0002211466D
+:100D2000FBF7D4FD184A01211848FBF717FE0028ED
+:100D300003D000221146FBF7C9FD1448144A0121D3
+:100D4000001DFBF70BFE002803D000221146FBF725
+:100D5000BDFD0E480F4A01210830FBF7FFFD0028BA
+:100D600003D000221146FBF7B1FD08480A4A0121D1
+:100D70000C30FBF7F3FD002803D000221146FBF7EF
+:100D8000A5FD08BD80290020DDCC01001028002031
+:100D9000E5F501008D060200F90602000870000A60
+:100DA00048700220704700000121814002484268DB
+:100DB0008A43426070470000F828002038B5154982
+:100DC000154A488890420FD04A78144C521CD2B22F
+:100DD0004A70237B934208D3083175DF002803D083
+:100DE000A169002900D0884738BD00254D70217CBD
+:100DF000002907D03B2176DF002803D0A169002914
+:100E000000D0884761690029EED0684605708847A0
+:100E100038BD00008C280020FFFF0000C42E0020F9
+:100E200012494868C005C00D19D0103840B20028DA
+:100E300007DA0207120F083A920892005118C9699E
+:100E400004E081080A4A8900891809688007C00EF1
+:100E5000C1400806800F012803D0032803D00220D8
+:100E600070470020704701207047000000ED00E04F
+:100E700000E400E042788378521C934200D10022C3
+:100E80000378934201D1002070470A60416840789E
+:100E90001822504308187047F8B51546069C1E46A0
+:100EA00007460222009400F00AF8002806D13346D3
+:100EB000102229463846009400F001F8F8BDFFB52D
+:100EC00083B0074600200C9C8646267805463AE00B
+:100ED0007868A90041180A88684682804988C180DC
+:100EE0000022694601A865DF002810D16846017814
+:100EF0000598814226D17046002801D0002200E0EA
+:100F000002222078891841181F2902D90C2007B025
+:100F1000F0BD7146002908D1401CC0B2411C069B9F
+:100F2000049A21701A5401208646217806980A18DE
+:100F3000694601A865DF0028E9D16946207809786B
+:100F4000401820706D1C3888A842C1DC704600280B
+:100F500004D020780699801B401E88550020D6E7D3
+:100F60000179002902D1007B002800D001207047C0
+:100F70001100000012000000130000001400000027
+:100F80001100030079DA01001200030079DA010090
+:100F90001300030079DA01001400030079DA01007C
+:100FA00023D1BCEA5F782315DEEF121200000000A7
+:100FB000FFFFFFFFFFFB0100D5F40100F1F301008B
+:100FC00091F50100FBFB0100A5F40100EDF3010028
+:100FD00089F50100F7FB0100F5F30100E9F30100D9
+:100FE00081F5010003000000081002000028002025
+:100FF000800100005CC201002C100200802900204A
+:101000004010000086C5010042010333FFFF0C328F
+:101010000D1801000F1801000A1801039BFFFF02C1
+:0C1020005001041BB1E6011424F4000090
+:040000050001C0C175
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/tests/resources/dfu_test_bootloader_b.hex b/circuitpython/lib/nrfutil/tests/resources/dfu_test_bootloader_b.hex
new file mode 100644
index 0000000..27c1b37
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/resources/dfu_test_bootloader_b.hex
@@ -0,0 +1,8 @@
+:020000040003F7
+:10C00000103C0020C9EE0300E3EE0300E5EE030060
+:10C010000000000000000000000000000000000020
+:10C02000000000000000000000000000D5C0030078
+:10C030000000000000000000E9EE0300EBEE03004A
+:10C04000EDEE0300EDEE0300EDEE0300EDEE030078
+:10C05000EDEE030000000000EDEE0300EDEE030046
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/tests/resources/dfu_test_softdevice_b.hex b/circuitpython/lib/nrfutil/tests/resources/dfu_test_softdevice_b.hex
new file mode 100644
index 0000000..d52e8e9
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/resources/dfu_test_softdevice_b.hex
@@ -0,0 +1,3 @@
+:020000040000FA
+:0869100000000000000000007F
+:00000001FF
diff --git a/circuitpython/lib/nrfutil/tests/resources/test.pem b/circuitpython/lib/nrfutil/tests/resources/test.pem
new file mode 100644
index 0000000..84fdffc
--- /dev/null
+++ b/circuitpython/lib/nrfutil/tests/resources/test.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEID2WUBCe/4kLhl5ekJ+O8PtprcahUNFE3RIm5htQzDedoAoGCCqGSM49
+AwEHoUQDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF7IoFubVru6oX9GCQm67NrXIm
+wgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA==
+-----END EC PRIVATE KEY-----