diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
commit | 4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch) | |
tree | 65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/lib/nrfutil | |
parent | 0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff) |
add circuitpython code
Diffstat (limited to 'circuitpython/lib/nrfutil')
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 Binary files differnew file mode 100644 index 0000000..450bb47 --- /dev/null +++ b/circuitpython/lib/nrfutil/binaries/win32/nrfutil.exe 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 Binary files differnew file mode 100644 index 0000000..3b67d78 --- /dev/null +++ b/circuitpython/lib/nrfutil/dist/nrfutil-0.5.2-py2.7.egg 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 Binary files differnew file mode 100644 index 0000000..45965ef --- /dev/null +++ b/circuitpython/lib/nrfutil/nordicsemi/__init__.pyc 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 Binary files differnew file mode 100644 index 0000000..b040cdf --- /dev/null +++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/bar_wanted.bin 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 Binary files differnew file mode 100644 index 0000000..b7e4cf7 --- /dev/null +++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foo_wanted.bin diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foobar_wanted.bin b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foobar_wanted.bin Binary files differnew file mode 100644 index 0000000..06b77f5 --- /dev/null +++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/foobar_wanted.bin 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 Binary files differnew file mode 100644 index 0000000..b745f0d --- /dev/null +++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/tests/firmwares/pca10028_nrf51422_xxac_blinky.bin 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 Binary files differnew file mode 100644 index 0000000..126f353 --- /dev/null +++ b/circuitpython/lib/nrfutil/nordicsemi/version.pyc 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 Binary files differnew file mode 100644 index 0000000..b745f0d --- /dev/null +++ b/circuitpython/lib/nrfutil/tests/resources/blinky.bin 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----- |