From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A8DFB400E19 for ; Wed, 27 May 2026 12:29:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779884947; cv=none; b=Atn5bUYFr2jBVQCvZwEFi+LkjBkev5X8ihgyXc8gl8+J/zrrvIhZVXsy6wxSE1x3hgkFK7hrOAzS8cuWumZn54zeRp4aQeTAL/fUV0N/FtvfS0IBdHAy+KhpnSqF/lsALzsO0pT+f2Wu4/PTerMMclubHetV9VPwVaSzzg9E+G8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779884947; c=relaxed/simple; bh=Nuble9OjqwPU5AoCFd7TRtazcS+q0pts+ppCwaNfDJA=; h=Message-ID:Subject:From:To:Cc:Date:In-Reply-To:References: Content-Type:MIME-Version; b=lJztYRhHuOH5jpzmWB4tu8HIGsDp079SIit1X1WcJqfvIWAzOaCrodt0iC3xMn5ertepNVjffiwGQ5bfZfxic2BYSjIf3COgWVZ9ovqCevBWrpn7b8rpEwT75EJFyaHxh8SKVeTp6x9R4EGx+y1ckiBqfPRzSeYQX2Bc2cWenuI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=v4roVZG7; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="v4roVZG7" 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=oRpmnEJVdN5ilKf8gB++MvtmHN2Ty60Ivu3aPM35too=; b=v4roVZG72zsFanWlMWjnfxNaZv 5loy9DZqh/L5q1e5K7g8tZ7mPSl7EqMWL3CHooETPysk0o8CU6rRU1376yCuQYFrMClxumE6xnTDB T0cXc/0FF0AD8MddU5AN5FfIdk+InVAqzp+ezDSlGqFXsUiRoT1nDfEBRUe9NECApIxHazxaBHQqM /QiBw+DgUFPtAg775RBCPiqkq9W46+6nzZzJMT1fOYn942arv3e+QgX7f7ps6W2ffU+aDm7RxbE5v HiJSfmQPum5qHtQVvmGTyswwvISPnZXlTFxyLEvVHw1qTbNCPMhES/VJnMvYRtl26WO6hQxbBzbX3 BpgVFJ7Q==; Received: from 54-240-197-239.amazon.com ([54.240.197.239] helo=lhr50-en-acc-sw5.amazon.com) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wSDN1-00000002LkQ-1Jl7; Wed, 27 May 2026 12:28:23 +0000 Message-ID: Subject: Re: [RFC PATCH v2 0/8] timekeeping: Fix draft tracking precision and add feed-forward discipline via vmclock From: David Woodhouse To: Miroslav Lichvar Cc: Richard Cochran , Wen Gu , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , Thomas =?ISO-8859-1?Q?Wei=DFschuh?= , Arnd Bergmann , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org, Marcelo Tosatti Date: Wed, 27 May 2026 13:28:15 +0100 In-Reply-To: References: <0d32da75fa88c92ac0225ef23a9045afdf2ac9fe.camel@infradead.org> <5323ed2a67d3a72d37f98ba04f2444841bc7bfae.camel@infradead.org> <69a953d665738f5021e511c44e193dd832ba009b.camel@infradead.org> Content-Type: multipart/signed; micalg="sha-256"; protocol="application/pkcs7-signature"; boundary="=-OruiMebHExXZe/oS0OYk" User-Agent: Evolution 3.52.3-0ubuntu1.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html --=-OruiMebHExXZe/oS0OYk Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, 2026-05-27 at 09:46 +0200, Miroslav Lichvar wrote: > On Tue, May 26, 2026 at 11:00:28AM +0100, David Woodhouse wrote: > > Let us assume that userspace, either from vmclock or direct discipline > > of the arch counter against external sources, has:=20 > > =C2=A0 =E2=80=A2 Reference time T. > > =C2=A0 =E2=80=A2 Arch counter value at time T. > > =C2=A0 =E2=80=A2 Period of a single arch counter tick. > >=20 > > This translates fairly directly into the kernel's tick_length and > > time_offset. But *only* if you know cycle_interval, ntp_error and other > > details. Which is why my timekeeping_set_reference() takes the > > information in that form, and then translates it within the core > > timekeeping. > >=20 > > If you can show me how to do that with adjtimex(), that would be great. >=20 > tick_length can be set by the adjtimex() modes ADJ_FREQUENCY (in > scaled units of 1/65536 ppm up to 500 ppm) and ADJ_TICK (in > microseconds per 1/USER_HZ tick). >=20 > time_offset can be set by the ADJ_OFFSET mode. The PLL needs to be > enabled first by setting the STA_PLL status (ADJ_STATUS mode) and also > the STA_FREQHOLD flag needs to be set to avoid changing the PLL > frequency. >=20 > The ntp_error and other details need to be exposed to userspace. Maybe > in the same API that will be used for reporting the time and frequency > offsets between system clocks. I don't think that's enough. Consider the fact that I've just had to apply a correction to my existing timekeeping_set_reference() proof of concept to make it calculate and set time_offset for the moment of the *next* tick, instead of at the *prior* tick: --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2443,13 +2443,17 @@ int timekeeping_set_reference(const struct tk_refer= ence *ref) 32 + ref->period_shift); ntp_set_tick_length(tk->id, new_tl); =20 - /* Compute phase offset at cycle_last and set time_offset to slew *= / - delta =3D tk->tkr_mono.cycle_last - ref->counter_value; + /* + * Compute phase offset at the *next* tick boundary, where the new + * tick_length will first take effect. Using cycle_last would leave + * a gap where the old mult accumulates additional phase error. + */ + delta =3D tk->tkr_mono.cycle_last + tk->cycle_interval - ref->count= er_value; ref_frac =3D mul_u64_u64_shr(delta, ref->period_frac_sec, ref->period_shift) + ref->time_frac_sec; ref_err =3D (s64)mul_u64_u64_shr(ref_frac, (u64)NSEC_PER_SEC << tk->tkr_mono.shift, 64) - - (s64)tk->tkr_mono.xtime_nsec; + (s64)(tk->tkr_mono.xtime_nsec + tk->xtime_interval); ntp_set_time_offset(tk->id, ref_err >> tk->tkr_mono.shift); tk->ntp_error =3D 0; =20 I just don't think we can do this from userspace, and I don't really see the *need* to. It seems cleaner just to have clock_set_time_reference() which matches what clock_get_time_reference() exports, instead of trying to shoe-horn it into the adjtimex API and force userspace to jump through hoops to reverse engineer things and apply racy adjustments. > > As chrony introduces a change on the host, QEMU propagates that to the > > guest (the vmclock: line is from QEMU), and the guest adjusts > > accordingly. And then converges *really* slowly, as even setting the > > time constant to 0 gives a half-life for time_offset of about 11 > > seconds. >=20 > A simple linear slew would be better for this. The offset is accurate, > there is no need for filtering. Perhaps so, although I was trying to avoid making any real changes to the core timekeeping other than fixing its accounting. In fact if I set the time constant to zero *and* set STA_NANO, that gives a half-life of about 2.4 seconds which should be fine. > > > I think a better solution is scaling of the clocksource, i.e. a layer > > > below the realtime clock. An additional multiplier applied in HW or > > > SW. That would address the problem for all system clocks, not just th= e > > > realtime clock. adjtimex() changes are applied on top of that, they > > > are not in conflict. > >=20 > > But we literally already have a way to 'scale' the counter in order to > > derive CLOCK_MONOTONIC/CLOCK_REALTIME: the kernel's timekeeping code. > > Currently driven *only* by NTP/adjtimex(). >=20 > I see that as a different purpose than guest migrations. A migrated > guest should have its clocksource frequency corrected while the clock > is controlled by NTP/PTP. If this mechanism was shared, that would not > be possible. If the *host* wants to use hardware frequency scaling to try to mask the effects of live migration by making the effective frequency of the TSC on the destination match the effective frequency of the TSC on the source at the moment of migration, then that's a choice for the host. I don't think it's likely to happen, as it brings a bunch of complexity on the host side for relatively little benefit. I don't think there's *any* chance of Linux ever doing the scaling of the clocksources on the software side. =20 > > Are you suggesting that the actual clocksource driver in the kernel for > > e.g. CSID_ARM_ARCH_COUNTER should *scale* the results it returns, > > instead of giving raw counter reads? So we have some NTP-like process > > to adjust each clocksource, in *addition* to the core kernel > > timekeeping? >=20 > Not so much NTP-like. There would be no mult dithering or phase > adjustments, only frequency. So clocksources would no longer be monotonic? > > And then those skewed clocksource values are only > > meaningful under a seqlock like the existing kernel timekeeper values > > are valid under the tk_data.seq seqlock? >=20 > I guess you are implying here this SW-fallback scaling would have a > significant impact on the performance. Could it not be applied at the > same time as the normal multiplier in the conversion to nanoseconds? >=20 > > And would we have a separate way to get real value, to use for > > CLOCK_MONOTONIC_RAW? >=20 > All system clocks should be scaled, that's my point. I'm not sure you'll achieve universal consensus on the concept that CLOCK_MONOTONIC_RAW should be skewed. I suspect it's best to ignore the special case of live migration for the moment. Treat it like any other update from the host which adjusts the frequency and phase_offset. It's up to the host to make it appear as if the guest TSC continued to tick at the source frequency while the guest was in the ether, and provide a vmclock update the moment it starts on the new host, letting the guest know the new frequency. The frequency adjustment is applied almost immediately (via an interrupt, directly *within* the kernel in my proof of concept case), and the resulting phase delta should be tiny. --=-OruiMebHExXZe/oS0OYk Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Disposition: attachment; filename="smime.p7s" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCD9Aw ggSOMIIDdqADAgECAhAOmiw0ECVD4cWj5DqVrT9PMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYT AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAi BgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yNDAxMzAwMDAwMDBaFw0zMTEx MDkyMzU5NTlaMEExCzAJBgNVBAYTAkFVMRAwDgYDVQQKEwdWZXJva2V5MSAwHgYDVQQDExdWZXJv a2V5IFNlY3VyZSBFbWFpbCBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMjvgLKj jfhCFqxYyRiW8g3cNFAvltDbK5AzcOaR7yVzVGadr4YcCVxjKrEJOgi7WEOH8rUgCNB5cTD8N/Et GfZI+LGqSv0YtNa54T9D1AWJy08ZKkWvfGGIXN9UFAPMJ6OLLH/UUEgFa+7KlrEvMUupDFGnnR06 aDJAwtycb8yXtILj+TvfhLFhafxroXrflspavejQkEiHjNjtHnwbZ+o43g0/yxjwnarGI3kgcak7 nnI9/8Lqpq79tLHYwLajotwLiGTB71AGN5xK+tzB+D4eN9lXayrjcszgbOv2ZCgzExQUAIt98mre 8EggKs9mwtEuKAhYBIP/0K6WsoMnQCcCAwEAAaOCAVwwggFYMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFIlICOogTndrhuWByNfhjWSEf/xwMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6en IZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDBAYIKwYBBQUHAwIweQYI KwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYB BQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RD QS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 QXNzdXJlZElEUm9vdENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEB ACiagCqvNVxOfSd0uYfJMiZsOEBXAKIR/kpqRp2YCfrP4Tz7fJogYN4fxNAw7iy/bPZcvpVCfe/H /CCcp3alXL0I8M/rnEnRlv8ItY4MEF+2T/MkdXI3u1vHy3ua8SxBM8eT9LBQokHZxGUX51cE0kwa uEOZ+PonVIOnMjuLp29kcNOVnzf8DGKiek+cT51FvGRjV6LbaxXOm2P47/aiaXrDD5O0RF5SiPo6 xD1/ClkCETyyEAE5LRJlXtx288R598koyFcwCSXijeVcRvBB1cNOLEbg7RMSw1AGq14fNe2cH1HG W7xyduY/ydQt6gv5r21mDOQ5SaZSWC/ZRfLDuEYwggWbMIIEg6ADAgECAhAH5JEPagNRXYDiRPdl c1vgMA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAkFVMRAwDgYDVQQKEwdWZXJva2V5MSAwHgYD VQQDExdWZXJva2V5IFNlY3VyZSBFbWFpbCBHMjAeFw0yNDEyMzAwMDAwMDBaFw0yODAxMDQyMzU5 NTlaMB4xHDAaBgNVBAMME2R3bXcyQGluZnJhZGVhZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDali7HveR1thexYXx/W7oMk/3Wpyppl62zJ8+RmTQH4yZeYAS/SRV6zmfXlXaZ sNOE6emg8WXLRS6BA70liot+u0O0oPnIvnx+CsMH0PD4tCKSCsdp+XphIJ2zkC9S7/yHDYnqegqt w4smkqUqf0WX/ggH1Dckh0vHlpoS1OoxqUg+ocU6WCsnuz5q5rzFsHxhD1qGpgFdZEk2/c//ZvUN i12vPWipk8TcJwHw9zoZ/ZrVNybpMCC0THsJ/UEVyuyszPtNYeYZAhOJ41vav1RhZJzYan4a1gU0 kKBPQklcpQEhq48woEu15isvwWh9/+5jjh0L+YNaN0I//nHSp6U9COUG9Z0cvnO8FM6PTqsnSbcc 0j+GchwOHRC7aP2t5v2stVx3KbptaYEzi4MQHxm/0+HQpMEVLLUiizJqS4PWPU6zfQTOMZ9uLQRR ci+c5xhtMEBszlQDOvEQcyEG+hc++fH47K+MmZz21bFNfoBxLP6bjR6xtPXtREF5lLXxp+CJ6KKS blPKeVRg/UtyJHeFKAZXO8Zeco7TZUMVHmK0ZZ1EpnZbnAhKE19Z+FJrQPQrlR0gO3lBzuyPPArV hvWxjlO7S4DmaEhLzarWi/ze7EGwWSuI2eEa/8zU0INUsGI4ywe7vepQz7IqaAovAX0d+f1YjbmC VsAwjhLmveFjNwIDAQABo4IBsDCCAawwHwYDVR0jBBgwFoAUiUgI6iBOd2uG5YHI1+GNZIR//HAw HQYDVR0OBBYEFFxiGptwbOfWOtMk5loHw7uqWUOnMDAGA1UdEQQpMCeBE2R3bXcyQGluZnJhZGVh ZC5vcmeBEGRhdmlkQHdvb2Rob3Uuc2UwFAYDVR0gBA0wCzAJBgdngQwBBQEBMA4GA1UdDwEB/wQE AwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwewYDVR0fBHQwcjA3oDWgM4YxaHR0 cDovL2NybDMuZGlnaWNlcnQuY29tL1Zlcm9rZXlTZWN1cmVFbWFpbEcyLmNybDA3oDWgM4YxaHR0 cDovL2NybDQuZGlnaWNlcnQuY29tL1Zlcm9rZXlTZWN1cmVFbWFpbEcyLmNybDB2BggrBgEFBQcB AQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0 aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL1Zlcm9rZXlTZWN1cmVFbWFpbEcyLmNydDANBgkq hkiG9w0BAQsFAAOCAQEAQXc4FPiPLRnTDvmOABEzkIumojfZAe5SlnuQoeFUfi+LsWCKiB8Uextv iBAvboKhLuN6eG/NC6WOzOCppn4mkQxRkOdLNThwMHW0d19jrZFEKtEG/epZ/hw/DdScTuZ2m7im 8ppItAT6GXD3aPhXkXnJpC/zTs85uNSQR64cEcBFjjoQDuSsTeJ5DAWf8EMyhMuD8pcbqx5kRvyt JPsWBQzv1Dsdv2LDPLNd/JUKhHSgr7nbUr4+aAP2PHTXGcEBh8lTeYea9p4d5k969pe0OHYMV5aL xERqTagmSetuIwolkAuBCzA9vulg8Y49Nz2zrpUGfKGOD0FMqenYxdJHgDCCBZswggSDoAMCAQIC EAfkkQ9qA1FdgOJE92VzW+AwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UEBhMCQVUxEDAOBgNVBAoT B1Zlcm9rZXkxIDAeBgNVBAMTF1Zlcm9rZXkgU2VjdXJlIEVtYWlsIEcyMB4XDTI0MTIzMDAwMDAw MFoXDTI4MDEwNDIzNTk1OVowHjEcMBoGA1UEAwwTZHdtdzJAaW5mcmFkZWFkLm9yZzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANqWLse95HW2F7FhfH9bugyT/danKmmXrbMnz5GZNAfj Jl5gBL9JFXrOZ9eVdpmw04Tp6aDxZctFLoEDvSWKi367Q7Sg+ci+fH4KwwfQ8Pi0IpIKx2n5emEg nbOQL1Lv/IcNiep6Cq3DiyaSpSp/RZf+CAfUNySHS8eWmhLU6jGpSD6hxTpYKye7PmrmvMWwfGEP WoamAV1kSTb9z/9m9Q2LXa89aKmTxNwnAfD3Ohn9mtU3JukwILRMewn9QRXK7KzM+01h5hkCE4nj W9q/VGFknNhqfhrWBTSQoE9CSVylASGrjzCgS7XmKy/BaH3/7mOOHQv5g1o3Qj/+cdKnpT0I5Qb1 nRy+c7wUzo9OqydJtxzSP4ZyHA4dELto/a3m/ay1XHcpum1pgTOLgxAfGb/T4dCkwRUstSKLMmpL g9Y9TrN9BM4xn24tBFFyL5znGG0wQGzOVAM68RBzIQb6Fz758fjsr4yZnPbVsU1+gHEs/puNHrG0 9e1EQXmUtfGn4InoopJuU8p5VGD9S3Ikd4UoBlc7xl5yjtNlQxUeYrRlnUSmdlucCEoTX1n4UmtA 9CuVHSA7eUHO7I88CtWG9bGOU7tLgOZoSEvNqtaL/N7sQbBZK4jZ4Rr/zNTQg1SwYjjLB7u96lDP sipoCi8BfR35/ViNuYJWwDCOEua94WM3AgMBAAGjggGwMIIBrDAfBgNVHSMEGDAWgBSJSAjqIE53 a4blgcjX4Y1khH/8cDAdBgNVHQ4EFgQUXGIam3Bs59Y60yTmWgfDu6pZQ6cwMAYDVR0RBCkwJ4ET ZHdtdzJAaW5mcmFkZWFkLm9yZ4EQZGF2aWRAd29vZGhvdS5zZTAUBgNVHSAEDTALMAkGB2eBDAEF AQEwDgYDVR0PAQH/BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDB7BgNVHR8E dDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vVmVyb2tleVNlY3VyZUVtYWlsRzIu Y3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vVmVyb2tleVNlY3VyZUVtYWlsRzIu Y3JsMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t MEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vVmVyb2tleVNlY3VyZUVt YWlsRzIuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBBdzgU+I8tGdMO+Y4AETOQi6aiN9kB7lKWe5Ch 4VR+L4uxYIqIHxR7G2+IEC9ugqEu43p4b80LpY7M4KmmfiaRDFGQ50s1OHAwdbR3X2OtkUQq0Qb9 6ln+HD8N1JxO5nabuKbymki0BPoZcPdo+FeRecmkL/NOzzm41JBHrhwRwEWOOhAO5KxN4nkMBZ/w QzKEy4PylxurHmRG/K0k+xYFDO/UOx2/YsM8s138lQqEdKCvudtSvj5oA/Y8dNcZwQGHyVN5h5r2 nh3mT3r2l7Q4dgxXlovERGpNqCZJ624jCiWQC4ELMD2+6WDxjj03PbOulQZ8oY4PQUyp6djF0keA MYIDuzCCA7cCAQEwVTBBMQswCQYDVQQGEwJBVTEQMA4GA1UEChMHVmVyb2tleTEgMB4GA1UEAxMX VmVyb2tleSBTZWN1cmUgRW1haWwgRzICEAfkkQ9qA1FdgOJE92VzW+AwDQYJYIZIAWUDBAIBBQCg ggE3MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI2MDUyNzEyMjgx NVowLwYJKoZIhvcNAQkEMSIEIL7ODLMrmcFnsivj6Ss9lS33/q3/XHWM19AJTbjqeDRiMGQGCSsG AQQBgjcQBDFXMFUwQTELMAkGA1UEBhMCQVUxEDAOBgNVBAoTB1Zlcm9rZXkxIDAeBgNVBAMTF1Zl cm9rZXkgU2VjdXJlIEVtYWlsIEcyAhAH5JEPagNRXYDiRPdlc1vgMGYGCyqGSIb3DQEJEAILMVeg VTBBMQswCQYDVQQGEwJBVTEQMA4GA1UEChMHVmVyb2tleTEgMB4GA1UEAxMXVmVyb2tleSBTZWN1 cmUgRW1haWwgRzICEAfkkQ9qA1FdgOJE92VzW+AwDQYJKoZIhvcNAQEBBQAEggIAuj5mT07Zye1t E/F/YzByg9VX9cqFErGcYzdY8ZQ1P8cMNcmIaDqq8MLdRVzPv0WsBCcoZTunT5YPppw9dzA8B21s nXKmNIdIL/beqxhfouGlPJP+TEZXw+5VD7gXTw/3nLha//WsBIhErfTEWB0Pj6AHfFVWeVig2B0X Z/EzHot4w7SIXzhmlFmzUvNFFNX+9dU9K2kWW/tgcunGKJw0tE4fxOcVjrkAVP3wOWo2r0hkdOw7 sou3AH4QmxBDmkRZvrwOgTlBGU+yA9gJzc+/MUSdQWWRbG+BgYrC+6R3kp47F5E8RJpM1iFb2mtA q4GJI2jHUGy2Xu1RxeS9LNgoA9rbbYl1pZUdqp59s+XqYm3eqdpoZrNmwTa49iaNVWWqui7aZhBS 5tvxcwl04juPwcF4echD7ogl2dtXAnbDgpbtS5ClJKMSpP5W+qpYSvdYwldXYIC0tHwdNxYHCqIc IE8+EHOiUXOORf8ATyyBKchFp/LaO0Tw4O/+zzUjVCB6I+aTK27LgWlBNIQK+Xug8J0UKduPUsva lJ4A7KGVenwBJ3VLN+gT15kWiM8Nenn20HYw/Ohj0b0vi03NSVQMEyFqwZ90Hxqz4+WWN1nz03i4 wGSyvtO50/FVMYHgS1Q95J9uVoP1qqkJaoqxHK0tkTIIGw3EiOluSB/ba3E/l+IAAAAAAAA= --=-OruiMebHExXZe/oS0OYk--