Received: by 2002:a05:7412:4e10:b0:e2:908c:2ebd with SMTP id gb16csp64624rdb; Tue, 7 Nov 2023 00:18:00 -0800 (PST) X-Google-Smtp-Source: AGHT+IFOr6l7SeI3pbMmYxCUVeDFpL/FaW3+Z5/A+L2QllgvEAceQSpLOAtwIq6iBg57csQFqpjh X-Received: by 2002:a05:6a00:2443:b0:6be:2e07:5c5c with SMTP id d3-20020a056a00244300b006be2e075c5cmr28744013pfj.20.1699345079860; Tue, 07 Nov 2023 00:17:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1699345079; cv=none; d=google.com; s=arc-20160816; b=BogAKhueQyP+sT3ss2lVwq8z4yKKJmuzwR0+7cR173XqQ39dBR46YbqJ2jOKutT1qr RNEZncdQC5uh8NF1bxTEmYf13uhbvfAnWG3rWPKjGNGMFjmLzXkMCeWvhi6rLqxoLlBE ExFkHcj7fkLWs/x0B6x9m6p+pioIU86tSWESoeR7roQtvew4gpQa0t9ckKtOcuU02f7u ziYWu+CFJKyzLDbI0U6RB3LFhYK67knMactXu+rEY7j6nXxrPTkb2XlTBX0p8xHmNi5U dhL8MSWLJ9qvzqzROyZKkp5C2HBeCQ/gQMpDJ+YtvFePymfiRi8zOC5WpjTQ9fnwTC1E +k5w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:user-agent:references:in-reply-to :date:cc:to:from:subject:message-id:dkim-signature; bh=u2HeZOCrWr7m2+yivFVVewtDLCGVF7UMVinO6IGMhKI=; fh=PqrLCHv7qgNX9ldy1CuvXxK3juKZAe284EE7a/023n8=; b=s4OynmwsEkuyCMAXiEsXPajRD9dqxuam3tVn9BykM3V5muMwmNZc4SPbC0cUh4s/Rq jc6l7sLGx1UmsRP8YemhjAkgxHYOq1EYg9nYhz+tQsTugQZx9GE5gAtzhxPJYnNRLmlh qBBrcuqEddBJ0jgMmICi0T+1Dko2XyHvRBB/YXgHXM5+0jyjgg3z51EeBpBKOk1qbyO/ z+b53njN2l0OIQkgZ2opBPyyY4b9tPY2YDG9yPDNhxSK6wzVyMJwvOQ9rhOYsjSb67+T 3+Jfhc4RZ4HUIqUoemYrZVjf5b/osjJ970TcKkz7KXjxOhhfyjuJwgDoaSF8/XRZQUpg u50Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@infradead.org header.s=casper.20170209 header.b=UZG4vlcl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from snail.vger.email (snail.vger.email. [2620:137:e000::3:7]) by mx.google.com with ESMTPS id p31-20020a056a000a1f00b006b7b42fe43asi10429361pfh.185.2023.11.07.00.17.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Nov 2023 00:17:59 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) client-ip=2620:137:e000::3:7; Authentication-Results: mx.google.com; dkim=pass header.i=@infradead.org header.s=casper.20170209 header.b=UZG4vlcl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id 83360811F13B; Tue, 7 Nov 2023 00:17:58 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233683AbjKGIR5 (ORCPT + 99 others); Tue, 7 Nov 2023 03:17:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233642AbjKGIRz (ORCPT ); Tue, 7 Nov 2023 03:17:55 -0500 Received: from casper.infradead.org (casper.infradead.org [IPv6:2001:8b0:10b:1236::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D2A192; Tue, 7 Nov 2023 00:17:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=MIME-Version:Content-Type:References: In-Reply-To:Date:Cc:To:From:Subject:Message-ID:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=u2HeZOCrWr7m2+yivFVVewtDLCGVF7UMVinO6IGMhKI=; b=UZG4vlclvTSre+uTyL5vYx+Mh8 blgnL5E+bqwThjQj9vhsJ3wNPRGyACfebAYTEv14sFQWYyRJhEOG66IRF8Q6m1AP/WbAfsjw6Dt1O 6xj9NAoRkyCwTTBffRy1/YRH+5x0uV+swqDny7ya/yk68riAzqVH+9uA6lpejvR3a2IzdjV6yNUgk qC1pEFBYK98wLK8yLtP5Gh9JOmgtrLEy9x/Z0ukrCCi2RODONuIxRAdlvHpvfPOvpf53DSL+9dshL aAt86STVLaW7g33n4ZVZUjP7Uz7QNJ3P5OI8QfPfRv+43uJGYCLe5y9tjyEEa93Szz2O/GG9tq+ss OfWecFmQ==; Received: from [2001:8b0:10b:5:a6cf:3641:9b8:6403] (helo=u3832b3a9db3152.ant.amazon.com) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1r0HHQ-00B9Eh-7e; Tue, 07 Nov 2023 08:17:49 +0000 Message-ID: <12e8ade22fe6c1e6bec74e60e8213302a7da635e.camel@infradead.org> Subject: Re: [PATCH v2] KVM: x86/xen: improve accuracy of Xen timers From: David Woodhouse To: Dongli Zhang , kvm@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Paul Durrant , Sean Christopherson , Paolo Bonzini , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" Date: Tue, 07 Nov 2023 08:17:48 +0000 In-Reply-To: <2bd5d543-08a0-a0f6-0f59-b8724a2d8d75@oracle.com> References: <96da7273adfff2a346de9a4a27ce064f6fe0d0a1.camel@infradead.org> <74f32bfae7243a78d0e74b1ba3a2d1ea4a4a7518.camel@infradead.org> <2bd5d543-08a0-a0f6-0f59-b8724a2d8d75@oracle.com> Content-Type: multipart/signed; micalg="sha-256"; protocol="application/pkcs7-signature"; boundary="=-jonb5B2Fg8DNd2j2Yc9x" User-Agent: Evolution 3.44.4-0ubuntu2 MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Tue, 07 Nov 2023 00:17:58 -0800 (PST) --=-jonb5B2Fg8DNd2j2Yc9x Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Mon, 2023-11-06 at 17:44 -0800, Dongli Zhang wrote: > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (vcpu->arch.hv_clock.vers= ion && vcpu->kvm->arch.use_master_clock && > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static_cp= u_has(X86_FEATURE_CONSTANT_TSC)) { >=20 > If there any reason to use both vcpu->kvm->arch.use_master_clock and > X86_FEATURE_CONSTANT_TSC? Er, paranoia? I'll recheck. > I think even __get_kvmclock() would not require both cases at the same ti= me? >=20 > =C2=A03071=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ka->use_ma= ster_clock && > =C2=A03072=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 (static_cpu_has(X86_FEATURE_CONSTANT_TSC) || __this_cpu_read(cpu_= tsc_khz))) { >=20 But it does. That requires ka->use_master_clock (line 3071) AND that we know the current CPU's TSC frequency (line 3072). My code insists on the CONSTANT_TSC form of "knowing the current CPU's TSC frequency" because even with a get_cpu(), it's not clear the guest *was* running on this vCPU when it did its calculations. So I don't want to go anywhere near the !CONSTANT_TSC case; it can use the fallback. > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} else { > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0/* > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * Without CONSTANT_TSC, get_kvmclock_ns() is the only= option. > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * Also if the guest PV clock hasn't been set up yet, = as is > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * likely to be the case during migration when the vCP= U has > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * not been run yet. It would be possible to calculate= the > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * scaling factors properly in that case but there's n= ot much > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * point in doing so. The get_kvmclock_ns() drift accu= mulates > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * over time, so it's OK to use it at startup. Besides= , on > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * migration there's going to be a little bit of skew = in the > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * precise moment at which timers fire anyway. Often t= hey'll > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * be in the "past" by the time the VM is running agai= n after > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 * migration. > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 */ > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0guest_now =3D get_kvmclock_ns(vcpu->kvm); > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0kernel_now =3D ktime_get(); >=20 > 1. Can I assume the issue is still there if we fall into the "else" case?= That > is, the increasing inaccuracy as the VM has been up for longer and longer= time? >=20 > If that is the case, which may be better? >=20 > (1) get_kvmclock_ns(), or > (2) always get_kvmclock_base_ns() + ka->kvmclock_offset, when pvclock is = not > enabled, regardless whether master clock is used. At least, the inaccurar= y is > not going to increase over guest time? No, those are both wrong, and drifting further away over time. They are each *differently* wrong, which is why periodically clamping (1) to (2) is also broken, as previously discussed. I know you've got a patch to do that clamping more *often* which would slightly reduce the pain because the kvmclock wouldn't jump backwards so *far* each time... but it's still wrong to do so at all (in either direction). >=20 > 2. I see 3 scenarios here: >=20 > (1) vcpu->arch.hv_clock.version and master clock is used. >=20 > In this case, the bugfix looks good. >=20 > (2) The master clock is used. However, pv clock is not enabled. >=20 > In this case, the bug is not resolved? ... even the master clock is used. Under Xen the PV clock is always enabled. It's in the vcpu_info structure which is required for any kind of event channel setup. >=20 > (3) The master clock is not used. >=20 > We fall into get_kvmclock_base_ns() + ka->kvmclock_offset. The behavior i= s not > changed. This looks good. >=20 >=20 > Just from my own point: as this patch involves relatively complex changes= , I > would suggest resolve the issue, but not use a temporary solution :) >=20 This is the conversation I had with Paul on Tuesday, when he wanted me to fix up this "(3) / behaviour is not changed" case. And yes, I argued that we *don't* want a temporary solution for this case. Because yes: > (I see you mentioned that you will be back with get_kvmclock_ns()) We need to fix get_kvmclock_ns() anyway. The systemic drift *and* the fact that we periodically clamp it to a different clock and make it jump. I was working on the former and have something half-done but was preempted by the realisation that the QEMU soft freeze is today, and I needed to flush my QEMU patch queue. But even once we fix get_kvmclock_ns(), *this* patch stands. Because it *also* addresses the "now" problem, where we get the time by one clock ... and then some time passes ... and we get the time by another clock, and subtract one from the other as if they were the *same* time. Using kvm_get_monotonic_and_clockread() gives us a single TSC read corresponding to the CLOCK_MONOTONIC time, from which we can calculate the kvmclock time. We just *happen* to calculate it correctly here, unlike anywhere else in KVM. > Based on your bug fix, I see the below cases: >=20 > If master clock is not used: > =C2=A0=C2=A0=C2=A0 get_kvmclock_base_ns() + ka->kvmclock_offset >=20 > If master clock is used: > =C2=A0=C2=A0=C2=A0 If pvclock is enabled: > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 use the &vcpu->arch.hv_clock t= o get current guest time > =C2=A0=C2=A0=C2=A0 Else > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 create a temporary hv_clock, b= ased on masterclock. I don't want to do that last 'else' clause yet, because that feels like a temporary workaround. It should be enough to call get_kvmclock_ns(), once we fix it. --=-jonb5B2Fg8DNd2j2Yc9x Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Disposition: attachment; filename="smime.p7s" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCEkQw ggYQMIID+KADAgECAhBNlCwQ1DvglAnFgS06KwZPMA0GCSqGSIb3DQEBDAUAMIGIMQswCQYDVQQG EwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoT FVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTAeFw0xODExMDIwMDAwMDBaFw0zMDEyMzEyMzU5NTlaMIGWMQswCQYDVQQG EwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYD VQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50 aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAyjztlApB/975Rrno1jvm2pK/KxBOqhq8gr2+JhwpKirSzZxQgT9tlC7zl6hn1fXjSo5MqXUf ItMltrMaXqcESJuK8dtK56NCSrq4iDKaKq9NxOXFmqXX2zN8HHGjQ2b2Xv0v1L5Nk1MQPKA19xeW QcpGEGFUUd0kN+oHox+L9aV1rjfNiCj3bJk6kJaOPabPi2503nn/ITX5e8WfPnGw4VuZ79Khj1YB rf24k5Ee1sLTHsLtpiK9OjG4iQRBdq6Z/TlVx/hGAez5h36bBJMxqdHLpdwIUkTqT8se3ed0PewD ch/8kHPo5fZl5u1B0ecpq/sDN/5sCG52Ds+QU5O5EwIDAQABo4IBZDCCAWAwHwYDVR0jBBgwFoAU U3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFAnA8vwL2pTbX/4r36iZQs/J4K0AMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0G CSqGSIb3DQEBDAUAA4ICAQBBRHUAqznCFfXejpVtMnFojADdF9d6HBA4kMjjsb0XMZHztuOCtKF+ xswhh2GqkW5JQrM8zVlU+A2VP72Ky2nlRA1GwmIPgou74TZ/XTarHG8zdMSgaDrkVYzz1g3nIVO9 IHk96VwsacIvBF8JfqIs+8aWH2PfSUrNxP6Ys7U0sZYx4rXD6+cqFq/ZW5BUfClN/rhk2ddQXyn7 kkmka2RQb9d90nmNHdgKrwfQ49mQ2hWQNDkJJIXwKjYA6VUR/fZUFeCUisdDe/0ABLTI+jheXUV1 eoYV7lNwNBKpeHdNuO6Aacb533JlfeUHxvBz9OfYWUiXu09sMAviM11Q0DuMZ5760CdO2VnpsXP4 KxaYIhvqPqUMWqRdWyn7crItNkZeroXaecG03i3mM7dkiPaCkgocBg0EBYsbZDZ8bsG3a08LwEsL 1Ygz3SBsyECa0waq4hOf/Z85F2w2ZpXfP+w8q4ifwO90SGZZV+HR/Jh6rEaVPDRF/CEGVqR1hiuQ OZ1YL5ezMTX0ZSLwrymUE0pwi/KDaiYB15uswgeIAcA6JzPFf9pLkAFFWs1QNyN++niFhsM47qod x/PL+5jR87myx5uYdBEQkkDc+lKB1Wct6ucXqm2EmsaQ0M95QjTmy+rDWjkDYdw3Ms6mSWE3Bn7i 5ZgtwCLXgAIe5W8mybM2JzCCBhQwggT8oAMCAQICEQDGvhmWZ0DEAx0oURL6O6l+MA0GCSqGSIb3 DQEBCwUAMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNlY3RpZ28g UlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMB4XDTIyMDEwNzAw MDAwMFoXDTI1MDEwNjIzNTk1OVowJDEiMCAGCSqGSIb3DQEJARYTZHdtdzJAaW5mcmFkZWFkLm9y ZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3GpC2bomUqk+91wLYBzDMcCj5C9m6 oZaHwvmIdXftOgTbCJXADo6G9T7BBAebw2JV38EINgKpy/ZHh7htyAkWYVoFsFPrwHounto8xTsy SSePMiPlmIdQ10BcVSXMUJ3Juu16GlWOnAMJY2oYfEzmE7uT9YgcBqKCo65pTFmOnR/VVbjJk4K2 xE34GC2nAdUQkPFuyaFisicc6HRMOYXPuF0DuwITEKnjxgNjP+qDrh0db7PAjO1D4d5ftfrsf+kd RR4gKVGSk8Tz2WwvtLAroJM4nXjNPIBJNT4w/FWWc/5qPHJy2U+eITZ5LLE5s45mX2oPFknWqxBo bQZ8a9dsZ3dSPZBvE9ZrmtFLrVrN4eo1jsXgAp1+p7bkfqd3BgBEmfsYWlBXO8rVXfvPgLs32VdV NZxb/CDWPqBsiYv0Hv3HPsz07j5b+/cVoWqyHDKzkaVbxfq/7auNVRmPB3v5SWEsH8xi4Bez2V9U KxfYCnqsjp8RaC2/khxKt0A552Eaxnz/4ly/2C7wkwTQnBmdlFYhAflWKQ03Ufiu8t3iBE3VJbc2 5oMrglj7TRZrmKq3CkbFnX0fyulB+kHimrt6PIWn7kgyl9aelIl6vtbhMA+l0nfrsORMa4kobqQ5 C5rveVgmcIad67EDa+UqEKy/GltUwlSh6xy+TrK1tzDvAgMBAAGjggHMMIIByDAfBgNVHSMEGDAW gBQJwPL8C9qU21/+K9+omULPyeCtADAdBgNVHQ4EFgQUzMeDMcimo0oz8o1R1Nver3ZVpSkwDgYD VR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMC MEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQEBMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGln by5jb20vQ1BTMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGln b1JTQUNsaWVudEF1dGhlbnRpY2F0aW9uYW5kU2VjdXJlRW1haWxDQS5jcmwwgYoGCCsGAQUFBwEB BH4wfDBVBggrBgEFBQcwAoZJaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNBQ2xpZW50 QXV0aGVudGljYXRpb25hbmRTZWN1cmVFbWFpbENBLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29j c3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETZHdtdzJAaW5mcmFkZWFkLm9yZzANBgkqhkiG9w0B AQsFAAOCAQEAyW6MUir5dm495teKqAQjDJwuFCi35h4xgnQvQ/fzPXmtR9t54rpmI2TfyvcKgOXp qa7BGXNFfh1JsqexVkIqZP9uWB2J+uVMD+XZEs/KYNNX2PvIlSPrzIB4Z2wyIGQpaPLlYflrrVFK v9CjT2zdqvy2maK7HKOQRt3BiJbVG5lRiwbbygldcALEV9ChWFfgSXvrWDZspnU3Gjw/rMHrGnql Htlyebp3pf3fSS9kzQ1FVtVIDrL6eqhTwJxe+pXSMMqFiN0whpBtXdyDjzBtQTaZJ7zTT/vlehc/ tDuqZwGHm/YJy883Ll+GP3NvOkgaRGWEuYWJJ6hFCkXYjyR9IzCCBhQwggT8oAMCAQICEQDGvhmW Z0DEAx0oURL6O6l+MA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0 ZWQxPjA8BgNVBAMTNVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJl IEVtYWlsIENBMB4XDTIyMDEwNzAwMDAwMFoXDTI1MDEwNjIzNTk1OVowJDEiMCAGCSqGSIb3DQEJ ARYTZHdtdzJAaW5mcmFkZWFkLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3 GpC2bomUqk+91wLYBzDMcCj5C9m6oZaHwvmIdXftOgTbCJXADo6G9T7BBAebw2JV38EINgKpy/ZH h7htyAkWYVoFsFPrwHounto8xTsySSePMiPlmIdQ10BcVSXMUJ3Juu16GlWOnAMJY2oYfEzmE7uT 9YgcBqKCo65pTFmOnR/VVbjJk4K2xE34GC2nAdUQkPFuyaFisicc6HRMOYXPuF0DuwITEKnjxgNj P+qDrh0db7PAjO1D4d5ftfrsf+kdRR4gKVGSk8Tz2WwvtLAroJM4nXjNPIBJNT4w/FWWc/5qPHJy 2U+eITZ5LLE5s45mX2oPFknWqxBobQZ8a9dsZ3dSPZBvE9ZrmtFLrVrN4eo1jsXgAp1+p7bkfqd3 BgBEmfsYWlBXO8rVXfvPgLs32VdVNZxb/CDWPqBsiYv0Hv3HPsz07j5b+/cVoWqyHDKzkaVbxfq/ 7auNVRmPB3v5SWEsH8xi4Bez2V9UKxfYCnqsjp8RaC2/khxKt0A552Eaxnz/4ly/2C7wkwTQnBmd lFYhAflWKQ03Ufiu8t3iBE3VJbc25oMrglj7TRZrmKq3CkbFnX0fyulB+kHimrt6PIWn7kgyl9ae lIl6vtbhMA+l0nfrsORMa4kobqQ5C5rveVgmcIad67EDa+UqEKy/GltUwlSh6xy+TrK1tzDvAgMB AAGjggHMMIIByDAfBgNVHSMEGDAWgBQJwPL8C9qU21/+K9+omULPyeCtADAdBgNVHQ4EFgQUzMeD Mcimo0oz8o1R1Nver3ZVpSkwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw FAYIKwYBBQUHAwQGCCsGAQUFBwMCMEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQEBMCUwIwYIKwYB BQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9j cmwuc2VjdGlnby5jb20vU2VjdGlnb1JTQUNsaWVudEF1dGhlbnRpY2F0aW9uYW5kU2VjdXJlRW1h aWxDQS5jcmwwgYoGCCsGAQUFBwEBBH4wfDBVBggrBgEFBQcwAoZJaHR0cDovL2NydC5zZWN0aWdv LmNvbS9TZWN0aWdvUlNBQ2xpZW50QXV0aGVudGljYXRpb25hbmRTZWN1cmVFbWFpbENBLmNydDAj BggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETZHdtdzJAaW5m cmFkZWFkLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAyW6MUir5dm495teKqAQjDJwuFCi35h4xgnQv Q/fzPXmtR9t54rpmI2TfyvcKgOXpqa7BGXNFfh1JsqexVkIqZP9uWB2J+uVMD+XZEs/KYNNX2PvI lSPrzIB4Z2wyIGQpaPLlYflrrVFKv9CjT2zdqvy2maK7HKOQRt3BiJbVG5lRiwbbygldcALEV9Ch WFfgSXvrWDZspnU3Gjw/rMHrGnqlHtlyebp3pf3fSS9kzQ1FVtVIDrL6eqhTwJxe+pXSMMqFiN0w hpBtXdyDjzBtQTaZJ7zTT/vlehc/tDuqZwGHm/YJy883Ll+GP3NvOkgaRGWEuYWJJ6hFCkXYjyR9 IzGCBMcwggTDAgEBMIGsMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVz dGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMT NVNlY3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBAhEA xr4ZlmdAxAMdKFES+jupfjANBglghkgBZQMEAgEFAKCCAeswGAYJKoZIhvcNAQkDMQsGCSqGSIb3 DQEHATAcBgkqhkiG9w0BCQUxDxcNMjMxMTA3MDgxNzQ4WjAvBgkqhkiG9w0BCQQxIgQgb5anloGU JBzi9l8+1dfhEa4yGM1uXKiX0RabQ3jOZJgwgb0GCSsGAQQBgjcQBDGBrzCBrDCBljELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYG A1UEChMPU2VjdGlnbyBMaW1pdGVkMT4wPAYDVQQDEzVTZWN0aWdvIFJTQSBDbGllbnQgQXV0aGVu dGljYXRpb24gYW5kIFNlY3VyZSBFbWFpbCBDQQIRAMa+GZZnQMQDHShREvo7qX4wgb8GCyqGSIb3 DQEJEAILMYGvoIGsMIGWMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVy MRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxPjA8BgNVBAMTNVNl Y3RpZ28gUlNBIENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBAhEAxr4Z lmdAxAMdKFES+jupfjANBgkqhkiG9w0BAQEFAASCAgAxE+tTqJ7og4GBL7iKL6KgfEU/FL2dDkwV CxywXrkKj4twGDBUq9d454AXXoLYmUzRXfC4VUu5kYidTRIk/uVh8Sa6x7QdNuy/BxkAzCymFR4d 6vZKvNdgad6AFeowJR2Qi1/Am8puL48K2VjkmOBAUnnT33R9P+GJ+w+7gHnWnwX0CzvNF1RenuGS 76RU4hXJQ33cw2TUcdm3zdwhr6UuZlajco8L1180dxUio9bIPMKUjGGko+HX3Ver8QARjgN9Mmn6 61xWY71EUxNv67l8RTj935ZMonsyYhUBdegg5/2A6jnPQp8hsYCXzolVWLHtkzabta2yjqdz4wKB alQXrIFt6hGd9vKHaidqNPOXsCg3nCS7o+Q4OXoZABiybaItRfPsGOlNw2mybWIUXRBKVrEi73ww YzT7m+TJUiI5TdNp2Jx0hCu2ZFtko7US6xqWb3Lxvi3SjUx3xm/qLYuKindCffSGphy7NotBd3N4 KO4num6aGaxwhlScJBqSaIKK/dgAHWI4b9QeFcMyL8EoCQd3UeZTRQzLPBCiD8ryObQy9CYtIB6K V3mvf7vysx+5pazS1WPjSNe7M4aMrYIxFNtrZaCZLg1FrPNcuTYupRySGsYQ7CDTizMDqv+ilgVp TBlMCei5EmFq8Qj+ZRU2NOZmd51U3msBvKaJu/H5aAAAAAAAAA== --=-jonb5B2Fg8DNd2j2Yc9x--