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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BC1E7C4332F for ; Tue, 18 Oct 2022 00:52:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230448AbiJRAwn (ORCPT ); Mon, 17 Oct 2022 20:52:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46258 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230525AbiJRAwH (ORCPT ); Mon, 17 Oct 2022 20:52:07 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5DE6D82750 for ; Mon, 17 Oct 2022 17:52:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666054324; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Lch+0lg3n7TS+igKmtmFC8qqNbSDuMXa3xxdCzWFQyQ=; b=A+Gautvxoy4si5VMjhp//Er4IQ7S9l6vMbTVJi9uek568JoxjNq2JUjtw/eKo97oR1zpO7 VlH7+WirH5eh+KyqCDjmZG0ld+rXw6NqDgmQ5EGIIXfEZS/rSUFrZmphfMHmAcRADPHz/1 6m3840f1Gx0WlAnXHWg35C4elnTvhoY= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-376-b0g3CsSxPWelPq238NY-PQ-1; Mon, 17 Oct 2022 20:51:58 -0400 X-MC-Unique: b0g3CsSxPWelPq238NY-PQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9945E38012C3; Tue, 18 Oct 2022 00:51:57 +0000 (UTC) Received: from [10.64.54.70] (vpn2-54-70.bne.redhat.com [10.64.54.70]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 19C0B401D59; Tue, 18 Oct 2022 00:51:52 +0000 (UTC) Reply-To: Gavin Shan Subject: Re: [PATCH 4/6] KVM: selftests: memslot_perf_test: Support variable guest page size From: Gavin Shan To: "Maciej S. Szmigiero" Cc: kvm@vger.kernel.org, maz@kernel.org, linux-kernel@vger.kernel.org, zhenyzha@redhat.com, shan.gavin@gmail.com, kvmarm@lists.linux.dev, pbonzini@redhat.com, shuah@kernel.org, kvmarm@lists.cs.columbia.edu, ajones@ventanamicro.com References: <20221014071914.227134-1-gshan@redhat.com> <20221014071914.227134-5-gshan@redhat.com> <3eecebca-a526-d10a-02d3-496ce919d577@maciej.szmigiero.name> Message-ID: Date: Tue, 18 Oct 2022 08:51:50 +0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 10/18/22 8:46 AM, Gavin Shan wrote: > On 10/18/22 5:31 AM, Maciej S. Szmigiero wrote: >> On 14.10.2022 09:19, Gavin Shan wrote: >>> The test case is obviously broken on aarch64 because non-4KB guest >>> page size is supported. The guest page size on aarch64 could be 4KB, >>> 16KB or 64KB. >>> >>> This supports variable guest page size, mostly for aarch64. >>> >>>    - The host determines the guest page size when virtual machine is >>>      created. The value is also passed to guest through the synchronization >>>      area. >>> >>>    - The number of guest pages are unknown until the virtual machine >>>      is to be created. So all the related macros are dropped. Instead, >>>      their values are dynamically calculated based on the guest page >>>      size. >>> >>>    - The static checks on memory sizes and pages becomes dependent >>>      on guest page size, which is unknown until the virtual machine >>>      is about to be created. So all the static checks are converted >>>      to dynamic checks, done in check_memory_sizes(). >>> >>>    - As the address passed to madvise() should be aligned to host page, >>>      the size of page chunk is automatically selected, other than one >>>      page. >>> >>>    - All other changes included in this patch are almost mechanical >>>      replacing '4096' with 'guest_page_size'. >>> >>> Signed-off-by: Gavin Shan >>> --- >>>   .../testing/selftests/kvm/memslot_perf_test.c | 191 +++++++++++------- >>>   1 file changed, 115 insertions(+), 76 deletions(-) >>> >>> diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c >>> index d5aa9148f96f..d587bd952ff9 100644 >>> --- a/tools/testing/selftests/kvm/memslot_perf_test.c >>> +++ b/tools/testing/selftests/kvm/memslot_perf_test.c >>> @@ -26,14 +26,11 @@ >>>   #include >>>   #define MEM_SIZE        ((512U << 20) + 4096) >>> -#define MEM_SIZE_PAGES        (MEM_SIZE / 4096) >>>   #define MEM_GPA        0x10000000UL >>>   #define MEM_AUX_GPA        MEM_GPA >>>   #define MEM_SYNC_GPA        MEM_AUX_GPA >>>   #define MEM_TEST_GPA        (MEM_AUX_GPA + 4096) >>>   #define MEM_TEST_SIZE        (MEM_SIZE - 4096) >>> -static_assert(MEM_SIZE % 4096 == 0, "invalid mem size"); >>> -static_assert(MEM_TEST_SIZE % 4096 == 0, "invalid mem test size"); >>>   /* >>>    * 32 MiB is max size that gets well over 100 iterations on 509 slots. >>> @@ -42,29 +39,16 @@ static_assert(MEM_TEST_SIZE % 4096 == 0, "invalid mem test size"); >>>    * limited resolution). >>>    */ >>>   #define MEM_SIZE_MAP        ((32U << 20) + 4096) >>> -#define MEM_SIZE_MAP_PAGES    (MEM_SIZE_MAP / 4096) >>>   #define MEM_TEST_MAP_SIZE    (MEM_SIZE_MAP - 4096) >>> -#define MEM_TEST_MAP_SIZE_PAGES (MEM_TEST_MAP_SIZE / 4096) >>> -static_assert(MEM_SIZE_MAP % 4096 == 0, "invalid map test region size"); >>> -static_assert(MEM_TEST_MAP_SIZE % 4096 == 0, "invalid map test region size"); >>> -static_assert(MEM_TEST_MAP_SIZE_PAGES % 2 == 0, "invalid map test region size"); >>> -static_assert(MEM_TEST_MAP_SIZE_PAGES > 2, "invalid map test region size"); >>>   /* >>>    * 128 MiB is min size that fills 32k slots with at least one page in each >>>    * while at the same time gets 100+ iterations in such test >>> + * >>> + * 2 MiB chunk size like a typical huge page >>>    */ >>>   #define MEM_TEST_UNMAP_SIZE        (128U << 20) >>> -#define MEM_TEST_UNMAP_SIZE_PAGES    (MEM_TEST_UNMAP_SIZE / 4096) >>> -/* 2 MiB chunk size like a typical huge page */ >>> -#define MEM_TEST_UNMAP_CHUNK_PAGES    (2U << (20 - 12)) >>> -static_assert(MEM_TEST_UNMAP_SIZE <= MEM_TEST_SIZE, >>> -          "invalid unmap test region size"); >>> -static_assert(MEM_TEST_UNMAP_SIZE % 4096 == 0, >>> -          "invalid unmap test region size"); >>> -static_assert(MEM_TEST_UNMAP_SIZE_PAGES % >>> -          (2 * MEM_TEST_UNMAP_CHUNK_PAGES) == 0, >>> -          "invalid unmap test region size"); >>> +#define MEM_TEST_UNMAP_CHUNK_SIZE    (2U << 20) >>>   /* >>>    * For the move active test the middle of the test area is placed on >>> @@ -77,8 +61,7 @@ static_assert(MEM_TEST_UNMAP_SIZE_PAGES % >>>    * for the total size of 25 pages. >>>    * Hence, the maximum size here is 50 pages. >>>    */ >>> -#define MEM_TEST_MOVE_SIZE_PAGES    (50) >>> -#define MEM_TEST_MOVE_SIZE        (MEM_TEST_MOVE_SIZE_PAGES * 4096) >>> +#define MEM_TEST_MOVE_SIZE        0x32000 >> >> The above number seems less readable than an explicit value of 50 pages. >> >> In addition to that, it's 50 pages only with 4k page size, so at least >> the comment above needs to be updated to reflect this fact. >> > > Yeah, I will change the comments like below in next revision. > >  /* >   * When running this test with 32k memslots, actually 32763 excluding >   * the reserved memory slot 0, the memory for each slot is 0x4000 bytes. >   * The last slot contains 0x19000 bytes memory. Hence, the maximum size >   * here is 0x32000 bytes. >   */ > I will replace those numbers with readable ones like below :) /* * When running this test with 32k memslots, actually 32763 excluding * the reserved memory slot 0, the memory for each slot is 16KB. The * last slot contains 100KB memory with the remaining 84KB. Hence, * the maximum size is double of that (200KB) */ >>>   #define MEM_TEST_MOVE_GPA_DEST        (MEM_GPA + MEM_SIZE) >>>   static_assert(MEM_TEST_MOVE_SIZE <= MEM_TEST_SIZE, >>>             "invalid move test region size"); >> (...) >>> @@ -242,33 +229,34 @@ static struct vm_data *alloc_vm(void) >>>   } >>>   static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots, >>> -               void *guest_code, uint64_t mempages, >>> +               void *guest_code, uint64_t mem_size, >>>                  struct timespec *slot_runtime) >>>   { >>> -    uint64_t rempages; >>> +    uint64_t mempages, rempages; >>>       uint64_t guest_addr; >>> -    uint32_t slot; >>> +    uint32_t slot, guest_page_size; >>>       struct timespec tstart; >>>       struct sync_area *sync; >>> -    TEST_ASSERT(mempages > 1, >>> -            "Can't test without any memory"); >>> +    guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size; >>> +    mempages = mem_size / guest_page_size; >>> + >>> +    data->vm = __vm_create_with_one_vcpu(&data->vcpu, mempages, guest_code); >>> +    ucall_init(data->vm, NULL); >>> >> >> TEST_ASSERT(data->vm->page_size == guest_page_size, "Invalid VM page size") >> here would catch the case if someone accidentally modifies >> __vm_create_with_one_vcpu() to use other page size than specified for >> VM_MODE_DEFAULT. >> > > Sure, it's not harmful at least. > >>>       data->npages = mempages; >>> +    TEST_ASSERT(data->npages > 1, "Can't test without any memory"); >>>       data->nslots = nslots; >>> -    data->pages_per_slot = mempages / data->nslots; >>> +    data->pages_per_slot = data->npages / data->nslots; >>>       if (!data->pages_per_slot) { >>> -        *maxslots = mempages + 1; >>> +        *maxslots = data->npages + 1; >>>           return false; >>>       } >>> -    rempages = mempages % data->nslots; >>> +    rempages = data->npages % data->nslots; >>>       data->hva_slots = malloc(sizeof(*data->hva_slots) * data->nslots); >>>       TEST_ASSERT(data->hva_slots, "malloc() fail"); >>> -    data->vm = __vm_create_with_one_vcpu(&data->vcpu, mempages, guest_code); >>> -    ucall_init(data->vm, NULL); >>> - >>>       pr_info_v("Adding slots 1..%i, each slot with %"PRIu64" pages + %"PRIu64" extra pages last\n", >>>           data->nslots, data->pages_per_slot, rempages); >> (...) >>> @@ -856,6 +863,35 @@ static void help(char *name, struct test_args *targs) >>>           pr_info("%d: %s\n", ctr, tests[ctr].name); >>>   } >>> +static bool check_memory_sizes(void) >>> +{ >>> +    uint32_t guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size; >>> + >>> +    if (MEM_SIZE % guest_page_size || >>> +        MEM_TEST_SIZE % guest_page_size) { >>> +        pr_info("invalid MEM_SIZE or MEM_TEST_SIZE\n"); >>> +        return false; >>> +    } >>> + >>> +    if (MEM_SIZE_MAP % guest_page_size        || >>> +        MEM_TEST_MAP_SIZE % guest_page_size        || >>> +        (MEM_TEST_MAP_SIZE / guest_page_size) <= 2    || >>> +        (MEM_TEST_MAP_SIZE / guest_page_size) % 2) { >>> +        pr_info("invalid MEM_SIZE_MAP or MEM_TEST_MAP_SIZE\n"); >>> +        return false; >>> +    } >>> + >>> +    if (MEM_TEST_UNMAP_SIZE > MEM_TEST_SIZE        || >>> +        MEM_TEST_UNMAP_SIZE % guest_page_size    || >>> +        (MEM_TEST_UNMAP_SIZE / guest_page_size) % >>> +        (MEM_TEST_UNMAP_CHUNK_SIZE / guest_page_size)) { >> >> This should be (MEM_TEST_UNMAP_SIZE / guest_page_size) % (2 * MEM_TEST_UNMAP_CHUNK_SIZE / guest_page_size)) >> to match the old static_assert(). >> > > Nice catch! I will fix it up in next revision :) > Thanks, Gavin 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 mm01.cs.columbia.edu (mm01.cs.columbia.edu [128.59.11.253]) by smtp.lore.kernel.org (Postfix) with ESMTP id 00CEBC43217 for ; Tue, 18 Oct 2022 00:52:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by mm01.cs.columbia.edu (Postfix) with ESMTP id 6DDEC4B7B0; Mon, 17 Oct 2022 20:52:08 -0400 (EDT) X-Virus-Scanned: at lists.cs.columbia.edu Authentication-Results: mm01.cs.columbia.edu (amavisd-new); dkim=softfail (fail, message has been altered) header.i=@redhat.com Received: from mm01.cs.columbia.edu ([127.0.0.1]) by localhost (mm01.cs.columbia.edu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EF+qKhxAVzfk; Mon, 17 Oct 2022 20:52:06 -0400 (EDT) Received: from mm01.cs.columbia.edu (localhost [127.0.0.1]) by mm01.cs.columbia.edu (Postfix) with ESMTP id B4FAA4B6CF; Mon, 17 Oct 2022 20:52:06 -0400 (EDT) Received: from localhost (localhost [127.0.0.1]) by mm01.cs.columbia.edu (Postfix) with ESMTP id D58694B6CF for ; Mon, 17 Oct 2022 20:52:05 -0400 (EDT) X-Virus-Scanned: at lists.cs.columbia.edu Received: from mm01.cs.columbia.edu ([127.0.0.1]) by localhost (mm01.cs.columbia.edu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id AGibHG7eEnXz for ; Mon, 17 Oct 2022 20:52:04 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mm01.cs.columbia.edu (Postfix) with ESMTP id EEED74B133 for ; Mon, 17 Oct 2022 20:52:03 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666054323; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Lch+0lg3n7TS+igKmtmFC8qqNbSDuMXa3xxdCzWFQyQ=; b=FyhDjt8m/x6hSkD/x/flOdf8WAhnW0F8ZtEQ0mScs2ibGISjixycVoCo52WQEtP63hb2No F3VtJUQPHKe6l2//8vR+VfKpqUQgW4Dtl0j3EeAcWhCQwQH73SqSP7X1OlKfDWmyPLUUE/ 91AOlyyLxsveALAb+POoG4y8JEctTz0= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-376-b0g3CsSxPWelPq238NY-PQ-1; Mon, 17 Oct 2022 20:51:58 -0400 X-MC-Unique: b0g3CsSxPWelPq238NY-PQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9945E38012C3; Tue, 18 Oct 2022 00:51:57 +0000 (UTC) Received: from [10.64.54.70] (vpn2-54-70.bne.redhat.com [10.64.54.70]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 19C0B401D59; Tue, 18 Oct 2022 00:51:52 +0000 (UTC) Subject: Re: [PATCH 4/6] KVM: selftests: memslot_perf_test: Support variable guest page size From: Gavin Shan To: "Maciej S. Szmigiero" References: <20221014071914.227134-1-gshan@redhat.com> <20221014071914.227134-5-gshan@redhat.com> <3eecebca-a526-d10a-02d3-496ce919d577@maciej.szmigiero.name> Message-ID: Date: Tue, 18 Oct 2022 08:51:50 +0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-US X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 Cc: kvm@vger.kernel.org, maz@kernel.org, linux-kernel@vger.kernel.org, zhenyzha@redhat.com, shan.gavin@gmail.com, kvmarm@lists.linux.dev, pbonzini@redhat.com, shuah@kernel.org, kvmarm@lists.cs.columbia.edu, ajones@ventanamicro.com X-BeenThere: kvmarm@lists.cs.columbia.edu X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Gavin Shan List-Id: Where KVM/ARM decisions are made List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: base64 Content-Type: text/plain; charset="utf-8"; Format="flowed" Errors-To: kvmarm-bounces@lists.cs.columbia.edu Sender: kvmarm-bounces@lists.cs.columbia.edu T24gMTAvMTgvMjIgODo0NiBBTSwgR2F2aW4gU2hhbiB3cm90ZToKPiBPbiAxMC8xOC8yMiA1OjMx IEFNLCBNYWNpZWogUy4gU3ptaWdpZXJvIHdyb3RlOgo+PiBPbiAxNC4xMC4yMDIyIDA5OjE5LCBH YXZpbiBTaGFuIHdyb3RlOgo+Pj4gVGhlIHRlc3QgY2FzZSBpcyBvYnZpb3VzbHkgYnJva2VuIG9u IGFhcmNoNjQgYmVjYXVzZSBub24tNEtCIGd1ZXN0Cj4+PiBwYWdlIHNpemUgaXMgc3VwcG9ydGVk LiBUaGUgZ3Vlc3QgcGFnZSBzaXplIG9uIGFhcmNoNjQgY291bGQgYmUgNEtCLAo+Pj4gMTZLQiBv ciA2NEtCLgo+Pj4KPj4+IFRoaXMgc3VwcG9ydHMgdmFyaWFibGUgZ3Vlc3QgcGFnZSBzaXplLCBt b3N0bHkgZm9yIGFhcmNoNjQuCj4+Pgo+Pj4gwqDCoCAtIFRoZSBob3N0IGRldGVybWluZXMgdGhl IGd1ZXN0IHBhZ2Ugc2l6ZSB3aGVuIHZpcnR1YWwgbWFjaGluZSBpcwo+Pj4gwqDCoMKgwqAgY3Jl YXRlZC4gVGhlIHZhbHVlIGlzIGFsc28gcGFzc2VkIHRvIGd1ZXN0IHRocm91Z2ggdGhlIHN5bmNo cm9uaXphdGlvbgo+Pj4gwqDCoMKgwqAgYXJlYS4KPj4+Cj4+PiDCoMKgIC0gVGhlIG51bWJlciBv ZiBndWVzdCBwYWdlcyBhcmUgdW5rbm93biB1bnRpbCB0aGUgdmlydHVhbCBtYWNoaW5lCj4+PiDC oMKgwqDCoCBpcyB0byBiZSBjcmVhdGVkLiBTbyBhbGwgdGhlIHJlbGF0ZWQgbWFjcm9zIGFyZSBk cm9wcGVkLiBJbnN0ZWFkLAo+Pj4gwqDCoMKgwqAgdGhlaXIgdmFsdWVzIGFyZSBkeW5hbWljYWxs eSBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoZSBndWVzdCBwYWdlCj4+PiDCoMKgwqDCoCBzaXplLgo+ Pj4KPj4+IMKgwqAgLSBUaGUgc3RhdGljIGNoZWNrcyBvbiBtZW1vcnkgc2l6ZXMgYW5kIHBhZ2Vz IGJlY29tZXMgZGVwZW5kZW50Cj4+PiDCoMKgwqDCoCBvbiBndWVzdCBwYWdlIHNpemUsIHdoaWNo IGlzIHVua25vd24gdW50aWwgdGhlIHZpcnR1YWwgbWFjaGluZQo+Pj4gwqDCoMKgwqAgaXMgYWJv dXQgdG8gYmUgY3JlYXRlZC4gU28gYWxsIHRoZSBzdGF0aWMgY2hlY2tzIGFyZSBjb252ZXJ0ZWQK Pj4+IMKgwqDCoMKgIHRvIGR5bmFtaWMgY2hlY2tzLCBkb25lIGluIGNoZWNrX21lbW9yeV9zaXpl cygpLgo+Pj4KPj4+IMKgwqAgLSBBcyB0aGUgYWRkcmVzcyBwYXNzZWQgdG8gbWFkdmlzZSgpIHNo b3VsZCBiZSBhbGlnbmVkIHRvIGhvc3QgcGFnZSwKPj4+IMKgwqDCoMKgIHRoZSBzaXplIG9mIHBh Z2UgY2h1bmsgaXMgYXV0b21hdGljYWxseSBzZWxlY3RlZCwgb3RoZXIgdGhhbiBvbmUKPj4+IMKg wqDCoMKgIHBhZ2UuCj4+Pgo+Pj4gwqDCoCAtIEFsbCBvdGhlciBjaGFuZ2VzIGluY2x1ZGVkIGlu IHRoaXMgcGF0Y2ggYXJlIGFsbW9zdCBtZWNoYW5pY2FsCj4+PiDCoMKgwqDCoCByZXBsYWNpbmcg JzQwOTYnIHdpdGggJ2d1ZXN0X3BhZ2Vfc2l6ZScuCj4+Pgo+Pj4gU2lnbmVkLW9mZi1ieTogR2F2 aW4gU2hhbiA8Z3NoYW5AcmVkaGF0LmNvbT4KPj4+IC0tLQo+Pj4gwqAgLi4uL3Rlc3Rpbmcvc2Vs ZnRlc3RzL2t2bS9tZW1zbG90X3BlcmZfdGVzdC5jIHwgMTkxICsrKysrKysrKysrLS0tLS0tLQo+ Pj4gwqAgMSBmaWxlIGNoYW5nZWQsIDExNSBpbnNlcnRpb25zKCspLCA3NiBkZWxldGlvbnMoLSkK Pj4+Cj4+PiBkaWZmIC0tZ2l0IGEvdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMva3ZtL21lbXNsb3Rf cGVyZl90ZXN0LmMgYi90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9rdm0vbWVtc2xvdF9wZXJmX3Rl c3QuYwo+Pj4gaW5kZXggZDVhYTkxNDhmOTZmLi5kNTg3YmQ5NTJmZjkgMTAwNjQ0Cj4+PiAtLS0g YS90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9rdm0vbWVtc2xvdF9wZXJmX3Rlc3QuYwo+Pj4gKysr IGIvdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMva3ZtL21lbXNsb3RfcGVyZl90ZXN0LmMKPj4+IEBA IC0yNiwxNCArMjYsMTEgQEAKPj4+IMKgICNpbmNsdWRlIDxwcm9jZXNzb3IuaD4KPj4+IMKgICNk ZWZpbmUgTUVNX1NJWkXCoMKgwqDCoMKgwqDCoCAoKDUxMlUgPDwgMjApICsgNDA5NikKPj4+IC0j ZGVmaW5lIE1FTV9TSVpFX1BBR0VTwqDCoMKgwqDCoMKgwqAgKE1FTV9TSVpFIC8gNDA5NikKPj4+ IMKgICNkZWZpbmUgTUVNX0dQQcKgwqDCoMKgwqDCoMKgIDB4MTAwMDAwMDBVTAo+Pj4gwqAgI2Rl ZmluZSBNRU1fQVVYX0dQQcKgwqDCoMKgwqDCoMKgIE1FTV9HUEEKPj4+IMKgICNkZWZpbmUgTUVN X1NZTkNfR1BBwqDCoMKgwqDCoMKgwqAgTUVNX0FVWF9HUEEKPj4+IMKgICNkZWZpbmUgTUVNX1RF U1RfR1BBwqDCoMKgwqDCoMKgwqAgKE1FTV9BVVhfR1BBICsgNDA5NikKPj4+IMKgICNkZWZpbmUg TUVNX1RFU1RfU0laRcKgwqDCoMKgwqDCoMKgIChNRU1fU0laRSAtIDQwOTYpCj4+PiAtc3RhdGlj X2Fzc2VydChNRU1fU0laRSAlIDQwOTYgPT0gMCwgImludmFsaWQgbWVtIHNpemUiKTsKPj4+IC1z dGF0aWNfYXNzZXJ0KE1FTV9URVNUX1NJWkUgJSA0MDk2ID09IDAsICJpbnZhbGlkIG1lbSB0ZXN0 IHNpemUiKTsKPj4+IMKgIC8qCj4+PiDCoMKgICogMzIgTWlCIGlzIG1heCBzaXplIHRoYXQgZ2V0 cyB3ZWxsIG92ZXIgMTAwIGl0ZXJhdGlvbnMgb24gNTA5IHNsb3RzLgo+Pj4gQEAgLTQyLDI5ICsz OSwxNiBAQCBzdGF0aWNfYXNzZXJ0KE1FTV9URVNUX1NJWkUgJSA0MDk2ID09IDAsICJpbnZhbGlk IG1lbSB0ZXN0IHNpemUiKTsKPj4+IMKgwqAgKiBsaW1pdGVkIHJlc29sdXRpb24pLgo+Pj4gwqDC oCAqLwo+Pj4gwqAgI2RlZmluZSBNRU1fU0laRV9NQVDCoMKgwqDCoMKgwqDCoCAoKDMyVSA8PCAy MCkgKyA0MDk2KQo+Pj4gLSNkZWZpbmUgTUVNX1NJWkVfTUFQX1BBR0VTwqDCoMKgIChNRU1fU0la RV9NQVAgLyA0MDk2KQo+Pj4gwqAgI2RlZmluZSBNRU1fVEVTVF9NQVBfU0laRcKgwqDCoCAoTUVN X1NJWkVfTUFQIC0gNDA5NikKPj4+IC0jZGVmaW5lIE1FTV9URVNUX01BUF9TSVpFX1BBR0VTIChN RU1fVEVTVF9NQVBfU0laRSAvIDQwOTYpCj4+PiAtc3RhdGljX2Fzc2VydChNRU1fU0laRV9NQVAg JSA0MDk2ID09IDAsICJpbnZhbGlkIG1hcCB0ZXN0IHJlZ2lvbiBzaXplIik7Cj4+PiAtc3RhdGlj X2Fzc2VydChNRU1fVEVTVF9NQVBfU0laRSAlIDQwOTYgPT0gMCwgImludmFsaWQgbWFwIHRlc3Qg cmVnaW9uIHNpemUiKTsKPj4+IC1zdGF0aWNfYXNzZXJ0KE1FTV9URVNUX01BUF9TSVpFX1BBR0VT ICUgMiA9PSAwLCAiaW52YWxpZCBtYXAgdGVzdCByZWdpb24gc2l6ZSIpOwo+Pj4gLXN0YXRpY19h c3NlcnQoTUVNX1RFU1RfTUFQX1NJWkVfUEFHRVMgPiAyLCAiaW52YWxpZCBtYXAgdGVzdCByZWdp b24gc2l6ZSIpOwo+Pj4gwqAgLyoKPj4+IMKgwqAgKiAxMjggTWlCIGlzIG1pbiBzaXplIHRoYXQg ZmlsbHMgMzJrIHNsb3RzIHdpdGggYXQgbGVhc3Qgb25lIHBhZ2UgaW4gZWFjaAo+Pj4gwqDCoCAq IHdoaWxlIGF0IHRoZSBzYW1lIHRpbWUgZ2V0cyAxMDArIGl0ZXJhdGlvbnMgaW4gc3VjaCB0ZXN0 Cj4+PiArICoKPj4+ICsgKiAyIE1pQiBjaHVuayBzaXplIGxpa2UgYSB0eXBpY2FsIGh1Z2UgcGFn ZQo+Pj4gwqDCoCAqLwo+Pj4gwqAgI2RlZmluZSBNRU1fVEVTVF9VTk1BUF9TSVpFwqDCoMKgwqDC oMKgwqAgKDEyOFUgPDwgMjApCj4+PiAtI2RlZmluZSBNRU1fVEVTVF9VTk1BUF9TSVpFX1BBR0VT wqDCoMKgIChNRU1fVEVTVF9VTk1BUF9TSVpFIC8gNDA5NikKPj4+IC0vKiAyIE1pQiBjaHVuayBz aXplIGxpa2UgYSB0eXBpY2FsIGh1Z2UgcGFnZSAqLwo+Pj4gLSNkZWZpbmUgTUVNX1RFU1RfVU5N QVBfQ0hVTktfUEFHRVPCoMKgwqAgKDJVIDw8ICgyMCAtIDEyKSkKPj4+IC1zdGF0aWNfYXNzZXJ0 KE1FTV9URVNUX1VOTUFQX1NJWkUgPD0gTUVNX1RFU1RfU0laRSwKPj4+IC3CoMKgwqDCoMKgwqDC oMKgwqAgImludmFsaWQgdW5tYXAgdGVzdCByZWdpb24gc2l6ZSIpOwo+Pj4gLXN0YXRpY19hc3Nl cnQoTUVNX1RFU1RfVU5NQVBfU0laRSAlIDQwOTYgPT0gMCwKPj4+IC3CoMKgwqDCoMKgwqDCoMKg wqAgImludmFsaWQgdW5tYXAgdGVzdCByZWdpb24gc2l6ZSIpOwo+Pj4gLXN0YXRpY19hc3NlcnQo TUVNX1RFU1RfVU5NQVBfU0laRV9QQUdFUyAlCj4+PiAtwqDCoMKgwqDCoMKgwqDCoMKgICgyICog TUVNX1RFU1RfVU5NQVBfQ0hVTktfUEFHRVMpID09IDAsCj4+PiAtwqDCoMKgwqDCoMKgwqDCoMKg ICJpbnZhbGlkIHVubWFwIHRlc3QgcmVnaW9uIHNpemUiKTsKPj4+ICsjZGVmaW5lIE1FTV9URVNU X1VOTUFQX0NIVU5LX1NJWkXCoMKgwqAgKDJVIDw8IDIwKQo+Pj4gwqAgLyoKPj4+IMKgwqAgKiBG b3IgdGhlIG1vdmUgYWN0aXZlIHRlc3QgdGhlIG1pZGRsZSBvZiB0aGUgdGVzdCBhcmVhIGlzIHBs YWNlZCBvbgo+Pj4gQEAgLTc3LDggKzYxLDcgQEAgc3RhdGljX2Fzc2VydChNRU1fVEVTVF9VTk1B UF9TSVpFX1BBR0VTICUKPj4+IMKgwqAgKiBmb3IgdGhlIHRvdGFsIHNpemUgb2YgMjUgcGFnZXMu Cj4+PiDCoMKgICogSGVuY2UsIHRoZSBtYXhpbXVtIHNpemUgaGVyZSBpcyA1MCBwYWdlcy4KPj4+ IMKgwqAgKi8KPj4+IC0jZGVmaW5lIE1FTV9URVNUX01PVkVfU0laRV9QQUdFU8KgwqDCoCAoNTAp Cj4+PiAtI2RlZmluZSBNRU1fVEVTVF9NT1ZFX1NJWkXCoMKgwqDCoMKgwqDCoCAoTUVNX1RFU1Rf TU9WRV9TSVpFX1BBR0VTICogNDA5NikKPj4+ICsjZGVmaW5lIE1FTV9URVNUX01PVkVfU0laRcKg wqDCoMKgwqDCoMKgIDB4MzIwMDAKPj4KPj4gVGhlIGFib3ZlIG51bWJlciBzZWVtcyBsZXNzIHJl YWRhYmxlIHRoYW4gYW4gZXhwbGljaXQgdmFsdWUgb2YgNTAgcGFnZXMuCj4+Cj4+IEluIGFkZGl0 aW9uIHRvIHRoYXQsIGl0J3MgNTAgcGFnZXMgb25seSB3aXRoIDRrIHBhZ2Ugc2l6ZSwgc28gYXQg bGVhc3QKPj4gdGhlIGNvbW1lbnQgYWJvdmUgbmVlZHMgdG8gYmUgdXBkYXRlZCB0byByZWZsZWN0 IHRoaXMgZmFjdC4KPj4KPiAKPiBZZWFoLCBJIHdpbGwgY2hhbmdlIHRoZSBjb21tZW50cyBsaWtl IGJlbG93IGluIG5leHQgcmV2aXNpb24uCj4gCj4gIMKgLyoKPiAgwqAgKiBXaGVuIHJ1bm5pbmcg dGhpcyB0ZXN0IHdpdGggMzJrIG1lbXNsb3RzLCBhY3R1YWxseSAzMjc2MyBleGNsdWRpbmcKPiAg wqAgKiB0aGUgcmVzZXJ2ZWQgbWVtb3J5IHNsb3QgMCwgdGhlIG1lbW9yeSBmb3IgZWFjaCBzbG90 IGlzIDB4NDAwMCBieXRlcy4KPiAgwqAgKiBUaGUgbGFzdCBzbG90IGNvbnRhaW5zIDB4MTkwMDAg Ynl0ZXMgbWVtb3J5LiBIZW5jZSwgdGhlIG1heGltdW0gc2l6ZQo+ICDCoCAqIGhlcmUgaXMgMHgz MjAwMCBieXRlcy4KPiAgwqAgKi8KPiAKCkkgd2lsbCByZXBsYWNlIHRob3NlIG51bWJlcnMgd2l0 aCByZWFkYWJsZSBvbmVzIGxpa2UgYmVsb3cgOikKCi8qCiAgKiBXaGVuIHJ1bm5pbmcgdGhpcyB0 ZXN0IHdpdGggMzJrIG1lbXNsb3RzLCBhY3R1YWxseSAzMjc2MyBleGNsdWRpbmcKICAqIHRoZSBy ZXNlcnZlZCBtZW1vcnkgc2xvdCAwLCB0aGUgbWVtb3J5IGZvciBlYWNoIHNsb3QgaXMgMTZLQi4g VGhlCiAgKiBsYXN0IHNsb3QgY29udGFpbnMgMTAwS0IgbWVtb3J5IHdpdGggdGhlIHJlbWFpbmlu ZyA4NEtCLiBIZW5jZSwKICAqIHRoZSBtYXhpbXVtIHNpemUgaXMgZG91YmxlIG9mIHRoYXQgKDIw MEtCKQogICovCgo+Pj4gwqAgI2RlZmluZSBNRU1fVEVTVF9NT1ZFX0dQQV9ERVNUwqDCoMKgwqDC oMKgwqAgKE1FTV9HUEEgKyBNRU1fU0laRSkKPj4+IMKgIHN0YXRpY19hc3NlcnQoTUVNX1RFU1Rf TU9WRV9TSVpFIDw9IE1FTV9URVNUX1NJWkUsCj4+PiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICJp bnZhbGlkIG1vdmUgdGVzdCByZWdpb24gc2l6ZSIpOwo+PiAoLi4uKQo+Pj4gQEAgLTI0MiwzMyAr MjI5LDM0IEBAIHN0YXRpYyBzdHJ1Y3Qgdm1fZGF0YSAqYWxsb2Nfdm0odm9pZCkKPj4+IMKgIH0K Pj4+IMKgIHN0YXRpYyBib29sIHByZXBhcmVfdm0oc3RydWN0IHZtX2RhdGEgKmRhdGEsIGludCBu c2xvdHMsIHVpbnQ2NF90ICptYXhzbG90cywKPj4+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIHZvaWQgKmd1ZXN0X2NvZGUsIHVpbnQ2NF90IG1lbXBhZ2VzLAo+Pj4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgdm9pZCAqZ3Vlc3RfY29kZSwgdWludDY0X3QgbWVtX3NpemUsCj4+ PiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3QgdGltZXNwZWMgKnNsb3Rf cnVudGltZSkKPj4+IMKgIHsKPj4+IC3CoMKgwqAgdWludDY0X3QgcmVtcGFnZXM7Cj4+PiArwqDC oMKgIHVpbnQ2NF90IG1lbXBhZ2VzLCByZW1wYWdlczsKPj4+IMKgwqDCoMKgwqAgdWludDY0X3Qg Z3Vlc3RfYWRkcjsKPj4+IC3CoMKgwqAgdWludDMyX3Qgc2xvdDsKPj4+ICvCoMKgwqAgdWludDMy X3Qgc2xvdCwgZ3Vlc3RfcGFnZV9zaXplOwo+Pj4gwqDCoMKgwqDCoCBzdHJ1Y3QgdGltZXNwZWMg dHN0YXJ0Owo+Pj4gwqDCoMKgwqDCoCBzdHJ1Y3Qgc3luY19hcmVhICpzeW5jOwo+Pj4gLcKgwqDC oCBURVNUX0FTU0VSVChtZW1wYWdlcyA+IDEsCj4+PiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAi Q2FuJ3QgdGVzdCB3aXRob3V0IGFueSBtZW1vcnkiKTsKPj4+ICvCoMKgwqAgZ3Vlc3RfcGFnZV9z aXplID0gdm1fZ3Vlc3RfbW9kZV9wYXJhbXNbVk1fTU9ERV9ERUZBVUxUXS5wYWdlX3NpemU7Cj4+ PiArwqDCoMKgIG1lbXBhZ2VzID0gbWVtX3NpemUgLyBndWVzdF9wYWdlX3NpemU7Cj4+PiArCj4+ PiArwqDCoMKgIGRhdGEtPnZtID0gX192bV9jcmVhdGVfd2l0aF9vbmVfdmNwdSgmZGF0YS0+dmNw dSwgbWVtcGFnZXMsIGd1ZXN0X2NvZGUpOwo+Pj4gK8KgwqDCoCB1Y2FsbF9pbml0KGRhdGEtPnZt LCBOVUxMKTsKPj4+Cj4+Cj4+IFRFU1RfQVNTRVJUKGRhdGEtPnZtLT5wYWdlX3NpemUgPT0gZ3Vl c3RfcGFnZV9zaXplLCAiSW52YWxpZCBWTSBwYWdlIHNpemUiKQo+PiBoZXJlIHdvdWxkIGNhdGNo IHRoZSBjYXNlIGlmIHNvbWVvbmUgYWNjaWRlbnRhbGx5IG1vZGlmaWVzCj4+IF9fdm1fY3JlYXRl X3dpdGhfb25lX3ZjcHUoKSB0byB1c2Ugb3RoZXIgcGFnZSBzaXplIHRoYW4gc3BlY2lmaWVkIGZv cgo+PiBWTV9NT0RFX0RFRkFVTFQuCj4+Cj4gCj4gU3VyZSwgaXQncyBub3QgaGFybWZ1bCBhdCBs ZWFzdC4KPiAKPj4+IMKgwqDCoMKgwqAgZGF0YS0+bnBhZ2VzID0gbWVtcGFnZXM7Cj4+PiArwqDC oMKgIFRFU1RfQVNTRVJUKGRhdGEtPm5wYWdlcyA+IDEsICJDYW4ndCB0ZXN0IHdpdGhvdXQgYW55 IG1lbW9yeSIpOwo+Pj4gwqDCoMKgwqDCoCBkYXRhLT5uc2xvdHMgPSBuc2xvdHM7Cj4+PiAtwqDC oMKgIGRhdGEtPnBhZ2VzX3Blcl9zbG90ID0gbWVtcGFnZXMgLyBkYXRhLT5uc2xvdHM7Cj4+PiAr wqDCoMKgIGRhdGEtPnBhZ2VzX3Blcl9zbG90ID0gZGF0YS0+bnBhZ2VzIC8gZGF0YS0+bnNsb3Rz Owo+Pj4gwqDCoMKgwqDCoCBpZiAoIWRhdGEtPnBhZ2VzX3Blcl9zbG90KSB7Cj4+PiAtwqDCoMKg wqDCoMKgwqAgKm1heHNsb3RzID0gbWVtcGFnZXMgKyAxOwo+Pj4gK8KgwqDCoMKgwqDCoMKgICpt YXhzbG90cyA9IGRhdGEtPm5wYWdlcyArIDE7Cj4+PiDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJu IGZhbHNlOwo+Pj4gwqDCoMKgwqDCoCB9Cj4+PiAtwqDCoMKgIHJlbXBhZ2VzID0gbWVtcGFnZXMg JSBkYXRhLT5uc2xvdHM7Cj4+PiArwqDCoMKgIHJlbXBhZ2VzID0gZGF0YS0+bnBhZ2VzICUgZGF0 YS0+bnNsb3RzOwo+Pj4gwqDCoMKgwqDCoCBkYXRhLT5odmFfc2xvdHMgPSBtYWxsb2Moc2l6ZW9m KCpkYXRhLT5odmFfc2xvdHMpICogZGF0YS0+bnNsb3RzKTsKPj4+IMKgwqDCoMKgwqAgVEVTVF9B U1NFUlQoZGF0YS0+aHZhX3Nsb3RzLCAibWFsbG9jKCkgZmFpbCIpOwo+Pj4gLcKgwqDCoCBkYXRh LT52bSA9IF9fdm1fY3JlYXRlX3dpdGhfb25lX3ZjcHUoJmRhdGEtPnZjcHUsIG1lbXBhZ2VzLCBn dWVzdF9jb2RlKTsKPj4+IC3CoMKgwqAgdWNhbGxfaW5pdChkYXRhLT52bSwgTlVMTCk7Cj4+PiAt Cj4+PiDCoMKgwqDCoMKgIHByX2luZm9fdigiQWRkaW5nIHNsb3RzIDEuLiVpLCBlYWNoIHNsb3Qg d2l0aCAlIlBSSXU2NCIgcGFnZXMgKyAlIlBSSXU2NCIgZXh0cmEgcGFnZXMgbGFzdFxuIiwKPj4+ IMKgwqDCoMKgwqDCoMKgwqDCoCBkYXRhLT5uc2xvdHMsIGRhdGEtPnBhZ2VzX3Blcl9zbG90LCBy ZW1wYWdlcyk7Cj4+ICguLi4pCj4+PiBAQCAtODU2LDYgKzg2MywzNSBAQCBzdGF0aWMgdm9pZCBo ZWxwKGNoYXIgKm5hbWUsIHN0cnVjdCB0ZXN0X2FyZ3MgKnRhcmdzKQo+Pj4gwqDCoMKgwqDCoMKg wqDCoMKgIHByX2luZm8oIiVkOiAlc1xuIiwgY3RyLCB0ZXN0c1tjdHJdLm5hbWUpOwo+Pj4gwqAg fQo+Pj4gK3N0YXRpYyBib29sIGNoZWNrX21lbW9yeV9zaXplcyh2b2lkKQo+Pj4gK3sKPj4+ICvC oMKgwqAgdWludDMyX3QgZ3Vlc3RfcGFnZV9zaXplID0gdm1fZ3Vlc3RfbW9kZV9wYXJhbXNbVk1f TU9ERV9ERUZBVUxUXS5wYWdlX3NpemU7Cj4+PiArCj4+PiArwqDCoMKgIGlmIChNRU1fU0laRSAl IGd1ZXN0X3BhZ2Vfc2l6ZSB8fAo+Pj4gK8KgwqDCoMKgwqDCoMKgIE1FTV9URVNUX1NJWkUgJSBn dWVzdF9wYWdlX3NpemUpIHsKPj4+ICvCoMKgwqDCoMKgwqDCoCBwcl9pbmZvKCJpbnZhbGlkIE1F TV9TSVpFIG9yIE1FTV9URVNUX1NJWkVcbiIpOwo+Pj4gK8KgwqDCoMKgwqDCoMKgIHJldHVybiBm YWxzZTsKPj4+ICvCoMKgwqAgfQo+Pj4gKwo+Pj4gK8KgwqDCoCBpZiAoTUVNX1NJWkVfTUFQICUg Z3Vlc3RfcGFnZV9zaXplwqDCoMKgwqDCoMKgwqAgfHwKPj4+ICvCoMKgwqDCoMKgwqDCoCBNRU1f VEVTVF9NQVBfU0laRSAlIGd1ZXN0X3BhZ2Vfc2l6ZcKgwqDCoMKgwqDCoMKgIHx8Cj4+PiArwqDC oMKgwqDCoMKgwqAgKE1FTV9URVNUX01BUF9TSVpFIC8gZ3Vlc3RfcGFnZV9zaXplKSA8PSAywqDC oMKgIHx8Cj4+PiArwqDCoMKgwqDCoMKgwqAgKE1FTV9URVNUX01BUF9TSVpFIC8gZ3Vlc3RfcGFn ZV9zaXplKSAlIDIpIHsKPj4+ICvCoMKgwqDCoMKgwqDCoCBwcl9pbmZvKCJpbnZhbGlkIE1FTV9T SVpFX01BUCBvciBNRU1fVEVTVF9NQVBfU0laRVxuIik7Cj4+PiArwqDCoMKgwqDCoMKgwqAgcmV0 dXJuIGZhbHNlOwo+Pj4gK8KgwqDCoCB9Cj4+PiArCj4+PiArwqDCoMKgIGlmIChNRU1fVEVTVF9V Tk1BUF9TSVpFID4gTUVNX1RFU1RfU0laRcKgwqDCoMKgwqDCoMKgIHx8Cj4+PiArwqDCoMKgwqDC oMKgwqAgTUVNX1RFU1RfVU5NQVBfU0laRSAlIGd1ZXN0X3BhZ2Vfc2l6ZcKgwqDCoCB8fAo+Pj4g K8KgwqDCoMKgwqDCoMKgIChNRU1fVEVTVF9VTk1BUF9TSVpFIC8gZ3Vlc3RfcGFnZV9zaXplKSAl Cj4+PiArwqDCoMKgwqDCoMKgwqAgKE1FTV9URVNUX1VOTUFQX0NIVU5LX1NJWkUgLyBndWVzdF9w YWdlX3NpemUpKSB7Cj4+Cj4+IFRoaXMgc2hvdWxkIGJlIChNRU1fVEVTVF9VTk1BUF9TSVpFIC8g Z3Vlc3RfcGFnZV9zaXplKSAlICgyICogTUVNX1RFU1RfVU5NQVBfQ0hVTktfU0laRSAvIGd1ZXN0 X3BhZ2Vfc2l6ZSkpCj4+IHRvIG1hdGNoIHRoZSBvbGQgc3RhdGljX2Fzc2VydCgpLgo+Pgo+IAo+ IE5pY2UgY2F0Y2ghIEkgd2lsbCBmaXggaXQgdXAgaW4gbmV4dCByZXZpc2lvbiA6KQo+IAoKVGhh bmtzLApHYXZpbgoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X18Ka3ZtYXJtIG1haWxpbmcgbGlzdAprdm1hcm1AbGlzdHMuY3MuY29sdW1iaWEuZWR1Cmh0dHBz Oi8vbGlzdHMuY3MuY29sdW1iaWEuZWR1L21haWxtYW4vbGlzdGluZm8va3ZtYXJtCg==