From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from shymkent.ilbers.de ([unix socket]) by shymkent (Cyrus 2.5.10-Debian-2.5.10-3+deb9u2) with LMTPA; Tue, 29 Jul 2025 10:50:05 +0200 X-Sieve: CMU Sieve 2.4 Received: from mail-qv1-f56.google.com (mail-qv1-f56.google.com [209.85.219.56]) by shymkent.ilbers.de (8.15.2/8.15.2/Debian-8+deb9u1) with ESMTPS id 56T8o2e0017107 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 29 Jul 2025 10:50:03 +0200 Received: by mail-qv1-f56.google.com with SMTP id 6a1803df08f44-70747c020dasf9736186d6.0 for ; Tue, 29 Jul 2025 01:50:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1753778997; x=1754383797; darn=ilbers.de; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:x-original-sender :mime-version:subject:references:in-reply-to:message-id:to:from:date :from:to:cc:subject:date:message-id:reply-to; bh=3CIe7mJ2kqkNcyel23I0fc6ZqILB9AogKPRLmhxihxI=; b=OYwymbxzpvckDzjjqWnSv89jV0A/Wbu/PyB0iNgbh1MqbibCZP33+EYbzooXKJZ/8/ UsKlCr5Jj+4ZTUaTuWNKN6K9kQLMESaUqOXlE/UxRvjq3llXtDFrEbyKJHrvF7jSTwTY 8jQJb6fTmdr+0yRFzV1Mi4DKXJPSUv6lhl84tqVguEctfIu7QTvBYMd8TRQHlBzzTksR D5V5He1uOaJ+awxGX+SvONEAqbyNUaG6VZrXQDPuivwv9+kzuHm8kb9Lm03pJyHS3WJG 6jm1S3UsuZXYyWe1RXs5Xza12WPGMBmRnfl9ifjmzrVeRymY/FgL+CqWv/nzEoc0nu07 ZOaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753778997; x=1754383797; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence:reply-to :x-original-sender:mime-version:subject:references:in-reply-to :message-id:to:from:date:x-beenthere:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3CIe7mJ2kqkNcyel23I0fc6ZqILB9AogKPRLmhxihxI=; b=cyCzCA47e5VWthK+LtBidA7/cn/bYGVrU4wI1F4zG0xIRrBmhgzMVnMhcSdbnUyD8/ SOyIU6Ro2a2VPR+JxRN0dmXTKiixFiygecbuEbWziw11M8TmoKHaI3Q4LX9z/alPBrn2 w2K00wK3Zo2jtVaTqJrm0mAXbH4+XrdBrt/8Oa4K4rUg3mfwYJ6xxZkvikxcXsoDXNMG QhzaH+VtH/2iPNptE0oqNUzeeh87LfOgTV2i73IfdG1pm3/aTDcdHE3XqfodoBfNDAxM /DqPZxYjHtrytk8m2ls6PeNm+3x7sfSigQHnjmmSJJFCg5ONh3rXegccb4WkY3+EiP6S YteQ== X-Forwarded-Encrypted: i=1; AJvYcCWKVYzU2R1BGceavMbDFIMbm7ys0Dz8tm0F9dqhD24sD9KXyU9NfDbWMJDvhyzmLxeGVUbO@ilbers.de X-Gm-Message-State: AOJu0YwqA1pQdQVjf1BsAP7NApVqBSLdNf1hK31zk1kBy/VAFbjCnX1C 4LfcyWrH2b0021IRJ3g/uaqTXyPCEumj9B37lwJ4plsjLfagvhQsqSgu X-Google-Smtp-Source: AGHT+IHrZm5UFvlIDcokX72pckJkviczKmJwePMXKw9VMO7FQ0zKWgdO8bpDDRaNn9hXn/6CMKzMRg== X-Received: by 2002:a05:6214:4118:b0:704:7dfa:3fd with SMTP id 6a1803df08f44-7075778f659mr34899336d6.4.1753778996706; Tue, 29 Jul 2025 01:49:56 -0700 (PDT) X-BeenThere: isar-users@googlegroups.com; h=AZMbMZfQAEucXJ4cn/eXm+0rvb8OHcJKVC1c1KHr42KyiOepLQ== Received: by 2002:a05:6214:320f:b0:707:4680:6fef with SMTP id 6a1803df08f44-70746807264ls29439546d6.1.-pod-prod-06-us; Tue, 29 Jul 2025 01:49:55 -0700 (PDT) X-Received: by 2002:a05:620a:1595:b0:7e2:9c28:c308 with SMTP id af79cd13be357-7e63bf90949mr1437467385a.18.1753778995463; Tue, 29 Jul 2025 01:49:55 -0700 (PDT) Date: Tue, 29 Jul 2025 01:49:55 -0700 (PDT) From: "'Christoph' via isar-users" To: isar-users Message-Id: In-Reply-To: <8e74ae25f4e8add72fd17ce2284a48df7994edaa.camel@siemens.com> References: <20250220095944.114203-1-felix.moessbauer@siemens.com> <20250220095944.114203-2-felix.moessbauer@siemens.com> <8e74ae25f4e8add72fd17ce2284a48df7994edaa.camel@siemens.com> Subject: Re: [RFC PATCH 1/1] meta: add CycloneDX/SPDX SBOM generation MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_429714_1043403872.1753778995226" X-Original-Sender: christoph.steiger@siemens.com X-Original-From: Christoph Reply-To: Christoph Precedence: list Mailing-list: list isar-users@googlegroups.com; contact isar-users+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: isar-users@googlegroups.com X-Google-Group-Id: 914930254986 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Status: No, score=-4.9 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,HTML_MESSAGE,MAILING_LIST_MULTI, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H2,RCVD_IN_RP_CERTIFIED, RCVD_IN_RP_RNBL,RCVD_IN_RP_SAFE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on shymkent.ilbers.de X-TUID: nOWuM43xdxxN ------=_Part_429714_1043403872.1753778995226 Content-Type: multipart/alternative; boundary="----=_Part_429715_1765583369.1753778995226" ------=_Part_429715_1765583369.1753778995226 Content-Type: text/plain; charset="UTF-8" On Thu, 2025-02-20 at 10:59 +0100, 'Felix Moessbauer' via isar-users wrote: > From: Christoph Steiger > > Add a new class to allow generation of software bill of materials > (SBOM). Supported are the two standard SBOM formats CycloneDX and > SPDX. > SBOM generation is enabled per default for all images. > > Both formats support the minimal usecase of binary packages > information > and their dependencies. Unfortunately there is no proper way to > express > the relationships of debian source packages and their corresponding > binary packages in the CDX format, so it is left out there. > > The information included in the SBOM is parsed from the dpkg status > file found in the created image. Hi, while discussing various use-cases of the SBOM, I noticed, that the component description might not be precise enough to identify a debian package: while the purl SHOULD be sufficient to globally identify the package, there is no cryptographic hash provided that guarantees the integrity of the package. By that, different mirrors could theoretically offer different packages under the same purl. This works, as long as the repositories themselves are signed correctly and the key is added to the ISAR build. How about adding the "hashes" field for each binary package with the data from apt? Best regards, Felix Do you mean the "hashes" field in a CycloneDX component? It is a very good idea to add that. There is a checksum field for SPDX packages too which should semantically be the same. I will add it to the (long) list of features we want ;) > > Signed-off-by: Christoph Steiger > --- > meta/classes/create-sbom.bbclass | 49 ++++ > meta/classes/image.bbclass | 2 + > meta/lib/sbom.py | 446 > +++++++++++++++++++++++++++++++ > meta/lib/sbom_cdx_types.py | 82 ++++++ > meta/lib/sbom_spdx_types.py | 95 +++++++ > 5 files changed, 674 insertions(+) > create mode 100644 meta/classes/create-sbom.bbclass > create mode 100644 meta/lib/sbom.py > create mode 100644 meta/lib/sbom_cdx_types.py > create mode 100644 meta/lib/sbom_spdx_types.py > > diff --git a/meta/classes/create-sbom.bbclass b/meta/classes/create- > sbom.bbclass > new file mode 100644 > index 00000000..8c647699 > --- /dev/null > +++ b/meta/classes/create-sbom.bbclass > @@ -0,0 +1,49 @@ > +# This software is a part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +# sbom type to generate, accepted are "cyclonedx" and "spdx" > +SBOM_TYPE ?= "cyclonedx spdx" > + > +# general user variables > +SBOM_DISTRO_SUPPLIER ?= "ISAR" > +SBOM_DISTRO_NAME ?= "ISAR-Debian-GNU-Linux" > +SBOM_DISTRO_VERSION ?= "1.0.0" > +SBOM_DISTRO_SUMMARY ?= "Linux distribution built with ISAR" > +SBOM_DOCUMENT_UUID ?= "" > + > +# SPDX specific user variables > +SBOM_SPDX_NAMESPACE_PREFIX ?= "https://spdx.org/spdxdocs" > + > +SBOM_DEPLOY_BASE = "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}" > + > +SBOM_GEN_VERSION = "0.1.0" > + > +# adapted from the isar-cip-core image_uuid.bbclass > +def generate_document_uuid(d): > + import uuid > + > + base_hash = d.getVar("BB_TASKHASH") > + if base_hash is None: > + bb.warn("no BB_TASKHASH available, SBOM UUID is not > reproducible") > + return uuid.uuid4() > + return str(uuid.UUID(base_hash[:32], version=4)) > + > +python do_create_sbom() { > + import sbom > + > + dpkg_status = d.getVar("IMAGE_ROOTFS") + "/var/lib/dpkg/status" > + packages = sbom.Package.parse_status_file(dpkg_status) > + > + if not d.getVar("SBOM_DOCUMENT_UUID"): > + d.setVar("SBOM_DOCUMENT_UUID", generate_document_uuid(d)) > + > + sbom_type = d.getVar("SBOM_TYPE") > + if "cyclonedx" in sbom_type: > + sbom.generate(d, packages, sbom.SBOMType.CycloneDX, > d.getVar("SBOM_DEPLOY_BASE") + ".cyclonedx.json") > + if "spdx" in sbom_type: > + sbom.generate(d, packages, sbom.SBOMType.SPDX, > d.getVar("SBOM_DEPLOY_BASE") + ".spdx.json") > +} > + > +addtask do_create_sbom after do_rootfs before do_build > diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass > index 56eca202..e9da6a61 100644 > --- a/meta/classes/image.bbclass > +++ b/meta/classes/image.bbclass > @@ -81,6 +81,8 @@ inherit image-postproc-extension > inherit image-locales-extension > inherit image-account-extension > > +inherit create-sbom > + > # Extra space for rootfs in MB > ROOTFS_EXTRA ?= "64" > > diff --git a/meta/lib/sbom.py b/meta/lib/sbom.py > new file mode 100644 > index 00000000..d7c79e43 > --- /dev/null > +++ b/meta/lib/sbom.py > @@ -0,0 +1,446 @@ > +# This software is part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +from dataclasses import dataclass > +from datetime import datetime > +from enum import Enum > +from typing import Dict, List, Type > +import json > +import re > +from uuid import uuid4 > + > +import sbom_cdx_types as cdx > +import sbom_spdx_types as spdx > + > + > +class SBOMType(Enum): > + CycloneDX = (0,) > + SPDX = (1,) > + > + > +@dataclass > +class SourcePackage: > + name: str > + version: str | None > + > + def purl(self): > + """Return the PURL of the package.""" > + return "pkg:deb/debian/{}@{}?arch=source".format(self.name, > self.version) > + > + def bom_ref(self, sbom_type: SBOMType) -> str: > + """Return a unique BOM reference.""" > + if sbom_type == SBOMType.CycloneDX: > + return cdx.CDXREF_PREFIX + "{}-src".format(self.name) > + elif sbom_type == SBOMType.SPDX: > + return spdx.SPDX_REF_PREFIX + "{}-src".format(self.name) > + > + def parse(s: str) -> Type["SourcePackage"]: > + split = s.split(" ") > + name = split[0] > + try: > + version = " ".join(split[1:]).strip("()") > + except IndexError: > + version = None > + > + return SourcePackage(name=name, version=version) > + > + > +@dataclass > +class Dependency: > + name: str > + version: str | None > + > + def bom_ref(self, sbom_type: SBOMType) -> str: > + """Return a unique BOM reference.""" > + if sbom_type == SBOMType.CycloneDX: > + return cdx.CDX_REF_PREFIX + "{}".format(self.name) > + elif sbom_type == SBOMType.SPDX: > + return spdx.SPDX_REF_PREFIX + "{}".format(self.name) > + > + def parse_multiple(s: str) -> List[Type["Dependency"]]: > + """Parse a 'Depends' line in the dpkg status file.""" > + dependencies = [] > + for entry in s.split(","): > + entry = entry.strip() > + for entry in entry.split("|"): > + split = entry.split("(") > + name = split[0].strip() > + try: > + version = split[1].strip(")") > + except IndexError: > + version = None > + dependencies.append(Dependency(name=name, > version=version)) > + > + return dependencies > + > + > +@dataclass > +class Package: > + """Incomplete representation of a debian package.""" > + > + name: str > + section: str > + maintainer: str > + architecture: str > + source: SourcePackage > + version: str > + depends: List[Dependency] > + description: str > + homepage: str > + > + def purl(self) -> str: > + """Return the PURL of the package.""" > + purl = "pkg:deb/debian/{}@{}".format(self.name, > self.version) > + if self.architecture: > + purl = purl + "?arch={}".format(self.architecture) > + return purl > + > + def bom_ref(self, sbom_type: SBOMType) -> str: > + """Return a unique BOM reference.""" > + if sbom_type == SBOMType.CycloneDX: > + return cdx.CDX_REF_PREFIX + self.name > + elif sbom_type == SBOMType.SPDX: > + return spdx.SPDX_REF_PREFIX + self.name > + > + def parse_status_file(status_file: str) -> > List[Type["Package"]]: > + """Parse a dpkg status file.""" > + packages = [] > + with open(status_file, "r") as f: > + name = None > + section = None > + maintainer = None > + architecture = None > + source = None > + version = None > + dependencies = None > + description = None > + homepage = None > + for line in f.readlines(): > + if line.strip(): > + if line[0] == " ": > + # this is a description line, we ignore it > + continue > + else: > + split = line.split(":") > + key = split[0] > + value = ":".join(split[1:]).strip() > + if key == "Package": > + name = value > + elif key == "Section": > + section = value > + elif key == "Maintainer": > + maintainer = value > + elif key == "Architecture": > + architecture = value > + elif key == "Source": > + source = SourcePackage.parse(value) > + elif key == "Version": > + version = value > + elif key == "Depends": > + dependencies = > Dependency.parse_multiple(value) > + elif key == "Description": > + description = value > + elif key == "Homepage": > + homepage = value > + else: > + # fixup source version, if not specified it is > the same > + # as the package version > + if source and not source.version: > + source.version = version > + # empty line means new package, so finish the > current one > + packages.append( > + Package( > + name=name, > + section=section, > + maintainer=maintainer, > + architecture=architecture, > + source=source, > + version=version, > + depends=dependencies, > + description=description, > + homepage=homepage, > + ) > + ) > + name = None > + section = None > + maintainer = None > + architecture = None > + source = None > + version = None > + dependencies = None > + description = None > + homepage = None > + > + return packages > + > + > +def cyclonedx_bom(d, packages: List[Package]) -> Dict: > + """Return a valid CycloneDX SBOM.""" > + data = [] > + dependencies = [] > + > + pattern = > re.compile("(?P^[^<]*)(\\<(?P.*)\\>)?" > ) > + for package in packages: > + match = pattern.match(package.maintainer) > + supplier = cdx.CDXSupplier(name=match["supplier_name"]) > + supplier_email = match["supplier_email"] > + if supplier_email: > + supplier.contact = > [cdx.CDXSupplierContact(email=supplier_email)] > + entry = cdx.CDXComponent( > + type=cdx.CDX_COMPONENT_TYPE_LIBRARY, > + bom_ref=package.bom_ref(SBOMType.CycloneDX), > + supplier=supplier, > + name=package.name, > + version=package.version, > + description=package.description, > + purl=package.purl(), > + ) > + if package.homepage: > + entry.externalReferences = ( > + cdx.CDXExternalReference( > + url=package.homepage, > + type=cdx.CDX_PACKAGE_EXTREF_TYPE_WEBSITE, > + comment="homepage", > + ), > + ) > + data.append(entry) > + > + distro_bom_ref = cdx.CDX_REF_PREFIX + > d.getVar("SBOM_DISTRO_NAME") > + distro_dependencies = [] > + # after we have found all packages we can start to resolve > dependencies > + package_names = [package.name for package in packages] > + for package in packages: > + > distro_dependencies.append(package.bom_ref(SBOMType.CycloneDX)) > + if package.depends: > + deps = [] > + for dep in package.depends: > + dep_bom_ref = dep.bom_ref(SBOMType.CycloneDX) > + # it is possibe to specify the same package multiple > times, but > + # in different versions > + if dep.name in package_names and dep_bom_ref not in > deps: > + deps.append(dep_bom_ref) > + else: > + # this might happen if we have optional > dependencies > + continue > + dependency = cdx.CDXDependency( > + ref=package.bom_ref(SBOMType.CycloneDX), > + dependsOn=deps, > + ) > + dependencies.append(dependency) > + dependency = cdx.CDXDependency( > + ref=distro_bom_ref, > + dependsOn=distro_dependencies, > + ) > + dependencies.append(dependency) > + > + doc_uuid = d.getVar("SBOM_DOCUMENT_UUID") > + distro_component = cdx.CDXComponent( > + type=cdx.CDX_COMPONENT_TYPE_OS, > + bom_ref=cdx.CDX_REF_PREFIX + d.getVar("SBOM_DISTRO_NAME"), > + > supplier=cdx.CDXSupplier(name=d.getVar("SBOM_DISTRO_SUPPLIER")), > + name=d.getVar("SBOM_DISTRO_NAME"), > + version=d.getVar("SBOM_DISTRO_VERSION"), > + description=d.getVar("SBOM_DISTRO_SUMMARY"), > + ) > + > + timestamp = > datetime.fromtimestamp(int(d.getVar("SOURCE_DATE_EPOCH"))) > + bom = cdx.CDXBOM( > + bomFormat=cdx.CDX_BOM_FORMAT, > + specVersion=cdx.CDX_SPEC_VERSION, > + serialNumber="urn:uuid:{}".format(doc_uuid if doc_uuid else > uuid4()), > + version=1, > + metadata=cdx.CDXBOMMetadata( > + timestamp=timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"), > + component=distro_component, > + tools=cdx.CDXBOMMetadataTool( > + components=[ > + cdx.CDXComponent( > + type=cdx.CDX_COMPONENT_TYPE_APPLICATION, > + name="ISAR SBOM Generator", > + version=d.getVar("SBOM_GEN_VERSION"), > + ) > + ], > + ), > + ), > + components=data, > + dependencies=dependencies, > + ) > + return bom > + > + > +def spdx_bom(d, packages: List[Package]) -> Dict: > + "Return a valid SPDX SBOM." > + > + data = [] > + # create a "fake" entry for the distribution > + distro_ref = spdx.SPDX_REF_PREFIX + d.getVar("SBOM_DISTRO_NAME") > + distro_package = spdx.SPDXPackage( > + SPDXID=distro_ref, > + name=d.getVar("SBOM_DISTRO_NAME"), > + versionInfo=d.getVar("SBOM_DISTRO_VERSION"), > + primaryPackagePurpose=spdx.SPDX_PACKAGE_PURPOSE_OS, > + supplier="Organization: > {}".format(d.getVar("SBOM_DISTRO_SUPPLIER")), > + downloadLocation=spdx.SPDX_NOASSERTION, > + filesAnalyzed=False, > + licenseConcluded=spdx.SPDX_NOASSERTION, > + licenseDeclared=spdx.SPDX_NOASSERTION, > + copyrightText=spdx.SPDX_NOASSERTION, > + summary=d.getVar("SBOM_DISTRO_SUMMARY"), > + ) > + > + data.append(distro_package) > + > + pattern = > re.compile("(?P^[^<]*)(\\<(?P.*)\\>)?" > ) > + for package in packages: > + match = pattern.match(package.maintainer) > + supplier_name = match["supplier_name"] > + supplier_email = match["supplier_email"] > + if any([cue in supplier_name.lower() for cue in > spdx.SPDX_SUPPLIER_ORG_CUE]): > + supplier = "Organization: {}".format(supplier_name) > + else: > + supplier = "Person: {}".format(supplier_name) > + if supplier_email: > + supplier += "({})".format(supplier_email) > + > + entry = spdx.SPDXPackage( > + SPDXID=package.bom_ref(SBOMType.SPDX), > + name=package.name, > + versionInfo=package.version, > + primaryPackagePurpose=spdx.SPDX_PACKAGE_PURPOSE_LIBRARY, > + supplier=supplier, > + downloadLocation=spdx.SPDX_NOASSERTION, > + filesAnalyzed=False, > + # TODO: it should be possible to conclude > license/copyright > + # information, we could look e.g. in > /usr/share/doc/*/copyright > + licenseConcluded=spdx.SPDX_NOASSERTION, > + licenseDeclared=spdx.SPDX_NOASSERTION, > + copyrightText=spdx.SPDX_NOASSERTION, > + summary=package.description, > + externalRefs=[ > + spdx.SPDXExternalRef( > + > referenceCategory=spdx.SPDX_REFERENCE_CATEGORY_PKG_MANAGER, > + referenceType=spdx.SPDX_REFERENCE_TYPE_PURL, > + referenceLocator=package.purl(), > + ) > + ], > + ) > + if package.homepage: > + entry.homepage = package.homepage > + data.append(entry) > + > + if package.source: > + src_entry = spdx.SPDXPackage( > + SPDXID=package.source.bom_ref(SBOMType.SPDX), > + name=package.source.name, > + versionInfo=package.source.version, > + primaryPackagePurpose=spdx.SPDX_PACKAGE_PURPOSE_SRC, > + supplier=supplier, > + downloadLocation=spdx.SPDX_NOASSERTION, > + filesAnalyzed=False, > + licenseConcluded=spdx.SPDX_NOASSERTION, > + licenseDeclared=spdx.SPDX_NOASSERTION, > + copyrightText=spdx.SPDX_NOASSERTION, > + summary="debian source code package > '{}'".format(package.source.name), > + externalRefs=[ > + spdx.SPDXExternalRef( > + > referenceCategory=spdx.SPDX_REFERENCE_CATEGORY_PKG_MANAGER, > + referenceType=spdx.SPDX_REFERENCE_TYPE_PURL, > + referenceLocator=package.source.purl(), > + ) > + ], > + ) > + # source packages might be referenced multiple times > + if src_entry not in data: > + data.append(src_entry) > + > + relationships = [] > + # after we have found all packages we can start to resolve > dependencies > + package_names = [package.name for package in packages] > + for package in packages: > + relationships.append( > + spdx.SPDXRelationship( > + spdxElementId=package.bom_ref(SBOMType.SPDX), > + relatedSpdxElement=distro_ref, > + relationshipType=spdx.SPDX_RELATIONSHIP_PACKAGE_OF, > + ) > + ) > + if package.depends: > + for dep in package.depends: > + if dep.name in package_names: > + relationship = spdx.SPDXRelationship( > + > spdxElementId=package.bom_ref(SBOMType.SPDX), > + > relatedSpdxElement=dep.bom_ref(SBOMType.SPDX), > + > relationshipType=spdx.SPDX_RELATIONSHIP_DEPENDS_ON, > + ) > + relationships.append(relationship) > + else: > + # this might happen if we have optional > dependencies > + pass > + if package.source: > + relationship = spdx.SPDXRelationship( > + spdxElementId=package.source.bom_ref(SBOMType.SPDX), > + relatedSpdxElement=package.bom_ref(SBOMType.SPDX), > + relationshipType=spdx.SPDX_RELATIONSHIP_GENERATES, > + ) > + relationships.append(relationship) > + relationships.append( > + spdx.SPDXRelationship( > + spdxElementId=spdx.SPDX_REF_DOCUMENT, > + relatedSpdxElement=distro_ref, > + relationshipType=spdx.SPDX_RELATIONSHIP_DESCRIBES, > + ) > + ) > + > + namespace_uuid = d.getVar("SBOM_DOCUMENT_UUID") > + timestamp = > datetime.fromtimestamp(int(d.getVar("SOURCE_DATE_EPOCH"))) > + bom = spdx.SPDXBOM( > + SPDXID=spdx.SPDX_REF_DOCUMENT, > + spdxVersion=spdx.SPDX_VERSION, > + creationInfo=spdx.SPDXCreationInfo( > + comment="This document has been generated as part of an > ISAR build.", > + creators=[ > + "Tool: ISAR SBOM Generator - > {}".format(d.getVar("SBOM_GEN_VERSION")) > + ], > + created=timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"), > + ), > + name=d.getVar("SBOM_DISTRO_NAME"), > + dataLicense="CC0-1.0", > + documentNamespace="{}/{}-{}".format( > + d.getVar("SBOM_SPDX_NAMESPACE_PREFIX"), > + d.getVar("SBOM_DISTRO_NAME"), > + namespace_uuid if namespace_uuid else uuid4(), > + ), > + packages=data, > + relationships=relationships, > + ) > + return bom > + > + > +def fixup_dict(o): > + """Apply fixups for the BOMs. > + > + This is necessary for some field names and to remove fields with > a None > + value. > + """ > + dct = vars(o) > + new_dct = {} > + for k, v in dct.items(): > + # remove fields with no content > + if v is not None: > + # we can not name our fields with dashes, so convert > them > + k = k.replace("_", "-") > + new_dct[k] = v > + return new_dct > + > + > +def generate(d, packages: List[Package], sbom_type: SBOMType, out: > str): > + """Generate a SBOM.""" > + if sbom_type == SBOMType.CycloneDX: > + bom = cyclonedx_bom(d, packages) > + elif sbom_type == SBOMType.SPDX: > + bom = spdx_bom(d, packages) > + > + with open(out, "w") as bom_file: > + json.dump(bom, bom_file, indent=2, default=fixup_dict, > sort_keys=True) > diff --git a/meta/lib/sbom_cdx_types.py b/meta/lib/sbom_cdx_types.py > new file mode 100644 > index 00000000..4911cc23 > --- /dev/null > +++ b/meta/lib/sbom_cdx_types.py > @@ -0,0 +1,82 @@ > +# This software is part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +from dataclasses import dataclass > +from typing import List, Optional > + > +# Minimal implementation of some CycloneDX SBOM types. > +# Please mind that (almost) none of these types are complete, they > only > +# reflect what was strictly necessary for immediate SBOM creation > + > +CDX_BOM_FORMAT = "CycloneDX" > +CDX_SPEC_VERSION = "1.6" > + > +CDX_REF_PREFIX = "CDXRef-" > + > +CDX_PACKAGE_EXTREF_TYPE_WEBSITE = "website" > + > +CDX_COMPONENT_TYPE_LIBRARY = "library" > +CDX_COMPONENT_TYPE_APPLICATION = "application" > +CDX_COMPONENT_TYPE_OS = "operating-system" > + > + > +@dataclass > +class CDXDependency: > + ref: str > + dependsOn: Optional[str] > + > + > +@dataclass > +class CDXExternalReference: > + url: str > + type: str > + comment: Optional[str] = None > + > + > +@dataclass > +class CDXSupplierContact: > + email: Optional[str] = None > + > + > +@dataclass > +class CDXSupplier: > + name: Optional[str] = None > + contact: Optional[CDXSupplierContact] = None > + > + > +@dataclass > +class CDXComponent: > + type: str > + name: str > + bom_ref: Optional[str] = None > + supplier: Optional[str] = None > + version: Optional[CDXSupplier] = None > + description: Optional[str] = None > + purl: Optional[str] = None > + externalReferences: Optional[List[CDXExternalReference]] = None > + homepage: Optional[str] = None > + > + > +@dataclass > +class CDXBOMMetadataTool: > + components: Optional[List[CDXComponent]] > + > + > +@dataclass > +class CDXBOMMetadata: > + timestamp: Optional[str] = None > + component: Optional[str] = None > + tools: Optional[List[CDXBOMMetadataTool]] = None > + > + > +@dataclass > +class CDXBOM: > + bomFormat: str > + specVersion: str > + serialNumber: Optional[str] = None > + version: Optional[str] = None > + metadata: Optional[CDXBOMMetadata] = None > + components: Optional[List[CDXComponent]] = None > + dependencies: Optional[List[CDXDependency]] = None > diff --git a/meta/lib/sbom_spdx_types.py > b/meta/lib/sbom_spdx_types.py > new file mode 100644 > index 00000000..efd7cc0c > --- /dev/null > +++ b/meta/lib/sbom_spdx_types.py > @@ -0,0 +1,95 @@ > +# This software is part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +from dataclasses import dataclass > +from typing import List, Optional > + > +# Minimal implementation of some SPDX SBOM types. > +# Please mind that (almost) none of these types are complete, they > only > +# reflect what was strictly necessary for immediate SBOM creation > + > +SPDX_VERSION = "SPDX-2.3" > + > +SPDX_REF_PREFIX = "SPDXRef-" > + > +SPDX_REF_DOCUMENT = "SPDXRef-DOCUMENT" > + > +SPDX_PACKAGE_PURPOSE_LIBRARY = "LIBRARY" > +SPDX_PACKAGE_PURPOSE_OS = "OPERATING_SYSTEM" > +SPDX_PACKAGE_PURPOSE_SRC = "SOURCE" > + > +SPDX_NOASSERTION = "NOASSERTION" > + > +SPDX_RELATIONSHIP_DEPENDS_ON = "DEPENDS_ON" > +SPDX_RELATIONSHIP_PACKAGE_OF = "PACKAGE_OF" > +SPDX_RELATIONSHIP_GENERATES = "GENERATES" > +SPDX_RELATIONSHIP_DESCRIBES = "DESCRIBES" > + > +SPDX_REFERENCE_CATEGORY_PKG_MANAGER = "PACKAGE_MANAGER" > +SPDX_REFERENCE_TYPE_PURL = "purl" > + > +# cues for an organization in the maintainer name > +SPDX_SUPPLIER_ORG_CUE = [ > + "maintainers", > + "group", > + "developers", > + "team", > + "project", > + "task force", > + "strike force", > + "packagers", > +] > + > + > +@dataclass > +class SPDXRelationship: > + spdxElementId: str > + relatedSpdxElement: str > + relationshipType: str > + > + > +@dataclass > +class SPDXExternalRef: > + referenceCategory: str > + referenceType: str > + referenceLocator: str > + > + > +@dataclass > +class SPDXPackage: > + SPDXID: str > + name: str > + downloadLocation: str > + filesAnalyzed: Optional[bool] = False > + versionInfo: Optional[str] = None > + homepage: Optional[str] = None > + primaryPackagePurpose: Optional[str] = None > + supplier: Optional[str] = None > + licenseConcluded: Optional[str] = None > + licenseDeclared: Optional[str] = None > + copyrightText: Optional[str] = None > + summary: Optional[str] = None > + externalRefs: Optional[List[SPDXExternalRef]] = None > + > + > +@dataclass > +class SPDXCreationInfo: > + created: str > + comment: Optional[str] = None > + creators: List[str] = None > + > + > +@dataclass > +class SPDXBOM: > + """Incomplete BOM as of SPDX spec v2.3.""" > + > + SPDXID: str > + spdxVersion: str > + creationInfo: SPDXCreationInfo > + name: str > + dataLicense: str > + documentNamespace: str > + packages: List[SPDXPackage] > + relationships: List[SPDXRelationship] > -- > 2.39.5 -- Siemens AG Linux Expert Center Friedrich-Ludwig-Bauer-Str. 3 85748 Garching, Germany -- You received this message because you are subscribed to the Google Groups "isar-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/isar-users/dc9b7cec-3bb6-4ae7-9d74-e7b496d592f3n%40googlegroups.com. ------=_Part_429715_1765583369.1753778995226 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: base64 PGRpdj48YmxvY2txdW90ZSBzdHlsZT0ibWFyZ2luOiAwcHggMHB4IDBweCAwLjhleDsgYm9yZGVy LWxlZnQ6IDFweCBzb2xpZCByZ2IoMjA0LCAyMDQsIDIwNCk7IHBhZGRpbmctbGVmdDogMWV4OyI+ T24gVGh1LCAyMDI1LTAyLTIwIGF0IDEwOjU5ICswMTAwLCAnRmVsaXggTW9lc3NiYXVlcicgdmlh IGlzYXItdXNlcnM8YnIgLz53cm90ZTo8YnIgLz4mZ3Q7IEZyb206IENocmlzdG9waCBTdGVpZ2Vy ICZsdDs8YSBocmVmPSIiIHJlbD0ibm9mb2xsb3ciPmNocmlzdG9wLi4uQHNpZW1lbnMuY29tPC9h PiZndDs8YnIgLz4mZ3Q7IDxiciAvPiZndDsgQWRkIGEgbmV3IGNsYXNzIHRvIGFsbG93IGdlbmVy YXRpb24gb2Ygc29mdHdhcmUgYmlsbCBvZiBtYXRlcmlhbHM8YnIgLz4mZ3Q7IChTQk9NKS4gU3Vw cG9ydGVkIGFyZSB0aGUgdHdvIHN0YW5kYXJkIFNCT00gZm9ybWF0cyBDeWNsb25lRFggYW5kPGJy IC8+Jmd0OyBTUERYLjxiciAvPiZndDsgU0JPTSBnZW5lcmF0aW9uIGlzIGVuYWJsZWQgcGVyIGRl ZmF1bHQgZm9yIGFsbCBpbWFnZXMuPGJyIC8+Jmd0OyA8YnIgLz4mZ3Q7IEJvdGggZm9ybWF0cyBz dXBwb3J0IHRoZSBtaW5pbWFsIHVzZWNhc2Ugb2YgYmluYXJ5IHBhY2thZ2VzPGJyIC8+Jmd0OyBp bmZvcm1hdGlvbjxiciAvPiZndDsgYW5kIHRoZWlyIGRlcGVuZGVuY2llcy4gVW5mb3J0dW5hdGVs eSB0aGVyZSBpcyBubyBwcm9wZXIgd2F5IHRvPGJyIC8+Jmd0OyBleHByZXNzPGJyIC8+Jmd0OyB0 aGUgcmVsYXRpb25zaGlwcyBvZiBkZWJpYW4gc291cmNlIHBhY2thZ2VzIGFuZCB0aGVpciBjb3Jy ZXNwb25kaW5nPGJyIC8+Jmd0OyBiaW5hcnkgcGFja2FnZXMgaW4gdGhlIENEWCBmb3JtYXQsIHNv IGl0IGlzIGxlZnQgb3V0IHRoZXJlLjxiciAvPiZndDsgPGJyIC8+Jmd0OyBUaGUgaW5mb3JtYXRp b24gaW5jbHVkZWQgaW4gdGhlIFNCT00gaXMgcGFyc2VkIGZyb20gdGhlIGRwa2cgc3RhdHVzPGJy IC8+Jmd0OyBmaWxlIGZvdW5kIGluIHRoZSBjcmVhdGVkIGltYWdlLjxwPkhpLDwvcD48cD53aGls ZSBkaXNjdXNzaW5nIHZhcmlvdXMgdXNlLWNhc2VzIG9mIHRoZSBTQk9NLCBJIG5vdGljZWQsIHRo YXQgdGhlPGJyIC8+Y29tcG9uZW50IGRlc2NyaXB0aW9uIG1pZ2h0IG5vdCBiZSBwcmVjaXNlIGVu b3VnaCB0byBpZGVudGlmeSBhIGRlYmlhbjxiciAvPnBhY2thZ2U6IHdoaWxlIHRoZSBwdXJsIFNI T1VMRCBiZSBzdWZmaWNpZW50IHRvIGdsb2JhbGx5IGlkZW50aWZ5IHRoZTxiciAvPnBhY2thZ2Us IHRoZXJlIGlzIG5vIGNyeXB0b2dyYXBoaWMgaGFzaCBwcm92aWRlZCB0aGF0IGd1YXJhbnRlZXMg dGhlPGJyIC8+aW50ZWdyaXR5IG9mIHRoZSBwYWNrYWdlLiBCeSB0aGF0LCBkaWZmZXJlbnQgbWly cm9ycyBjb3VsZDxiciAvPnRoZW9yZXRpY2FsbHkgb2ZmZXIgZGlmZmVyZW50IHBhY2thZ2VzIHVu ZGVyIHRoZSBzYW1lIHB1cmwuIFRoaXMgd29ya3MsPGJyIC8+YXMgbG9uZyBhcyB0aGUgcmVwb3Np dG9yaWVzIHRoZW1zZWx2ZXMgYXJlIHNpZ25lZCBjb3JyZWN0bHkgYW5kIHRoZSBrZXk8YnIgLz5p cyBhZGRlZCB0byB0aGUgSVNBUiBidWlsZC48L3A+PHA+SG93IGFib3V0IGFkZGluZyB0aGUgImhh c2hlcyIgZmllbGQgZm9yIGVhY2ggYmluYXJ5IHBhY2thZ2Ugd2l0aCB0aGU8YnIgLz5kYXRhIGZy b20gYXB0PzwvcD48cD5CZXN0IHJlZ2FyZHMsPGJyIC8+RmVsaXg8L3A+PC9ibG9ja3F1b3RlPjxk aXY+RG8geW91IG1lYW4gdGhlICJoYXNoZXMiIGZpZWxkIGluIGEgQ3ljbG9uZURYIGNvbXBvbmVu dD8gSXQgaXMgYSB2ZXJ5PC9kaXY+PGRpdj5nb29kIGlkZWEgdG8gYWRkIHRoYXQuIFRoZXJlIGlz IGEgY2hlY2tzdW0gZmllbGQgZm9yIFNQRFggcGFja2FnZXMgdG9vPC9kaXY+PGRpdj53aGljaCBz aG91bGQgc2VtYW50aWNhbGx5IGJlIHRoZSBzYW1lLjxiciAvPjxiciAvPkkgd2lsbCBhZGQgaXQg dG8gdGhlIChsb25nKSBsaXN0IG9mIGZlYXR1cmVzIHdlIHdhbnQgOyk8YnIgLz48L2Rpdj48Ymxv Y2txdW90ZSBzdHlsZT0ibWFyZ2luOiAwcHggMHB4IDBweCAwLjhleDsgYm9yZGVyLWxlZnQ6IDFw eCBzb2xpZCByZ2IoMjA0LCAyMDQsIDIwNCk7IHBhZGRpbmctbGVmdDogMWV4OyI+PHA+PC9wPjxw PjwvcD48cD48L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+ Jmd0OyA8YnIgLz4mZ3Q7IFNpZ25lZC1vZmYtYnk6IENocmlzdG9waCBTdGVpZ2VyICZsdDs8YSBo cmVmPSIiIHJlbD0ibm9mb2xsb3ciPmNocmlzdG9wLi4uQHNpZW1lbnMuY29tPC9hPiZndDs8YnIg Lz4mZ3Q7IC0tLTxiciAvPiZndDsgwqBtZXRhL2NsYXNzZXMvY3JlYXRlLXNib20uYmJjbGFzcyB8 wqAgNDkgKysrKzxiciAvPiZndDsgwqBtZXRhL2NsYXNzZXMvaW1hZ2UuYmJjbGFzc8KgwqDCoMKg wqDCoCB8wqDCoCAyICs8YnIgLz4mZ3Q7IMKgbWV0YS9saWIvc2JvbS5wecKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIHwgNDQ2PGJyIC8+Jmd0OyArKysrKysrKysrKysrKysrKysrKysr KysrKysrKysrPGJyIC8+Jmd0OyDCoG1ldGEvbGliL3Nib21fY2R4X3R5cGVzLnB5wqDCoMKgwqDC oMKgIHzCoCA4MiArKysrKys8YnIgLz4mZ3Q7IMKgbWV0YS9saWIvc2JvbV9zcGR4X3R5cGVzLnB5 wqDCoMKgwqDCoCB8wqAgOTUgKysrKysrKzxiciAvPiZndDsgwqA1IGZpbGVzIGNoYW5nZWQsIDY3 NCBpbnNlcnRpb25zKCspPGJyIC8+Jmd0OyDCoGNyZWF0ZSBtb2RlIDEwMDY0NCBtZXRhL2NsYXNz ZXMvY3JlYXRlLXNib20uYmJjbGFzczxiciAvPiZndDsgwqBjcmVhdGUgbW9kZSAxMDA2NDQgbWV0 YS9saWIvc2JvbS5weTxiciAvPiZndDsgwqBjcmVhdGUgbW9kZSAxMDA2NDQgbWV0YS9saWIvc2Jv bV9jZHhfdHlwZXMucHk8YnIgLz4mZ3Q7IMKgY3JlYXRlIG1vZGUgMTAwNjQ0IG1ldGEvbGliL3Ni b21fc3BkeF90eXBlcy5weTxiciAvPiZndDsgPGJyIC8+Jmd0OyBkaWZmIC0tZ2l0IGEvbWV0YS9j bGFzc2VzL2NyZWF0ZS1zYm9tLmJiY2xhc3MgYi9tZXRhL2NsYXNzZXMvY3JlYXRlLTxiciAvPiZn dDsgc2JvbS5iYmNsYXNzPGJyIC8+Jmd0OyBuZXcgZmlsZSBtb2RlIDEwMDY0NDxiciAvPiZndDsg aW5kZXggMDAwMDAwMDAuLjhjNjQ3Njk5PGJyIC8+Jmd0OyAtLS0gL2Rldi9udWxsPGJyIC8+Jmd0 OyArKysgYi9tZXRhL2NsYXNzZXMvY3JlYXRlLXNib20uYmJjbGFzczxiciAvPiZndDsgQEAgLTAs MCArMSw0OSBAQDxiciAvPiZndDsgKyMgVGhpcyBzb2Z0d2FyZSBpcyBhIHBhcnQgb2YgSVNBUi48 YnIgLz4mZ3Q7ICsjIENvcHlyaWdodCAoQykgMjAyNSBTaWVtZW5zIEFHPGJyIC8+Jmd0OyArIzxi ciAvPiZndDsgKyMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVDxiciAvPiZndDsgKzxiciAv PiZndDsgKyMgc2JvbSB0eXBlIHRvIGdlbmVyYXRlLCBhY2NlcHRlZCBhcmUgImN5Y2xvbmVkeCIg YW5kICJzcGR4IjxiciAvPiZndDsgK1NCT01fVFlQRSA/PSAiY3ljbG9uZWR4IHNwZHgiPGJyIC8+ Jmd0OyArPGJyIC8+Jmd0OyArIyBnZW5lcmFsIHVzZXIgdmFyaWFibGVzPGJyIC8+Jmd0OyArU0JP TV9ESVNUUk9fU1VQUExJRVIgPz0gIklTQVIiPGJyIC8+Jmd0OyArU0JPTV9ESVNUUk9fTkFNRSA/ PSAiSVNBUi1EZWJpYW4tR05VLUxpbnV4IjxiciAvPiZndDsgK1NCT01fRElTVFJPX1ZFUlNJT04g Pz0gIjEuMC4wIjxiciAvPiZndDsgK1NCT01fRElTVFJPX1NVTU1BUlkgPz0gIkxpbnV4IGRpc3Ry aWJ1dGlvbiBidWlsdCB3aXRoIElTQVIiPGJyIC8+Jmd0OyArU0JPTV9ET0NVTUVOVF9VVUlEID89 ICIiPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArIyBTUERYIHNwZWNpZmljIHVzZXIgdmFyaWFibGVz PGJyIC8+Jmd0OyArU0JPTV9TUERYX05BTUVTUEFDRV9QUkVGSVggPz0gIjxhIGhyZWY9Imh0dHBz Oi8vc3BkeC5vcmcvc3BkeGRvY3MiIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vZm9sbG93Ij5odHRw czovL3NwZHgub3JnL3NwZHhkb2NzPC9hPiI8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICtTQk9NX0RF UExPWV9CQVNFID0gIiR7REVQTE9ZX0RJUl9JTUFHRX0vJHtJTUFHRV9GVUxMTkFNRX0iPGJyIC8+ Jmd0OyArPGJyIC8+Jmd0OyArU0JPTV9HRU5fVkVSU0lPTiA9ICIwLjEuMCI8YnIgLz4mZ3Q7ICs8 YnIgLz4mZ3Q7ICsjIGFkYXB0ZWQgZnJvbSB0aGUgaXNhci1jaXAtY29yZSBpbWFnZV91dWlkLmJi Y2xhc3M8YnIgLz4mZ3Q7ICtkZWYgZ2VuZXJhdGVfZG9jdW1lbnRfdXVpZChkKTo8YnIgLz4mZ3Q7 ICvCoMKgwqAgaW1wb3J0IHV1aWQ8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAgYmFzZV9o YXNoID0gZC5nZXRWYXIoIkJCX1RBU0tIQVNIIik8YnIgLz4mZ3Q7ICvCoMKgwqAgaWYgYmFzZV9o YXNoIGlzIE5vbmU6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgYmIud2Fybigibm8gQkJfVEFT S0hBU0ggYXZhaWxhYmxlLCBTQk9NIFVVSUQgaXMgbm90PGJyIC8+Jmd0OyByZXByb2R1Y2libGUi KTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHJldHVybiB1dWlkLnV1aWQ0KCk8YnIgLz4mZ3Q7 ICvCoMKgwqAgcmV0dXJuIHN0cih1dWlkLlVVSUQoYmFzZV9oYXNoWzozMl0sIHZlcnNpb249NCkp PGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArcHl0aG9uIGRvX2NyZWF0ZV9zYm9tKCkgezxiciAvPiZn dDsgK8KgwqDCoCBpbXBvcnQgc2JvbTxiciAvPiZndDsgKzxiciAvPiZndDsgK8KgwqDCoCBkcGtn X3N0YXR1cyA9IGQuZ2V0VmFyKCJJTUFHRV9ST09URlMiKSArICIvdmFyL2xpYi9kcGtnL3N0YXR1 cyI8YnIgLz4mZ3Q7ICvCoMKgwqAgcGFja2FnZXMgPSBzYm9tLlBhY2thZ2UucGFyc2Vfc3RhdHVz X2ZpbGUoZHBrZ19zdGF0dXMpPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDCoMKgIGlmIG5vdCBk LmdldFZhcigiU0JPTV9ET0NVTUVOVF9VVUlEIik6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAg ZC5zZXRWYXIoIlNCT01fRE9DVU1FTlRfVVVJRCIsIGdlbmVyYXRlX2RvY3VtZW50X3V1aWQoZCkp PGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDCoMKgIHNib21fdHlwZSA9IGQuZ2V0VmFyKCJTQk9N X1RZUEUiKTxiciAvPiZndDsgK8KgwqDCoCBpZiAiY3ljbG9uZWR4IiBpbiBzYm9tX3R5cGU6PGJy IC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgc2JvbS5nZW5lcmF0ZShkLCBwYWNrYWdlcywgc2JvbS5T Qk9NVHlwZS5DeWNsb25lRFgsPGJyIC8+Jmd0OyBkLmdldFZhcigiU0JPTV9ERVBMT1lfQkFTRSIp ICsgIi5jeWNsb25lZHguanNvbiIpPGJyIC8+Jmd0OyArwqDCoMKgIGlmICJzcGR4IiBpbiBzYm9t X3R5cGU6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgc2JvbS5nZW5lcmF0ZShkLCBwYWNrYWdl cywgc2JvbS5TQk9NVHlwZS5TUERYLDxiciAvPiZndDsgZC5nZXRWYXIoIlNCT01fREVQTE9ZX0JB U0UiKSArICIuc3BkeC5qc29uIik8YnIgLz4mZ3Q7ICt9PGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyAr YWRkdGFzayBkb19jcmVhdGVfc2JvbSBhZnRlciBkb19yb290ZnMgYmVmb3JlIGRvX2J1aWxkPGJy IC8+Jmd0OyBkaWZmIC0tZ2l0IGEvbWV0YS9jbGFzc2VzL2ltYWdlLmJiY2xhc3MgYi9tZXRhL2Ns YXNzZXMvaW1hZ2UuYmJjbGFzczxiciAvPiZndDsgaW5kZXggNTZlY2EyMDIuLmU5ZGE2YTYxIDEw MDY0NDxiciAvPiZndDsgLS0tIGEvbWV0YS9jbGFzc2VzL2ltYWdlLmJiY2xhc3M8YnIgLz4mZ3Q7 ICsrKyBiL21ldGEvY2xhc3Nlcy9pbWFnZS5iYmNsYXNzPGJyIC8+Jmd0OyBAQCAtODEsNiArODEs OCBAQCBpbmhlcml0IGltYWdlLXBvc3Rwcm9jLWV4dGVuc2lvbjxiciAvPiZndDsgwqBpbmhlcml0 IGltYWdlLWxvY2FsZXMtZXh0ZW5zaW9uPGJyIC8+Jmd0OyDCoGluaGVyaXQgaW1hZ2UtYWNjb3Vu dC1leHRlbnNpb248YnIgLz4mZ3Q7IMKgPGJyIC8+Jmd0OyAraW5oZXJpdCBjcmVhdGUtc2JvbTxi ciAvPiZndDsgKzxiciAvPiZndDsgwqAjIEV4dHJhIHNwYWNlIGZvciByb290ZnMgaW4gTUI8YnIg Lz4mZ3Q7IMKgUk9PVEZTX0VYVFJBID89ICI2NCI8YnIgLz4mZ3Q7IMKgPGJyIC8+Jmd0OyBkaWZm IC0tZ2l0IGEvbWV0YS9saWIvc2JvbS5weSBiL21ldGEvbGliL3Nib20ucHk8YnIgLz4mZ3Q7IG5l dyBmaWxlIG1vZGUgMTAwNjQ0PGJyIC8+Jmd0OyBpbmRleCAwMDAwMDAwMC4uZDdjNzllNDM8YnIg Lz4mZ3Q7IC0tLSAvZGV2L251bGw8YnIgLz4mZ3Q7ICsrKyBiL21ldGEvbGliL3Nib20ucHk8YnIg Lz4mZ3Q7IEBAIC0wLDAgKzEsNDQ2IEBAPGJyIC8+Jmd0OyArIyBUaGlzIHNvZnR3YXJlIGlzIHBh cnQgb2YgSVNBUi48YnIgLz4mZ3Q7ICsjIENvcHlyaWdodCAoQykgMjAyNSBTaWVtZW5zIEFHPGJy IC8+Jmd0OyArIzxiciAvPiZndDsgKyMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVDxiciAv PiZndDsgKzxiciAvPiZndDsgK2Zyb20gZGF0YWNsYXNzZXMgaW1wb3J0IGRhdGFjbGFzczxiciAv PiZndDsgK2Zyb20gZGF0ZXRpbWUgaW1wb3J0IGRhdGV0aW1lPGJyIC8+Jmd0OyArZnJvbSBlbnVt IGltcG9ydCBFbnVtPGJyIC8+Jmd0OyArZnJvbSB0eXBpbmcgaW1wb3J0IERpY3QsIExpc3QsIFR5 cGU8YnIgLz4mZ3Q7ICtpbXBvcnQganNvbjxiciAvPiZndDsgK2ltcG9ydCByZTxiciAvPiZndDsg K2Zyb20gdXVpZCBpbXBvcnQgdXVpZDQ8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICtpbXBvcnQgc2Jv bV9jZHhfdHlwZXMgYXMgY2R4PGJyIC8+Jmd0OyAraW1wb3J0IHNib21fc3BkeF90eXBlcyBhcyBz cGR4PGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArY2xhc3MgU0JPTVR5cGUoRW51 bSk6PGJyIC8+Jmd0OyArwqDCoMKgIEN5Y2xvbmVEWCA9ICgwLCk8YnIgLz4mZ3Q7ICvCoMKgwqAg U1BEWCA9ICgxLCk8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICtAZGF0YWNsYXNz PGJyIC8+Jmd0OyArY2xhc3MgU291cmNlUGFja2FnZTo8YnIgLz4mZ3Q7ICvCoMKgwqAgbmFtZTog c3RyPGJyIC8+Jmd0OyArwqDCoMKgIHZlcnNpb246IHN0ciB8IE5vbmU8YnIgLz4mZ3Q7ICs8YnIg Lz4mZ3Q7ICvCoMKgwqAgZGVmIHB1cmwoc2VsZik6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAg IiIiUmV0dXJuIHRoZSBQVVJMIG9mIHRoZSBwYWNrYWdlLiIiIjxiciAvPiZndDsgK8KgwqDCoMKg wqDCoMKgIHJldHVybiAicGtnOmRlYi9kZWJpYW4ve31Ae30/YXJjaD1zb3VyY2UiLmZvcm1hdCg8 YSBocmVmPSJodHRwOi8vc2VsZi5uYW1lIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub2ZvbGxvdyI+ c2VsZi5uYW1lPC9hPiw8YnIgLz4mZ3Q7IHNlbGYudmVyc2lvbik8YnIgLz4mZ3Q7ICs8YnIgLz4m Z3Q7ICvCoMKgwqAgZGVmIGJvbV9yZWYoc2VsZiwgc2JvbV90eXBlOiBTQk9NVHlwZSkgLSZndDsg c3RyOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgICIiIlJldHVybiBhIHVuaXF1ZSBCT00gcmVm ZXJlbmNlLiIiIjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGlmIHNib21fdHlwZSA9PSBTQk9N VHlwZS5DeWNsb25lRFg6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1cm4g Y2R4LkNEWFJFRl9QUkVGSVggKyAie30tc3JjIi5mb3JtYXQoPGEgaHJlZj0iaHR0cDovL3NlbGYu bmFtZSIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9mb2xsb3ciPnNlbGYubmFtZTwvYT4pPGJyIC8+ Jmd0OyArwqDCoMKgwqDCoMKgwqAgZWxpZiBzYm9tX3R5cGUgPT0gU0JPTVR5cGUuU1BEWDo8YnIg Lz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiBzcGR4LlNQRFhfUkVGX1BSRUZJ WCArICJ7fS1zcmMiLmZvcm1hdCg8YSBocmVmPSJodHRwOi8vc2VsZi5uYW1lIiB0YXJnZXQ9Il9i bGFuayIgcmVsPSJub2ZvbGxvdyI+c2VsZi5uYW1lPC9hPik8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7 ICvCoMKgwqAgZGVmIHBhcnNlKHM6IHN0cikgLSZndDsgVHlwZVsiU291cmNlUGFja2FnZSJdOjxi ciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHNwbGl0ID0gcy5zcGxpdCgiICIpPGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqAgbmFtZSA9IHNwbGl0WzBdPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAg dHJ5OjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdmVyc2lvbiA9ICIgIi5qb2lu KHNwbGl0WzE6XSkuc3RyaXAoIigpIik8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBleGNlcHQg SW5kZXhFcnJvcjo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHZlcnNpb24gPSBO b25lPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgcmV0dXJuIFNvdXJjZVBh Y2thZ2UobmFtZT1uYW1lLCB2ZXJzaW9uPXZlcnNpb24pPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyAr PGJyIC8+Jmd0OyArQGRhdGFjbGFzczxiciAvPiZndDsgK2NsYXNzIERlcGVuZGVuY3k6PGJyIC8+ Jmd0OyArwqDCoMKgIG5hbWU6IHN0cjxiciAvPiZndDsgK8KgwqDCoCB2ZXJzaW9uOiBzdHIgfCBO b25lPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDCoMKgIGRlZiBib21fcmVmKHNlbGYsIHNib21f dHlwZTogU0JPTVR5cGUpIC0mZ3Q7IHN0cjo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCAiIiJS ZXR1cm4gYSB1bmlxdWUgQk9NIHJlZmVyZW5jZS4iIiI8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDC oCBpZiBzYm9tX3R5cGUgPT0gU0JPTVR5cGUuQ3ljbG9uZURYOjxiciAvPiZndDsgK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqAgcmV0dXJuIGNkeC5DRFhfUkVGX1BSRUZJWCArICJ7fSIuZm9ybWF0KDxh IGhyZWY9Imh0dHA6Ly9zZWxmLm5hbWUiIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vZm9sbG93Ij5z ZWxmLm5hbWU8L2E+KTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGVsaWYgc2JvbV90eXBlID09 IFNCT01UeXBlLlNQRFg6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1cm4g c3BkeC5TUERYX1JFRl9QUkVGSVggKyAie30iLmZvcm1hdCg8YSBocmVmPSJodHRwOi8vc2VsZi5u YW1lIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub2ZvbGxvdyI+c2VsZi5uYW1lPC9hPik8YnIgLz4m Z3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAgZGVmIHBhcnNlX211bHRpcGxlKHM6IHN0cikgLSZndDsg TGlzdFtUeXBlWyJEZXBlbmRlbmN5Il1dOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgICIiIlBh cnNlIGEgJ0RlcGVuZHMnIGxpbmUgaW4gdGhlIGRwa2cgc3RhdHVzIGZpbGUuIiIiPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqAgZGVwZW5kZW5jaWVzID0gW108YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoCBmb3IgZW50cnkgaW4gcy5zcGxpdCgiLCIpOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqAgZW50cnkgPSBlbnRyeS5zdHJpcCgpPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBmb3IgZW50cnkgaW4gZW50cnkuc3BsaXQoInwiKTo8YnIgLz4mZ3Q7ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3BsaXQgPSBlbnRyeS5zcGxpdCgiKCIpPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIG5hbWUgPSBzcGxpdFswXS5zdHJpcCgp PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHRyeTo8YnIgLz4mZ3Q7 ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB2ZXJzaW9uID0gc3BsaXRb MV0uc3RyaXAoIikiKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBl eGNlcHQgSW5kZXhFcnJvcjo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCB2ZXJzaW9uID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBkZXBlbmRlbmNpZXMuYXBwZW5kKERlcGVuZGVuY3kobmFtZT1uYW1lLDxiciAv PiZndDsgdmVyc2lvbj12ZXJzaW9uKSk8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoCByZXR1cm4gZGVwZW5kZW5jaWVzPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0 OyArQGRhdGFjbGFzczxiciAvPiZndDsgK2NsYXNzIFBhY2thZ2U6PGJyIC8+Jmd0OyArwqDCoMKg ICIiIkluY29tcGxldGUgcmVwcmVzZW50YXRpb24gb2YgYSBkZWJpYW4gcGFja2FnZS4iIiI8YnIg Lz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAgbmFtZTogc3RyPGJyIC8+Jmd0OyArwqDCoMKgIHNl Y3Rpb246IHN0cjxiciAvPiZndDsgK8KgwqDCoCBtYWludGFpbmVyOiBzdHI8YnIgLz4mZ3Q7ICvC oMKgwqAgYXJjaGl0ZWN0dXJlOiBzdHI8YnIgLz4mZ3Q7ICvCoMKgwqAgc291cmNlOiBTb3VyY2VQ YWNrYWdlPGJyIC8+Jmd0OyArwqDCoMKgIHZlcnNpb246IHN0cjxiciAvPiZndDsgK8KgwqDCoCBk ZXBlbmRzOiBMaXN0W0RlcGVuZGVuY3ldPGJyIC8+Jmd0OyArwqDCoMKgIGRlc2NyaXB0aW9uOiBz dHI8YnIgLz4mZ3Q7ICvCoMKgwqAgaG9tZXBhZ2U6IHN0cjxiciAvPiZndDsgKzxiciAvPiZndDsg K8KgwqDCoCBkZWYgcHVybChzZWxmKSAtJmd0OyBzdHI6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKg wqAgIiIiUmV0dXJuIHRoZSBQVVJMIG9mIHRoZSBwYWNrYWdlLiIiIjxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgIHB1cmwgPSAicGtnOmRlYi9kZWJpYW4ve31Ae30iLmZvcm1hdCg8YSBocmVmPSJo dHRwOi8vc2VsZi5uYW1lIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub2ZvbGxvdyI+c2VsZi5uYW1l PC9hPiw8YnIgLz4mZ3Q7IHNlbGYudmVyc2lvbik8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBp ZiBzZWxmLmFyY2hpdGVjdHVyZTo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHB1 cmwgPSBwdXJsICsgIj9hcmNoPXt9Ii5mb3JtYXQoc2VsZi5hcmNoaXRlY3R1cmUpPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqAgcmV0dXJuIHB1cmw8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKg wqAgZGVmIGJvbV9yZWYoc2VsZiwgc2JvbV90eXBlOiBTQk9NVHlwZSkgLSZndDsgc3RyOjxiciAv PiZndDsgK8KgwqDCoMKgwqDCoMKgICIiIlJldHVybiBhIHVuaXF1ZSBCT00gcmVmZXJlbmNlLiIi IjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGlmIHNib21fdHlwZSA9PSBTQk9NVHlwZS5DeWNs b25lRFg6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1cm4gY2R4LkNEWF9S RUZfUFJFRklYICsgPGEgaHJlZj0iaHR0cDovL3NlbGYubmFtZSIgdGFyZ2V0PSJfYmxhbmsiIHJl bD0ibm9mb2xsb3ciPnNlbGYubmFtZTwvYT48YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBlbGlm IHNib21fdHlwZSA9PSBTQk9NVHlwZS5TUERYOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqAgcmV0dXJuIHNwZHguU1BEWF9SRUZfUFJFRklYICsgPGEgaHJlZj0iaHR0cDovL3NlbGYu bmFtZSIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9mb2xsb3ciPnNlbGYubmFtZTwvYT48YnIgLz4m Z3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAgZGVmIHBhcnNlX3N0YXR1c19maWxlKHN0YXR1c19maWxl OiBzdHIpIC0mZ3Q7PGJyIC8+Jmd0OyBMaXN0W1R5cGVbIlBhY2thZ2UiXV06PGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqAgIiIiUGFyc2UgYSBkcGtnIHN0YXR1cyBmaWxlLiIiIjxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgIHBhY2thZ2VzID0gW108YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCB3 aXRoIG9wZW4oc3RhdHVzX2ZpbGUsICJyIikgYXMgZjo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIG5hbWUgPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBz ZWN0aW9uID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbWFpbnRhaW5l ciA9IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGFyY2hpdGVjdHVyZSA9 IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNvdXJjZSA9IE5vbmU8YnIg Lz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHZlcnNpb24gPSBOb25lPGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXBlbmRlbmNpZXMgPSBOb25lPGJyIC8+Jmd0OyArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBkZXNjcmlwdGlvbiA9IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGhvbWVwYWdlID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqAgZm9yIGxpbmUgaW4gZi5yZWFkbGluZXMoKTo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgbGluZS5zdHJpcCgpOjxiciAvPiZndDsgK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmIGxpbmVbMF0gPT0gIiAiOjxiciAvPiZn dDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgIyB0aGlz IGlzIGEgZGVzY3JpcHRpb24gbGluZSwgd2UgaWdub3JlIGl0PGJyIC8+Jmd0OyArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjb250aW51ZTxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVsc2U6PGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzcGxpdCA9IGxp bmUuc3BsaXQoIjoiKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAga2V5ID0gc3BsaXRbMF08YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHZhbHVlID0gIjoiLmpvaW4oc3BsaXRbMTpd KS5zdHJpcCgpPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBpZiBrZXkgPT0gIlBhY2thZ2UiOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBuYW1lID0gdmFsdWU8YnIg Lz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVs aWYga2V5ID09ICJTZWN0aW9uIjo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc2VjdGlvbiA9IHZhbHVlPGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlbGlmIGtleSA9 PSAiTWFpbnRhaW5lciI6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIG1haW50YWluZXIgPSB2YWx1ZTxiciAvPiZndDsgK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZWxpZiBrZXkgPT0g IkFyY2hpdGVjdHVyZSI6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGFyY2hpdGVjdHVyZSA9IHZhbHVlPGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlbGlmIGtleSA9 PSAiU291cmNlIjo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgc291cmNlID0gU291cmNlUGFja2FnZS5wYXJzZSh2YWx1ZSk8 YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IGVsaWYga2V5ID09ICJWZXJzaW9uIjo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdmVyc2lvbiA9IHZhbHVlPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlbGlmIGtl eSA9PSAiRGVwZW5kcyI6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRlcGVuZGVuY2llcyA9PGJyIC8+Jmd0OyBEZXBlbmRl bmN5LnBhcnNlX211bHRpcGxlKHZhbHVlKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZWxpZiBrZXkgPT0gIkRlc2NyaXB0aW9uIjo8YnIg Lz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgZGVzY3JpcHRpb24gPSB2YWx1ZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZWxpZiBrZXkgPT0gIkhvbWVwYWdlIjo8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgaG9tZXBhZ2UgPSB2YWx1ZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBlbHNlOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgICMgZml4dXAgc291cmNlIHZlcnNpb24sIGlmIG5vdCBzcGVjaWZpZWQgaXQgaXM8YnIgLz4m Z3Q7IHRoZSBzYW1lPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgIyBhcyB0aGUgcGFja2FnZSB2ZXJzaW9uPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgc291cmNlIGFuZCBub3Qgc291cmNlLnZlcnNpb246 PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBzb3VyY2UudmVyc2lvbiA9IHZlcnNpb248YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCAjIGVtcHR5IGxpbmUgbWVhbnMgbmV3IHBhY2thZ2UsIHNvIGZp bmlzaCB0aGU8YnIgLz4mZ3Q7IGN1cnJlbnQgb25lPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcGFja2FnZXMuYXBwZW5kKDxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgUGFja2FnZSg8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgbmFtZT1uYW1lLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzZWN0aW9uPXNlY3Rpb24sPGJyIC8+Jmd0OyArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIG1haW50YWlu ZXI9bWFpbnRhaW5lciw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgYXJjaGl0ZWN0dXJlPWFyY2hpdGVjdHVyZSw8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgc291cmNlPXNvdXJjZSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdmVyc2lvbj12ZXJzaW9uLDxiciAvPiZndDsgK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXBl bmRzPWRlcGVuZGVuY2llcyw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGVzY3JpcHRpb249ZGVzY3JpcHRpb24sPGJyIC8+ Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIGhvbWVwYWdlPWhvbWVwYWdlLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgICk8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBuYW1lID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIHNlY3Rpb24gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbWFpbnRhaW5lciA9IE5vbmU8YnIgLz4mZ3Q7ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBhcmNoaXRlY3R1cmUgPSBOb25l PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc291cmNl ID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IHZlcnNpb24gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgZGVwZW5kZW5jaWVzID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRlc2NyaXB0aW9uID0gTm9uZTxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGhvbWVwYWdlID0gTm9uZTxiciAvPiZn dDsgKzxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHJldHVybiBwYWNrYWdlczxiciAvPiZndDsg KzxiciAvPiZndDsgKzxiciAvPiZndDsgK2RlZiBjeWNsb25lZHhfYm9tKGQsIHBhY2thZ2VzOiBM aXN0W1BhY2thZ2VdKSAtJmd0OyBEaWN0OjxiciAvPiZndDsgK8KgwqDCoCAiIiJSZXR1cm4gYSB2 YWxpZCBDeWNsb25lRFggU0JPTS4iIiI8YnIgLz4mZ3Q7ICvCoMKgwqAgZGF0YSA9IFtdPGJyIC8+ Jmd0OyArwqDCoMKgIGRlcGVuZGVuY2llcyA9IFtdPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDC oMKgIHBhdHRlcm4gPTxiciAvPiZndDsgcmUuY29tcGlsZSgiKD9QJmx0O3N1cHBsaWVyX25hbWUm Z3Q7XlteJmx0O10qKShcXCZsdDsoP1AmbHQ7c3VwcGxpZXJfZW1haWwmZ3Q7LiopXFwmZ3Q7KT8i PGJyIC8+Jmd0OyApPGJyIC8+Jmd0OyArwqDCoMKgIGZvciBwYWNrYWdlIGluIHBhY2thZ2VzOjxi ciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIG1hdGNoID0gcGF0dGVybi5tYXRjaChwYWNrYWdlLm1h aW50YWluZXIpPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgc3VwcGxpZXIgPSBjZHguQ0RYU3Vw cGxpZXIobmFtZT1tYXRjaFsic3VwcGxpZXJfbmFtZSJdKTxiciAvPiZndDsgK8KgwqDCoMKgwqDC oMKgIHN1cHBsaWVyX2VtYWlsID0gbWF0Y2hbInN1cHBsaWVyX2VtYWlsIl08YnIgLz4mZ3Q7ICvC oMKgwqDCoMKgwqDCoCBpZiBzdXBwbGllcl9lbWFpbDo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIHN1cHBsaWVyLmNvbnRhY3QgPTxiciAvPiZndDsgW2NkeC5DRFhTdXBwbGllckNv bnRhY3QoZW1haWw9c3VwcGxpZXJfZW1haWwpXTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGVu dHJ5ID0gY2R4LkNEWENvbXBvbmVudCg8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IHR5cGU9Y2R4LkNEWF9DT01QT05FTlRfVFlQRV9MSUJSQVJZLDxiciAvPiZndDsgK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqAgYm9tX3JlZj1wYWNrYWdlLmJvbV9yZWYoU0JPTVR5cGUuQ3ljbG9uZURY KSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN1cHBsaWVyPXN1cHBsaWVyLDxi ciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbmFtZT08YSBocmVmPSJodHRwOi8vcGFj a2FnZS5uYW1lIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub2ZvbGxvdyI+cGFja2FnZS5uYW1lPC9h Piw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHZlcnNpb249cGFja2FnZS52ZXJz aW9uLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGVzY3JpcHRpb249cGFja2Fn ZS5kZXNjcmlwdGlvbiw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHB1cmw9cGFj a2FnZS5wdXJsKCksPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgKTxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgIGlmIHBhY2thZ2UuaG9tZXBhZ2U6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBlbnRyeS5leHRlcm5hbFJlZmVyZW5jZXMgPSAoPGJyIC8+Jmd0OyArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNkeC5DRFhFeHRlcm5hbFJlZmVyZW5jZSg8YnIgLz4mZ3Q7 ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB1cmw9cGFja2FnZS5ob21l cGFnZSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB0 eXBlPWNkeC5DRFhfUEFDS0FHRV9FWFRSRUZfVFlQRV9XRUJTSVRFLDxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNvbW1lbnQ9ImhvbWVwYWdlIiw8YnIg Lz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKSw8YnIgLz4mZ3Q7ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgICk8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBkYXRhLmFwcGVu ZChlbnRyeSk8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAgZGlzdHJvX2JvbV9yZWYgPSBj ZHguQ0RYX1JFRl9QUkVGSVggKzxiciAvPiZndDsgZC5nZXRWYXIoIlNCT01fRElTVFJPX05BTUUi KTxiciAvPiZndDsgK8KgwqDCoCBkaXN0cm9fZGVwZW5kZW5jaWVzID0gW108YnIgLz4mZ3Q7ICvC oMKgwqAgIyBhZnRlciB3ZSBoYXZlIGZvdW5kIGFsbCBwYWNrYWdlcyB3ZSBjYW4gc3RhcnQgdG8g cmVzb2x2ZTxiciAvPiZndDsgZGVwZW5kZW5jaWVzPGJyIC8+Jmd0OyArwqDCoMKgIHBhY2thZ2Vf bmFtZXMgPSBbPGEgaHJlZj0iaHR0cDovL3BhY2thZ2UubmFtZSIgdGFyZ2V0PSJfYmxhbmsiIHJl bD0ibm9mb2xsb3ciPnBhY2thZ2UubmFtZTwvYT4gZm9yIHBhY2thZ2UgaW4gcGFja2FnZXNdPGJy IC8+Jmd0OyArwqDCoMKgIGZvciBwYWNrYWdlIGluIHBhY2thZ2VzOjxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgPGJyIC8+Jmd0OyBkaXN0cm9fZGVwZW5kZW5jaWVzLmFwcGVuZChwYWNrYWdlLmJv bV9yZWYoU0JPTVR5cGUuQ3ljbG9uZURYKSk8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBpZiBw YWNrYWdlLmRlcGVuZHM6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXBzID0g W108YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGZvciBkZXAgaW4gcGFja2FnZS5k ZXBlbmRzOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXBfYm9t X3JlZiA9IGRlcC5ib21fcmVmKFNCT01UeXBlLkN5Y2xvbmVEWCk8YnIgLz4mZ3Q7ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgIyBpdCBpcyBwb3NzaWJlIHRvIHNwZWNpZnkgdGhlIHNh bWUgcGFja2FnZSBtdWx0aXBsZTxiciAvPiZndDsgdGltZXMsIGJ1dDxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAjIGluIGRpZmZlcmVudCB2ZXJzaW9uczxiciAvPiZn dDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiA8YSBocmVmPSJodHRwOi8vZGVw Lm5hbWUiIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vZm9sbG93Ij5kZXAubmFtZTwvYT4gaW4gcGFj a2FnZV9uYW1lcyBhbmQgZGVwX2JvbV9yZWYgbm90IGluPGJyIC8+Jmd0OyBkZXBzOjxiciAvPiZn dDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRlcHMuYXBwZW5kKGRl cF9ib21fcmVmKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlbHNl OjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICMgdGhp cyBtaWdodCBoYXBwZW4gaWYgd2UgaGF2ZSBvcHRpb25hbDxiciAvPiZndDsgZGVwZW5kZW5jaWVz PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY29udGlu dWU8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRlcGVuZGVuY3kgPSBjZHguQ0RY RGVwZW5kZW5jeSg8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmVm PXBhY2thZ2UuYm9tX3JlZihTQk9NVHlwZS5DeWNsb25lRFgpLDxiciAvPiZndDsgK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXBlbmRzT249ZGVwcyw8YnIgLz4mZ3Q7ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgICk8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRlcGVu ZGVuY2llcy5hcHBlbmQoZGVwZW5kZW5jeSk8YnIgLz4mZ3Q7ICvCoMKgwqAgZGVwZW5kZW5jeSA9 IGNkeC5DRFhEZXBlbmRlbmN5KDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHJlZj1kaXN0cm9f Ym9tX3JlZiw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBkZXBlbmRzT249ZGlzdHJvX2RlcGVu ZGVuY2llcyw8YnIgLz4mZ3Q7ICvCoMKgwqAgKTxiciAvPiZndDsgK8KgwqDCoCBkZXBlbmRlbmNp ZXMuYXBwZW5kKGRlcGVuZGVuY3kpPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDCoMKgIGRvY191 dWlkID0gZC5nZXRWYXIoIlNCT01fRE9DVU1FTlRfVVVJRCIpPGJyIC8+Jmd0OyArwqDCoMKgIGRp c3Ryb19jb21wb25lbnQgPSBjZHguQ0RYQ29tcG9uZW50KDxiciAvPiZndDsgK8KgwqDCoMKgwqDC oMKgIHR5cGU9Y2R4LkNEWF9DT01QT05FTlRfVFlQRV9PUyw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoCBib21fcmVmPWNkeC5DRFhfUkVGX1BSRUZJWCArIGQuZ2V0VmFyKCJTQk9NX0RJU1RST19O QU1FIiksPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqA8YnIgLz4mZ3Q7IHN1cHBsaWVyPWNkeC5D RFhTdXBwbGllcihuYW1lPWQuZ2V0VmFyKCJTQk9NX0RJU1RST19TVVBQTElFUiIpKSw8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoCBuYW1lPWQuZ2V0VmFyKCJTQk9NX0RJU1RST19OQU1FIiksPGJy IC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgdmVyc2lvbj1kLmdldFZhcigiU0JPTV9ESVNUUk9fVkVS U0lPTiIpLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGRlc2NyaXB0aW9uPWQuZ2V0VmFyKCJT Qk9NX0RJU1RST19TVU1NQVJZIiksPGJyIC8+Jmd0OyArwqDCoMKgICk8YnIgLz4mZ3Q7ICs8YnIg Lz4mZ3Q7ICvCoMKgwqAgdGltZXN0YW1wID08YnIgLz4mZ3Q7IGRhdGV0aW1lLmZyb210aW1lc3Rh bXAoaW50KGQuZ2V0VmFyKCJTT1VSQ0VfREFURV9FUE9DSCIpKSk8YnIgLz4mZ3Q7ICvCoMKgwqAg Ym9tID0gY2R4LkNEWEJPTSg8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBib21Gb3JtYXQ9Y2R4 LkNEWF9CT01fRk9STUFULDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHNwZWNWZXJzaW9uPWNk eC5DRFhfU1BFQ19WRVJTSU9OLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHNlcmlhbE51bWJl cj0idXJuOnV1aWQ6e30iLmZvcm1hdChkb2NfdXVpZCBpZiBkb2NfdXVpZCBlbHNlPGJyIC8+Jmd0 OyB1dWlkNCgpKSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCB2ZXJzaW9uPTEsPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqAgbWV0YWRhdGE9Y2R4LkNEWEJPTU1ldGFkYXRhKDxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdGltZXN0YW1wPXRpbWVzdGFtcC5zdHJmdGltZSgiJVkt JW0tJWRUJUg6JU06JVNaIiksPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjb21w b25lbnQ9ZGlzdHJvX2NvbXBvbmVudCw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IHRvb2xzPWNkeC5DRFhCT01NZXRhZGF0YVRvb2woPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGNvbXBvbmVudHM9WzxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNkeC5DRFhDb21wb25lbnQoPGJyIC8+Jmd0OyArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB0eXBlPWNkeC5DRFhfQ09N UE9ORU5UX1RZUEVfQVBQTElDQVRJT04sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBuYW1lPSJJU0FSIFNCT00gR2VuZXJhdG9yIiw8YnIg Lz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHZl cnNpb249ZC5nZXRWYXIoIlNCT01fR0VOX1ZFUlNJT04iKSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCApPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIF0sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCApLDxi ciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgICksPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgY29t cG9uZW50cz1kYXRhLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGRlcGVuZGVuY2llcz1kZXBl bmRlbmNpZXMsPGJyIC8+Jmd0OyArwqDCoMKgICk8YnIgLz4mZ3Q7ICvCoMKgwqAgcmV0dXJuIGJv bTxiciAvPiZndDsgKzxiciAvPiZndDsgKzxiciAvPiZndDsgK2RlZiBzcGR4X2JvbShkLCBwYWNr YWdlczogTGlzdFtQYWNrYWdlXSkgLSZndDsgRGljdDo8YnIgLz4mZ3Q7ICvCoMKgwqAgIlJldHVy biBhIHZhbGlkIFNQRFggU0JPTS4iPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDCoMKgIGRhdGEg PSBbXTxiciAvPiZndDsgK8KgwqDCoCAjIGNyZWF0ZSBhICJmYWtlIsKgIGVudHJ5IGZvciB0aGUg ZGlzdHJpYnV0aW9uPGJyIC8+Jmd0OyArwqDCoMKgIGRpc3Ryb19yZWYgPSBzcGR4LlNQRFhfUkVG X1BSRUZJWCArIGQuZ2V0VmFyKCJTQk9NX0RJU1RST19OQU1FIik8YnIgLz4mZ3Q7ICvCoMKgwqAg ZGlzdHJvX3BhY2thZ2UgPSBzcGR4LlNQRFhQYWNrYWdlKDxiciAvPiZndDsgK8KgwqDCoMKgwqDC oMKgIFNQRFhJRD1kaXN0cm9fcmVmLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIG5hbWU9ZC5n ZXRWYXIoIlNCT01fRElTVFJPX05BTUUiKSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCB2ZXJz aW9uSW5mbz1kLmdldFZhcigiU0JPTV9ESVNUUk9fVkVSU0lPTiIpLDxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgIHByaW1hcnlQYWNrYWdlUHVycG9zZT1zcGR4LlNQRFhfUEFDS0FHRV9QVVJQT1NF X09TLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHN1cHBsaWVyPSJPcmdhbml6YXRpb246PGJy IC8+Jmd0OyB7fSIuZm9ybWF0KGQuZ2V0VmFyKCJTQk9NX0RJU1RST19TVVBQTElFUiIpKSw8YnIg Lz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBkb3dubG9hZExvY2F0aW9uPXNwZHguU1BEWF9OT0FTU0VS VElPTiw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBmaWxlc0FuYWx5emVkPUZhbHNlLDxiciAv PiZndDsgK8KgwqDCoMKgwqDCoMKgIGxpY2Vuc2VDb25jbHVkZWQ9c3BkeC5TUERYX05PQVNTRVJU SU9OLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGxpY2Vuc2VEZWNsYXJlZD1zcGR4LlNQRFhf Tk9BU1NFUlRJT04sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgY29weXJpZ2h0VGV4dD1zcGR4 LlNQRFhfTk9BU1NFUlRJT04sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgc3VtbWFyeT1kLmdl dFZhcigiU0JPTV9ESVNUUk9fU1VNTUFSWSIpLDxiciAvPiZndDsgK8KgwqDCoCApPGJyIC8+Jmd0 OyArPGJyIC8+Jmd0OyArwqDCoMKgIGRhdGEuYXBwZW5kKGRpc3Ryb19wYWNrYWdlKTxiciAvPiZn dDsgKzxiciAvPiZndDsgK8KgwqDCoCBwYXR0ZXJuID08YnIgLz4mZ3Q7IHJlLmNvbXBpbGUoIig/ UCZsdDtzdXBwbGllcl9uYW1lJmd0O15bXiZsdDtdKikoXFwmbHQ7KD9QJmx0O3N1cHBsaWVyX2Vt YWlsJmd0Oy4qKVxcJmd0Oyk/IjxiciAvPiZndDsgKTxiciAvPiZndDsgK8KgwqDCoCBmb3IgcGFj a2FnZSBpbiBwYWNrYWdlczo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBtYXRjaCA9IHBhdHRl cm4ubWF0Y2gocGFja2FnZS5tYWludGFpbmVyKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHN1 cHBsaWVyX25hbWUgPSBtYXRjaFsic3VwcGxpZXJfbmFtZSJdPGJyIC8+Jmd0OyArwqDCoMKgwqDC oMKgwqAgc3VwcGxpZXJfZW1haWwgPSBtYXRjaFsic3VwcGxpZXJfZW1haWwiXTxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgIGlmIGFueShbY3VlIGluIHN1cHBsaWVyX25hbWUubG93ZXIoKSBmb3Ig Y3VlIGluPGJyIC8+Jmd0OyBzcGR4LlNQRFhfU1VQUExJRVJfT1JHX0NVRV0pOjxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3VwcGxpZXIgPSAiT3JnYW5pemF0aW9uOiB7fSIuZm9y bWF0KHN1cHBsaWVyX25hbWUpPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgZWxzZTo8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN1cHBsaWVyID0gIlBlcnNvbjoge30iLmZvcm1h dChzdXBwbGllcl9uYW1lKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGlmIHN1cHBsaWVyX2Vt YWlsOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3VwcGxpZXIgKz0gIih7fSki LmZvcm1hdChzdXBwbGllcl9lbWFpbCk8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoCBlbnRyeSA9IHNwZHguU1BEWFBhY2thZ2UoPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBTUERYSUQ9cGFja2FnZS5ib21fcmVmKFNCT01UeXBlLlNQRFgpLDxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbmFtZT08YSBocmVmPSJodHRwOi8vcGFja2FnZS5uYW1l IiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub2ZvbGxvdyI+cGFja2FnZS5uYW1lPC9hPiw8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHZlcnNpb25JbmZvPXBhY2thZ2UudmVyc2lvbiw8 YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHByaW1hcnlQYWNrYWdlUHVycG9zZT1z cGR4LlNQRFhfUEFDS0FHRV9QVVJQT1NFX0xJQlJBUlksPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBzdXBwbGllcj1zdXBwbGllciw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGRvd25sb2FkTG9jYXRpb249c3BkeC5TUERYX05PQVNTRVJUSU9OLDxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZmlsZXNBbmFseXplZD1GYWxzZSw8YnIgLz4mZ3Q7ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgICMgVE9ETzogaXQgc2hvdWxkIGJlIHBvc3NpYmxlIHRvIGNv bmNsdWRlPGJyIC8+Jmd0OyBsaWNlbnNlL2NvcHlyaWdodDxiciAvPiZndDsgK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqAgIyBpbmZvcm1hdGlvbiwgd2UgY291bGQgbG9vayBlLmcuIGluPGJyIC8+Jmd0 OyAvdXNyL3NoYXJlL2RvYy8qL2NvcHlyaWdodDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqAgbGljZW5zZUNvbmNsdWRlZD1zcGR4LlNQRFhfTk9BU1NFUlRJT04sPGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBsaWNlbnNlRGVjbGFyZWQ9c3BkeC5TUERYX05PQVNTRVJU SU9OLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY29weXJpZ2h0VGV4dD1zcGR4 LlNQRFhfTk9BU1NFUlRJT04sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdW1t YXJ5PXBhY2thZ2UuZGVzY3JpcHRpb24sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBleHRlcm5hbFJlZnM9WzxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBzcGR4LlNQRFhFeHRlcm5hbFJlZig8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoDxiciAvPiZndDsgcmVmZXJlbmNlQ2F0ZWdvcnk9c3BkeC5TUERYX1JF RkVSRU5DRV9DQVRFR09SWV9QS0dfTUFOQUdFUiw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZWZlcmVuY2VUeXBlPXNwZHguU1BEWF9SRUZFUkVOQ0Vf VFlQRV9QVVJMLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIHJlZmVyZW5jZUxvY2F0b3I9cGFja2FnZS5wdXJsKCksPGJyIC8+Jmd0OyArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgICk8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IF0sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgKTxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKg IGlmIHBhY2thZ2UuaG9tZXBhZ2U6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBl bnRyeS5ob21lcGFnZSA9IHBhY2thZ2UuaG9tZXBhZ2U8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDC oCBkYXRhLmFwcGVuZChlbnRyeSk8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDC oCBpZiBwYWNrYWdlLnNvdXJjZTo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNy Y19lbnRyeSA9IHNwZHguU1BEWFBhY2thZ2UoPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIFNQRFhJRD1wYWNrYWdlLnNvdXJjZS5ib21fcmVmKFNCT01UeXBlLlNQRFgp LDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBuYW1lPTxhIGhyZWY9 Imh0dHA6Ly9wYWNrYWdlLnNvdXJjZS5uYW1lIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub2ZvbGxv dyI+cGFja2FnZS5zb3VyY2UubmFtZTwvYT4sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIHZlcnNpb25JbmZvPXBhY2thZ2Uuc291cmNlLnZlcnNpb24sPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHByaW1hcnlQYWNrYWdlUHVycG9zZT1z cGR4LlNQRFhfUEFDS0FHRV9QVVJQT1NFX1NSQyw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgc3VwcGxpZXI9c3VwcGxpZXIsPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIGRvd25sb2FkTG9jYXRpb249c3BkeC5TUERYX05PQVNTRVJUSU9O LDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBmaWxlc0FuYWx5emVk PUZhbHNlLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBsaWNlbnNl Q29uY2x1ZGVkPXNwZHguU1BEWF9OT0FTU0VSVElPTiw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgbGljZW5zZURlY2xhcmVkPXNwZHguU1BEWF9OT0FTU0VSVElPTiw8 YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY29weXJpZ2h0VGV4dD1z cGR4LlNQRFhfTk9BU1NFUlRJT04sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHN1bW1hcnk9ImRlYmlhbiBzb3VyY2UgY29kZSBwYWNrYWdlPGJyIC8+Jmd0OyAne30n Ii5mb3JtYXQoPGEgaHJlZj0iaHR0cDovL3BhY2thZ2Uuc291cmNlLm5hbWUiIHRhcmdldD0iX2Js YW5rIiByZWw9Im5vZm9sbG93Ij5wYWNrYWdlLnNvdXJjZS5uYW1lPC9hPiksPGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGV4dGVybmFsUmVmcz1bPGJyIC8+Jmd0OyAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3BkeC5TUERYRXh0ZXJuYWxS ZWYoPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoDxiciAvPiZndDsgcmVmZXJlbmNlQ2F0ZWdvcnk9c3BkeC5TUERYX1JFRkVSRU5DRV9DQVRF R09SWV9QS0dfTUFOQUdFUiw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIHJlZmVyZW5jZVR5cGU9c3BkeC5TUERYX1JFRkVSRU5DRV9UWVBF X1BVUkwsPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCByZWZlcmVuY2VMb2NhdG9yPXBhY2thZ2Uuc291cmNlLnB1cmwoKSw8YnIgLz4mZ3Q7 ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCApPGJyIC8+Jmd0OyArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIF0sPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCApPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAjIHNvdXJjZSBwYWNr YWdlcyBtaWdodCBiZSByZWZlcmVuY2VkIG11bHRpcGxlIHRpbWVzPGJyIC8+Jmd0OyArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBpZiBzcmNfZW50cnkgbm90IGluIGRhdGE6PGJyIC8+Jmd0OyArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRhdGEuYXBwZW5kKHNyY19lbnRyeSk8YnIgLz4m Z3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAgcmVsYXRpb25zaGlwcyA9IFtdPGJyIC8+Jmd0OyArwqDC oMKgICMgYWZ0ZXIgd2UgaGF2ZSBmb3VuZCBhbGwgcGFja2FnZXMgd2UgY2FuIHN0YXJ0IHRvIHJl c29sdmU8YnIgLz4mZ3Q7IGRlcGVuZGVuY2llczxiciAvPiZndDsgK8KgwqDCoCBwYWNrYWdlX25h bWVzID0gWzxhIGhyZWY9Imh0dHA6Ly9wYWNrYWdlLm5hbWUiIHRhcmdldD0iX2JsYW5rIiByZWw9 Im5vZm9sbG93Ij5wYWNrYWdlLm5hbWU8L2E+IGZvciBwYWNrYWdlIGluIHBhY2thZ2VzXTxiciAv PiZndDsgK8KgwqDCoCBmb3IgcGFja2FnZSBpbiBwYWNrYWdlczo8YnIgLz4mZ3Q7ICvCoMKgwqDC oMKgwqDCoCByZWxhdGlvbnNoaXBzLmFwcGVuZCg8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHNwZHguU1BEWFJlbGF0aW9uc2hpcCg8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgc3BkeEVsZW1lbnRJZD1wYWNrYWdlLmJvbV9yZWYoU0JPTVR5cGUuU1BE WCksPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJlbGF0ZWRTcGR4 RWxlbWVudD1kaXN0cm9fcmVmLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCByZWxhdGlvbnNoaXBUeXBlPXNwZHguU1BEWF9SRUxBVElPTlNISVBfUEFDS0FHRV9PRiw8 YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICk8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoCApPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgaWYgcGFja2FnZS5kZXBlbmRzOjxiciAv PiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZm9yIGRlcCBpbiBwYWNrYWdlLmRlcGVuZHM6 PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmIDxhIGhyZWY9Imh0 dHA6Ly9kZXAubmFtZSIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9mb2xsb3ciPmRlcC5uYW1lPC9h PiBpbiBwYWNrYWdlX25hbWVzOjxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIHJlbGF0aW9uc2hpcCA9IHNwZHguU1BEWFJlbGF0aW9uc2hpcCg8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgPGJyIC8+ Jmd0OyBzcGR4RWxlbWVudElkPXBhY2thZ2UuYm9tX3JlZihTQk9NVHlwZS5TUERYKSw8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgPGJyIC8+ Jmd0OyByZWxhdGVkU3BkeEVsZW1lbnQ9ZGVwLmJvbV9yZWYoU0JPTVR5cGUuU1BEWCksPGJyIC8+ Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoDxiciAv PiZndDsgcmVsYXRpb25zaGlwVHlwZT1zcGR4LlNQRFhfUkVMQVRJT05TSElQX0RFUEVORFNfT04s PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKTxiciAv PiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJlbGF0aW9uc2hp cHMuYXBwZW5kKHJlbGF0aW9uc2hpcCk8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgZWxzZTo8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCAjIHRoaXMgbWlnaHQgaGFwcGVuIGlmIHdlIGhhdmUgb3B0aW9uYWw8YnIgLz4mZ3Q7 IGRlcGVuZGVuY2llczxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHBhc3M8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBpZiBwYWNrYWdlLnNvdXJjZTo8 YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJlbGF0aW9uc2hpcCA9IHNwZHguU1BE WFJlbGF0aW9uc2hpcCg8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg c3BkeEVsZW1lbnRJZD1wYWNrYWdlLnNvdXJjZS5ib21fcmVmKFNCT01UeXBlLlNQRFgpLDxiciAv PiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZWxhdGVkU3BkeEVsZW1lbnQ9 cGFja2FnZS5ib21fcmVmKFNCT01UeXBlLlNQRFgpLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCByZWxhdGlvbnNoaXBUeXBlPXNwZHguU1BEWF9SRUxBVElPTlNISVBf R0VORVJBVEVTLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKTxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmVsYXRpb25zaGlwcy5hcHBlbmQocmVsYXRpb25zaGlw KTxiciAvPiZndDsgK8KgwqDCoCByZWxhdGlvbnNoaXBzLmFwcGVuZCg8YnIgLz4mZ3Q7ICvCoMKg wqDCoMKgwqDCoCBzcGR4LlNQRFhSZWxhdGlvbnNoaXAoPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBzcGR4RWxlbWVudElkPXNwZHguU1BEWF9SRUZfRE9DVU1FTlQsPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZWxhdGVkU3BkeEVsZW1lbnQ9ZGlzdHJvX3JlZiw8 YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJlbGF0aW9uc2hpcFR5cGU9c3BkeC5T UERYX1JFTEFUSU9OU0hJUF9ERVNDUklCRVMsPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgKTxi ciAvPiZndDsgK8KgwqDCoCApPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArwqDCoMKgIG5hbWVzcGFj ZV91dWlkID0gZC5nZXRWYXIoIlNCT01fRE9DVU1FTlRfVVVJRCIpPGJyIC8+Jmd0OyArwqDCoMKg IHRpbWVzdGFtcCA9PGJyIC8+Jmd0OyBkYXRldGltZS5mcm9tdGltZXN0YW1wKGludChkLmdldFZh cigiU09VUkNFX0RBVEVfRVBPQ0giKSkpPGJyIC8+Jmd0OyArwqDCoMKgIGJvbSA9IHNwZHguU1BE WEJPTSg8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBTUERYSUQ9c3BkeC5TUERYX1JFRl9ET0NV TUVOVCw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBzcGR4VmVyc2lvbj1zcGR4LlNQRFhfVkVS U0lPTiw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoCBjcmVhdGlvbkluZm89c3BkeC5TUERYQ3Jl YXRpb25JbmZvKDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY29tbWVudD0iVGhp cyBkb2N1bWVudCBoYXMgYmVlbiBnZW5lcmF0ZWQgYXMgcGFydCBvZiBhbjxiciAvPiZndDsgSVNB UiBidWlsZC4iLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY3JlYXRvcnM9Wzxi ciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAiVG9vbDogSVNBUiBTQk9N IEdlbmVyYXRvciAtPGJyIC8+Jmd0OyB7fSIuZm9ybWF0KGQuZ2V0VmFyKCJTQk9NX0dFTl9WRVJT SU9OIikpPGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBdLDxiciAvPiZndDsgK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqAgY3JlYXRlZD10aW1lc3RhbXAuc3RyZnRpbWUoIiVZLSVtLSVk VCVIOiVNOiVTWiIpLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgICksPGJyIC8+Jmd0OyArwqDC oMKgwqDCoMKgwqAgbmFtZT1kLmdldFZhcigiU0JPTV9ESVNUUk9fTkFNRSIpLDxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgIGRhdGFMaWNlbnNlPSJDQzAtMS4wIiw8YnIgLz4mZ3Q7ICvCoMKgwqDC oMKgwqDCoCBkb2N1bWVudE5hbWVzcGFjZT0ie30ve30te30iLmZvcm1hdCg8YnIgLz4mZ3Q7ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGQuZ2V0VmFyKCJTQk9NX1NQRFhfTkFNRVNQQUNFX1BSRUZJ WCIpLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZC5nZXRWYXIoIlNCT01fRElT VFJPX05BTUUiKSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIG5hbWVzcGFjZV91 dWlkIGlmIG5hbWVzcGFjZV91dWlkIGVsc2UgdXVpZDQoKSw8YnIgLz4mZ3Q7ICvCoMKgwqDCoMKg wqDCoCApLDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIHBhY2thZ2VzPWRhdGEsPGJyIC8+Jmd0 OyArwqDCoMKgwqDCoMKgwqAgcmVsYXRpb25zaGlwcz1yZWxhdGlvbnNoaXBzLDxiciAvPiZndDsg K8KgwqDCoCApPGJyIC8+Jmd0OyArwqDCoMKgIHJldHVybiBib208YnIgLz4mZ3Q7ICs8YnIgLz4m Z3Q7ICs8YnIgLz4mZ3Q7ICtkZWYgZml4dXBfZGljdChvKTo8YnIgLz4mZ3Q7ICvCoMKgwqAgIiIi QXBwbHkgZml4dXBzIGZvciB0aGUgQk9Ncy48YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAg VGhpcyBpcyBuZWNlc3NhcnkgZm9yIHNvbWUgZmllbGQgbmFtZXMgYW5kIHRvIHJlbW92ZSBmaWVs ZHMgd2l0aDxiciAvPiZndDsgYSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgIHZhbHVlLjxiciAvPiZn dDsgK8KgwqDCoCAiIiI8YnIgLz4mZ3Q7ICvCoMKgwqAgZGN0ID0gdmFycyhvKTxiciAvPiZndDsg K8KgwqDCoCBuZXdfZGN0ID0ge308YnIgLz4mZ3Q7ICvCoMKgwqAgZm9yIGssIHYgaW4gZGN0Lml0 ZW1zKCk6PGJyIC8+Jmd0OyArwqDCoMKgwqDCoMKgwqAgIyByZW1vdmUgZmllbGRzIHdpdGggbm8g Y29udGVudDxiciAvPiZndDsgK8KgwqDCoMKgwqDCoMKgIGlmIHYgaXMgbm90IE5vbmU6PGJyIC8+ Jmd0OyArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAjIHdlIGNhbiBub3QgbmFtZSBvdXIgZmllbGRz IHdpdGggZGFzaGVzLCBzbyBjb252ZXJ0PGJyIC8+Jmd0OyB0aGVtPGJyIC8+Jmd0OyArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBrID0gay5yZXBsYWNlKCJfIiwgIi0iKTxiciAvPiZndDsgK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqAgbmV3X2RjdFtrXSA9IHY8YnIgLz4mZ3Q7ICvCoMKgwqAgcmV0dXJu IG5ld19kY3Q8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICtkZWYgZ2VuZXJhdGUo ZCwgcGFja2FnZXM6IExpc3RbUGFja2FnZV0sIHNib21fdHlwZTogU0JPTVR5cGUsIG91dDo8YnIg Lz4mZ3Q7IHN0cik6PGJyIC8+Jmd0OyArwqDCoMKgICIiIkdlbmVyYXRlIGEgU0JPTS4iIiI8YnIg Lz4mZ3Q7ICvCoMKgwqAgaWYgc2JvbV90eXBlID09IFNCT01UeXBlLkN5Y2xvbmVEWDo8YnIgLz4m Z3Q7ICvCoMKgwqDCoMKgwqDCoCBib20gPSBjeWNsb25lZHhfYm9tKGQsIHBhY2thZ2VzKTxiciAv PiZndDsgK8KgwqDCoCBlbGlmIHNib21fdHlwZSA9PSBTQk9NVHlwZS5TUERYOjxiciAvPiZndDsg K8KgwqDCoMKgwqDCoMKgIGJvbSA9IHNwZHhfYm9tKGQsIHBhY2thZ2VzKTxiciAvPiZndDsgKzxi ciAvPiZndDsgK8KgwqDCoCB3aXRoIG9wZW4ob3V0LCAidyIpIGFzIGJvbV9maWxlOjxiciAvPiZn dDsgK8KgwqDCoMKgwqDCoMKgIGpzb24uZHVtcChib20sIGJvbV9maWxlLCBpbmRlbnQ9MiwgZGVm YXVsdD1maXh1cF9kaWN0LDxiciAvPiZndDsgc29ydF9rZXlzPVRydWUpPGJyIC8+Jmd0OyBkaWZm IC0tZ2l0IGEvbWV0YS9saWIvc2JvbV9jZHhfdHlwZXMucHkgYi9tZXRhL2xpYi9zYm9tX2NkeF90 eXBlcy5weTxiciAvPiZndDsgbmV3IGZpbGUgbW9kZSAxMDA2NDQ8YnIgLz4mZ3Q7IGluZGV4IDAw MDAwMDAwLi40OTExY2MyMzxiciAvPiZndDsgLS0tIC9kZXYvbnVsbDxiciAvPiZndDsgKysrIGIv bWV0YS9saWIvc2JvbV9jZHhfdHlwZXMucHk8YnIgLz4mZ3Q7IEBAIC0wLDAgKzEsODIgQEA8YnIg Lz4mZ3Q7ICsjIFRoaXMgc29mdHdhcmUgaXMgcGFydCBvZiBJU0FSLjxiciAvPiZndDsgKyMgQ29w eXJpZ2h0IChDKSAyMDI1IFNpZW1lbnMgQUc8YnIgLz4mZ3Q7ICsjPGJyIC8+Jmd0OyArIyBTUERY LUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArZnJvbSBkYXRh Y2xhc3NlcyBpbXBvcnQgZGF0YWNsYXNzPGJyIC8+Jmd0OyArZnJvbSB0eXBpbmcgaW1wb3J0IExp c3QsIE9wdGlvbmFsPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArIyBNaW5pbWFsIGltcGxlbWVudGF0 aW9uIG9mIHNvbWUgQ3ljbG9uZURYIFNCT00gdHlwZXMuPGJyIC8+Jmd0OyArIyBQbGVhc2UgbWlu ZCB0aGF0IChhbG1vc3QpIG5vbmUgb2YgdGhlc2UgdHlwZXMgYXJlIGNvbXBsZXRlLCB0aGV5PGJy IC8+Jmd0OyBvbmx5PGJyIC8+Jmd0OyArIyByZWZsZWN0IHdoYXQgd2FzIHN0cmljdGx5IG5lY2Vz c2FyeSBmb3IgaW1tZWRpYXRlIFNCT00gY3JlYXRpb248YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICtD RFhfQk9NX0ZPUk1BVCA9ICJDeWNsb25lRFgiPGJyIC8+Jmd0OyArQ0RYX1NQRUNfVkVSU0lPTiA9 ICIxLjYiPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArQ0RYX1JFRl9QUkVGSVggPSAiQ0RYUmVmLSI8 YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICtDRFhfUEFDS0FHRV9FWFRSRUZfVFlQRV9XRUJTSVRFID0g IndlYnNpdGUiPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArQ0RYX0NPTVBPTkVOVF9UWVBFX0xJQlJB UlkgPSAibGlicmFyeSI8YnIgLz4mZ3Q7ICtDRFhfQ09NUE9ORU5UX1RZUEVfQVBQTElDQVRJT04g PSAiYXBwbGljYXRpb24iPGJyIC8+Jmd0OyArQ0RYX0NPTVBPTkVOVF9UWVBFX09TID0gIm9wZXJh dGluZy1zeXN0ZW0iPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArQGRhdGFjbGFz czxiciAvPiZndDsgK2NsYXNzIENEWERlcGVuZGVuY3k6PGJyIC8+Jmd0OyArwqDCoMKgIHJlZjog c3RyPGJyIC8+Jmd0OyArwqDCoMKgIGRlcGVuZHNPbjogT3B0aW9uYWxbc3RyXTxiciAvPiZndDsg KzxiciAvPiZndDsgKzxiciAvPiZndDsgK0BkYXRhY2xhc3M8YnIgLz4mZ3Q7ICtjbGFzcyBDRFhF eHRlcm5hbFJlZmVyZW5jZTo8YnIgLz4mZ3Q7ICvCoMKgwqAgdXJsOiBzdHI8YnIgLz4mZ3Q7ICvC oMKgwqAgdHlwZTogc3RyPGJyIC8+Jmd0OyArwqDCoMKgIGNvbW1lbnQ6IE9wdGlvbmFsW3N0cl0g PSBOb25lPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArQGRhdGFjbGFzczxiciAv PiZndDsgK2NsYXNzIENEWFN1cHBsaWVyQ29udGFjdDo8YnIgLz4mZ3Q7ICvCoMKgwqAgZW1haWw6 IE9wdGlvbmFsW3N0cl0gPSBOb25lPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyAr QGRhdGFjbGFzczxiciAvPiZndDsgK2NsYXNzIENEWFN1cHBsaWVyOjxiciAvPiZndDsgK8KgwqDC oCBuYW1lOiBPcHRpb25hbFtzdHJdID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoCBjb250YWN0OiBP cHRpb25hbFtDRFhTdXBwbGllckNvbnRhY3RdID0gTm9uZTxiciAvPiZndDsgKzxiciAvPiZndDsg KzxiciAvPiZndDsgK0BkYXRhY2xhc3M8YnIgLz4mZ3Q7ICtjbGFzcyBDRFhDb21wb25lbnQ6PGJy IC8+Jmd0OyArwqDCoMKgIHR5cGU6IHN0cjxiciAvPiZndDsgK8KgwqDCoCBuYW1lOiBzdHI8YnIg Lz4mZ3Q7ICvCoMKgwqAgYm9tX3JlZjogT3B0aW9uYWxbc3RyXSA9IE5vbmU8YnIgLz4mZ3Q7ICvC oMKgwqAgc3VwcGxpZXI6IE9wdGlvbmFsW3N0cl0gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgIHZl cnNpb246IE9wdGlvbmFsW0NEWFN1cHBsaWVyXSA9IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqAgZGVz Y3JpcHRpb246IE9wdGlvbmFsW3N0cl0gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgIHB1cmw6IE9w dGlvbmFsW3N0cl0gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgIGV4dGVybmFsUmVmZXJlbmNlczog T3B0aW9uYWxbTGlzdFtDRFhFeHRlcm5hbFJlZmVyZW5jZV1dID0gTm9uZTxiciAvPiZndDsgK8Kg wqDCoCBob21lcGFnZTogT3B0aW9uYWxbc3RyXSA9IE5vbmU8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7 ICs8YnIgLz4mZ3Q7ICtAZGF0YWNsYXNzPGJyIC8+Jmd0OyArY2xhc3MgQ0RYQk9NTWV0YWRhdGFU b29sOjxiciAvPiZndDsgK8KgwqDCoCBjb21wb25lbnRzOiBPcHRpb25hbFtMaXN0W0NEWENvbXBv bmVudF1dPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArQGRhdGFjbGFzczxiciAv PiZndDsgK2NsYXNzIENEWEJPTU1ldGFkYXRhOjxiciAvPiZndDsgK8KgwqDCoCB0aW1lc3RhbXA6 IE9wdGlvbmFsW3N0cl0gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgIGNvbXBvbmVudDogT3B0aW9u YWxbc3RyXSA9IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqAgdG9vbHM6IE9wdGlvbmFsW0xpc3RbQ0RY Qk9NTWV0YWRhdGFUb29sXV0gPSBOb25lPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0 OyArQGRhdGFjbGFzczxiciAvPiZndDsgK2NsYXNzIENEWEJPTTo8YnIgLz4mZ3Q7ICvCoMKgwqAg Ym9tRm9ybWF0OiBzdHI8YnIgLz4mZ3Q7ICvCoMKgwqAgc3BlY1ZlcnNpb246IHN0cjxiciAvPiZn dDsgK8KgwqDCoCBzZXJpYWxOdW1iZXI6IE9wdGlvbmFsW3N0cl0gPSBOb25lPGJyIC8+Jmd0OyAr wqDCoMKgIHZlcnNpb246IE9wdGlvbmFsW3N0cl0gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKgIG1l dGFkYXRhOiBPcHRpb25hbFtDRFhCT01NZXRhZGF0YV0gPSBOb25lPGJyIC8+Jmd0OyArwqDCoMKg IGNvbXBvbmVudHM6IE9wdGlvbmFsW0xpc3RbQ0RYQ29tcG9uZW50XV0gPSBOb25lPGJyIC8+Jmd0 OyArwqDCoMKgIGRlcGVuZGVuY2llczogT3B0aW9uYWxbTGlzdFtDRFhEZXBlbmRlbmN5XV0gPSBO b25lPGJyIC8+Jmd0OyBkaWZmIC0tZ2l0IGEvbWV0YS9saWIvc2JvbV9zcGR4X3R5cGVzLnB5PGJy IC8+Jmd0OyBiL21ldGEvbGliL3Nib21fc3BkeF90eXBlcy5weTxiciAvPiZndDsgbmV3IGZpbGUg bW9kZSAxMDA2NDQ8YnIgLz4mZ3Q7IGluZGV4IDAwMDAwMDAwLi5lZmQ3Y2MwYzxiciAvPiZndDsg LS0tIC9kZXYvbnVsbDxiciAvPiZndDsgKysrIGIvbWV0YS9saWIvc2JvbV9zcGR4X3R5cGVzLnB5 PGJyIC8+Jmd0OyBAQCAtMCwwICsxLDk1IEBAPGJyIC8+Jmd0OyArIyBUaGlzIHNvZnR3YXJlIGlz IHBhcnQgb2YgSVNBUi48YnIgLz4mZ3Q7ICsjIENvcHlyaWdodCAoQykgMjAyNSBTaWVtZW5zIEFH PGJyIC8+Jmd0OyArIzxiciAvPiZndDsgKyMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVDxi ciAvPiZndDsgKzxiciAvPiZndDsgK2Zyb20gZGF0YWNsYXNzZXMgaW1wb3J0IGRhdGFjbGFzczxi ciAvPiZndDsgK2Zyb20gdHlwaW5nIGltcG9ydCBMaXN0LCBPcHRpb25hbDxiciAvPiZndDsgKzxi ciAvPiZndDsgKyMgTWluaW1hbCBpbXBsZW1lbnRhdGlvbiBvZiBzb21lIFNQRFggU0JPTSB0eXBl cy48YnIgLz4mZ3Q7ICsjIFBsZWFzZSBtaW5kIHRoYXQgKGFsbW9zdCkgbm9uZSBvZiB0aGVzZSB0 eXBlcyBhcmUgY29tcGxldGUsIHRoZXk8YnIgLz4mZ3Q7IG9ubHk8YnIgLz4mZ3Q7ICsjIHJlZmxl Y3Qgd2hhdCB3YXMgc3RyaWN0bHkgbmVjZXNzYXJ5IGZvciBpbW1lZGlhdGUgU0JPTSBjcmVhdGlv bjxiciAvPiZndDsgKzxiciAvPiZndDsgK1NQRFhfVkVSU0lPTiA9ICJTUERYLTIuMyI8YnIgLz4m Z3Q7ICs8YnIgLz4mZ3Q7ICtTUERYX1JFRl9QUkVGSVggPSAiU1BEWFJlZi0iPGJyIC8+Jmd0OyAr PGJyIC8+Jmd0OyArU1BEWF9SRUZfRE9DVU1FTlQgPSAiU1BEWFJlZi1ET0NVTUVOVCI8YnIgLz4m Z3Q7ICs8YnIgLz4mZ3Q7ICtTUERYX1BBQ0tBR0VfUFVSUE9TRV9MSUJSQVJZID0gIkxJQlJBUlki PGJyIC8+Jmd0OyArU1BEWF9QQUNLQUdFX1BVUlBPU0VfT1MgPSAiT1BFUkFUSU5HX1NZU1RFTSI8 YnIgLz4mZ3Q7ICtTUERYX1BBQ0tBR0VfUFVSUE9TRV9TUkMgPSAiU09VUkNFIjxiciAvPiZndDsg KzxiciAvPiZndDsgK1NQRFhfTk9BU1NFUlRJT04gPSAiTk9BU1NFUlRJT04iPGJyIC8+Jmd0OyAr PGJyIC8+Jmd0OyArU1BEWF9SRUxBVElPTlNISVBfREVQRU5EU19PTiA9ICJERVBFTkRTX09OIjxi ciAvPiZndDsgK1NQRFhfUkVMQVRJT05TSElQX1BBQ0tBR0VfT0YgPSAiUEFDS0FHRV9PRiI8YnIg Lz4mZ3Q7ICtTUERYX1JFTEFUSU9OU0hJUF9HRU5FUkFURVMgPSAiR0VORVJBVEVTIjxiciAvPiZn dDsgK1NQRFhfUkVMQVRJT05TSElQX0RFU0NSSUJFUyA9ICJERVNDUklCRVMiPGJyIC8+Jmd0OyAr PGJyIC8+Jmd0OyArU1BEWF9SRUZFUkVOQ0VfQ0FURUdPUllfUEtHX01BTkFHRVIgPSAiUEFDS0FH RV9NQU5BR0VSIjxiciAvPiZndDsgK1NQRFhfUkVGRVJFTkNFX1RZUEVfUFVSTCA9ICJwdXJsIjxi ciAvPiZndDsgKzxiciAvPiZndDsgKyMgY3VlcyBmb3IgYW4gb3JnYW5pemF0aW9uIGluIHRoZSBt YWludGFpbmVyIG5hbWU8YnIgLz4mZ3Q7ICtTUERYX1NVUFBMSUVSX09SR19DVUUgPSBbPGJyIC8+ Jmd0OyArwqDCoMKgICJtYWludGFpbmVycyIsPGJyIC8+Jmd0OyArwqDCoMKgICJncm91cCIsPGJy IC8+Jmd0OyArwqDCoMKgICJkZXZlbG9wZXJzIiw8YnIgLz4mZ3Q7ICvCoMKgwqAgInRlYW0iLDxi ciAvPiZndDsgK8KgwqDCoCAicHJvamVjdCIsPGJyIC8+Jmd0OyArwqDCoMKgICJ0YXNrIGZvcmNl Iiw8YnIgLz4mZ3Q7ICvCoMKgwqAgInN0cmlrZSBmb3JjZSIsPGJyIC8+Jmd0OyArwqDCoMKgICJw YWNrYWdlcnMiLDxiciAvPiZndDsgK108YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7 ICtAZGF0YWNsYXNzPGJyIC8+Jmd0OyArY2xhc3MgU1BEWFJlbGF0aW9uc2hpcDo8YnIgLz4mZ3Q7 ICvCoMKgwqAgc3BkeEVsZW1lbnRJZDogc3RyPGJyIC8+Jmd0OyArwqDCoMKgIHJlbGF0ZWRTcGR4 RWxlbWVudDogc3RyPGJyIC8+Jmd0OyArwqDCoMKgIHJlbGF0aW9uc2hpcFR5cGU6IHN0cjxiciAv PiZndDsgKzxiciAvPiZndDsgKzxiciAvPiZndDsgK0BkYXRhY2xhc3M8YnIgLz4mZ3Q7ICtjbGFz cyBTUERYRXh0ZXJuYWxSZWY6PGJyIC8+Jmd0OyArwqDCoMKgIHJlZmVyZW5jZUNhdGVnb3J5OiBz dHI8YnIgLz4mZ3Q7ICvCoMKgwqAgcmVmZXJlbmNlVHlwZTogc3RyPGJyIC8+Jmd0OyArwqDCoMKg IHJlZmVyZW5jZUxvY2F0b3I6IHN0cjxiciAvPiZndDsgKzxiciAvPiZndDsgKzxiciAvPiZndDsg K0BkYXRhY2xhc3M8YnIgLz4mZ3Q7ICtjbGFzcyBTUERYUGFja2FnZTo8YnIgLz4mZ3Q7ICvCoMKg wqAgU1BEWElEOiBzdHI8YnIgLz4mZ3Q7ICvCoMKgwqAgbmFtZTogc3RyPGJyIC8+Jmd0OyArwqDC oMKgIGRvd25sb2FkTG9jYXRpb246IHN0cjxiciAvPiZndDsgK8KgwqDCoCBmaWxlc0FuYWx5emVk OiBPcHRpb25hbFtib29sXSA9IEZhbHNlPGJyIC8+Jmd0OyArwqDCoMKgIHZlcnNpb25JbmZvOiBP cHRpb25hbFtzdHJdID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoCBob21lcGFnZTogT3B0aW9uYWxb c3RyXSA9IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqAgcHJpbWFyeVBhY2thZ2VQdXJwb3NlOiBPcHRp b25hbFtzdHJdID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoCBzdXBwbGllcjogT3B0aW9uYWxbc3Ry XSA9IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqAgbGljZW5zZUNvbmNsdWRlZDogT3B0aW9uYWxbc3Ry XSA9IE5vbmU8YnIgLz4mZ3Q7ICvCoMKgwqAgbGljZW5zZURlY2xhcmVkOiBPcHRpb25hbFtzdHJd ID0gTm9uZTxiciAvPiZndDsgK8KgwqDCoCBjb3B5cmlnaHRUZXh0OiBPcHRpb25hbFtzdHJdID0g Tm9uZTxiciAvPiZndDsgK8KgwqDCoCBzdW1tYXJ5OiBPcHRpb25hbFtzdHJdID0gTm9uZTxiciAv PiZndDsgK8KgwqDCoCBleHRlcm5hbFJlZnM6IE9wdGlvbmFsW0xpc3RbU1BEWEV4dGVybmFsUmVm XV0gPSBOb25lPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArPGJyIC8+Jmd0OyArQGRhdGFjbGFzczxi ciAvPiZndDsgK2NsYXNzIFNQRFhDcmVhdGlvbkluZm86PGJyIC8+Jmd0OyArwqDCoMKgIGNyZWF0 ZWQ6IHN0cjxiciAvPiZndDsgK8KgwqDCoCBjb21tZW50OiBPcHRpb25hbFtzdHJdID0gTm9uZTxi ciAvPiZndDsgK8KgwqDCoCBjcmVhdG9yczogTGlzdFtzdHJdID0gTm9uZTxiciAvPiZndDsgKzxi ciAvPiZndDsgKzxiciAvPiZndDsgK0BkYXRhY2xhc3M8YnIgLz4mZ3Q7ICtjbGFzcyBTUERYQk9N OjxiciAvPiZndDsgK8KgwqDCoCAiIiJJbmNvbXBsZXRlIEJPTSBhcyBvZiBTUERYIHNwZWMgdjIu My4iIiI8YnIgLz4mZ3Q7ICs8YnIgLz4mZ3Q7ICvCoMKgwqAgU1BEWElEOiBzdHI8YnIgLz4mZ3Q7 ICvCoMKgwqAgc3BkeFZlcnNpb246IHN0cjxiciAvPiZndDsgK8KgwqDCoCBjcmVhdGlvbkluZm86 IFNQRFhDcmVhdGlvbkluZm88YnIgLz4mZ3Q7ICvCoMKgwqAgbmFtZTogc3RyPGJyIC8+Jmd0OyAr wqDCoMKgIGRhdGFMaWNlbnNlOiBzdHI8YnIgLz4mZ3Q7ICvCoMKgwqAgZG9jdW1lbnROYW1lc3Bh Y2U6IHN0cjxiciAvPiZndDsgK8KgwqDCoCBwYWNrYWdlczogTGlzdFtTUERYUGFja2FnZV08YnIg Lz4mZ3Q7ICvCoMKgwqAgcmVsYXRpb25zaGlwczogTGlzdFtTUERYUmVsYXRpb25zaGlwXTxiciAv PiZndDsgLS0gPGJyIC8+Jmd0OyAyLjM5LjU8L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+PC9w PjxwPjwvcD48cD48L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+LS0gPGJyIC8+PC9wPjxwPjwv cD48cD48L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+PC9w PjxwPjwvcD48cD5TaWVtZW5zIEFHPGJyIC8+TGludXggRXhwZXJ0IENlbnRlcjxiciAvPkZyaWVk cmljaC1MdWR3aWctQmF1ZXItU3RyLiAzPGJyIC8+ODU3NDggR2FyY2hpbmcsIEdlcm1hbnk8L3A+ PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+PHA+PC9wPjwvYmxvY2tx dW90ZT48L2Rpdj4NCg0KPHA+PC9wPgoKLS0gPGJyIC8+CllvdSByZWNlaXZlZCB0aGlzIG1lc3Nh Z2UgYmVjYXVzZSB5b3UgYXJlIHN1YnNjcmliZWQgdG8gdGhlIEdvb2dsZSBHcm91cHMgJnF1b3Q7 aXNhci11c2VycyZxdW90OyBncm91cC48YnIgLz4KVG8gdW5zdWJzY3JpYmUgZnJvbSB0aGlzIGdy b3VwIGFuZCBzdG9wIHJlY2VpdmluZyBlbWFpbHMgZnJvbSBpdCwgc2VuZCBhbiBlbWFpbCB0byA8 YSBocmVmPSJtYWlsdG86aXNhci11c2Vycyt1bnN1YnNjcmliZUBnb29nbGVncm91cHMuY29tIj5p c2FyLXVzZXJzK3Vuc3Vic2NyaWJlQGdvb2dsZWdyb3Vwcy5jb208L2E+LjxiciAvPgpUbyB2aWV3 IHRoaXMgZGlzY3Vzc2lvbiB2aXNpdCA8YSBocmVmPSJodHRwczovL2dyb3Vwcy5nb29nbGUuY29t L2QvbXNnaWQvaXNhci11c2Vycy9kYzliN2NlYy0zYmI2LTRhZTctOWQ3NC1lN2I0OTZkNTkyZjNu JTQwZ29vZ2xlZ3JvdXBzLmNvbT91dG1fbWVkaXVtPWVtYWlsJnV0bV9zb3VyY2U9Zm9vdGVyIj5o dHRwczovL2dyb3Vwcy5nb29nbGUuY29tL2QvbXNnaWQvaXNhci11c2Vycy9kYzliN2NlYy0zYmI2 LTRhZTctOWQ3NC1lN2I0OTZkNTkyZjNuJTQwZ29vZ2xlZ3JvdXBzLmNvbTwvYT4uPGJyIC8+Cg== ------=_Part_429715_1765583369.1753778995226-- ------=_Part_429714_1043403872.1753778995226--