From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A721CC433F5 for ; Wed, 6 Oct 2021 17:42:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 90A0460F6C for ; Wed, 6 Oct 2021 17:42:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239860AbhJFRoB (ORCPT ); Wed, 6 Oct 2021 13:44:01 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:53654 "EHLO mx01.bbu.dsd.mx.bitdefender.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238664AbhJFRmp (ORCPT ); Wed, 6 Oct 2021 13:42:45 -0400 Received: from smtp.bitdefender.com (smtp01.buh.bitdefender.com [10.17.80.75]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id BF2F0306E47B; Wed, 6 Oct 2021 20:30:52 +0300 (EEST) Received: from localhost (unknown [91.199.104.28]) by smtp.bitdefender.com (Postfix) with ESMTPSA id A51BA3064495; Wed, 6 Oct 2021 20:30:52 +0300 (EEST) X-Is-Junk-Enabled: fGZTSsP0qEJE2AIKtlSuFiRRwg9xyHmJ From: =?UTF-8?q?Adalbert=20Laz=C4=83r?= To: kvm@vger.kernel.org Cc: virtualization@lists.linux-foundation.org, Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Mathieu Tarral , Tamas K Lengyel , =?UTF-8?q?Adalbert=20Laz=C4=83r?= Subject: [PATCH v12 00/77] VM introspection Date: Wed, 6 Oct 2021 20:29:56 +0300 Message-Id: <20211006173113.26445-1-alazar@bitdefender.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The KVM introspection subsystem provides a facility for applications running on the host or in a separate VM, to control the execution of other VMs (pause, resume, shutdown), query the state of the vCPUs (GPRs, MSRs etc.), alter the page access bits in the shadow page tables (only for the hardware backed ones, eg. Intel's EPT) and receive notifications when events of interest have taken place (shadow page table level faults, key MSR writes, hypercalls etc.). Some notifications can be responded to with an action (like preventing an MSR from being written), others are mere informative (like breakpoint events which can be used for execution tracing). With few exceptions, all events are optional. An application using this subsystem will explicitly register for them. The use case that gave way for the creation of this subsystem is to monitor the guest OS and as such the ABI/API is highly influenced by how the guest software (kernel, applications) sees the world. For example, some events provide information specific for the host CPU architecture (eg. MSR_IA32_SYSENTER_EIP) merely because its leveraged by guest software to implement a critical feature (fast system calls). At the moment, the target audience for KVMI are security software authors that wish to perform forensics on newly discovered threats (exploits) or to implement another layer of security like preventing a large set of kernel rootkits simply by "locking" the kernel image in the shadow page tables (ie. enforce .text r-x, .rodata rw- etc.). It's the latter case that made KVMI a separate subsystem, even though many of these features are available in the device manager. The ability to build a security application that does not interfere (in terms of performance) with the guest software asks for a specialized interface that is designed for minimum overhead. Patches 1-28: make preparatory changes Patches 29-75: add basic introspection capabilities Patch 76: support introspection tools that write-protect guest page tables Patch 77: notify the introspection tool even on emulation failures (when the read/write callbacks used by the emulator, kvm_page_preread/kvm_page_prewrite, are not called) Changes since [v11](https://lore.kernel.org/kvm/20201207204622.15258-1-alazar@bitdefender.com/): - rebase to 5.15 (from 5.10) - remove patches no longer needed - remove kvm_get_max_gfn()/KVMI_VM_GET_MAX_GFN (a couple of tests are needed to see if it is better to send the memory size from QEMU, during handshake) Adalbert Lazăr (23): KVM: UAPI: add error codes used by the VM introspection code KVM: add kvm_vcpu_kick_and_wait() KVM: x86: add kvm_x86_ops.control_cr3_intercept() KVM: x86: add kvm_x86_ops.desc_ctrl_supported() KVM: x86: add kvm_x86_ops.control_desc_intercept() KVM: x86: export kvm_vcpu_ioctl_x86_set_xsave() KVM: introspection: add hook/unhook ioctls KVM: introspection: add permission access ioctls KVM: introspection: add the read/dispatch message function KVM: introspection: add KVMI_GET_VERSION KVM: introspection: add KVMI_VM_CHECK_COMMAND and KVMI_VM_CHECK_EVENT KVM: introspection: add KVM_INTROSPECTION_PREUNHOOK KVM: introspection: add KVMI_VM_EVENT_UNHOOK KVM: introspection: add KVMI_VM_CONTROL_EVENTS KVM: introspection: add a jobs list to every introspected vCPU KVM: introspection: add KVMI_VM_PAUSE_VCPU KVM: introspection: add support for vCPU events KVM: introspection: add KVMI_VCPU_EVENT_PAUSE KVM: introspection: add KVMI_VM_CONTROL_CLEANUP KVM: introspection: add KVMI_VCPU_GET_XCR KVM: introspection: add KVMI_VCPU_SET_XSAVE KVM: introspection: extend KVMI_GET_VERSION with struct kvmi_features KVM: introspection: add KVMI_VCPU_TRANSLATE_GVA Marian Rotariu (1): KVM: introspection: add KVMI_VCPU_GET_CPUID Mihai Donțu (32): KVM: x86: add kvm_arch_vcpu_get_regs() and kvm_arch_vcpu_get_sregs() KVM: x86: avoid injecting #PF when emulate the VMCALL instruction KVM: x86: add kvm_x86_ops.control_msr_intercept() KVM: x86: save the error code during EPT/NPF exits handling KVM: x86: add kvm_x86_ops.fault_gla() KVM: x86: extend kvm_mmu_gva_to_gpa_system() with the 'access' parameter KVM: x86: page track: provide all callbacks with the guest virtual address KVM: x86: page track: add track_create_slot() callback KVM: x86: page_track: add support for preread, prewrite and preexec KVM: x86: wire in the preread/prewrite/preexec page trackers KVM: introduce VM introspection KVM: introspection: add KVMI_VM_GET_INFO KVM: introspection: add KVMI_VM_READ_PHYSICAL/KVMI_VM_WRITE_PHYSICAL KVM: introspection: handle vCPU introspection requests KVM: introspection: handle vCPU commands KVM: introspection: add KVMI_VCPU_GET_INFO KVM: introspection: add the crash action handling on the event reply KVM: introspection: add KVMI_VCPU_CONTROL_EVENTS KVM: introspection: add KVMI_VCPU_GET_REGISTERS KVM: introspection: add KVMI_VCPU_SET_REGISTERS KVM: introspection: add KVMI_VCPU_EVENT_HYPERCALL KVM: introspection: add KVMI_VCPU_EVENT_BREAKPOINT KVM: introspection: add KVMI_VCPU_CONTROL_CR and KVMI_VCPU_EVENT_CR KVM: introspection: add KVMI_VCPU_INJECT_EXCEPTION + KVMI_VCPU_EVENT_TRAP KVM: introspection: add KVMI_VCPU_EVENT_XSETBV KVM: introspection: add KVMI_VCPU_GET_XSAVE KVM: introspection: add KVMI_VCPU_GET_MTRR_TYPE KVM: introspection: add KVMI_VCPU_CONTROL_MSR and KVMI_VCPU_EVENT_MSR KVM: introspection: add KVMI_VM_SET_PAGE_ACCESS KVM: introspection: add KVMI_VCPU_EVENT_PF KVM: introspection: emulate a guest page table walk on SPT violations due to A/D bit updates KVM: x86: call the page tracking code on emulation failure Mircea Cîrjaliu (2): KVM: x86: disable gpa_available optimization for fetch and page-walk SPT violations KVM: introspection: add vCPU related data Nicușor Cîțu (19): KVM: x86: add kvm_arch_vcpu_set_regs() KVM: x86: add kvm_x86_ops.bp_intercepted() KVM: x86: add kvm_x86_ops.cr3_write_intercepted() KVM: svm: add support for descriptor-table VM-exits KVM: x86: add kvm_x86_ops.desc_intercepted() KVM: x86: add kvm_x86_ops.msr_write_intercepted() KVM: x86: svm: use the vmx convention to control the MSR interception KVM: x86: add kvm_x86_ops.control_singlestep() KVM: x86: export kvm_arch_vcpu_set_guest_debug() KVM: x86: export kvm_inject_pending_exception() KVM: x86: export kvm_vcpu_ioctl_x86_get_xsave() KVM: introspection: add cleanup support for vCPUs KVM: introspection: restore the state of #BP interception on unhook KVM: introspection: restore the state of CR3 interception on unhook KVM: introspection: add KVMI_VCPU_EVENT_DESCRIPTOR KVM: introspection: restore the state of descriptor-table register interception on unhook KVM: introspection: restore the state of MSR interception on unhook KVM: introspection: add KVMI_VCPU_CONTROL_SINGLESTEP KVM: introspection: add KVMI_VCPU_EVENT_SINGLESTEP Documentation/virt/kvm/api.rst | 160 ++ Documentation/virt/kvm/hypercalls.rst | 35 + Documentation/virt/kvm/kvmi.rst | 1554 +++++++++++++ arch/x86/include/asm/kvm-x86-ops.h | 10 + arch/x86/include/asm/kvm_host.h | 46 +- arch/x86/include/asm/kvm_page_track.h | 69 +- arch/x86/include/asm/kvmi_host.h | 111 + arch/x86/include/asm/vmx.h | 2 + arch/x86/include/uapi/asm/kvmi.h | 167 ++ arch/x86/kvm/Kconfig | 10 + arch/x86/kvm/Makefile | 2 + arch/x86/kvm/emulate.c | 4 + arch/x86/kvm/kvm_emulate.h | 1 + arch/x86/kvm/kvmi.c | 1134 ++++++++++ arch/x86/kvm/kvmi.h | 24 + arch/x86/kvm/kvmi_msg.c | 456 ++++ arch/x86/kvm/mmu/mmu.c | 158 +- arch/x86/kvm/mmu/mmu_internal.h | 6 + arch/x86/kvm/mmu/page_track.c | 144 +- arch/x86/kvm/mmu/spte.c | 23 + arch/x86/kvm/mmu/tdp_mmu.c | 106 + arch/x86/kvm/mmu/tdp_mmu.h | 6 + arch/x86/kvm/svm/sev.c | 18 +- arch/x86/kvm/svm/svm.c | 303 ++- arch/x86/kvm/svm/svm.h | 10 +- arch/x86/kvm/vmx/capabilities.h | 7 +- arch/x86/kvm/vmx/vmx.c | 150 +- arch/x86/kvm/vmx/vmx.h | 4 - arch/x86/kvm/x86.c | 301 ++- drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +- include/linux/kvm_host.h | 16 + include/linux/kvmi_host.h | 110 + include/uapi/linux/kvm.h | 20 + include/uapi/linux/kvm_para.h | 5 + include/uapi/linux/kvmi.h | 240 ++ tools/testing/selftests/kvm/Makefile | 1 + .../testing/selftests/kvm/x86_64/kvmi_test.c | 1993 +++++++++++++++++ virt/kvm/introspection/kvmi.c | 1265 +++++++++++ virt/kvm/introspection/kvmi_int.h | 129 ++ virt/kvm/introspection/kvmi_msg.c | 902 ++++++++ virt/kvm/kvm_main.c | 73 + 41 files changed, 9618 insertions(+), 159 deletions(-) create mode 100644 Documentation/virt/kvm/kvmi.rst create mode 100644 arch/x86/include/asm/kvmi_host.h create mode 100644 arch/x86/include/uapi/asm/kvmi.h create mode 100644 arch/x86/kvm/kvmi.c create mode 100644 arch/x86/kvm/kvmi.h create mode 100644 arch/x86/kvm/kvmi_msg.c create mode 100644 include/linux/kvmi_host.h create mode 100644 include/uapi/linux/kvmi.h create mode 100644 tools/testing/selftests/kvm/x86_64/kvmi_test.c create mode 100644 virt/kvm/introspection/kvmi.c create mode 100644 virt/kvm/introspection/kvmi_int.h create mode 100644 virt/kvm/introspection/kvmi_msg.c base-commit: 542a2640a2f491902fd366b5bb54a2b20ac5a2c5 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4EF0EC4321E for ; Wed, 6 Oct 2021 17:55:55 +0000 (UTC) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1F9B0611AE for ; Wed, 6 Oct 2021 17:55:55 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 1F9B0611AE Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=lists.linux-foundation.org Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id AC03360EE9; Wed, 6 Oct 2021 17:55:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id M86yhjAlVk_f; Wed, 6 Oct 2021 17:55:51 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 496F860F1E; Wed, 6 Oct 2021 17:55:51 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0A06BC002C; Wed, 6 Oct 2021 17:55:50 +0000 (UTC) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 22A72C001D for ; Wed, 6 Oct 2021 17:55:46 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 0989760F01 for ; Wed, 6 Oct 2021 17:55:44 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id q1AkVXnWUfyo for ; Wed, 6 Oct 2021 17:55:42 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.8.0 Received: from mx01.bbu.dsd.mx.bitdefender.com (mx01.bbu.dsd.mx.bitdefender.com [91.199.104.161]) by smtp3.osuosl.org (Postfix) with ESMTPS id 865F660EEA for ; Wed, 6 Oct 2021 17:55:42 +0000 (UTC) Received: from smtp.bitdefender.com (smtp01.buh.bitdefender.com [10.17.80.75]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id BF2F0306E47B; Wed, 6 Oct 2021 20:30:52 +0300 (EEST) Received: from localhost (unknown [91.199.104.28]) by smtp.bitdefender.com (Postfix) with ESMTPSA id A51BA3064495; Wed, 6 Oct 2021 20:30:52 +0300 (EEST) X-Is-Junk-Enabled: fGZTSsP0qEJE2AIKtlSuFiRRwg9xyHmJ From: =?UTF-8?q?Adalbert=20Laz=C4=83r?= To: kvm@vger.kernel.org Subject: [PATCH v12 00/77] VM introspection Date: Wed, 6 Oct 2021 20:29:56 +0300 Message-Id: <20211006173113.26445-1-alazar@bitdefender.com> MIME-Version: 1.0 Cc: Tamas K Lengyel , Wanpeng Li , Sean Christopherson , Joerg Roedel , virtualization@lists.linux-foundation.org, =?UTF-8?q?Adalbert=20Laz=C4=83r?= , Mathieu Tarral , Paolo Bonzini , Jim Mattson X-BeenThere: virtualization@lists.linux-foundation.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux virtualization List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: virtualization-bounces@lists.linux-foundation.org Sender: "Virtualization" VGhlIEtWTSBpbnRyb3NwZWN0aW9uIHN1YnN5c3RlbSBwcm92aWRlcyBhIGZhY2lsaXR5IGZvciBh cHBsaWNhdGlvbnMKcnVubmluZyBvbiB0aGUgaG9zdCBvciBpbiBhIHNlcGFyYXRlIFZNLCB0byBj b250cm9sIHRoZSBleGVjdXRpb24gb2YKb3RoZXIgVk1zIChwYXVzZSwgcmVzdW1lLCBzaHV0ZG93 biksIHF1ZXJ5IHRoZSBzdGF0ZSBvZiB0aGUgdkNQVXMgKEdQUnMsCk1TUnMgZXRjLiksIGFsdGVy IHRoZSBwYWdlIGFjY2VzcyBiaXRzIGluIHRoZSBzaGFkb3cgcGFnZSB0YWJsZXMgKG9ubHkKZm9y IHRoZSBoYXJkd2FyZSBiYWNrZWQgb25lcywgZWcuIEludGVsJ3MgRVBUKSBhbmQgcmVjZWl2ZSBu b3RpZmljYXRpb25zCndoZW4gZXZlbnRzIG9mIGludGVyZXN0IGhhdmUgdGFrZW4gcGxhY2UgKHNo YWRvdyBwYWdlIHRhYmxlIGxldmVsIGZhdWx0cywKa2V5IE1TUiB3cml0ZXMsIGh5cGVyY2FsbHMg ZXRjLikuIFNvbWUgbm90aWZpY2F0aW9ucyBjYW4gYmUgcmVzcG9uZGVkCnRvIHdpdGggYW4gYWN0 aW9uIChsaWtlIHByZXZlbnRpbmcgYW4gTVNSIGZyb20gYmVpbmcgd3JpdHRlbiksIG90aGVycwph cmUgbWVyZSBpbmZvcm1hdGl2ZSAobGlrZSBicmVha3BvaW50IGV2ZW50cyB3aGljaCBjYW4gYmUg dXNlZCBmb3IKZXhlY3V0aW9uIHRyYWNpbmcpLiAgV2l0aCBmZXcgZXhjZXB0aW9ucywgYWxsIGV2 ZW50cyBhcmUgb3B0aW9uYWwuIEFuCmFwcGxpY2F0aW9uIHVzaW5nIHRoaXMgc3Vic3lzdGVtIHdp bGwgZXhwbGljaXRseSByZWdpc3RlciBmb3IgdGhlbS4KClRoZSB1c2UgY2FzZSB0aGF0IGdhdmUg d2F5IGZvciB0aGUgY3JlYXRpb24gb2YgdGhpcyBzdWJzeXN0ZW0gaXMgdG8KbW9uaXRvciB0aGUg Z3Vlc3QgT1MgYW5kIGFzIHN1Y2ggdGhlIEFCSS9BUEkgaXMgaGlnaGx5IGluZmx1ZW5jZWQgYnkg aG93CnRoZSBndWVzdCBzb2Z0d2FyZSAoa2VybmVsLCBhcHBsaWNhdGlvbnMpIHNlZXMgdGhlIHdv cmxkLiBGb3IgZXhhbXBsZSwKc29tZSBldmVudHMgcHJvdmlkZSBpbmZvcm1hdGlvbiBzcGVjaWZp YyBmb3IgdGhlIGhvc3QgQ1BVIGFyY2hpdGVjdHVyZQooZWcuIE1TUl9JQTMyX1NZU0VOVEVSX0VJ UCkgbWVyZWx5IGJlY2F1c2UgaXRzIGxldmVyYWdlZCBieSBndWVzdCBzb2Z0d2FyZQp0byBpbXBs ZW1lbnQgYSBjcml0aWNhbCBmZWF0dXJlIChmYXN0IHN5c3RlbSBjYWxscykuCgpBdCB0aGUgbW9t ZW50LCB0aGUgdGFyZ2V0IGF1ZGllbmNlIGZvciBLVk1JIGFyZSBzZWN1cml0eSBzb2Z0d2FyZSBh dXRob3JzCnRoYXQgd2lzaCB0byBwZXJmb3JtIGZvcmVuc2ljcyBvbiBuZXdseSBkaXNjb3ZlcmVk IHRocmVhdHMgKGV4cGxvaXRzKQpvciB0byBpbXBsZW1lbnQgYW5vdGhlciBsYXllciBvZiBzZWN1 cml0eSBsaWtlIHByZXZlbnRpbmcgYSBsYXJnZSBzZXQKb2Yga2VybmVsIHJvb3RraXRzIHNpbXBs eSBieSAibG9ja2luZyIgdGhlIGtlcm5lbCBpbWFnZSBpbiB0aGUgc2hhZG93CnBhZ2UgdGFibGVz IChpZS4gZW5mb3JjZSAudGV4dCByLXgsIC5yb2RhdGEgcnctIGV0Yy4pLiBJdCdzIHRoZSBsYXR0 ZXIKY2FzZSB0aGF0IG1hZGUgS1ZNSSBhIHNlcGFyYXRlIHN1YnN5c3RlbSwgZXZlbiB0aG91Z2gg bWFueSBvZiB0aGVzZQpmZWF0dXJlcyBhcmUgYXZhaWxhYmxlIGluIHRoZSBkZXZpY2UgbWFuYWdl ci4gVGhlIGFiaWxpdHkgdG8gYnVpbGQgYQpzZWN1cml0eSBhcHBsaWNhdGlvbiB0aGF0IGRvZXMg bm90IGludGVyZmVyZSAoaW4gdGVybXMgb2YgcGVyZm9ybWFuY2UpCndpdGggdGhlIGd1ZXN0IHNv ZnR3YXJlIGFza3MgZm9yIGEgc3BlY2lhbGl6ZWQgaW50ZXJmYWNlIHRoYXQgaXMgZGVzaWduZWQK Zm9yIG1pbmltdW0gb3ZlcmhlYWQuCgpQYXRjaGVzIDEtMjg6IG1ha2UgcHJlcGFyYXRvcnkgY2hh bmdlcwoKUGF0Y2hlcyAyOS03NTogYWRkIGJhc2ljIGludHJvc3BlY3Rpb24gY2FwYWJpbGl0aWVz CgpQYXRjaCA3Njogc3VwcG9ydCBpbnRyb3NwZWN0aW9uIHRvb2xzIHRoYXQgd3JpdGUtcHJvdGVj dCBndWVzdCBwYWdlIHRhYmxlcwoKUGF0Y2ggNzc6IG5vdGlmeSB0aGUgaW50cm9zcGVjdGlvbiB0 b29sIGV2ZW4gb24gZW11bGF0aW9uIGZhaWx1cmVzCiAgICAgICAgICAod2hlbiB0aGUgcmVhZC93 cml0ZSBjYWxsYmFja3MgdXNlZCBieSB0aGUgZW11bGF0b3IsCiAgICAgICAgICAga3ZtX3BhZ2Vf cHJlcmVhZC9rdm1fcGFnZV9wcmV3cml0ZSwgYXJlIG5vdCBjYWxsZWQpCgpDaGFuZ2VzIHNpbmNl IFt2MTFdKGh0dHBzOi8vbG9yZS5rZXJuZWwub3JnL2t2bS8yMDIwMTIwNzIwNDYyMi4xNTI1OC0x LWFsYXphckBiaXRkZWZlbmRlci5jb20vKToKICAtIHJlYmFzZSB0byA1LjE1IChmcm9tIDUuMTAp CiAgLSByZW1vdmUgcGF0Y2hlcyBubyBsb25nZXIgbmVlZGVkCiAgLSByZW1vdmUga3ZtX2dldF9t YXhfZ2ZuKCkvS1ZNSV9WTV9HRVRfTUFYX0dGTiAoYSBjb3VwbGUgb2YgdGVzdHMgYXJlIG5lZWRl ZCB0byBzZWUKICAgIGlmIGl0IGlzIGJldHRlciB0byBzZW5kIHRoZSBtZW1vcnkgc2l6ZSBmcm9t IFFFTVUsIGR1cmluZyBoYW5kc2hha2UpCgpBZGFsYmVydCBMYXrEg3IgKDIzKToKICBLVk06IFVB UEk6IGFkZCBlcnJvciBjb2RlcyB1c2VkIGJ5IHRoZSBWTSBpbnRyb3NwZWN0aW9uIGNvZGUKICBL Vk06IGFkZCBrdm1fdmNwdV9raWNrX2FuZF93YWl0KCkKICBLVk06IHg4NjogYWRkIGt2bV94ODZf b3BzLmNvbnRyb2xfY3IzX2ludGVyY2VwdCgpCiAgS1ZNOiB4ODY6IGFkZCBrdm1feDg2X29wcy5k ZXNjX2N0cmxfc3VwcG9ydGVkKCkKICBLVk06IHg4NjogYWRkIGt2bV94ODZfb3BzLmNvbnRyb2xf ZGVzY19pbnRlcmNlcHQoKQogIEtWTTogeDg2OiBleHBvcnQga3ZtX3ZjcHVfaW9jdGxfeDg2X3Nl dF94c2F2ZSgpCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBhZGQgaG9vay91bmhvb2sgaW9jdGxzCiAg S1ZNOiBpbnRyb3NwZWN0aW9uOiBhZGQgcGVybWlzc2lvbiBhY2Nlc3MgaW9jdGxzCiAgS1ZNOiBp bnRyb3NwZWN0aW9uOiBhZGQgdGhlIHJlYWQvZGlzcGF0Y2ggbWVzc2FnZSBmdW5jdGlvbgogIEtW TTogaW50cm9zcGVjdGlvbjogYWRkIEtWTUlfR0VUX1ZFUlNJT04KICBLVk06IGludHJvc3BlY3Rp b246IGFkZCBLVk1JX1ZNX0NIRUNLX0NPTU1BTkQgYW5kIEtWTUlfVk1fQ0hFQ0tfRVZFTlQKICBL Vk06IGludHJvc3BlY3Rpb246IGFkZCBLVk1fSU5UUk9TUEVDVElPTl9QUkVVTkhPT0sKICBLVk06 IGludHJvc3BlY3Rpb246IGFkZCBLVk1JX1ZNX0VWRU5UX1VOSE9PSwogIEtWTTogaW50cm9zcGVj dGlvbjogYWRkIEtWTUlfVk1fQ09OVFJPTF9FVkVOVFMKICBLVk06IGludHJvc3BlY3Rpb246IGFk ZCBhIGpvYnMgbGlzdCB0byBldmVyeSBpbnRyb3NwZWN0ZWQgdkNQVQogIEtWTTogaW50cm9zcGVj dGlvbjogYWRkIEtWTUlfVk1fUEFVU0VfVkNQVQogIEtWTTogaW50cm9zcGVjdGlvbjogYWRkIHN1 cHBvcnQgZm9yIHZDUFUgZXZlbnRzCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBhZGQgS1ZNSV9WQ1BV X0VWRU5UX1BBVVNFCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBhZGQgS1ZNSV9WTV9DT05UUk9MX0NM RUFOVVAKICBLVk06IGludHJvc3BlY3Rpb246IGFkZCBLVk1JX1ZDUFVfR0VUX1hDUgogIEtWTTog aW50cm9zcGVjdGlvbjogYWRkIEtWTUlfVkNQVV9TRVRfWFNBVkUKICBLVk06IGludHJvc3BlY3Rp b246IGV4dGVuZCBLVk1JX0dFVF9WRVJTSU9OIHdpdGggc3RydWN0IGt2bWlfZmVhdHVyZXMKICBL Vk06IGludHJvc3BlY3Rpb246IGFkZCBLVk1JX1ZDUFVfVFJBTlNMQVRFX0dWQQoKTWFyaWFuIFJv dGFyaXUgKDEpOgogIEtWTTogaW50cm9zcGVjdGlvbjogYWRkIEtWTUlfVkNQVV9HRVRfQ1BVSUQK Ck1paGFpIERvbsibdSAoMzIpOgogIEtWTTogeDg2OiBhZGQga3ZtX2FyY2hfdmNwdV9nZXRfcmVn cygpIGFuZCBrdm1fYXJjaF92Y3B1X2dldF9zcmVncygpCiAgS1ZNOiB4ODY6IGF2b2lkIGluamVj dGluZyAjUEYgd2hlbiBlbXVsYXRlIHRoZSBWTUNBTEwgaW5zdHJ1Y3Rpb24KICBLVk06IHg4Njog YWRkIGt2bV94ODZfb3BzLmNvbnRyb2xfbXNyX2ludGVyY2VwdCgpCiAgS1ZNOiB4ODY6IHNhdmUg dGhlIGVycm9yIGNvZGUgZHVyaW5nIEVQVC9OUEYgZXhpdHMgaGFuZGxpbmcKICBLVk06IHg4Njog YWRkIGt2bV94ODZfb3BzLmZhdWx0X2dsYSgpCiAgS1ZNOiB4ODY6IGV4dGVuZCBrdm1fbW11X2d2 YV90b19ncGFfc3lzdGVtKCkgd2l0aCB0aGUgJ2FjY2VzcycKICAgIHBhcmFtZXRlcgogIEtWTTog eDg2OiBwYWdlIHRyYWNrOiBwcm92aWRlIGFsbCBjYWxsYmFja3Mgd2l0aCB0aGUgZ3Vlc3Qgdmly dHVhbAogICAgYWRkcmVzcwogIEtWTTogeDg2OiBwYWdlIHRyYWNrOiBhZGQgdHJhY2tfY3JlYXRl X3Nsb3QoKSBjYWxsYmFjawogIEtWTTogeDg2OiBwYWdlX3RyYWNrOiBhZGQgc3VwcG9ydCBmb3Ig cHJlcmVhZCwgcHJld3JpdGUgYW5kIHByZWV4ZWMKICBLVk06IHg4Njogd2lyZSBpbiB0aGUgcHJl cmVhZC9wcmV3cml0ZS9wcmVleGVjIHBhZ2UgdHJhY2tlcnMKICBLVk06IGludHJvZHVjZSBWTSBp bnRyb3NwZWN0aW9uCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBhZGQgS1ZNSV9WTV9HRVRfSU5GTwog IEtWTTogaW50cm9zcGVjdGlvbjogYWRkIEtWTUlfVk1fUkVBRF9QSFlTSUNBTC9LVk1JX1ZNX1dS SVRFX1BIWVNJQ0FMCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBoYW5kbGUgdkNQVSBpbnRyb3NwZWN0 aW9uIHJlcXVlc3RzCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBoYW5kbGUgdkNQVSBjb21tYW5kcwog IEtWTTogaW50cm9zcGVjdGlvbjogYWRkIEtWTUlfVkNQVV9HRVRfSU5GTwogIEtWTTogaW50cm9z cGVjdGlvbjogYWRkIHRoZSBjcmFzaCBhY3Rpb24gaGFuZGxpbmcgb24gdGhlIGV2ZW50IHJlcGx5 CiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBhZGQgS1ZNSV9WQ1BVX0NPTlRST0xfRVZFTlRTCiAgS1ZN OiBpbnRyb3NwZWN0aW9uOiBhZGQgS1ZNSV9WQ1BVX0dFVF9SRUdJU1RFUlMKICBLVk06IGludHJv c3BlY3Rpb246IGFkZCBLVk1JX1ZDUFVfU0VUX1JFR0lTVEVSUwogIEtWTTogaW50cm9zcGVjdGlv bjogYWRkIEtWTUlfVkNQVV9FVkVOVF9IWVBFUkNBTEwKICBLVk06IGludHJvc3BlY3Rpb246IGFk ZCBLVk1JX1ZDUFVfRVZFTlRfQlJFQUtQT0lOVAogIEtWTTogaW50cm9zcGVjdGlvbjogYWRkIEtW TUlfVkNQVV9DT05UUk9MX0NSIGFuZCBLVk1JX1ZDUFVfRVZFTlRfQ1IKICBLVk06IGludHJvc3Bl Y3Rpb246IGFkZCBLVk1JX1ZDUFVfSU5KRUNUX0VYQ0VQVElPTiArCiAgICBLVk1JX1ZDUFVfRVZF TlRfVFJBUAogIEtWTTogaW50cm9zcGVjdGlvbjogYWRkIEtWTUlfVkNQVV9FVkVOVF9YU0VUQlYK ICBLVk06IGludHJvc3BlY3Rpb246IGFkZCBLVk1JX1ZDUFVfR0VUX1hTQVZFCiAgS1ZNOiBpbnRy b3NwZWN0aW9uOiBhZGQgS1ZNSV9WQ1BVX0dFVF9NVFJSX1RZUEUKICBLVk06IGludHJvc3BlY3Rp b246IGFkZCBLVk1JX1ZDUFVfQ09OVFJPTF9NU1IgYW5kIEtWTUlfVkNQVV9FVkVOVF9NU1IKICBL Vk06IGludHJvc3BlY3Rpb246IGFkZCBLVk1JX1ZNX1NFVF9QQUdFX0FDQ0VTUwogIEtWTTogaW50 cm9zcGVjdGlvbjogYWRkIEtWTUlfVkNQVV9FVkVOVF9QRgogIEtWTTogaW50cm9zcGVjdGlvbjog ZW11bGF0ZSBhIGd1ZXN0IHBhZ2UgdGFibGUgd2FsayBvbiBTUFQgdmlvbGF0aW9ucwogICAgZHVl IHRvIEEvRCBiaXQgdXBkYXRlcwogIEtWTTogeDg2OiBjYWxsIHRoZSBwYWdlIHRyYWNraW5nIGNv ZGUgb24gZW11bGF0aW9uIGZhaWx1cmUKCk1pcmNlYSBDw65yamFsaXUgKDIpOgogIEtWTTogeDg2 OiBkaXNhYmxlIGdwYV9hdmFpbGFibGUgb3B0aW1pemF0aW9uIGZvciBmZXRjaCBhbmQgcGFnZS13 YWxrCiAgICBTUFQgdmlvbGF0aW9ucwogIEtWTTogaW50cm9zcGVjdGlvbjogYWRkIHZDUFUgcmVs YXRlZCBkYXRhCgpOaWN1yJlvciBDw67Im3UgKDE5KToKICBLVk06IHg4NjogYWRkIGt2bV9hcmNo X3ZjcHVfc2V0X3JlZ3MoKQogIEtWTTogeDg2OiBhZGQga3ZtX3g4Nl9vcHMuYnBfaW50ZXJjZXB0 ZWQoKQogIEtWTTogeDg2OiBhZGQga3ZtX3g4Nl9vcHMuY3IzX3dyaXRlX2ludGVyY2VwdGVkKCkK ICBLVk06IHN2bTogYWRkIHN1cHBvcnQgZm9yIGRlc2NyaXB0b3ItdGFibGUgVk0tZXhpdHMKICBL Vk06IHg4NjogYWRkIGt2bV94ODZfb3BzLmRlc2NfaW50ZXJjZXB0ZWQoKQogIEtWTTogeDg2OiBh ZGQga3ZtX3g4Nl9vcHMubXNyX3dyaXRlX2ludGVyY2VwdGVkKCkKICBLVk06IHg4Njogc3ZtOiB1 c2UgdGhlIHZteCBjb252ZW50aW9uIHRvIGNvbnRyb2wgdGhlIE1TUiBpbnRlcmNlcHRpb24KICBL Vk06IHg4NjogYWRkIGt2bV94ODZfb3BzLmNvbnRyb2xfc2luZ2xlc3RlcCgpCiAgS1ZNOiB4ODY6 IGV4cG9ydCBrdm1fYXJjaF92Y3B1X3NldF9ndWVzdF9kZWJ1ZygpCiAgS1ZNOiB4ODY6IGV4cG9y dCBrdm1faW5qZWN0X3BlbmRpbmdfZXhjZXB0aW9uKCkKICBLVk06IHg4NjogZXhwb3J0IGt2bV92 Y3B1X2lvY3RsX3g4Nl9nZXRfeHNhdmUoKQogIEtWTTogaW50cm9zcGVjdGlvbjogYWRkIGNsZWFu dXAgc3VwcG9ydCBmb3IgdkNQVXMKICBLVk06IGludHJvc3BlY3Rpb246IHJlc3RvcmUgdGhlIHN0 YXRlIG9mICNCUCBpbnRlcmNlcHRpb24gb24gdW5ob29rCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiBy ZXN0b3JlIHRoZSBzdGF0ZSBvZiBDUjMgaW50ZXJjZXB0aW9uIG9uIHVuaG9vawogIEtWTTogaW50 cm9zcGVjdGlvbjogYWRkIEtWTUlfVkNQVV9FVkVOVF9ERVNDUklQVE9SCiAgS1ZNOiBpbnRyb3Nw ZWN0aW9uOiByZXN0b3JlIHRoZSBzdGF0ZSBvZiBkZXNjcmlwdG9yLXRhYmxlIHJlZ2lzdGVyCiAg ICBpbnRlcmNlcHRpb24gb24gdW5ob29rCiAgS1ZNOiBpbnRyb3NwZWN0aW9uOiByZXN0b3JlIHRo ZSBzdGF0ZSBvZiBNU1IgaW50ZXJjZXB0aW9uIG9uIHVuaG9vawogIEtWTTogaW50cm9zcGVjdGlv bjogYWRkIEtWTUlfVkNQVV9DT05UUk9MX1NJTkdMRVNURVAKICBLVk06IGludHJvc3BlY3Rpb246 IGFkZCBLVk1JX1ZDUFVfRVZFTlRfU0lOR0xFU1RFUAoKIERvY3VtZW50YXRpb24vdmlydC9rdm0v YXBpLnJzdCAgICAgICAgICAgICAgICB8ICAxNjAgKysKIERvY3VtZW50YXRpb24vdmlydC9rdm0v aHlwZXJjYWxscy5yc3QgICAgICAgICB8ICAgMzUgKwogRG9jdW1lbnRhdGlvbi92aXJ0L2t2bS9r dm1pLnJzdCAgICAgICAgICAgICAgIHwgMTU1NCArKysrKysrKysrKysrCiBhcmNoL3g4Ni9pbmNs dWRlL2FzbS9rdm0teDg2LW9wcy5oICAgICAgICAgICAgfCAgIDEwICsKIGFyY2gveDg2L2luY2x1 ZGUvYXNtL2t2bV9ob3N0LmggICAgICAgICAgICAgICB8ICAgNDYgKy0KIGFyY2gveDg2L2luY2x1 ZGUvYXNtL2t2bV9wYWdlX3RyYWNrLmggICAgICAgICB8ICAgNjkgKy0KIGFyY2gveDg2L2luY2x1 ZGUvYXNtL2t2bWlfaG9zdC5oICAgICAgICAgICAgICB8ICAxMTEgKwogYXJjaC94ODYvaW5jbHVk ZS9hc20vdm14LmggICAgICAgICAgICAgICAgICAgIHwgICAgMiArCiBhcmNoL3g4Ni9pbmNsdWRl L3VhcGkvYXNtL2t2bWkuaCAgICAgICAgICAgICAgfCAgMTY3ICsrCiBhcmNoL3g4Ni9rdm0vS2Nv bmZpZyAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgIDEwICsKIGFyY2gveDg2L2t2bS9NYWtl ZmlsZSAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgIDIgKwogYXJjaC94ODYva3ZtL2VtdWxh dGUuYyAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgNCArCiBhcmNoL3g4Ni9rdm0va3ZtX2Vt dWxhdGUuaCAgICAgICAgICAgICAgICAgICAgfCAgICAxICsKIGFyY2gveDg2L2t2bS9rdm1pLmMg ICAgICAgICAgICAgICAgICAgICAgICAgICB8IDExMzQgKysrKysrKysrKwogYXJjaC94ODYva3Zt L2t2bWkuaCAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAyNCArCiBhcmNoL3g4Ni9rdm0v a3ZtaV9tc2cuYyAgICAgICAgICAgICAgICAgICAgICAgfCAgNDU2ICsrKysKIGFyY2gveDg2L2t2 bS9tbXUvbW11LmMgICAgICAgICAgICAgICAgICAgICAgICB8ICAxNTggKy0KIGFyY2gveDg2L2t2 bS9tbXUvbW11X2ludGVybmFsLmggICAgICAgICAgICAgICB8ICAgIDYgKwogYXJjaC94ODYva3Zt L21tdS9wYWdlX3RyYWNrLmMgICAgICAgICAgICAgICAgIHwgIDE0NCArLQogYXJjaC94ODYva3Zt L21tdS9zcHRlLmMgICAgICAgICAgICAgICAgICAgICAgIHwgICAyMyArCiBhcmNoL3g4Ni9rdm0v bW11L3RkcF9tbXUuYyAgICAgICAgICAgICAgICAgICAgfCAgMTA2ICsKIGFyY2gveDg2L2t2bS9t bXUvdGRwX21tdS5oICAgICAgICAgICAgICAgICAgICB8ICAgIDYgKwogYXJjaC94ODYva3ZtL3N2 bS9zZXYuYyAgICAgICAgICAgICAgICAgICAgICAgIHwgICAxOCArLQogYXJjaC94ODYva3ZtL3N2 bS9zdm0uYyAgICAgICAgICAgICAgICAgICAgICAgIHwgIDMwMyArKy0KIGFyY2gveDg2L2t2bS9z dm0vc3ZtLmggICAgICAgICAgICAgICAgICAgICAgICB8ICAgMTAgKy0KIGFyY2gveDg2L2t2bS92 bXgvY2FwYWJpbGl0aWVzLmggICAgICAgICAgICAgICB8ICAgIDcgKy0KIGFyY2gveDg2L2t2bS92 bXgvdm14LmMgICAgICAgICAgICAgICAgICAgICAgICB8ICAxNTAgKy0KIGFyY2gveDg2L2t2bS92 bXgvdm14LmggICAgICAgICAgICAgICAgICAgICAgICB8ICAgIDQgLQogYXJjaC94ODYva3ZtL3g4 Ni5jICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgIDMwMSArKy0KIGRyaXZlcnMvZ3B1L2Ry bS9pOTE1L2d2dC9rdm1ndC5jICAgICAgICAgICAgICB8ICAgIDIgKy0KIGluY2x1ZGUvbGludXgv a3ZtX2hvc3QuaCAgICAgICAgICAgICAgICAgICAgICB8ICAgMTYgKwogaW5jbHVkZS9saW51eC9r dm1pX2hvc3QuaCAgICAgICAgICAgICAgICAgICAgIHwgIDExMCArCiBpbmNsdWRlL3VhcGkvbGlu dXgva3ZtLmggICAgICAgICAgICAgICAgICAgICAgfCAgIDIwICsKIGluY2x1ZGUvdWFwaS9saW51 eC9rdm1fcGFyYS5oICAgICAgICAgICAgICAgICB8ICAgIDUgKwogaW5jbHVkZS91YXBpL2xpbnV4 L2t2bWkuaCAgICAgICAgICAgICAgICAgICAgIHwgIDI0MCArKwogdG9vbHMvdGVzdGluZy9zZWxm dGVzdHMva3ZtL01ha2VmaWxlICAgICAgICAgIHwgICAgMSArCiAuLi4vdGVzdGluZy9zZWxmdGVz dHMva3ZtL3g4Nl82NC9rdm1pX3Rlc3QuYyAgfCAxOTkzICsrKysrKysrKysrKysrKysrCiB2aXJ0 L2t2bS9pbnRyb3NwZWN0aW9uL2t2bWkuYyAgICAgICAgICAgICAgICAgfCAxMjY1ICsrKysrKysr KysrCiB2aXJ0L2t2bS9pbnRyb3NwZWN0aW9uL2t2bWlfaW50LmggICAgICAgICAgICAgfCAgMTI5 ICsrCiB2aXJ0L2t2bS9pbnRyb3NwZWN0aW9uL2t2bWlfbXNnLmMgICAgICAgICAgICAgfCAgOTAy ICsrKysrKysrCiB2aXJ0L2t2bS9rdm1fbWFpbi5jICAgICAgICAgICAgICAgICAgICAgICAgICAg fCAgIDczICsKIDQxIGZpbGVzIGNoYW5nZWQsIDk2MTggaW5zZXJ0aW9ucygrKSwgMTU5IGRlbGV0 aW9ucygtKQogY3JlYXRlIG1vZGUgMTAwNjQ0IERvY3VtZW50YXRpb24vdmlydC9rdm0va3ZtaS5y c3QKIGNyZWF0ZSBtb2RlIDEwMDY0NCBhcmNoL3g4Ni9pbmNsdWRlL2FzbS9rdm1pX2hvc3QuaAog Y3JlYXRlIG1vZGUgMTAwNjQ0IGFyY2gveDg2L2luY2x1ZGUvdWFwaS9hc20va3ZtaS5oCiBjcmVh dGUgbW9kZSAxMDA2NDQgYXJjaC94ODYva3ZtL2t2bWkuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGFy Y2gveDg2L2t2bS9rdm1pLmgKIGNyZWF0ZSBtb2RlIDEwMDY0NCBhcmNoL3g4Ni9rdm0va3ZtaV9t c2cuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1ZGUvbGludXgva3ZtaV9ob3N0LmgKIGNyZWF0 ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL3VhcGkvbGludXgva3ZtaS5oCiBjcmVhdGUgbW9kZSAxMDA2 NDQgdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMva3ZtL3g4Nl82NC9rdm1pX3Rlc3QuYwogY3JlYXRl IG1vZGUgMTAwNjQ0IHZpcnQva3ZtL2ludHJvc3BlY3Rpb24va3ZtaS5jCiBjcmVhdGUgbW9kZSAx MDA2NDQgdmlydC9rdm0vaW50cm9zcGVjdGlvbi9rdm1pX2ludC5oCiBjcmVhdGUgbW9kZSAxMDA2 NDQgdmlydC9rdm0vaW50cm9zcGVjdGlvbi9rdm1pX21zZy5jCgoKYmFzZS1jb21taXQ6IDU0MmEy NjQwYTJmNDkxOTAyZmQzNjZiNWJiNTRhMmIyMGFjNWEyYzUKX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX18KVmlydHVhbGl6YXRpb24gbWFpbGluZyBsaXN0ClZp cnR1YWxpemF0aW9uQGxpc3RzLmxpbnV4LWZvdW5kYXRpb24ub3JnCmh0dHBzOi8vbGlzdHMubGlu dXhmb3VuZGF0aW9uLm9yZy9tYWlsbWFuL2xpc3RpbmZvL3ZpcnR1YWxpemF0aW9u