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 X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 22FF3C48BCD for ; Tue, 8 Jun 2021 19:05:40 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 DB181610A1 for ; Tue, 8 Jun 2021 19:05:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DB181610A1 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 523B06E58E; Tue, 8 Jun 2021 19:05:37 +0000 (UTC) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 5F2786E22F; Tue, 8 Jun 2021 19:05:35 +0000 (UTC) IronPort-SDR: WPxh+z59xx2oFybS3jjDNNPG3+0hCvnseYhzMdpQOeLLVvg29iWaIX3kiAYmgUipZpPvpWHpym AoHPG+DiK/3Q== X-IronPort-AV: E=McAfee;i="6200,9189,10009"; a="204731974" X-IronPort-AV: E=Sophos;i="5.83,259,1616482800"; d="scan'208";a="204731974" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jun 2021 12:05:33 -0700 IronPort-SDR: KENBEHXB+95XM96rDm4wmZEEW/wo+e3FfnydcA80jbh+ettG8DIqv7lK7q1zr760JvWEBq7SQH 7ALHcv91U4ZA== X-IronPort-AV: E=Sophos;i="5.83,259,1616482800"; d="scan'208";a="635164426" Received: from arajji-mobl.ger.corp.intel.com (HELO [10.249.254.90]) ([10.249.254.90]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jun 2021 12:05:31 -0700 Message-ID: <64b9de0f0fb3e9cac656201bb846c45db0fc8085.camel@linux.intel.com> Subject: Re: [Intel-gfx] [PATCH 7/9] drm/i915/gt: Pipelined page migration From: Thomas =?ISO-8859-1?Q?Hellstr=F6m?= To: Matthew Auld Date: Tue, 08 Jun 2021 21:05:29 +0200 In-Reply-To: References: <20210608092846.64198-1-thomas.hellstrom@linux.intel.com> <20210608092846.64198-8-thomas.hellstrom@linux.intel.com> Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.40.1 (3.40.1-1.fc34) MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Intel Graphics Development , Matthew Auld , ML dri-devel , Chris Wilson Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On Tue, 2021-06-08 at 17:18 +0100, Matthew Auld wrote: > On Tue, 8 Jun 2021 at 10:29, Thomas Hellström > wrote: > > > > From: Chris Wilson > > > > If we pipeline the PTE updates and then do the copy of those pages > > within a single unpreemptible command packet, we can submit the > > copies > > and leave them to be scheduled without having to synchronously wait > > under a global lock. In order to manage migration, we need to > > preallocate the page tables (and keep them pinned and available for > > use > > at any time), causing a bottleneck for migrations as all clients > > must > > contend on the limited resources. By inlining the ppGTT updates and > > performing the blit atomically, each client only owns the PTE while > > in > > use, and so we can reschedule individual operations however we see > > fit. > > And most importantly, we do not need to take a global lock on the > > shared > > vm, and wait until the operation is complete before releasing the > > lock > > for others to claim the PTE for themselves. > > > > Signed-off-by: Chris Wilson > > Co-developed-by: Thomas Hellström > > > > Signed-off-by: Thomas Hellström > > --- > >  drivers/gpu/drm/i915/Makefile                 |   1 + > >  drivers/gpu/drm/i915/gt/intel_engine.h        |   1 + > >  drivers/gpu/drm/i915/gt/intel_gpu_commands.h  |   2 + > >  drivers/gpu/drm/i915/gt/intel_migrate.c       | 543 > > ++++++++++++++++++ > >  drivers/gpu/drm/i915/gt/intel_migrate.h       |  45 ++ > >  drivers/gpu/drm/i915/gt/intel_migrate_types.h |  15 + > >  drivers/gpu/drm/i915/gt/intel_ring.h          |   1 + > >  drivers/gpu/drm/i915/gt/selftest_migrate.c    | 291 ++++++++++ > >  .../drm/i915/selftests/i915_live_selftests.h  |   1 + > >  9 files changed, 900 insertions(+) > >  create mode 100644 drivers/gpu/drm/i915/gt/intel_migrate.c > >  create mode 100644 drivers/gpu/drm/i915/gt/intel_migrate.h > >  create mode 100644 drivers/gpu/drm/i915/gt/intel_migrate_types.h > >  create mode 100644 drivers/gpu/drm/i915/gt/selftest_migrate.c > > > > diff --git a/drivers/gpu/drm/i915/Makefile > > b/drivers/gpu/drm/i915/Makefile > > index ea8ee4b3e018..9f18902be626 100644 > > --- a/drivers/gpu/drm/i915/Makefile > > +++ b/drivers/gpu/drm/i915/Makefile > > @@ -109,6 +109,7 @@ gt-y += \ > >         gt/intel_gtt.o \ > >         gt/intel_llc.o \ > >         gt/intel_lrc.o \ > > +       gt/intel_migrate.o \ > >         gt/intel_mocs.o \ > >         gt/intel_ppgtt.o \ > >         gt/intel_rc6.o \ > > diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h > > b/drivers/gpu/drm/i915/gt/intel_engine.h > > index 0862c42b4cac..949965680c37 100644 > > --- a/drivers/gpu/drm/i915/gt/intel_engine.h > > +++ b/drivers/gpu/drm/i915/gt/intel_engine.h > > @@ -188,6 +188,7 @@ intel_write_status_page(struct intel_engine_cs > > *engine, int reg, u32 value) > >  #define I915_GEM_HWS_PREEMPT_ADDR      (I915_GEM_HWS_PREEMPT * > > sizeof(u32)) > >  #define I915_GEM_HWS_SEQNO             0x40 > >  #define I915_GEM_HWS_SEQNO_ADDR                (I915_GEM_HWS_SEQNO > > * sizeof(u32)) > > +#define I915_GEM_HWS_MIGRATE           (0x42 * sizeof(u32)) > >  #define I915_GEM_HWS_SCRATCH           0x80 > > > >  #define I915_HWS_CSB_BUF0_INDEX                0x10 > > diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h > > b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h > > index 2694dbb9967e..1c3af0fc0456 100644 > > --- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h > > +++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h > > @@ -123,8 +123,10 @@ > >  #define   MI_SEMAPHORE_SAD_NEQ_SDD     (5 << 12) > >  #define   MI_SEMAPHORE_TOKEN_MASK      REG_GENMASK(9, 5) > >  #define   MI_SEMAPHORE_TOKEN_SHIFT     5 > > +#define MI_STORE_DATA_IMM      MI_INSTR(0x20, 0) > >  #define MI_STORE_DWORD_IMM     MI_INSTR(0x20, 1) > >  #define MI_STORE_DWORD_IMM_GEN4        MI_INSTR(0x20, 2) > > +#define MI_STORE_QWORD_IMM_GEN8 (MI_INSTR(0x20, 3) | REG_BIT(21)) > >  #define   MI_MEM_VIRTUAL       (1 << 22) /* 945,g33,965 */ > >  #define   MI_USE_GGTT          (1 << 22) /* g4x+ */ > >  #define MI_STORE_DWORD_INDEX   MI_INSTR(0x21, 1) > > diff --git a/drivers/gpu/drm/i915/gt/intel_migrate.c > > b/drivers/gpu/drm/i915/gt/intel_migrate.c > > new file mode 100644 > > index 000000000000..1f60f8ee36f8 > > --- /dev/null > > +++ b/drivers/gpu/drm/i915/gt/intel_migrate.c > > @@ -0,0 +1,543 @@ > > +// SPDX-License-Identifier: MIT > > +/* > > + * Copyright © 2020 Intel Corporation > > + */ > > + > > +#include "i915_drv.h" > > +#include "intel_context.h" > > +#include "intel_gpu_commands.h" > > +#include "intel_gt.h" > > +#include "intel_gtt.h" > > +#include "intel_migrate.h" > > +#include "intel_ring.h" > > + > > +struct insert_pte_data { > > +       u64 offset; > > +       bool is_lmem; > > +}; > > + > > +#define CHUNK_SZ SZ_8M /* ~1ms at 8GiB/s preemption delay */ > > + > > +static bool engine_supports_migration(struct intel_engine_cs > > *engine) > > +{ > > +       if (!engine) > > +               return false; > > + > > +       /* > > +        * We need the ability to prevent aribtration > > (MI_ARB_ON_OFF), > > +        * the ability to write PTE using inline data > > (MI_STORE_DATA) > > +        * and of course the ability to do the block transfer > > (blits). > > +        */ > > +       GEM_BUG_ON(engine->class != COPY_ENGINE_CLASS); > > + > > +       return true; > > +} > > + > > +static void insert_pte(struct i915_address_space *vm, > > +                      struct i915_page_table *pt, > > +                      void *data) > > +{ > > +       struct insert_pte_data *d = data; > > + > > +       vm->insert_page(vm, px_dma(pt), d->offset, I915_CACHE_NONE, > > +                       d->is_lmem ? PTE_LM : 0); > > +       d->offset += PAGE_SIZE; > > +} > > + > > +static struct i915_address_space *migrate_vm(struct intel_gt *gt) > > +{ > > +       struct i915_vm_pt_stash stash = {}; > > +       struct i915_ppgtt *vm; > > +       int err; > > +       int i; > > + > > +       /* > > +        * We construct a very special VM for use by all migration > > contexts, > > +        * it is kept pinned so that it can be used at any time. As > > we need > > +        * to pre-allocate the page directories for the migration > > VM, this > > +        * limits us to only using a small number of prepared vma. > > +        * > > +        * To be able to pipeline and reschedule migration > > operations while > > +        * avoiding unnecessary contention on the vm itself, the > > PTE updates > > +        * are inline with the blits. All the blits use the same > > fixed > > +        * addresses, with the backing store redirection being > > updated on the > > +        * fly. Only 2 implicit vma are used for all migration > > operations. > > +        * > > +        * We lay the ppGTT out as: > > +        * > > +        *      [0, CHUNK_SZ) -> first object > > +        *      [CHUNK_SZ, 2 * CHUNK_SZ) -> second object > > +        *      [2 * CHUNK_SZ, 2 * CHUNK_SZ + 2 * CHUNK_SZ >> 9] -> > > PTE > > +        * > > +        * By exposing the dma addresses of the page directories > > themselves > > +        * within the ppGTT, we are then able to rewrite the PTE > > prior to use. > > +        * But the PTE update and subsequent migration operation > > must be atomic, > > +        * i.e. within the same non-preemptible window so that we > > do not switch > > +        * to another migration context that overwrites the PTE. > > +        */ > > + > > +       vm = i915_ppgtt_create(gt); > > +       if (IS_ERR(vm)) > > +               return ERR_CAST(vm); > > + > > +       if (!vm->vm.allocate_va_range || !vm->vm.foreach) { > > +               err = -ENODEV; > > +               goto err_vm; > > +       } > > + > > +       /* > > +        * Each engine instance is assigned its own chunk in the > > VM, so > > +        * that we can run multiple instances concurrently > > +        */ > > +       for (i = 0; i < ARRAY_SIZE(gt- > > >engine_class[COPY_ENGINE_CLASS]); i++) { > > +               struct intel_engine_cs *engine; > > +               u64 base = (u64)i << 32; > > +               struct insert_pte_data d = {}; > > +               struct i915_gem_ww_ctx ww; > > +               u64 sz; > > + > > +               engine = gt->engine_class[COPY_ENGINE_CLASS][i]; > > +               if (!engine_supports_migration(engine)) > > +                       continue; > > + > > +               /* > > +                * We copy in 8MiB chunks. Each PDE covers 2MiB, so > > we need > > +                * 4x2 page directories for source/destination. > > +                */ > > +               sz = 2 * CHUNK_SZ; > > +               d.offset = base + sz; > > + > > +               /* > > +                * We need another page directory setup so that we > > can write > > +                * the 8x512 PTE in each chunk. > > +                */ > > +               sz += (sz >> 12) * sizeof(u64); > > + > > +               err = i915_vm_alloc_pt_stash(&vm->vm, &stash, sz); > > +               if (err) > > +                       goto err_vm; > > + > > +               for_i915_gem_ww(&ww, err, true) { > > +                       err = i915_vm_lock_objects(&vm->vm, &ww); > > +                       if (err) > > +                               continue; > > +                       err = i915_vm_map_pt_stash(&vm->vm, > > &stash); > > +                       if (err) > > +                               continue; > > + > > +                       vm->vm.allocate_va_range(&vm->vm, &stash, > > base, base + sz); > > +               } > > +               i915_vm_free_pt_stash(&vm->vm, &stash); > > +               if (err) > > +                       goto err_vm; > > + > > +               /* Now allow the GPU to rewrite the PTE via its own > > ppGTT */ > > +               d.is_lmem = i915_gem_object_is_lmem(vm- > > >vm.scratch[0]); > > +               vm->vm.foreach(&vm->vm, base, base + sz, > > insert_pte, &d); > > Will this play nice with Xe HP where we have min page size > restrictions for the GTT + lmem? The page-table allocations sidestep > such restrictions since they were previously never inserted into the > GTT. Maybe we need the flat-ppGTT at some point? Perhaps add a TODO > or > something? I've previously discussed that with Chris, and apparently it should be as easy as adjusting the sz >> 12 above. But yeah, Chris also brought up the flat-ppGTT idea as something we should look into. Mieanwhile, we should add a TODO. /Thomas 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 X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 303E6C47082 for ; Tue, 8 Jun 2021 19:05:38 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 E126960FEA for ; Tue, 8 Jun 2021 19:05:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E126960FEA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 456386E22F; Tue, 8 Jun 2021 19:05:37 +0000 (UTC) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 5F2786E22F; Tue, 8 Jun 2021 19:05:35 +0000 (UTC) IronPort-SDR: WPxh+z59xx2oFybS3jjDNNPG3+0hCvnseYhzMdpQOeLLVvg29iWaIX3kiAYmgUipZpPvpWHpym AoHPG+DiK/3Q== X-IronPort-AV: E=McAfee;i="6200,9189,10009"; a="204731974" X-IronPort-AV: E=Sophos;i="5.83,259,1616482800"; d="scan'208";a="204731974" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jun 2021 12:05:33 -0700 IronPort-SDR: KENBEHXB+95XM96rDm4wmZEEW/wo+e3FfnydcA80jbh+ettG8DIqv7lK7q1zr760JvWEBq7SQH 7ALHcv91U4ZA== X-IronPort-AV: E=Sophos;i="5.83,259,1616482800"; d="scan'208";a="635164426" Received: from arajji-mobl.ger.corp.intel.com (HELO [10.249.254.90]) ([10.249.254.90]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jun 2021 12:05:31 -0700 Message-ID: <64b9de0f0fb3e9cac656201bb846c45db0fc8085.camel@linux.intel.com> From: Thomas =?ISO-8859-1?Q?Hellstr=F6m?= To: Matthew Auld Date: Tue, 08 Jun 2021 21:05:29 +0200 In-Reply-To: References: <20210608092846.64198-1-thomas.hellstrom@linux.intel.com> <20210608092846.64198-8-thomas.hellstrom@linux.intel.com> User-Agent: Evolution 3.40.1 (3.40.1-1.fc34) MIME-Version: 1.0 Subject: Re: [Intel-gfx] [PATCH 7/9] drm/i915/gt: Pipelined page migration X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Intel Graphics Development , Matthew Auld , ML dri-devel , Chris Wilson Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" T24gVHVlLCAyMDIxLTA2LTA4IGF0IDE3OjE4ICswMTAwLCBNYXR0aGV3IEF1bGQgd3JvdGU6Cj4g T24gVHVlLCA4IEp1biAyMDIxIGF0IDEwOjI5LCBUaG9tYXMgSGVsbHN0csO2bQo+IDx0aG9tYXMu aGVsbHN0cm9tQGxpbnV4LmludGVsLmNvbT4gd3JvdGU6Cj4gPiAKPiA+IEZyb206IENocmlzIFdp bHNvbiA8Y2hyaXNAY2hyaXMtd2lsc29uLmNvLnVrPgo+ID4gCj4gPiBJZiB3ZSBwaXBlbGluZSB0 aGUgUFRFIHVwZGF0ZXMgYW5kIHRoZW4gZG8gdGhlIGNvcHkgb2YgdGhvc2UgcGFnZXMKPiA+IHdp dGhpbiBhIHNpbmdsZSB1bnByZWVtcHRpYmxlIGNvbW1hbmQgcGFja2V0LCB3ZSBjYW4gc3VibWl0 IHRoZQo+ID4gY29waWVzCj4gPiBhbmQgbGVhdmUgdGhlbSB0byBiZSBzY2hlZHVsZWQgd2l0aG91 dCBoYXZpbmcgdG8gc3luY2hyb25vdXNseSB3YWl0Cj4gPiB1bmRlciBhIGdsb2JhbCBsb2NrLiBJ biBvcmRlciB0byBtYW5hZ2UgbWlncmF0aW9uLCB3ZSBuZWVkIHRvCj4gPiBwcmVhbGxvY2F0ZSB0 aGUgcGFnZSB0YWJsZXMgKGFuZCBrZWVwIHRoZW0gcGlubmVkIGFuZCBhdmFpbGFibGUgZm9yCj4g PiB1c2UKPiA+IGF0IGFueSB0aW1lKSwgY2F1c2luZyBhIGJvdHRsZW5lY2sgZm9yIG1pZ3JhdGlv bnMgYXMgYWxsIGNsaWVudHMKPiA+IG11c3QKPiA+IGNvbnRlbmQgb24gdGhlIGxpbWl0ZWQgcmVz b3VyY2VzLiBCeSBpbmxpbmluZyB0aGUgcHBHVFQgdXBkYXRlcyBhbmQKPiA+IHBlcmZvcm1pbmcg dGhlIGJsaXQgYXRvbWljYWxseSwgZWFjaCBjbGllbnQgb25seSBvd25zIHRoZSBQVEUgd2hpbGUK PiA+IGluCj4gPiB1c2UsIGFuZCBzbyB3ZSBjYW4gcmVzY2hlZHVsZSBpbmRpdmlkdWFsIG9wZXJh dGlvbnMgaG93ZXZlciB3ZSBzZWUKPiA+IGZpdC4KPiA+IEFuZCBtb3N0IGltcG9ydGFudGx5LCB3 ZSBkbyBub3QgbmVlZCB0byB0YWtlIGEgZ2xvYmFsIGxvY2sgb24gdGhlCj4gPiBzaGFyZWQKPiA+ IHZtLCBhbmQgd2FpdCB1bnRpbCB0aGUgb3BlcmF0aW9uIGlzIGNvbXBsZXRlIGJlZm9yZSByZWxl YXNpbmcgdGhlCj4gPiBsb2NrCj4gPiBmb3Igb3RoZXJzIHRvIGNsYWltIHRoZSBQVEUgZm9yIHRo ZW1zZWx2ZXMuCj4gPiAKPiA+IFNpZ25lZC1vZmYtYnk6IENocmlzIFdpbHNvbiA8Y2hyaXNAY2hy aXMtd2lsc29uLmNvLnVrPgo+ID4gQ28tZGV2ZWxvcGVkLWJ5OiBUaG9tYXMgSGVsbHN0csO2bQo+ ID4gPHRob21hcy5oZWxsc3Ryb21AbGludXguaW50ZWwuY29tPgo+ID4gU2lnbmVkLW9mZi1ieTog VGhvbWFzIEhlbGxzdHLDtm0gPHRob21hcy5oZWxsc3Ryb21AbGludXguaW50ZWwuY29tPgo+ID4g LS0tCj4gPiDCoGRyaXZlcnMvZ3B1L2RybS9pOTE1L01ha2VmaWxlwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgfMKgwqAgMSArCj4gPiDCoGRyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L2lu dGVsX2VuZ2luZS5owqDCoMKgwqDCoMKgwqAgfMKgwqAgMSArCj4gPiDCoGRyaXZlcnMvZ3B1L2Ry bS9pOTE1L2d0L2ludGVsX2dwdV9jb21tYW5kcy5owqAgfMKgwqAgMiArCj4gPiDCoGRyaXZlcnMv Z3B1L2RybS9pOTE1L2d0L2ludGVsX21pZ3JhdGUuY8KgwqDCoMKgwqDCoCB8IDU0Mwo+ID4gKysr KysrKysrKysrKysrKysrCj4gPiDCoGRyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L2ludGVsX21pZ3Jh dGUuaMKgwqDCoMKgwqDCoCB8wqAgNDUgKysKPiA+IMKgZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3Qv aW50ZWxfbWlncmF0ZV90eXBlcy5oIHzCoCAxNSArCj4gPiDCoGRyaXZlcnMvZ3B1L2RybS9pOTE1 L2d0L2ludGVsX3JpbmcuaMKgwqDCoMKgwqDCoMKgwqDCoCB8wqDCoCAxICsKPiA+IMKgZHJpdmVy cy9ncHUvZHJtL2k5MTUvZ3Qvc2VsZnRlc3RfbWlncmF0ZS5jwqDCoMKgIHwgMjkxICsrKysrKysr KysKPiA+IMKgLi4uL2RybS9pOTE1L3NlbGZ0ZXN0cy9pOTE1X2xpdmVfc2VsZnRlc3RzLmjCoCB8 wqDCoCAxICsKPiA+IMKgOSBmaWxlcyBjaGFuZ2VkLCA5MDAgaW5zZXJ0aW9ucygrKQo+ID4gwqBj cmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvaW50ZWxfbWlncmF0ZS5j Cj4gPiDCoGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0vaTkxNS9ndC9pbnRlbF9t aWdyYXRlLmgKPiA+IMKgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZ3B1L2RybS9pOTE1L2d0 L2ludGVsX21pZ3JhdGVfdHlwZXMuaAo+ID4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9n cHUvZHJtL2k5MTUvZ3Qvc2VsZnRlc3RfbWlncmF0ZS5jCj4gPiAKPiA+IGRpZmYgLS1naXQgYS9k cml2ZXJzL2dwdS9kcm0vaTkxNS9NYWtlZmlsZQo+ID4gYi9kcml2ZXJzL2dwdS9kcm0vaTkxNS9N YWtlZmlsZQo+ID4gaW5kZXggZWE4ZWU0YjNlMDE4Li45ZjE4OTAyYmU2MjYgMTAwNjQ0Cj4gPiAt LS0gYS9kcml2ZXJzL2dwdS9kcm0vaTkxNS9NYWtlZmlsZQo+ID4gKysrIGIvZHJpdmVycy9ncHUv ZHJtL2k5MTUvTWFrZWZpbGUKPiA+IEBAIC0xMDksNiArMTA5LDcgQEAgZ3QteSArPSBcCj4gPiDC oMKgwqDCoMKgwqDCoCBndC9pbnRlbF9ndHQubyBcCj4gPiDCoMKgwqDCoMKgwqDCoCBndC9pbnRl bF9sbGMubyBcCj4gPiDCoMKgwqDCoMKgwqDCoCBndC9pbnRlbF9scmMubyBcCj4gPiArwqDCoMKg wqDCoMKgIGd0L2ludGVsX21pZ3JhdGUubyBcCj4gPiDCoMKgwqDCoMKgwqDCoCBndC9pbnRlbF9t b2NzLm8gXAo+ID4gwqDCoMKgwqDCoMKgwqAgZ3QvaW50ZWxfcHBndHQubyBcCj4gPiDCoMKgwqDC oMKgwqDCoCBndC9pbnRlbF9yYzYubyBcCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJt L2k5MTUvZ3QvaW50ZWxfZW5naW5lLmgKPiA+IGIvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvaW50 ZWxfZW5naW5lLmgKPiA+IGluZGV4IDA4NjJjNDJiNGNhYy4uOTQ5OTY1NjgwYzM3IDEwMDY0NAo+ ID4gLS0tIGEvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvaW50ZWxfZW5naW5lLmgKPiA+ICsrKyBi L2RyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L2ludGVsX2VuZ2luZS5oCj4gPiBAQCAtMTg4LDYgKzE4 OCw3IEBAIGludGVsX3dyaXRlX3N0YXR1c19wYWdlKHN0cnVjdCBpbnRlbF9lbmdpbmVfY3MKPiA+ ICplbmdpbmUsIGludCByZWcsIHUzMiB2YWx1ZSkKPiA+IMKgI2RlZmluZSBJOTE1X0dFTV9IV1Nf UFJFRU1QVF9BRERSwqDCoMKgwqDCoCAoSTkxNV9HRU1fSFdTX1BSRUVNUFQgKgo+ID4gc2l6ZW9m KHUzMikpCj4gPiDCoCNkZWZpbmUgSTkxNV9HRU1fSFdTX1NFUU5PwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIDB4NDAKPiA+IMKgI2RlZmluZSBJOTE1X0dFTV9IV1NfU0VRTk9fQUREUsKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoSTkxNV9HRU1fSFdTX1NFUU5PCj4gPiAqIHNpemVvZih1 MzIpKQo+ID4gKyNkZWZpbmUgSTkxNV9HRU1fSFdTX01JR1JBVEXCoMKgwqDCoMKgwqDCoMKgwqDC oCAoMHg0MiAqIHNpemVvZih1MzIpKQo+ID4gwqAjZGVmaW5lIEk5MTVfR0VNX0hXU19TQ1JBVENI wqDCoMKgwqDCoMKgwqDCoMKgwqAgMHg4MAo+ID4gCj4gPiDCoCNkZWZpbmUgSTkxNV9IV1NfQ1NC X0JVRjBfSU5ERVjCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgMHgxMAo+ID4gZGlmZiAt LWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L2ludGVsX2dwdV9jb21tYW5kcy5oCj4gPiBi L2RyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L2ludGVsX2dwdV9jb21tYW5kcy5oCj4gPiBpbmRleCAy Njk0ZGJiOTk2N2UuLjFjM2FmMGZjMDQ1NiAxMDA2NDQKPiA+IC0tLSBhL2RyaXZlcnMvZ3B1L2Ry bS9pOTE1L2d0L2ludGVsX2dwdV9jb21tYW5kcy5oCj4gPiArKysgYi9kcml2ZXJzL2dwdS9kcm0v aTkxNS9ndC9pbnRlbF9ncHVfY29tbWFuZHMuaAo+ID4gQEAgLTEyMyw4ICsxMjMsMTAgQEAKPiA+ IMKgI2RlZmluZcKgwqAgTUlfU0VNQVBIT1JFX1NBRF9ORVFfU0REwqDCoMKgwqAgKDUgPDwgMTIp Cj4gPiDCoCNkZWZpbmXCoMKgIE1JX1NFTUFQSE9SRV9UT0tFTl9NQVNLwqDCoMKgwqDCoCBSRUdf R0VOTUFTSyg5LCA1KQo+ID4gwqAjZGVmaW5lwqDCoCBNSV9TRU1BUEhPUkVfVE9LRU5fU0hJRlTC oMKgwqDCoCA1Cj4gPiArI2RlZmluZSBNSV9TVE9SRV9EQVRBX0lNTcKgwqDCoMKgwqAgTUlfSU5T VFIoMHgyMCwgMCkKPiA+IMKgI2RlZmluZSBNSV9TVE9SRV9EV09SRF9JTU3CoMKgwqDCoCBNSV9J TlNUUigweDIwLCAxKQo+ID4gwqAjZGVmaW5lIE1JX1NUT1JFX0RXT1JEX0lNTV9HRU40wqDCoMKg wqDCoMKgwqAgTUlfSU5TVFIoMHgyMCwgMikKPiA+ICsjZGVmaW5lIE1JX1NUT1JFX1FXT1JEX0lN TV9HRU44IChNSV9JTlNUUigweDIwLCAzKSB8IFJFR19CSVQoMjEpKQo+ID4gwqAjZGVmaW5lwqDC oCBNSV9NRU1fVklSVFVBTMKgwqDCoMKgwqDCoCAoMSA8PCAyMikgLyogOTQ1LGczMyw5NjUgKi8K PiA+IMKgI2RlZmluZcKgwqAgTUlfVVNFX0dHVFTCoMKgwqDCoMKgwqDCoMKgwqAgKDEgPDwgMjIp IC8qIGc0eCsgKi8KPiA+IMKgI2RlZmluZSBNSV9TVE9SRV9EV09SRF9JTkRFWMKgwqAgTUlfSU5T VFIoMHgyMSwgMSkKPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vaTkxNS9ndC9pbnRl bF9taWdyYXRlLmMKPiA+IGIvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvaW50ZWxfbWlncmF0ZS5j Cj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+ID4gaW5kZXggMDAwMDAwMDAwMDAwLi4xZjYwZjhl ZTM2ZjgKPiA+IC0tLSAvZGV2L251bGwKPiA+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9pOTE1L2d0 L2ludGVsX21pZ3JhdGUuYwo+ID4gQEAgLTAsMCArMSw1NDMgQEAKPiA+ICsvLyBTUERYLUxpY2Vu c2UtSWRlbnRpZmllcjogTUlUCj4gPiArLyoKPiA+ICsgKiBDb3B5cmlnaHQgwqkgMjAyMCBJbnRl bCBDb3Jwb3JhdGlvbgo+ID4gKyAqLwo+ID4gKwo+ID4gKyNpbmNsdWRlICJpOTE1X2Rydi5oIgo+ ID4gKyNpbmNsdWRlICJpbnRlbF9jb250ZXh0LmgiCj4gPiArI2luY2x1ZGUgImludGVsX2dwdV9j b21tYW5kcy5oIgo+ID4gKyNpbmNsdWRlICJpbnRlbF9ndC5oIgo+ID4gKyNpbmNsdWRlICJpbnRl bF9ndHQuaCIKPiA+ICsjaW5jbHVkZSAiaW50ZWxfbWlncmF0ZS5oIgo+ID4gKyNpbmNsdWRlICJp bnRlbF9yaW5nLmgiCj4gPiArCj4gPiArc3RydWN0IGluc2VydF9wdGVfZGF0YSB7Cj4gPiArwqDC oMKgwqDCoMKgIHU2NCBvZmZzZXQ7Cj4gPiArwqDCoMKgwqDCoMKgIGJvb2wgaXNfbG1lbTsKPiA+ ICt9Owo+ID4gKwo+ID4gKyNkZWZpbmUgQ0hVTktfU1ogU1pfOE0gLyogfjFtcyBhdCA4R2lCL3Mg cHJlZW1wdGlvbiBkZWxheSAqLwo+ID4gKwo+ID4gK3N0YXRpYyBib29sIGVuZ2luZV9zdXBwb3J0 c19taWdyYXRpb24oc3RydWN0IGludGVsX2VuZ2luZV9jcwo+ID4gKmVuZ2luZSkKPiA+ICt7Cj4g PiArwqDCoMKgwqDCoMKgIGlmICghZW5naW5lKQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgcmV0dXJuIGZhbHNlOwo+ID4gKwo+ID4gK8KgwqDCoMKgwqDCoCAvKgo+ID4gK8KgwqDC oMKgwqDCoMKgICogV2UgbmVlZCB0aGUgYWJpbGl0eSB0byBwcmV2ZW50IGFyaWJ0cmF0aW9uCj4g PiAoTUlfQVJCX09OX09GRiksCj4gPiArwqDCoMKgwqDCoMKgwqAgKiB0aGUgYWJpbGl0eSB0byB3 cml0ZSBQVEUgdXNpbmcgaW5saW5lIGRhdGEKPiA+IChNSV9TVE9SRV9EQVRBKQo+ID4gK8KgwqDC oMKgwqDCoMKgICogYW5kIG9mIGNvdXJzZSB0aGUgYWJpbGl0eSB0byBkbyB0aGUgYmxvY2sgdHJh bnNmZXIKPiA+IChibGl0cykuCj4gPiArwqDCoMKgwqDCoMKgwqAgKi8KPiA+ICvCoMKgwqDCoMKg wqAgR0VNX0JVR19PTihlbmdpbmUtPmNsYXNzICE9IENPUFlfRU5HSU5FX0NMQVNTKTsKPiA+ICsK PiA+ICvCoMKgwqDCoMKgwqAgcmV0dXJuIHRydWU7Cj4gPiArfQo+ID4gKwo+ID4gK3N0YXRpYyB2 b2lkIGluc2VydF9wdGUoc3RydWN0IGk5MTVfYWRkcmVzc19zcGFjZSAqdm0sCj4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCBpOTE1X3BhZ2VfdGFi bGUgKnB0LAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB2 b2lkICpkYXRhKQo+ID4gK3sKPiA+ICvCoMKgwqDCoMKgwqAgc3RydWN0IGluc2VydF9wdGVfZGF0 YSAqZCA9IGRhdGE7Cj4gPiArCj4gPiArwqDCoMKgwqDCoMKgIHZtLT5pbnNlcnRfcGFnZSh2bSwg cHhfZG1hKHB0KSwgZC0+b2Zmc2V0LCBJOTE1X0NBQ0hFX05PTkUsCj4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZC0+aXNfbG1lbSA/IFBURV9MTSA6IDAp Owo+ID4gK8KgwqDCoMKgwqDCoCBkLT5vZmZzZXQgKz0gUEFHRV9TSVpFOwo+ID4gK30KPiA+ICsK PiA+ICtzdGF0aWMgc3RydWN0IGk5MTVfYWRkcmVzc19zcGFjZSAqbWlncmF0ZV92bShzdHJ1Y3Qg aW50ZWxfZ3QgKmd0KQo+ID4gK3sKPiA+ICvCoMKgwqDCoMKgwqAgc3RydWN0IGk5MTVfdm1fcHRf c3Rhc2ggc3Rhc2ggPSB7fTsKPiA+ICvCoMKgwqDCoMKgwqAgc3RydWN0IGk5MTVfcHBndHQgKnZt Owo+ID4gK8KgwqDCoMKgwqDCoCBpbnQgZXJyOwo+ID4gK8KgwqDCoMKgwqDCoCBpbnQgaTsKPiA+ ICsKPiA+ICvCoMKgwqDCoMKgwqAgLyoKPiA+ICvCoMKgwqDCoMKgwqDCoCAqIFdlIGNvbnN0cnVj dCBhIHZlcnkgc3BlY2lhbCBWTSBmb3IgdXNlIGJ5IGFsbCBtaWdyYXRpb24KPiA+IGNvbnRleHRz LAo+ID4gK8KgwqDCoMKgwqDCoMKgICogaXQgaXMga2VwdCBwaW5uZWQgc28gdGhhdCBpdCBjYW4g YmUgdXNlZCBhdCBhbnkgdGltZS4gQXMKPiA+IHdlIG5lZWQKPiA+ICvCoMKgwqDCoMKgwqDCoCAq IHRvIHByZS1hbGxvY2F0ZSB0aGUgcGFnZSBkaXJlY3RvcmllcyBmb3IgdGhlIG1pZ3JhdGlvbgo+ ID4gVk0sIHRoaXMKPiA+ICvCoMKgwqDCoMKgwqDCoCAqIGxpbWl0cyB1cyB0byBvbmx5IHVzaW5n IGEgc21hbGwgbnVtYmVyIG9mIHByZXBhcmVkIHZtYS4KPiA+ICvCoMKgwqDCoMKgwqDCoCAqCj4g PiArwqDCoMKgwqDCoMKgwqAgKiBUbyBiZSBhYmxlIHRvIHBpcGVsaW5lIGFuZCByZXNjaGVkdWxl IG1pZ3JhdGlvbgo+ID4gb3BlcmF0aW9ucyB3aGlsZQo+ID4gK8KgwqDCoMKgwqDCoMKgICogYXZv aWRpbmcgdW5uZWNlc3NhcnkgY29udGVudGlvbiBvbiB0aGUgdm0gaXRzZWxmLCB0aGUKPiA+IFBU RSB1cGRhdGVzCj4gPiArwqDCoMKgwqDCoMKgwqAgKiBhcmUgaW5saW5lIHdpdGggdGhlIGJsaXRz LiBBbGwgdGhlIGJsaXRzIHVzZSB0aGUgc2FtZQo+ID4gZml4ZWQKPiA+ICvCoMKgwqDCoMKgwqDC oCAqIGFkZHJlc3Nlcywgd2l0aCB0aGUgYmFja2luZyBzdG9yZSByZWRpcmVjdGlvbiBiZWluZwo+ ID4gdXBkYXRlZCBvbiB0aGUKPiA+ICvCoMKgwqDCoMKgwqDCoCAqIGZseS4gT25seSAyIGltcGxp Y2l0IHZtYSBhcmUgdXNlZCBmb3IgYWxsIG1pZ3JhdGlvbgo+ID4gb3BlcmF0aW9ucy4KPiA+ICvC oMKgwqDCoMKgwqDCoCAqCj4gPiArwqDCoMKgwqDCoMKgwqAgKiBXZSBsYXkgdGhlIHBwR1RUIG91 dCBhczoKPiA+ICvCoMKgwqDCoMKgwqDCoCAqCj4gPiArwqDCoMKgwqDCoMKgwqAgKsKgwqDCoMKg wqAgWzAsIENIVU5LX1NaKSAtPiBmaXJzdCBvYmplY3QKPiA+ICvCoMKgwqDCoMKgwqDCoCAqwqDC oMKgwqDCoCBbQ0hVTktfU1osIDIgKiBDSFVOS19TWikgLT4gc2Vjb25kIG9iamVjdAo+ID4gK8Kg wqDCoMKgwqDCoMKgICrCoMKgwqDCoMKgIFsyICogQ0hVTktfU1osIDIgKiBDSFVOS19TWiArIDIg KiBDSFVOS19TWiA+PiA5XSAtPgo+ID4gUFRFCj4gPiArwqDCoMKgwqDCoMKgwqAgKgo+ID4gK8Kg wqDCoMKgwqDCoMKgICogQnkgZXhwb3NpbmcgdGhlIGRtYSBhZGRyZXNzZXMgb2YgdGhlIHBhZ2Ug ZGlyZWN0b3JpZXMKPiA+IHRoZW1zZWx2ZXMKPiA+ICvCoMKgwqDCoMKgwqDCoCAqIHdpdGhpbiB0 aGUgcHBHVFQsIHdlIGFyZSB0aGVuIGFibGUgdG8gcmV3cml0ZSB0aGUgUFRFCj4gPiBwcmlvciB0 byB1c2UuCj4gPiArwqDCoMKgwqDCoMKgwqAgKiBCdXQgdGhlIFBURSB1cGRhdGUgYW5kIHN1YnNl cXVlbnQgbWlncmF0aW9uIG9wZXJhdGlvbgo+ID4gbXVzdCBiZSBhdG9taWMsCj4gPiArwqDCoMKg wqDCoMKgwqAgKiBpLmUuIHdpdGhpbiB0aGUgc2FtZSBub24tcHJlZW1wdGlibGUgd2luZG93IHNv IHRoYXQgd2UKPiA+IGRvIG5vdCBzd2l0Y2gKPiA+ICvCoMKgwqDCoMKgwqDCoCAqIHRvIGFub3Ro ZXIgbWlncmF0aW9uIGNvbnRleHQgdGhhdCBvdmVyd3JpdGVzIHRoZSBQVEUuCj4gPiArwqDCoMKg wqDCoMKgwqAgKi8KPiA+ICsKPiA+ICvCoMKgwqDCoMKgwqAgdm0gPSBpOTE1X3BwZ3R0X2NyZWF0 ZShndCk7Cj4gPiArwqDCoMKgwqDCoMKgIGlmIChJU19FUlIodm0pKQo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIEVSUl9DQVNUKHZtKTsKPiA+ICsKPiA+ICvCoMKgwqDC oMKgwqAgaWYgKCF2bS0+dm0uYWxsb2NhdGVfdmFfcmFuZ2UgfHwgIXZtLT52bS5mb3JlYWNoKSB7 Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlcnIgPSAtRU5PREVWOwo+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byBlcnJfdm07Cj4gPiArwqDCoMKgwqDCoMKg IH0KPiA+ICsKPiA+ICvCoMKgwqDCoMKgwqAgLyoKPiA+ICvCoMKgwqDCoMKgwqDCoCAqIEVhY2gg ZW5naW5lIGluc3RhbmNlIGlzIGFzc2lnbmVkIGl0cyBvd24gY2h1bmsgaW4gdGhlCj4gPiBWTSwg c28KPiA+ICvCoMKgwqDCoMKgwqDCoCAqIHRoYXQgd2UgY2FuIHJ1biBtdWx0aXBsZSBpbnN0YW5j ZXMgY29uY3VycmVudGx5Cj4gPiArwqDCoMKgwqDCoMKgwqAgKi8KPiA+ICvCoMKgwqDCoMKgwqAg Zm9yIChpID0gMDsgaSA8IEFSUkFZX1NJWkUoZ3QtCj4gPiA+ZW5naW5lX2NsYXNzW0NPUFlfRU5H SU5FX0NMQVNTXSk7IGkrKykgewo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3Ry dWN0IGludGVsX2VuZ2luZV9jcyAqZW5naW5lOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgdTY0IGJhc2UgPSAodTY0KWkgPDwgMzI7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBzdHJ1Y3QgaW5zZXJ0X3B0ZV9kYXRhIGQgPSB7fTsKPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIHN0cnVjdCBpOTE1X2dlbV93d19jdHggd3c7Cj4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCB1NjQgc3o7Cj4gPiArCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBlbmdpbmUgPSBndC0+ZW5naW5lX2NsYXNzW0NPUFlfRU5HSU5FX0NMQVNTXVtp XTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmICghZW5naW5lX3N1cHBvcnRz X21pZ3JhdGlvbihlbmdpbmUpKQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGNvbnRpbnVlOwo+ID4gKwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgLyoKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKiBXZSBjb3B5IGlu IDhNaUIgY2h1bmtzLiBFYWNoIFBERSBjb3ZlcnMgMk1pQiwgc28KPiA+IHdlIG5lZWQKPiA+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKiA0eDIgcGFnZSBkaXJlY3RvcmllcyBmb3Ig c291cmNlL2Rlc3RpbmF0aW9uLgo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAq Lwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3ogPSAyICogQ0hVTktfU1o7Cj4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkLm9mZnNldCA9IGJhc2UgKyBzejsKPiA+ ICsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIC8qCj4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgICogV2UgbmVlZCBhbm90aGVyIHBhZ2UgZGlyZWN0b3J5IHNldHVw IHNvIHRoYXQgd2UKPiA+IGNhbiB3cml0ZQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAqIHRoZSA4eDUxMiBQVEUgaW4gZWFjaCBjaHVuay4KPiA+ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgKi8KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN6ICs9 IChzeiA+PiAxMikgKiBzaXplb2YodTY0KTsKPiA+ICsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIGVyciA9IGk5MTVfdm1fYWxsb2NfcHRfc3Rhc2goJnZtLT52bSwgJnN0YXNoLCBz eik7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoZXJyKQo+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGdvdG8gZXJyX3ZtOwo+ID4g Kwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZm9yX2k5MTVfZ2VtX3d3KCZ3dywg ZXJyLCB0cnVlKSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgZXJyID0gaTkxNV92bV9sb2NrX29iamVjdHMoJnZtLT52bSwgJnd3KTsKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoZXJyKQo+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBjb250aW51ZTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBlcnIgPSBpOTE1X3ZtX21hcF9wdF9zdGFzaCgmdm0tPnZtLAo+ID4gJnN0YXNoKTsKPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoZXJyKQo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBjb250aW51ZTsKPiA+ICsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCB2bS0+dm0uYWxsb2NhdGVfdmFfcmFuZ2UoJnZtLT52bSwgJnN0YXNo LAo+ID4gYmFzZSwgYmFzZSArIHN6KTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IH0KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGk5MTVfdm1fZnJlZV9wdF9zdGFz aCgmdm0tPnZtLCAmc3Rhc2gpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYg KGVycikKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBn b3RvIGVycl92bTsKPiA+ICsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIC8qIE5v dyBhbGxvdyB0aGUgR1BVIHRvIHJld3JpdGUgdGhlIFBURSB2aWEgaXRzIG93bgo+ID4gcHBHVFQg Ki8KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGQuaXNfbG1lbSA9IGk5MTVfZ2Vt X29iamVjdF9pc19sbWVtKHZtLQo+ID4gPnZtLnNjcmF0Y2hbMF0pOwo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgdm0tPnZtLmZvcmVhY2goJnZtLT52bSwgYmFzZSwgYmFzZSArIHN6 LAo+ID4gaW5zZXJ0X3B0ZSwgJmQpOwo+IAo+IFdpbGwgdGhpcyBwbGF5IG5pY2Ugd2l0aCBYZSBI UCB3aGVyZSB3ZSBoYXZlIG1pbiBwYWdlIHNpemUKPiByZXN0cmljdGlvbnMgZm9yIHRoZSBHVFQg KyBsbWVtPyBUaGUgcGFnZS10YWJsZSBhbGxvY2F0aW9ucyBzaWRlc3RlcAo+IHN1Y2ggcmVzdHJp Y3Rpb25zIHNpbmNlIHRoZXkgd2VyZSBwcmV2aW91c2x5IG5ldmVyIGluc2VydGVkIGludG8gdGhl Cj4gR1RULiBNYXliZSB3ZSBuZWVkIHRoZSBmbGF0LXBwR1RUIGF0IHNvbWUgcG9pbnQ/IFBlcmhh cHMgYWRkIGEgVE9ETwo+IG9yCj4gc29tZXRoaW5nPwoKSSd2ZSBwcmV2aW91c2x5IGRpc2N1c3Nl ZCB0aGF0IHdpdGggQ2hyaXMsIGFuZCBhcHBhcmVudGx5IGl0IHNob3VsZCBiZQphcyBlYXN5IGFz IGFkanVzdGluZyB0aGUgc3ogPj4gMTIgYWJvdmUuIEJ1dCB5ZWFoLCBDaHJpcyBhbHNvIGJyb3Vn aHQKdXAgdGhlIGZsYXQtcHBHVFQgaWRlYSBhcyBzb21ldGhpbmcgd2Ugc2hvdWxkIGxvb2sgaW50 by4KCk1pZWFud2hpbGUsIHdlIHNob3VsZCBhZGQgYSBUT0RPLgoKL1Rob21hcwoKCgpfX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpJbnRlbC1nZnggbWFpbGlu ZyBsaXN0CkludGVsLWdmeEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVl ZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9pbnRlbC1nZngK