assets

package
v0.15.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2020 License: MIT Imports: 0 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var FS = map[string][]byte{
	"/requirements.txt": []byte(`forensicstore>=0.17.0,<0.18.0
`),
	"/scripts/elementary-hotfixes.py": []byte(`#!/usr/bin/env python
# Copyright (c) 2019 Siemens AG
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Author(s): Demian Kellermann
"""
This plugin parses different registry entries for installed Hotfixes (patches) to the Windows system
as well as to other software components
"""
import json
import logging
import re
import struct
import sys
from collections import defaultdict
from datetime import datetime

import forensicstore
import storeutil

LOGGER = logging.getLogger(__name__)

HOTFIX_PATHS_INSTALLER = [
    'hkey_local_machine\\software\\microsoft\\windows\\currentversion\\component based servicing\\packages\\',
]
HOTFIX_PATHS_ADDITIONAL = [
    'hkey_local_machine\\software\\wow6432node\\microsoft\\updates\\',
    'hkey_local_machine\\software\\microsoft\\updates\\',
]

KB_REGEX = re.compile(r'KB\d+')


def _analyze_installer(obj):
    entries = []
    installer_entries = defaultdict(set)

    hotfix_infos = {v["name"].lower(): v["data"] for v in obj["values"]}

    if hotfix_infos.get('InstallClient') != 'WindowsUpdateAgent':
        return []
    hotfix = KB_REGEX.search(obj["key"].split('\\')[-1])
    if not hotfix:
        # some entries do not have the KB number in the title, but something like "RollupFix", check
        # the InstallLocation value in this case
        location = hotfix_infos.get('InstallLocation')
        if location:
            hotfix = KB_REGEX.search(location)
    if not hotfix:
        LOGGER.info("Non KB entry for WindowsUpdateAgent found: %s", obj["key"])
        return []
    install_high = hotfix_infos.get('InstallTimeHigh')
    install_low = hotfix_infos.get('InstallTimeLow')
    if install_high and install_low:
        timestamp = filetime_to_timestamp(filetime_join(install_high, install_low))
    else:
        timestamp = ''
    installer_entries[hotfix.group(0)].add(timestamp)

    for hotfix in installer_entries:
        entries.append({
            'Hotfix': hotfix,
            'Installed': sorted(installer_entries[hotfix])[0] if installer_entries[hotfix] else '-',
            'Source': 'Component Based Servicing',
            "type": "hotfix"
        })

    return entries


def _analyze_additional(key):
    hotfix = key["key"].split('\\')[-1]
    product = key["key"].split('\\')[-2]
    return [{
        'Hotfix': hotfix,
        'Installed': key["modified_time"],
        'Source': 'Microsoft Updates',
        'Component': product,
        "type": "hotfix"
    }]


def transform(obj):
    if any(map(lambda path: obj["key"].lower().startswith(path), HOTFIX_PATHS_INSTALLER)):
        return _analyze_installer(obj)
    if any(map(lambda path: obj["key"].lower().startswith(path), HOTFIX_PATHS_ADDITIONAL)):
        return _analyze_additional(obj)
    return []


def filetime_join(upper, lower):
    """
    :param upper: upper part of the number
    :param lower: lower part of the number
    """
    return struct.unpack('Q', struct.pack('ii', lower, upper))[0]


def filetime_to_timestamp(filetime_64):
    """
    The FILETIME timestamp is a 64-bit integer that contains the number
    of 100th nano seconds since 1601-01-01 00:00:00.
    The number is usually saved in the registry using two DWORD["values"]
    :return: string of UTC time
    """
    # pylint: disable=invalid-name
    HUNDREDS_OF_NANOSECONDS_IN_A_SECOND = 10000000
    UNIXEPOCH_AS_FILETIME = 116444736000000000

    datetime_stamp = datetime.utcfromtimestamp(
        (filetime_64 - UNIXEPOCH_AS_FILETIME) / HUNDREDS_OF_NANOSECONDS_IN_A_SECOND)
    return datetime_stamp.isoformat()


def main(url):
    print(json.dumps({"header": ["Hotfix", "Installed", "Source", "Component"]}))
    LOGGER.debug("search for hotfixes")
    store = forensicstore.open(url)

    hklmsw = "HKEY_LOCAL_MACHINE\\SOFTWARE\\"
    conditions = [
        {'key': hklmsw + "Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\Packages\\%"},
        {'key': hklmsw + "WOW6432Node\\Microsoft\\Updates\\%\\%"},
        {'key': hklmsw + "Microsoft\\Updates\\%\\%"}
    ]
    for item in store.select(conditions):
        for result in transform(item):
            print(json.dumps(result))
    store.close()


if __name__ == '__main__':
    logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
    parser = storeutil.ScriptArgumentParser(
        'hotfixes', description='Process windows hotfixes', store_arg=True, filter_arg=False,
    )
    args, _ = parser.parse_known_args(sys.argv[1:])
    main(args.forensicstore)
`),
	"/scripts/elementary-hotfixes.py.info": []byte(`{"Use": "hotfixes <forensicstore>", "Short": "Process windows hotfixes"}
`),
	"/scripts/elementary-networking.py": []byte(`#!/usr/bin/env python
# Copyright (c) 2019 Siemens AG
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Author(s): Demian Kellermann
import json
import sys

import forensicstore
import storeutil

NAMES_KEY = r"\control\network\{4d36e972-e325-11ce-bfc1-08002be10318}"
INTERFACE_KEY = r'\services\tcpip\parameters\interfaces'


def transform(objs):
    """
    This plugin parses network configuration from the SYSTEM hive and correlates it with other keys to
    get the network interface name and the last configuration
    """
    names_keys = []
    interface_keys = []
    for obj in objs:
        key = obj["key"].lower()
        if NAMES_KEY in key:
            names_keys.append(obj)
        elif INTERFACE_KEY in key:
            interface_keys.append(obj)

    results = []
    for interface_key in interface_keys:
        result = {}

        interface_id = interface_key["key"].split('\\')[-1]

        interface_infos = {}

        # create a map from values
        if "values" in interface_key:
            # return interface_key["values"]
            interface_infos = {
                v["name"].lower(): v["data"] if "data" in v else ""
                for v in interface_key["values"]
            }

        missing_value = '(not specified)'
        result['type'] = "known_network"
        result['GUID'] = interface_id
        result['DHCP'] = 'yes' if interface_infos.get(
            'enabledhcp', missing_value) == 1 else 'no'
        result['IPs'] = interface_infos.get('ipaddress', missing_value)
        result['SubNetMask'] = interface_infos.get('subnetmask',
                                                   missing_value)
        result['NameServer'] = interface_infos.get('nameserver',
                                                   missing_value)
        result['IP Key Changed'] = interface_key['modified_time']

        # search names key
        name_key = None
        for key in names_keys:
            if interface_id.lower() in key["key"].lower():
                name_key = key

        if name_key is not None:
            # create a map from values
            name_infos = {
                v["name"].lower(): v["data"] if "data" in v else ""
                for v in name_key["values"]
            }

            result['Network Key Changed'] = name_key["modified_time"]
            result['Friendly Name'] = name_infos["name"]
        else:
            result['Network Key Changed'] = missing_value
            result['Friendly Name'] = missing_value
        results.append(result)

    return results


def main(url):
    print(json.dumps({
        "header": ["GUID", "DHCP", "IPs", "SubNetMask", "NameServer",
                   "IP Key Changed", "Network Key Changed", "Friendly Name"]}))
    store = forensicstore.open(url)
    conditions = [
        {'key': r"HKEY_LOCAL_MACHINE\SYSTEM\%ControlSet%\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\%"},
        {'key': r"HKEY_LOCAL_MACHINE\SYSTEM\%ControlSet%\Services\Tcpip\Parameters\Interfaces\%"}
    ]
    items = store.select(conditions)
    for result in transform(items):
        print(json.dumps(result))
    store.close()


if __name__ == '__main__':
    parser = storeutil.ScriptArgumentParser(
        'networking', description='Process networking artifacts', store_arg=True, filter_arg=False,
    )
    args, _ = parser.parse_known_args(sys.argv[1:])
    main(args.forensicstore)
`),
	"/scripts/elementary-networking.py.info": []byte(`{"Use": "networking <forensicstore>", "Short": "Process windows network interfaces"}
`),
	"/scripts/elementary-runkeys.py": []byte(`#!/usr/bin/env python
# Copyright (c) 2019 Siemens AG
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Author(s): Jonas Plum
import json
import sys

import forensicstore
import storeutil

def transform(items):
    results = []
    for item in items:
        if "values" in item:
            for value in item["values"]:
                results.append({
                    "Key": item["key"],
                    "Command": value["data"],
                    "Name": value["name"],
                    "SID": item["key"].split("\\")[1],
                    "type": "runkey",
                })

    return results


def main(url):
    print(json.dumps({"header": ["Name", "Command", "SID", "Key"]}))

    store = forensicstore.open(url)
    hklmsw = "HKEY_LOCAL_MACHINE\\Software\\"
    hkusw = "HKEY_USERS\\%\\Software\\"
    conditions = [
        {'key': hklmsw + r"Microsoft\Windows\CurrentVersion\Policies\Explorer\Run"},
        {'key': hklmsw + r"Microsoft\Windows\CurrentVersion\Run"},
        {'key': hklmsw + r"Microsoft\Windows\CurrentVersion\RunOnce"},
        {'key': hklmsw + r"Microsoft\Windows\CurrentVersion\RunOnce\Setup"},
        {'key': hklmsw + r"Microsoft\Windows\CurrentVersion\RunOnceEx"},
        {'key': hklmsw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\Run"},
        {'key': hklmsw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce"},
        {'key': hklmsw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce\Setup"},
        {'key': hklmsw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceEx"},
        {'key': hklmsw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run"},
        {'key': hkusw + r"Microsoft\Windows\CurrentVersion\Policies\Explorer\Run"},
        {'key': hkusw + r"Microsoft\Windows\CurrentVersion\Run"},
        {'key': hkusw + r"Microsoft\Windows\CurrentVersion\RunOnce"},
        {'key': hkusw + r"Microsoft\Windows\CurrentVersion\RunOnce\Setup"},
        {'key': hkusw + r"Microsoft\Windows\CurrentVersion\RunOnceEx"},
        {'key': hkusw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run"},
        {'key': hkusw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\Run"},
        {'key': hkusw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce"},
        {'key': hkusw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce\Setup"},
        {'key': hkusw + r"Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceEx"}
    ]
    items = store.select(conditions)
    for result in transform(items):
        print(json.dumps(result))
    store.close()


if __name__ == '__main__':
    parser = storeutil.ScriptArgumentParser(
        'run-keys', description='Process windows run keys', store_arg=True, filter_arg=False,
    )
    args, _ = parser.parse_known_args(sys.argv[1:])
    main(args.forensicstore)
`),
	"/scripts/elementary-runkeys.py.info": []byte(`{"Use": "run-keys <forensicstore>", "Short": "Process windows run keys"}
`),
	"/scripts/elementary-services.py": {
		0x23, 0x21, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x65,
		0x6e, 0x76, 0x20, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x0a, 0x23, 0x20,
		0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63,
		0x29, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x53, 0x69, 0x65, 0x6d, 0x65,
		0x6e, 0x73, 0x20, 0x41, 0x47, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x50, 0x65,
		0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20,
		0x68, 0x65, 0x72, 0x65, 0x62, 0x79, 0x20, 0x67, 0x72, 0x61, 0x6e, 0x74,
		0x65, 0x64, 0x2c, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x6f, 0x66, 0x20,
		0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x2c, 0x20, 0x74, 0x6f, 0x20, 0x61,
		0x6e, 0x79, 0x20, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x20, 0x6f, 0x62,
		0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x63, 0x6f,
		0x70, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x23, 0x20, 0x74, 0x68, 0x69, 0x73,
		0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6e,
		0x64, 0x20, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64,
		0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69,
		0x6f, 0x6e, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x20, 0x28, 0x74, 0x68,
		0x65, 0x20, 0x22, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x22,
		0x29, 0x2c, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x61, 0x6c, 0x20, 0x69,
		0x6e, 0x0a, 0x23, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74,
		0x77, 0x61, 0x72, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74,
		0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
		0x2c, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20,
		0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x6c, 0x69, 0x6d, 0x69,
		0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72,
		0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x0a, 0x23, 0x20, 0x75,
		0x73, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x6d, 0x6f,
		0x64, 0x69, 0x66, 0x79, 0x2c, 0x20, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x2c,
		0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x2c, 0x20, 0x64, 0x69,
		0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2c, 0x20, 0x73, 0x75,
		0x62, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x61, 0x6e,
		0x64, 0x2f, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6c, 0x6c, 0x20, 0x63, 0x6f,
		0x70, 0x69, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x0a, 0x23, 0x20, 0x74, 0x68,
		0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2c, 0x20,
		0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69,
		0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f,
		0x20, 0x77, 0x68, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x6f,
		0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x75,
		0x72, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64,
		0x6f, 0x20, 0x73, 0x6f, 0x2c, 0x0a, 0x23, 0x20, 0x73, 0x75, 0x62, 0x6a,
		0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66,
		0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6e,
		0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x23, 0x0a, 0x23,
		0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x20, 0x63,
		0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6e, 0x6f, 0x74,
		0x69, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73,
		0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20,
		0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x20, 0x73, 0x68, 0x61, 0x6c, 0x6c,
		0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
		0x20, 0x69, 0x6e, 0x20, 0x61, 0x6c, 0x6c, 0x0a, 0x23, 0x20, 0x63, 0x6f,
		0x70, 0x69, 0x65, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x75, 0x62, 0x73,
		0x74, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x70, 0x6f, 0x72, 0x74,
		0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
		0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x0a, 0x23, 0x0a,
		0x23, 0x20, 0x54, 0x48, 0x45, 0x20, 0x53, 0x4f, 0x46, 0x54, 0x57, 0x41,
		0x52, 0x45, 0x20, 0x49, 0x53, 0x20, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44,
		0x45, 0x44, 0x20, 0x22, 0x41, 0x53, 0x20, 0x49, 0x53, 0x22, 0x2c, 0x20,
		0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x20, 0x57, 0x41, 0x52, 0x52,
		0x41, 0x4e, 0x54, 0x59, 0x20, 0x4f, 0x46, 0x20, 0x41, 0x4e, 0x59, 0x20,
		0x4b, 0x49, 0x4e, 0x44, 0x2c, 0x20, 0x45, 0x58, 0x50, 0x52, 0x45, 0x53,
		0x53, 0x20, 0x4f, 0x52, 0x0a, 0x23, 0x20, 0x49, 0x4d, 0x50, 0x4c, 0x49,
		0x45, 0x44, 0x2c, 0x20, 0x49, 0x4e, 0x43, 0x4c, 0x55, 0x44, 0x49, 0x4e,
		0x47, 0x20, 0x42, 0x55, 0x54, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4c, 0x49,
		0x4d, 0x49, 0x54, 0x45, 0x44, 0x20, 0x54, 0x4f, 0x20, 0x54, 0x48, 0x45,
		0x20, 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x49, 0x45, 0x53, 0x20,
		0x4f, 0x46, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41, 0x4e, 0x54, 0x41,
		0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x2c, 0x20, 0x46, 0x49, 0x54, 0x4e,
		0x45, 0x53, 0x53, 0x0a, 0x23, 0x20, 0x46, 0x4f, 0x52, 0x20, 0x41, 0x20,
		0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50,
		0x55, 0x52, 0x50, 0x4f, 0x53, 0x45, 0x20, 0x41, 0x4e, 0x44, 0x20, 0x4e,
		0x4f, 0x4e, 0x49, 0x4e, 0x46, 0x52, 0x49, 0x4e, 0x47, 0x45, 0x4d, 0x45,
		0x4e, 0x54, 0x2e, 0x20, 0x49, 0x4e, 0x20, 0x4e, 0x4f, 0x20, 0x45, 0x56,
		0x45, 0x4e, 0x54, 0x20, 0x53, 0x48, 0x41, 0x4c, 0x4c, 0x20, 0x54, 0x48,
		0x45, 0x20, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x53, 0x20, 0x4f, 0x52,
		0x0a, 0x23, 0x20, 0x43, 0x4f, 0x50, 0x59, 0x52, 0x49, 0x47, 0x48, 0x54,
		0x20, 0x48, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x53, 0x20, 0x42, 0x45, 0x20,
		0x4c, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x46, 0x4f, 0x52, 0x20, 0x41,
		0x4e, 0x59, 0x20, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x2c, 0x20, 0x44, 0x41,
		0x4d, 0x41, 0x47, 0x45, 0x53, 0x20, 0x4f, 0x52, 0x20, 0x4f, 0x54, 0x48,
		0x45, 0x52, 0x20, 0x4c, 0x49, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59,
		0x2c, 0x20, 0x57, 0x48, 0x45, 0x54, 0x48, 0x45, 0x52, 0x0a, 0x23, 0x20,
		0x49, 0x4e, 0x20, 0x41, 0x4e, 0x20, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e,
		0x20, 0x4f, 0x46, 0x20, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x54,
		0x2c, 0x20, 0x54, 0x4f, 0x52, 0x54, 0x20, 0x4f, 0x52, 0x20, 0x4f, 0x54,
		0x48, 0x45, 0x52, 0x57, 0x49, 0x53, 0x45, 0x2c, 0x20, 0x41, 0x52, 0x49,
		0x53, 0x49, 0x4e, 0x47, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x2c, 0x20, 0x4f,
		0x55, 0x54, 0x20, 0x4f, 0x46, 0x20, 0x4f, 0x52, 0x20, 0x49, 0x4e, 0x0a,
		0x23, 0x20, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e,
		0x20, 0x57, 0x49, 0x54, 0x48, 0x20, 0x54, 0x48, 0x45, 0x20, 0x53, 0x4f,
		0x46, 0x54, 0x57, 0x41, 0x52, 0x45, 0x20, 0x4f, 0x52, 0x20, 0x54, 0x48,
		0x45, 0x20, 0x55, 0x53, 0x45, 0x20, 0x4f, 0x52, 0x20, 0x4f, 0x54, 0x48,
		0x45, 0x52, 0x20, 0x44, 0x45, 0x41, 0x4c, 0x49, 0x4e, 0x47, 0x53, 0x20,
		0x49, 0x4e, 0x20, 0x54, 0x48, 0x45, 0x20, 0x53, 0x4f, 0x46, 0x54, 0x57,
		0x41, 0x52, 0x45, 0x2e, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x41, 0x75, 0x74,
		0x68, 0x6f, 0x72, 0x28, 0x73, 0x29, 0x3a, 0x20, 0x44, 0x65, 0x6d, 0x69,
		0x61, 0x6e, 0x20, 0x4b, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x6d, 0x61, 0x6e,
		0x6e, 0x0a, 0x0a, 0x22, 0x22, 0x22, 0x20, 0x57, 0x69, 0x6e, 0x64, 0x6f,
		0x77, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20,
		0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x20, 0x22, 0x22, 0x22, 0x0a, 0x69,
		0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x69,
		0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0a, 0x0a, 0x69,
		0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x65, 0x6e, 0x73,
		0x69, 0x63, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x0a, 0x69, 0x6d, 0x70, 0x6f,
		0x72, 0x74, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x75, 0x74, 0x69, 0x6c,
		0x0a, 0x0a, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73,
		0x66, 0x6f, 0x72, 0x6d, 0x28, 0x6f, 0x62, 0x6a, 0x73, 0x29, 0x3a, 0x0a,
		0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x20,
		0x70, 0x61, 0x72, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57,
		0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x53, 0x59, 0x53, 0x54, 0x45,
		0x4d, 0x20, 0x68, 0x69, 0x76, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20,
		0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x69, 0x6e, 0x73, 0x74,
		0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c,
		0x61, 0x79, 0x73, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, 0x74,
		0x61, 0x72, 0x74, 0x75, 0x70, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0a,
		0x20, 0x20, 0x20, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x74, 0x68, 0x65,
		0x72, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
		0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x23, 0x20, 0x70, 0x79, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64,
		0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x74, 0x6f, 0x6f, 0x2d, 0x6d,
		0x61, 0x6e, 0x79, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x73, 0x0a, 0x0a,
		0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5f, 0x66,
		0x6f, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20,
		0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x72,
		0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x0a, 0x20,
		0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6f, 0x62, 0x6a, 0x20, 0x69,
		0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x20, 0x6f, 0x62,
		0x6a, 0x5b, 0x22, 0x6b, 0x65, 0x79, 0x22, 0x5d, 0x2e, 0x6c, 0x6f, 0x77,
		0x65, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x2e, 0x65, 0x6e, 0x64, 0x73,
		0x77, 0x69, 0x74, 0x68, 0x28, 0x27, 0x5c, 0x5c, 0x70, 0x61, 0x72, 0x61,
		0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x27, 0x29, 0x3a, 0x0a, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61,
		0x72, 0x61, 0x6d, 0x73, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x73, 0x65, 0x72,
		0x76, 0x69, 0x63, 0x65, 0x73, 0x5b, 0x6b, 0x65, 0x79, 0x2e, 0x72, 0x65,
		0x70, 0x6c, 0x61, 0x63, 0x65, 0x28, 0x27, 0x5c, 0x5c, 0x70, 0x61, 0x72,
		0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x27, 0x2c, 0x20, 0x27, 0x27,
		0x29, 0x5d, 0x20, 0x3d, 0x20, 0x6f, 0x62, 0x6a, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x69, 0x66, 0x20, 0x6b, 0x65,
		0x79, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x27, 0x5c, 0x5c, 0x27,
		0x29, 0x5b, 0x2d, 0x32, 0x5d, 0x20, 0x21, 0x3d, 0x20, 0x27, 0x73, 0x65,
		0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x27, 0x3a, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, 0x20, 0x73,
		0x6b, 0x69, 0x70, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x75,
		0x62, 0x6b, 0x65, 0x79, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e,
		0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
		0x6c, 0x73, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
		0x73, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x28, 0x6f, 0x62, 0x6a,
		0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65,
		0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x5b, 0x5d,
		0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6f, 0x62, 0x6a,
		0x20, 0x69, 0x6e, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
		0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61,
		0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6b, 0x65, 0x79,
		0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5f, 0x66, 0x6f,
		0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x67,
		0x65, 0x74, 0x28, 0x6f, 0x62, 0x6a, 0x5b, 0x22, 0x6b, 0x65, 0x79, 0x22,
		0x5d, 0x2e, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x28, 0x29, 0x2c, 0x20, 0x4e,
		0x6f, 0x6e, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
		0x72, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22,
		0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x20, 0x69, 0x6e, 0x20, 0x70,
		0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6b, 0x65,
		0x79, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,
		0x73, 0x20, 0x3d, 0x20, 0x7b, 0x76, 0x5b, 0x22, 0x6e, 0x61, 0x6d, 0x65,
		0x22, 0x5d, 0x2e, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x28, 0x29, 0x3a, 0x20,
		0x76, 0x5b, 0x22, 0x64, 0x61, 0x74, 0x61, 0x22, 0x5d, 0x20, 0x66, 0x6f,
		0x72, 0x20, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
		0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x5b, 0x22, 0x76,
		0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x5d, 0x20, 0x69, 0x66, 0x20, 0x22,
		0x64, 0x61, 0x74, 0x61, 0x22, 0x20, 0x69, 0x6e, 0x20, 0x76, 0x20, 0x61,
		0x6e, 0x64, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x20, 0x69, 0x6e,
		0x20, 0x76, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
		0x72, 0x73, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74,
		0x74, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65,
		0x74, 0x65, 0x72, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x5b, 0x22, 0x6d, 0x6f,
		0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22,
		0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
		0x73, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
		0x72, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x61,
		0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f,
		0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x27, 0x27,
		0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
		0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x20, 0x6e, 0x6f,
		0x74, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x3a, 0x0a, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f,
		0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f,
		0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x76, 0x5b,
		0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x2e, 0x6c, 0x6f, 0x77, 0x65,
		0x72, 0x28, 0x29, 0x3a, 0x20, 0x76, 0x5b, 0x22, 0x64, 0x61, 0x74, 0x61,
		0x22, 0x5d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x76, 0x20, 0x69, 0x6e, 0x20,
		0x6f, 0x62, 0x6a, 0x5b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22,
		0x5d, 0x20, 0x69, 0x66, 0x20, 0x22, 0x64, 0x61, 0x74, 0x61, 0x22, 0x20,
		0x69, 0x6e, 0x20, 0x76, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x6e, 0x61,
		0x6d, 0x65, 0x22, 0x20, 0x69, 0x6e, 0x20, 0x76, 0x7d, 0x0a, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f,
		0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x73,
		0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65,
		0x73, 0x2e, 0x67, 0x65, 0x74, 0x28, 0x27, 0x73, 0x74, 0x61, 0x72, 0x74,
		0x27, 0x2c, 0x20, 0x30, 0x78, 0x34, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
		0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x72, 0x76,
		0x69, 0x63, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x67,
		0x65, 0x74, 0x28, 0x27, 0x74, 0x79, 0x70, 0x65, 0x27, 0x2c, 0x20, 0x4e,
		0x6f, 0x6e, 0x65, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x3d, 0x20,
		0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x73,
		0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x4e, 0x61,
		0x6d, 0x65, 0x27, 0x3a, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x22, 0x6b, 0x65,
		0x79, 0x22, 0x5d, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x22, 0x5c,
		0x5c, 0x22, 0x29, 0x5b, 0x2d, 0x31, 0x5d, 0x2c, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x44, 0x65,
		0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x27, 0x3a, 0x20,
		0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75,
		0x65, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x28, 0x27, 0x64, 0x65, 0x73, 0x63,
		0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x27, 0x27,
		0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x27, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e,
		0x61, 0x6d, 0x65, 0x27, 0x3a, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x67, 0x65, 0x74,
		0x28, 0x27, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x6e, 0x61, 0x6d,
		0x65, 0x27, 0x2c, 0x20, 0x27, 0x27, 0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x47, 0x72,
		0x6f, 0x75, 0x70, 0x27, 0x3a, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x67, 0x65, 0x74,
		0x28, 0x27, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x27, 0x2c, 0x20, 0x27, 0x27,
		0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x27, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x4d, 0x6f,
		0x64, 0x65, 0x27, 0x3a, 0x20, 0x53, 0x54, 0x41, 0x52, 0x54, 0x55, 0x50,
		0x5f, 0x54, 0x59, 0x50, 0x45, 0x53, 0x2e, 0x67, 0x65, 0x74, 0x28, 0x73,
		0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x73,
		0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x29, 0x2c, 0x0a,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x27, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x54, 0x79, 0x70,
		0x65, 0x27, 0x3a, 0x20, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
		0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x62, 0x69,
		0x74, 0x6d, 0x61, 0x73, 0x6b, 0x28, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x49, 0x6d,
		0x61, 0x67, 0x65, 0x50, 0x61, 0x74, 0x68, 0x27, 0x3a, 0x20, 0x73, 0x65,
		0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73,
		0x2e, 0x67, 0x65, 0x74, 0x28, 0x27, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x70,
		0x61, 0x74, 0x68, 0x27, 0x2c, 0x20, 0x27, 0x27, 0x29, 0x2c, 0x0a, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27,
		0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x44, 0x4c, 0x4c, 0x27,
		0x3a, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
		0x2e, 0x67, 0x65, 0x74, 0x28, 0x27, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x64, 0x6c, 0x6c, 0x27, 0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x53, 0x65, 0x72,
		0x76, 0x69, 0x63, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x68, 0x61,
		0x6e, 0x67, 0x65, 0x64, 0x27, 0x3a, 0x20, 0x6f, 0x62, 0x6a, 0x5b, 0x22,
		0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d,
		0x65, 0x22, 0x5d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,
		0x74, 0x65, 0x72, 0x73, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x68, 0x61,
		0x6e, 0x67, 0x65, 0x64, 0x27, 0x3a, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
		0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x77,
		0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x53, 0x6f, 0x75,
		0x72, 0x63, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x27, 0x3a, 0x20, 0x6f, 0x62,
		0x6a, 0x5b, 0x22, 0x6b, 0x65, 0x79, 0x22, 0x5d, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x72, 0x65,
		0x73, 0x75, 0x6c, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x28,
		0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x29, 0x0a, 0x0a, 0x20, 0x20,
		0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x61, 0x72,
		0x73, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x0a, 0x0a, 0x0a,
		0x53, 0x54, 0x41, 0x52, 0x54, 0x55, 0x50, 0x5f, 0x54, 0x59, 0x50, 0x45,
		0x53, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x23, 0x20,
		0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, 0x73,
		0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63,
		0x6f, 0x6d, 0x2f, 0x64, 0x65, 0x2d, 0x64, 0x65, 0x2f, 0x64, 0x6f, 0x74,
		0x6e, 0x65, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x79, 0x73, 0x74,
		0x65, 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70, 0x72,
		0x6f, 0x63, 0x65, 0x73, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x6d, 0x6f, 0x64, 0x65, 0x3f, 0x76,
		0x69, 0x65, 0x77, 0x3d, 0x6e, 0x65, 0x74, 0x66, 0x72, 0x61, 0x6d, 0x65,
		0x77, 0x6f, 0x72, 0x6b, 0x2d, 0x34, 0x2e, 0x37, 0x2e, 0x32, 0x0a, 0x20,
		0x20, 0x20, 0x20, 0x30, 0x78, 0x30, 0x3a, 0x20, 0x22, 0x42, 0x6f, 0x6f,
		0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x31, 0x3a,
		0x20, 0x22, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22, 0x2c, 0x0a, 0x20,
		0x20, 0x20, 0x20, 0x30, 0x78, 0x32, 0x3a, 0x20, 0x22, 0x41, 0x75, 0x74,
		0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x30, 0x78, 0x33, 0x3a, 0x20, 0x22, 0x4d, 0x61, 0x6e, 0x75, 0x61,
		0x6c, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x34, 0x3a,
		0x20, 0x22, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x0a,
		0x7d, 0x0a, 0x0a, 0x23, 0x20, 0x45, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65,
		0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x61,
		0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20,
		0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x64, 0x20, 0x66,
		0x6f, 0x72, 0x20, 0x61, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64,
		0x20, 0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x20, 0x73,
		0x74, 0x61, 0x72, 0x74, 0x2c, 0x20, 0x61, 0x20, 0x44, 0x57, 0x4f, 0x52,
		0x44, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x20, 0x76,
		0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x65, 0x73,
		0x65, 0x6e, 0x74, 0x0a, 0x23, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20,
		0x48, 0x4b, 0x45, 0x59, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x4d,
		0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5c, 0x53, 0x59, 0x53, 0x54, 0x45,
		0x4d, 0x5c, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
		0x74, 0x72, 0x6f, 0x6c, 0x53, 0x65, 0x74, 0x5c, 0x73, 0x65, 0x72, 0x76,
		0x69, 0x63, 0x65, 0x73, 0x5c, 0x3c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3e, 0x2e, 0x20, 0x49, 0x74, 0x27,
		0x73, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x20, 0x44, 0x65, 0x6c, 0x61,
		0x79, 0x65, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x53, 0x74, 0x61, 0x72, 0x74,
		0x20, 0x61, 0x6e, 0x64, 0x0a, 0x23, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20,
		0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x31, 0x2c, 0x20, 0x61, 0x6c,
		0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x53,
		0x74, 0x61, 0x72, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f,
		0x66, 0x20, 0x32, 0x20, 0xe2, 0x80, 0x94, 0x20, 0x77, 0x68, 0x69, 0x63,
		0x68, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x72,
		0x6d, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, 0x6f,
		0x72, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x20,
		0x73, 0x74, 0x61, 0x72, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x45, 0x52, 0x56,
		0x49, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x53, 0x20, 0x3d, 0x20,
		0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x23, 0x20, 0x68, 0x74, 0x74, 0x70,
		0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x2e, 0x6d, 0x69, 0x63,
		0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64,
		0x65, 0x2d, 0x64, 0x65, 0x2f, 0x64, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x2f,
		0x61, 0x70, 0x69, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73,
		0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73,
		0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x74, 0x79, 0x70,
		0x65, 0x3f, 0x76, 0x69, 0x65, 0x77, 0x3d, 0x6e, 0x65, 0x74, 0x66, 0x72,
		0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2d, 0x34, 0x2e, 0x37, 0x2e,
		0x32, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x31, 0x3a, 0x20, 0x22,
		0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72,
		0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x32, 0x3a, 0x20,
		0x22, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x44,
		0x72, 0x69, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x30, 0x78, 0x34, 0x3a, 0x20, 0x22, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65,
		0x72, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x38, 0x3a,
		0x20, 0x22, 0x52, 0x65, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x72,
		0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x30, 0x78, 0x31, 0x30, 0x3a, 0x20, 0x22, 0x57, 0x69, 0x6e, 0x33,
		0x32, 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x22,
		0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x32, 0x30, 0x3a, 0x20,
		0x22, 0x57, 0x69, 0x6e, 0x33, 0x32, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50,
		0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x30, 0x78, 0x31, 0x30, 0x30, 0x3a, 0x20, 0x22, 0x49, 0x6e, 0x74,
		0x65, 0x72, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, 0x72, 0x6f, 0x63,
		0x65, 0x73, 0x73, 0x22, 0x2c, 0x0a, 0x7d, 0x0a, 0x0a, 0x0a, 0x64, 0x65,
		0x66, 0x20, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x74, 0x79,
		0x70, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x62, 0x69, 0x74, 0x6d,
		0x61, 0x73, 0x6b, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x29, 0x3a, 0x0a, 0x20,
		0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61,
		0x73, 0x6b, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x0a, 0x20, 0x20,
		0x20, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74,
		0x28, 0x6d, 0x61, 0x73, 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74,
		0x79, 0x70, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20,
		0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x74, 0x20, 0x69, 0x6e,
		0x20, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50,
		0x45, 0x53, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x20, 0x26, 0x20, 0x6d, 0x61, 0x73,
		0x6b, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x70,
		0x65, 0x6e, 0x64, 0x28, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f,
		0x54, 0x59, 0x50, 0x45, 0x53, 0x5b, 0x62, 0x69, 0x74, 0x5d, 0x29, 0x0a,
		0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x27,
		0x2c, 0x20, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x74, 0x79, 0x70,
		0x65, 0x73, 0x29, 0x0a, 0x0a, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x6d, 0x61,
		0x69, 0x6e, 0x28, 0x75, 0x72, 0x6c, 0x29, 0x3a, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6a, 0x73, 0x6f, 0x6e, 0x2e,
		0x64, 0x75, 0x6d, 0x70, 0x73, 0x28, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22,
		0x3a, 0x20, 0x5b, 0x27, 0x4e, 0x61, 0x6d, 0x65, 0x27, 0x2c, 0x20, 0x27,
		0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x27,
		0x2c, 0x20, 0x27, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61,
		0x6d, 0x65, 0x27, 0x2c, 0x20, 0x27, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x27,
		0x2c, 0x20, 0x27, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x4d, 0x6f, 0x64,
		0x65, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27,
		0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x54, 0x79, 0x70, 0x65,
		0x27, 0x2c, 0x20, 0x27, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74,
		0x68, 0x27, 0x2c, 0x20, 0x27, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
		0x20, 0x44, 0x4c, 0x4c, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x20, 0x20, 0x27, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x4b,
		0x65, 0x79, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x27, 0x2c,
		0x20, 0x27, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
		0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
		0x27, 0x2c, 0x20, 0x27, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x4b,
		0x65, 0x79, 0x27, 0x5d, 0x7d, 0x29, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x6f, 0x72,
		0x65, 0x6e, 0x73, 0x69, 0x63, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x6f,
		0x70, 0x65, 0x6e, 0x28, 0x75, 0x72, 0x6c, 0x29, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20,
		0x3d, 0x20, 0x5b, 0x7b, 0x27, 0x6b, 0x65, 0x79, 0x27, 0x3a, 0x20, 0x22,
		0x48, 0x4b, 0x45, 0x59, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x4d,
		0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5c, 0x5c, 0x53, 0x59, 0x53, 0x54,
		0x45, 0x4d, 0x5c, 0x5c, 0x25, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
		0x53, 0x65, 0x74, 0x25, 0x5c, 0x5c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
		0x65, 0x73, 0x5c, 0x5c, 0x25, 0x22, 0x7d, 0x5d, 0x0a, 0x20, 0x20, 0x20,
		0x20, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x69, 0x73,
		0x74, 0x28, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x73, 0x65, 0x6c, 0x65,
		0x63, 0x74, 0x28, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
		0x73, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20,
		0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x72,
		0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x28, 0x69, 0x74, 0x65, 0x6d,
		0x73, 0x29, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
		0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6a, 0x73, 0x6f, 0x6e, 0x2e, 0x64,
		0x75, 0x6d, 0x70, 0x73, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x29,
		0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e,
		0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x0a, 0x0a, 0x69, 0x66,
		0x20, 0x5f, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x5f, 0x20, 0x3d, 0x3d,
		0x20, 0x27, 0x5f, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x5f, 0x27, 0x3a,
		0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x20,
		0x3d, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x75, 0x74, 0x69, 0x6c, 0x2e,
		0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65,
		0x6e, 0x74, 0x50, 0x61, 0x72, 0x73, 0x65, 0x72, 0x28, 0x0a, 0x20, 0x20,
		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x73, 0x65, 0x72, 0x76, 0x69,
		0x63, 0x65, 0x73, 0x27, 0x2c, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
		0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x27, 0x50, 0x72, 0x6f, 0x63, 0x65,
		0x73, 0x73, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x73,
		0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x27, 0x2c, 0x20, 0x73, 0x74,
		0x6f, 0x72, 0x65, 0x5f, 0x61, 0x72, 0x67, 0x3d, 0x54, 0x72, 0x75, 0x65,
		0x2c, 0x20, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x72, 0x67,
		0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
		0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20,
		0x5f, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x70,
		0x61, 0x72, 0x73, 0x65, 0x5f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x5f, 0x61,
		0x72, 0x67, 0x73, 0x28, 0x73, 0x79, 0x73, 0x2e, 0x61, 0x72, 0x67, 0x76,
		0x5b, 0x31, 0x3a, 0x5d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61,
		0x69, 0x6e, 0x28, 0x61, 0x72, 0x67, 0x73, 0x2e, 0x66, 0x6f, 0x72, 0x65,
		0x6e, 0x73, 0x69, 0x63, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x29, 0x0a,
	},
	"/scripts/elementary-services.py.info": []byte(`{"Use": "services <forensicstore>", "Short": "Process windows services"}
`),
	"/scripts/elementary-software.py": []byte(`#!/usr/bin/env python
# Copyright (c) 2019 Siemens AG
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Author(s): Demian Kellermann

"""
This plugin parses the Windows Uninstaller registry keys for a list of installed software
"""
import json
import sys

import forensicstore
import storeutil


def transform(obj):
    uninstall_entry = {
        "Name": "",
        "Key Timestamp": obj.get("modified", ""),
        "Version": "",
        "Publisher": "",
        "InstallDate": "",
        "Source": "",
        "Location": "",
        "Uninstall": "",
        "Key": obj["key"]
    }

    if "values" not in obj:
        return []

    uninstall_infos = {v["name"].lower(): v["data"] if "data" in v else "" for v in obj["values"]}

    uninstall_entry['Name'] = uninstall_infos.get("displayname", '')
    uninstall_entry['Version'] = uninstall_infos.get("displayversion", '')
    uninstall_entry['Publisher'] = uninstall_infos.get("publisher", '')
    if uninstall_infos.get('installdate', None) is not None:
        strnum = str(uninstall_infos.get('installdate'))
        uninstall_entry['InstallDate'] = '{}-{}-{}'.format(
            strnum[0:4], strnum[4:6], strnum[6:8])
    else:
        uninstall_entry['InstallDate'] = ''
    uninstall_entry['Source'] = uninstall_infos.get('installsource', '')
    uninstall_entry['Location'] = uninstall_infos.get(
        'installlocation', '')
    uninstall_entry['Uninstall'] = uninstall_infos.get(
        'uninstallstring', '')
    uninstall_entry["type"] = "uninstall_entry"

    return [uninstall_entry]


def main(url):
    print(json.dumps({
        "header": ["Name", "Version", "Publisher", "InstallDate",
                   "Source", "Location", "Uninstall", "Key", "Key Timestamp"]}))

    store = forensicstore.open(url)
    conditions = [{
        'key': "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%"
    }, {
        'key': "HKEY_USERS\\%\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%"
    }]
    for item in store.select(conditions):
        results = transform(item)
        for result in results:
            print(json.dumps(result))
    store.close()


if __name__ == '__main__':
    parser = storeutil.ScriptArgumentParser(
        'software', description='Process uninstall entries', store_arg=True, filter_arg=False,
    )
    args, _ = parser.parse_known_args(sys.argv[1:])
    main(args.forensicstore)
`),
	"/scripts/elementary-software.py.info": []byte(`{"Use": "software <forensicstore>", "Short": "Process uninstall entries"}
`),
	"/scripts/elementary-usb.py": []byte(`#!/usr/bin/env python
#  Copyright (c) 2020 Siemens AG
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy of
#  this software and associated documentation files (the "Software"), to deal in
#  the Software without restriction, including without limitation the rights to
#  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
#  the Software, and to permit persons to whom the Software is furnished to do so,
#  subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in all
#  copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
#  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
#  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
#  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
#  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
#  Author(s): Jonas Plum, Korbinian Karl
import json
import logging
import sys

import forensicstore
import storeutil

LOGGER = logging.getLogger(__name__)


class USBForensicStoreExtractor:
    # pylint: disable=fixme,too-few-public-methods

    def __init__(self, store):
        self.artifact_names = ["WindowsUSBDeviceInformations", "WindowsUSBUserMountedDevices",
                               "WindowsUSBVolumeAndDriveMapping"]
        self.forensicstore = store
        # self.filter = store_filter

    def get_usb_usage_data(self):
        """
        Collects all kinds of data about usb devices and their usage on a given forensicstore.

        :return: A list containing dicts about used usb devices
        """
        system_mounted_usb_info = self._get_system_usb_data()
        usb_user_mounted_devices = self._get_user_usb_data(system_mounted_usb_info)
        return self._get_all_usb_data(usb_user_mounted_devices)

    def _get_system_usb_data(self):
        system_mounted_usb_info = {}
        usb_system_mounted_devices = list(self.forensicstore.select([{"artifact": "WindowsUSBVolumeAndDriveMapping"}]))
        if not usb_system_mounted_devices:
            return {}
        usb_system_mounted_devices = [device.get('values') for device in usb_system_mounted_devices].pop()

        # Collects some information about the system mounted usb devices
        for mapping in usb_system_mounted_devices:
            splitted_values = mapping.get("name").split("\\").pop()
            if splitted_values.startswith("Volume"):
                volume_guid = splitted_values.replace("Volume", '')
                try:
                    device_details = bytes.fromhex(mapping.get("data")).decode("utf16")
                    if device_details and device_details.startswith("_??_USBSTOR#Disk"):
                        cleaned_details = device_details.split("&")
                        vendor_name = cleaned_details[1]
                        product_name = cleaned_details[2]
                        usb_revision = cleaned_details[3].split("#")[0]
                        usb_serial_number = cleaned_details[3].split("#")[1]
                        system_mounted_usb_info.update({volume_guid: {"vendor_name": vendor_name.replace("Ven_", ""),
                                                                      "product_name": product_name.replace("Prod_", ""),
                                                                      "usb_revision": usb_revision.replace("Rev_", ""),
                                                                      "usb_uid": usb_serial_number,
                                                                      }})
                except UnicodeError:
                    pass
        return system_mounted_usb_info

    def _get_user_usb_data(self, system_mounted_usb_info: dict):
        usb_user_mounted_data = self.forensicstore.select([{"artifact": "WindowsUSBUserMountedDevices"}])

        # Categorises found system usb usage to user usb usage.
        usb_user_mounted_devices = []
        for device in usb_user_mounted_data:
            splitted_reg_key = device.get("key").split("\\")
            rear_reg_key = splitted_reg_key[-1]
            if rear_reg_key.startswith("{") and rear_reg_key in system_mounted_usb_info:
                usb_dict = system_mounted_usb_info[rear_reg_key]
                usb_dict.update({"volume_guid": rear_reg_key.replace("{", "").replace("}", "")})
                user_sid = splitted_reg_key[1]
                usb_dict.update({"user_sid": user_sid})
                usb_user_mounted_devices.append(usb_dict)

        return usb_user_mounted_devices

    def _get_all_usb_data(self, usb_user_mounted_devices: list):
        usb_device_information = self.forensicstore.select([{"artifact": "WindowsUSBDeviceInformations"}])

        # Combines the gathered information to create a dictionary of actual used usb devices and some meta data.
        # Also keeps track about non mounted usb devices.
        mounted_device_ids = [device.get("usb_uid") for device in usb_user_mounted_devices]
        for device in usb_device_information:
            splitted_reg_key = device.get("key").split("/")

            # TODO: Can probably done better through a regex.
            if len(splitted_reg_key) == 7:
                device_id = splitted_reg_key[-1].split("&")[0]

                if device_id in mounted_device_ids:
                    for user_mounted_device in usb_user_mounted_devices:
                        if device_id == user_mounted_device.get("usb_uid"):
                            friendly_name = [value.get("data") for value in device.get("values")
                                             if value.get("name") == "FriendlyName"].pop()
                            user_mounted_device.update({"friendly_name": friendly_name})
                            user_mounted_device.update(self._get_first_insert_timestamps(device_id))
                else:
                    usb_revision = splitted_reg_key[5].split("&")[3].replace("Rev_", "")
                    device_dict = {"vendor_name": None, "product_name": None, "usb_revision": usb_revision,
                                   "usb_uid": device_id, "volume_guid": None, "user_sid": None}
                    device_dict.update(self._get_first_insert_timestamps(device_id))
                    for value in device.get("values"):
                        if value.get("name") == "FriendlyName":
                            device_dict.update({"friendly_name": value.get("data")})
                    usb_user_mounted_devices.append(device_dict)

        return usb_user_mounted_devices

    def _get_first_insert_timestamps(self, device_id):
        items = self.forensicstore.select([{"name": "setupapi.dev.log"}])
        # fsf = self.forensicstore.remote_fs.open("WindowsDeviceSetup/setupapi.dev.log", mode='rb')
        for item in items:
            if "export_path" not in item:
                continue
            fsf = self.forensicstore.fs.open(item["export_path"], mode='rt')

            inital_timestamp = {"first_insert": None}
            if device_id:

                # Checks each line for the first insert timestamp in setupapi.dev.log
                for line in fsf:
                    try:
                        log_line = line.decode("utf-8")
                        if "Device Install (Hardware initiated)" in log_line and device_id in log_line:
                            splitted_log_line = next(fsf).decode("UTF-8").split(' ')
                            date = splitted_log_line.pop().replace("\r\n", "")
                            time = splitted_log_line.pop()
                            inital_timestamp = {"first_insert": date + " " + time}
                            break

                    except UnicodeDecodeError:
                        pass
        return inital_timestamp

    @staticmethod
    def _get_all_insert_timestamps():
        # TODO get all insert timestamps via the last change timestamp of the usb UID.
        # fs = self.forensicstore
        return []


def main(url):
    print(json.dumps({
        "header": ["vendor_name", "product_name", "usb_revision", "usb_uid", "volume_guid", "user_sid"],
    }))

    LOGGER.debug("process usb")
    store = forensicstore.open(url)

    usb_usage_data = USBForensicStoreExtractor(store).get_usb_usage_data()
    for result in usb_usage_data:
        result["type"] = "usb-device"
        print(json.dumps(result))
    store.close()


if __name__ == '__main__':
    logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
    parser = storeutil.ScriptArgumentParser(
        'usb', description='Process usb artifacts', store_arg=True, filter_arg=False,
    )
    args, _ = parser.parse_known_args(sys.argv[1:])
    main(args.forensicstore)
`),
	"/scripts/elementary-usb.py.info": []byte(`{
  "Use": "usb <forensicstore>",
  "Short": "Process windows usb artifacts"
}
`),
	"/scripts/storeutil.py": []byte(`# Copyright (c) 2020 Siemens AG
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Author(s): Jonas Plum

import argparse


def merge_conditions(list_a, list_b):
    if list_a is None:
        return list_b
    if list_b is None:
        return list_a
    list_c = []
    for item_a in list_a:
        for item_b in list_b:
            list_c.append({**item_a, **item_b})
    return list_c


class DictListAction(argparse.Action):
    # pylint: disable=too-few-public-methods

    def __call__(self, parser, namespace, values, option_string=None):
        flag = {}
        for kv in values.split(","):
            key, value = kv.split("=")
            flag[key] = value
        if hasattr(namespace, self.dest):
            flags = getattr(namespace, self.dest)
            if flags is not None:
                flags.append(flag)
                setattr(namespace, self.dest, flags)
                return
        setattr(namespace, self.dest, [flag])


class ScriptArgumentParser(argparse.ArgumentParser):
    def __init__(self, subcommand, store_arg, filter_arg, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.subcommand = subcommand
        if store_arg:
            self.add_argument('forensicstore', type=str, help='the processed forensicstore')
        if filter_arg:
            self.add_argument(
                "--filter",
                dest="filter",
                action=DictListAction,
                metavar="type=file,name=System.evtx...",
                help="filter processed items")
`),
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL