From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Mathias Dahl Newsgroups: gmane.emacs.devel Subject: Re: Abbrev suggestions - feedback appreciated Date: Sun, 17 May 2020 16:59:11 +0200 Message-ID: References: <871smeoalc.fsf@gnu.org> <87fuatmw71.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="000000000000b1b70305a5d94a3c" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="93236"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun May 17 16:59:55 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jaKlf-000OAz-Gl for ged-emacs-devel@m.gmane-mx.org; Sun, 17 May 2020 16:59:55 +0200 Original-Received: from localhost ([::1]:41584 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jaKle-0008NE-K6 for ged-emacs-devel@m.gmane-mx.org; Sun, 17 May 2020 10:59:54 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:45020) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jaKlB-0007xO-GA for emacs-devel@gnu.org; Sun, 17 May 2020 10:59:25 -0400 Original-Received: from mail-vs1-xe2e.google.com ([2607:f8b0:4864:20::e2e]:34005) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jaKlA-0001Fr-CE for emacs-devel@gnu.org; Sun, 17 May 2020 10:59:25 -0400 Original-Received: by mail-vs1-xe2e.google.com with SMTP id v26so4074852vsa.1 for ; Sun, 17 May 2020 07:59:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=u+tbyYZ8mZ6yKAA0DosP52dWxqZF9bsKEqXrKo2yWto=; b=f5BNTUFJNcQFpunQSe2NMvHCFrYTVHTcVdAenCK6474zBVXZi84TSkrTKMumurflEm h3zptUuZSaa5XpA5cA64PtFeCkbUFEatAYPHGOeesSKDXHKsZdcL4+vVfoH09VkpU3FF kxawUtNVM4+3WZANQy7Pk32+rAGqHcbOY4aDctn6LFzesCLfXuMmchDrYjVGc0GddN2K YWj9bxNp9SLJ/0J6OpfvCaSnapHdDSJTbsFCWnJEpt2Rt+fExvicUnc2iTkqY+/f5+fV XhbleB+FEOhbCK1myzakcRY9ePh9eNVdugPg6sZ1XrrOGKKcq3sY+C8c2NcWyu29jadr wPOA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=u+tbyYZ8mZ6yKAA0DosP52dWxqZF9bsKEqXrKo2yWto=; b=iIwm3NpQ8BgONFj+3fZ/82iNOjlxOk9ILuS5LlN/Bx+W1E/jcl3lfoHNzjjIWfNnwX bcgBKGkms+cCa5CFdN2BqvhtE9iGUbvdJoRO+xHrEYCVkalmvp2o200o/614wnBfInMC iUeT2HhkqDihUpt5ktFFQVeUjWuYAOu5NDPIj+VZIhy9YPCH62FuNh38okMe4ocLdf7e WRVQByyNOAHpt413izDLZA9ktt+zOihTtISevNiifdhwRcYgIFVBMRmXHUP/OEPJ53xj AJavy2bn0PWNYaAwD/J+LtD0k/D3glaKKSCVA2Ux+xQIfbyqoB7rAeM/8iP0yqlhGCuv tDOQ== X-Gm-Message-State: AOAM533WK72Jx+cL8YVkm8ZYQwZ7FeU68qLhRE5w5wX07/vIZzsPFiai 7nqUgujrK7VMhqembXnkPRY9/QnLljhW4EcIh2pmIg7tjSg= X-Google-Smtp-Source: ABdhPJwJgA/s5JOXBvdOngheim0XEpK5VwoZHN5yzrSopq+0ZurlvmbSY3CfLFCCjDG0oTyHe7DMVM99Y6yFALeLtw0= X-Received: by 2002:a67:ed51:: with SMTP id m17mr8340914vsp.158.1589727563198; Sun, 17 May 2020 07:59:23 -0700 (PDT) In-Reply-To: Received-SPF: pass client-ip=2607:f8b0:4864:20::e2e; envelope-from=mathias.dahl@gmail.com; helo=mail-vs1-xe2e.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_PASS=-0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:250609 Archived-At: --000000000000b1b70305a5d94a3c Content-Type: text/plain; charset="UTF-8" > > I'm not suggesting to implement > `abbrev-get-active-expansions` differently. > I'm suggesting to implement something else. I.e. > > (defmacro abbrev-do-active-expansions (VAR &rest BODY) > "Bind VAR to an active expansion and run BODY with it. > Repeat it for all active expansions." > ...) > > or > > (defun abbrev-mapc-active-expansions (FUNC) > "Call FUNC on each active expansion." > > This way you don't need to build a list of active expansions: you run > FUNC or BODY on each expansion when you encounter it. > Ah, of course, got it now! :) I tried a few versions of this now. I need to go through the complete list of active abbrevs/expansions since I want to find one that is valid and I also want to find the "best" one (according to what we discussed before). I defined 10,000 dummy abbrevs (a1 .. a10000) and used the profiler to compare memory usage and... I did not get any conclusive results. And between runs I get different memory values reported. If I can draw any conclusions at all it would be that the old version (that used another function to get the active abbrevs) and the new one (that does what needs to be done while collecting the active abbrevs) are more or less the same, from the perspective on memory consumption. Here is the original version, slightly modified. I added a new cache to make the abbrev-suggest-expansion-exist-at-point function not have to call buffer-substring for a certain length many times. (defun abbrev-suggest () "Suggest an abbrev to the user based on the text before point. Uses `abbrev-suggest-hint-threshold' to find out if the user should be informed about the existing abbrev." (interactive) (abbrev-suggest-previous-chars-clear) (let (abbrev-found) (dolist (expansion (abbrev-get-active-expansions)) (when (and (abbrev-suggest-above-threshold expansion) (abbrev-suggest-expansion-exist-at-point expansion)) (setq abbrev-found (abbrev-suggest-best-abbrev expansion abbrev-found)))) (when abbrev-found (abbrev-suggest-inform-user abbrev-found)))) One of the profiler runs: Function Bytes % - command-execute 6,191,706 99% - call-interactively 6,191,706 99% - funcall-interactively 6,191,706 99% + profiler-stop 3,178,331 51% - abbrev-suggest 3,012,912 48% - let 3,012,912 48% - let 3,012,760 48% - while 2,046,520 33% - let 1,704,376 27% - if 1,704,376 27% - and 1,704,376 27% - abbrev-suggest-expansion-exist-at-point 1,023,256 16% - string= 1,023,256 16% - abbrev-suggest-previous-chars 682,168 11% + let 1,048 0% - abbrev-get-active-expansions 966,240 15% - let 966,240 15% - let 966,240 15% - while 966,240 15% - let 966,240 15% - mapatoms 966,240 15% - # 870,144 14% - let 771,936 12% - symbol-value 675,840 10% - abbrev--symbol 483,648 7% + let* 289,344 4% + if 96,096 1% + if 152 0% Here is the new version: (defun abbrev-suggest () "Suggest an abbrev to the user based on the text before point. Uses `abbrev-suggest-hint-threshold' to find out if the user should be informed about the existing abbrev." (interactive) (abbrev-suggest-previous-chars-clear) (let (best-abbrev) (dolist (table (abbrev--active-tables-including-parents)) (mapatoms (lambda (e) (let ((value (symbol-value (abbrev--symbol e table))) abbrev) (when value (setq abbrev (cons value (symbol-name e))) (when (and (abbrev-suggest-above-threshold abbrev) (abbrev-suggest-expansion-exist-at-point abbrev)) (setq best-abbrev (abbrev-suggest-best-abbrev abbrev best-abbrev)))))) table)) (when best-abbrev (abbrev-suggest-inform-user best-abbrev)))) Here is a run with the profiler of the above: Function Bytes % - command-execute 4,996,751 99% - call-interactively 4,996,751 99% - funcall-interactively 4,996,751 99% + profiler-stop 3,179,816 63% - abbrev-suggest 1,816,472 36% - let 1,816,472 36% - let 1,815,264 36% - while 1,815,264 36% - let 1,815,264 36% - mapatoms 1,815,264 36% - # 1,815,264 36% - let 284,064 5% - if 284,064 5% - progn 284,064 5% setq 284,064 5% + if 1,208 0% profiler-start 463 0% Are these numbers as expected? Sometimes, all of a sudden, regardless of what version of the function I use, the memory consumed by abbrev-suggest can be as low as 80,000 bytes. What have happened then? Something the GC does? Thanks! /Mathias --000000000000b1b70305a5d94a3c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: base64 PGRpdiBkaXI9Imx0ciI+PGRpdiBjbGFzcz0iZ21haWxfcXVvdGUiPjxibG9ja3F1b3RlIGNsYXNz PSJnbWFpbF9xdW90ZSIgc3R5bGU9Im1hcmdpbjowcHggMHB4IDBweCAwLjhleDtib3JkZXItbGVm dDoxcHggc29saWQgcmdiKDIwNCwyMDQsMjA0KTtwYWRkaW5nLWxlZnQ6MWV4Ij5JJiMzOTttIG5v dCBzdWdnZXN0aW5nIHRvIGltcGxlbWVudDxicj4NCmBhYmJyZXYtZ2V0LWFjdGl2ZS1leHBhbnNp b25zYCBkaWZmZXJlbnRseS48YnI+DQpJJiMzOTttIHN1Z2dlc3RpbmcgdG8gaW1wbGVtZW50IHNv bWV0aGluZyBlbHNlLsKgIEkuZS48YnI+DQo8YnI+DQrCoCDCoCAoZGVmbWFjcm8gYWJicmV2LWRv LWFjdGl2ZS1leHBhbnNpb25zIChWQVIgJmFtcDtyZXN0IEJPRFkpPGJyPg0KwqAgwqAgwqAgJnF1 b3Q7QmluZCBWQVIgdG8gYW4gYWN0aXZlIGV4cGFuc2lvbiBhbmQgcnVuIEJPRFkgd2l0aCBpdC48 YnI+DQrCoCDCoCBSZXBlYXQgaXQgZm9yIGFsbCBhY3RpdmUgZXhwYW5zaW9ucy4mcXVvdDs8YnI+ DQrCoCDCoCDCoCAuLi4pPGJyPg0KPGJyPg0Kb3I8YnI+DQo8YnI+DQrCoCDCoCAoZGVmdW4gYWJi cmV2LW1hcGMtYWN0aXZlLWV4cGFuc2lvbnMgKEZVTkMpPGJyPg0KwqAgwqAgwqAgJnF1b3Q7Q2Fs bCBGVU5DIG9uIGVhY2ggYWN0aXZlIGV4cGFuc2lvbi4mcXVvdDs8YnI+DQo8YnI+DQpUaGlzIHdh eSB5b3UgZG9uJiMzOTt0IG5lZWQgdG8gYnVpbGQgYSBsaXN0IG9mIGFjdGl2ZSBleHBhbnNpb25z OiB5b3UgcnVuPGJyPg0KRlVOQyBvciBCT0RZIG9uIGVhY2ggZXhwYW5zaW9uIHdoZW4geW91IGVu Y291bnRlciBpdC48YnI+PC9ibG9ja3F1b3RlPjxkaXY+PGJyPjwvZGl2PjxkaXY+QWgsIG9mIGNv dXJzZSwgZ290IGl0IG5vdyEgOikgSSB0cmllZCBhIGZldyB2ZXJzaW9ucyBvZiB0aGlzIG5vdy4g SSBuZWVkIHRvIGdvIHRocm91Z2g8L2Rpdj48ZGl2PnRoZSBjb21wbGV0ZSBsaXN0IG9mIGFjdGl2 ZSBhYmJyZXZzL2V4cGFuc2lvbnMgc2luY2UgSSB3YW50IHRvIGZpbmQgb25lIHRoYXQgaXMgdmFs aWQ8L2Rpdj48ZGl2PmFuZCBJIGFsc28gd2FudCB0byBmaW5kIHRoZSAmcXVvdDtiZXN0JnF1b3Q7 IG9uZSAoYWNjb3JkaW5nIHRvIHdoYXQgd2UgZGlzY3Vzc2VkIGJlZm9yZSkuPC9kaXY+PGRpdj7C oDwvZGl2PjxkaXY+SSBkZWZpbmVkIDEwLDAwMCBkdW1teSBhYmJyZXZzIChhMSAuLiBhMTAwMDAp IGFuZCB1c2VkIHRoZSBwcm9maWxlciB0byBjb21wYXJlPC9kaXY+PGRpdj5tZW1vcnkgdXNhZ2Ug YW5kLi4uIEkgZGlkIG5vdCBnZXQgYW55IGNvbmNsdXNpdmUgcmVzdWx0cy4gQW5kIGJldHdlZW4g cnVucyBJIGdldCBkaWZmZXJlbnQ8L2Rpdj48ZGl2Pm1lbW9yecKgdmFsdWVzIHJlcG9ydGVkLjwv ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SWYgSSBjYW4gZHJhdyBhbnkgY29uY2x1c2lvbnMgYXQg YWxsIGl0IHdvdWxkIGJlIHRoYXQgdGhlIG9sZCB2ZXJzaW9uICh0aGF0IHVzZWQgYW5vdGhlcjwv ZGl2PjxkaXY+ZnVuY3Rpb24gdG8gZ2V0IHRoZSBhY3RpdmUgYWJicmV2cykgYW5kIHRoZSBuZXcg b25lICh0aGF0IGRvZXMgd2hhdCBuZWVkcyB0byBiZSBkb25lPC9kaXY+PGRpdj53aGlsZSBjb2xs ZWN0aW5nIHRoZSBhY3RpdmUgYWJicmV2cykgYXJlIG1vcmUgb3IgbGVzcyB0aGUgc2FtZSwgZnJv bSB0aGUgcGVyc3BlY3RpdmU8L2Rpdj48ZGl2Pm9uIG1lbW9yeSBjb25zdW1wdGlvbi48L2Rpdj48 ZGl2Pjxicj48L2Rpdj48ZGl2PkhlcmUgaXMgdGhlIG9yaWdpbmFsIHZlcnNpb24sIHNsaWdodGx5 IG1vZGlmaWVkLiBJIGFkZGVkIGEgbmV3IGNhY2hlIHRvIG1ha2UgdGhlPC9kaXY+PGRpdj7CoGFi YnJldi1zdWdnZXN0LWV4cGFuc2lvbi1leGlzdC1hdC1wb2ludCBmdW5jdGlvbiBub3QgaGF2ZSB0 byBjYWxsIGJ1ZmZlci1zdWJzdHJpbmc8YnI+PC9kaXY+PGRpdj5mb3IgYSBjZXJ0YWluIGxlbmd0 aCBtYW55IHRpbWVzLjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PGZvbnQgZmFjZT0ibW9ub3Nw YWNlIj4oZGVmdW4gYWJicmV2LXN1Z2dlc3QgKCk8YnI+wqAgJnF1b3Q7U3VnZ2VzdCBhbiBhYmJy ZXYgdG8gdGhlIHVzZXIgYmFzZWQgb24gdGhlIHRleHQgYmVmb3JlIHBvaW50Ljxicj5Vc2VzIGBh YmJyZXYtc3VnZ2VzdC1oaW50LXRocmVzaG9sZCYjMzk7IHRvIGZpbmQgb3V0IGlmIHRoZSB1c2Vy IHNob3VsZCBiZTxicj5pbmZvcm1lZCBhYm91dCB0aGUgZXhpc3RpbmcgYWJicmV2LiZxdW90Ozxi cj7CoCAoaW50ZXJhY3RpdmUpPGJyPsKgIChhYmJyZXYtc3VnZ2VzdC1wcmV2aW91cy1jaGFycy1j bGVhcik8YnI+wqAgKGxldCAoYWJicmV2LWZvdW5kKTxicj7CoCDCoCAoZG9saXN0IChleHBhbnNp b24gKGFiYnJldi1nZXQtYWN0aXZlLWV4cGFuc2lvbnMpKTxicj7CoCDCoCDCoCAod2hlbiAoYW5k IChhYmJyZXYtc3VnZ2VzdC1hYm92ZS10aHJlc2hvbGQgZXhwYW5zaW9uKTxicj7CoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoChhYmJyZXYtc3VnZ2VzdC1leHBhbnNpb24tZXhpc3QtYXQtcG9pbnQg ZXhwYW5zaW9uKSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgKHNldHEgYWJicmV2LWZvdW5kIChhYmJy ZXYtc3VnZ2VzdC1iZXN0LWFiYnJldjxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCBleHBhbnNpb24gYWJicmV2LWZvdW5kKSkpKTxicj7CoCDCoCAod2hl biBhYmJyZXYtZm91bmQ8YnI+wqAgwqAgwqAgKGFiYnJldi1zdWdnZXN0LWluZm9ybS11c2VyIGFi YnJldi1mb3VuZCkpKSk8YnI+PC9mb250Pjxicj48L2Rpdj48ZGl2Pk9uZSBvZiB0aGUgcHJvZmls ZXIgcnVuczo8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2Pjxmb250IGZhY2U9Im1vbm9zcGFjZSI+ wqBGdW5jdGlvbiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoEJ5dGVzIMKgIMKgJTxicj4tIGNv bW1hbmQtZXhlY3V0ZSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCA2LDE5MSw3MDYgwqA5OSU8YnI+wqAtIGNhbGwtaW50ZXJhY3Rp dmVseSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCA2LDE5MSw3MDYgwqA5OSU8YnI+wqAgLSBmdW5jYWxsLWludGVyYWN0aXZlbHkgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgNiwxOTEsNzA2IMKg OTklPGJyPsKgIMKgKyBwcm9maWxlci1zdG9wIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgMywxNzgsMzMxIMKgNTElPGJyPsKgIMKg LSBhYmJyZXYtc3VnZ2VzdCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCAzLDAxMiw5MTIgwqA0OCU8YnI+wqAgwqAgLSBsZXQgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgMywwMTIsOTEyIMKgNDglPGJyPsKgIMKgIMKgLSBsZXQgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAzLDAxMiw3NjAgwqA0OCU8YnI+wqAgwqAgwqAgLSB3aGlsZSDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAyLDA0 Niw1MjAgwqAzMyU8YnI+wqAgwqAgwqAgwqAtIGxldCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoDEsNzA0LDM3NiDC oDI3JTxicj7CoCDCoCDCoCDCoCAtIGlmIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgMSw3MDQsMzc2IMKgMjclPGJy PsKgIMKgIMKgIMKgIMKgLSBhbmQgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAxLDcwNCwzNzYgwqAyNyU8YnI+wqAgwqAg wqAgwqAgwqAgLSBhYmJyZXYtc3VnZ2VzdC1leHBhbnNpb24tZXhpc3QtYXQtcG9pbnQgwqAgwqAg wqAgwqAgMSwwMjMsMjU2IMKgMTYlPGJyPsKgIMKgIMKgIMKgIMKgIMKgLSBzdHJpbmc9IMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgMSww MjMsMjU2IMKgMTYlPGJyPsKgIMKgIMKgIMKgIMKgIMKgIC0gYWJicmV2LXN1Z2dlc3QtcHJldmlv dXMtY2hhcnMgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgNjgyLDE2OCDCoDExJTxicj7CoCDC oCDCoCDCoCDCoCDCoCDCoCsgbGV0IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgMSwwNDggwqAgMCU8YnI+wqAgwqAgwqAg LSBhYmJyZXYtZ2V0LWFjdGl2ZS1leHBhbnNpb25zIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgOTY2LDI0MCDCoDE1JTxicj7CoCDCoCDCoCDCoC0gbGV0IMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgOTY2LDI0MCDCoDE1JTxicj7CoCDCoCDCoCDCoCAtIGxldCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCA5 NjYsMjQwIMKgMTUlPGJyPsKgIMKgIMKgIMKgIMKgLSB3aGlsZSDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoDk2NiwyNDAg wqAxNSU8YnI+wqAgwqAgwqAgwqAgwqAgLSBsZXQgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgOTY2LDI0MCDCoDE1JTxi cj7CoCDCoCDCoCDCoCDCoCDCoC0gbWFwYXRvbXMgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgOTY2LDI0MCDCoDE1JTxicj7CoCDCoCDC oCDCoCDCoCDCoCAtICMmbHQ7bGFtYmRhIDB4MTk5NDFjN2Q4MzI1NDQyMyZndDsgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqA4NzAsMTQ0IMKgMTQlPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKg LSBsZXQgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqA3NzEsOTM2IMKgMTIlPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIC0gc3lt Ym9sLXZhbHVlIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgNjc1LDg0MCDCoDEwJTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoC0gYWJicmV2LS1zeW1i b2wgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgNDgzLDY0OCDC oCA3JTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCArIGxldCogwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAyODksMzQ0IMKgIDQlPGJy PsKgIMKgIMKgIMKgIMKgIMKgIMKgICsgaWYgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgOTYsMDk2IMKgIDElPGJyPsKgIMKg IMKgKyBpZiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAxNTIgwqAgMCU8YnI+PC9mb250Pjwv ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SGVyZSBpcyB0aGUgbmV3IHZlcnNpb246PC9kaXY+PGRp dj48YnI+PC9kaXY+PGRpdj48Zm9udCBmYWNlPSJtb25vc3BhY2UiPihkZWZ1biBhYmJyZXYtc3Vn Z2VzdCAoKTxicj7CoCAmcXVvdDtTdWdnZXN0IGFuIGFiYnJldiB0byB0aGUgdXNlciBiYXNlZCBv biB0aGUgdGV4dCBiZWZvcmUgcG9pbnQuPGJyPlVzZXMgYGFiYnJldi1zdWdnZXN0LWhpbnQtdGhy ZXNob2xkJiMzOTsgdG8gZmluZCBvdXQgaWYgdGhlIHVzZXIgc2hvdWxkIGJlPGJyPmluZm9ybWVk IGFib3V0IHRoZSBleGlzdGluZyBhYmJyZXYuJnF1b3Q7PGJyPsKgIChpbnRlcmFjdGl2ZSk8YnI+ wqAgKGFiYnJldi1zdWdnZXN0LXByZXZpb3VzLWNoYXJzLWNsZWFyKTxicj7CoCAobGV0IChiZXN0 LWFiYnJldik8YnI+wqAgwqAgKGRvbGlzdCAodGFibGUgKGFiYnJldi0tYWN0aXZlLXRhYmxlcy1p bmNsdWRpbmctcGFyZW50cykpPGJyPsKgIMKgIMKgIChtYXBhdG9tcyAobGFtYmRhIChlKTxicj7C oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAobGV0ICgodmFsdWUgKHN5bWJvbC12YWx1ZSAoYWJi cmV2LS1zeW1ib2wgZSB0YWJsZSkpKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCBhYmJyZXYpPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgICh3aGVuIHZhbHVl PGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIChzZXRxIGFiYnJldiAoY29ucyB2 YWx1ZSAoc3ltYm9sLW5hbWUgZSkpKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCAod2hlbiAoYW5kIChhYmJyZXYtc3VnZ2VzdC1hYm92ZS10aHJlc2hvbGQgYWJicmV2KTxicj7C oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChhYmJyZXYt c3VnZ2VzdC1leHBhbnNpb24tZXhpc3QtYXQtcG9pbnQgYWJicmV2KSk8YnI+wqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKHNldHEgYmVzdC1hYmJyZXYgKGFiYnJldi1zdWdnZXN0 LWJlc3QtYWJicmV2IGFiYnJldiBiZXN0LWFiYnJldikpKSkpKTxicj7CoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCB0YWJsZSkpPGJyPsKgIMKgICh3aGVuIGJlc3QtYWJicmV2PGJyPsKgIMKgIMKgIChh YmJyZXYtc3VnZ2VzdC1pbmZvcm0tdXNlciBiZXN0LWFiYnJldikpKSk8YnI+PC9mb250Pjxicj48 L2Rpdj48ZGl2PkhlcmUgaXMgYSBydW4gd2l0aCB0aGUgcHJvZmlsZXIgb2YgdGhlIGFib3ZlOjwv ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PGZvbnQgZmFjZT0ibW9ub3NwYWNlIj7CoEZ1bmN0aW9u IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgQnl0ZXMgwqAgwqAlPGJyPi0gY29tbWFuZC1leGVj dXRlIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIDQsOTk2LDc1MSDCoDk5JTxicj7CoC0gY2FsbC1pbnRlcmFjdGl2ZWx5IMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIDQsOTk2 LDc1MSDCoDk5JTxicj7CoCAtIGZ1bmNhbGwtaW50ZXJhY3RpdmVseSDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCA0LDk5Niw3NTEgwqA5OSU8YnI+wqAg wqArIHByb2ZpbGVyLXN0b3AgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAzLDE3OSw4MTYgwqA2MyU8YnI+wqAgwqAtIGFiYnJldi1z dWdnZXN0IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIDEsODE2LDQ3MiDCoDM2JTxicj7CoCDCoCAtIGxldCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCAxLDgxNiw0NzIgwqAzNiU8YnI+wqAgwqAgwqAtIGxldCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoDEsODE1 LDI2NCDCoDM2JTxicj7CoCDCoCDCoCAtIHdoaWxlIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIDEsODE1LDI2NCDCoDM2 JTxicj7CoCDCoCDCoCDCoC0gbGV0IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgMSw4MTUsMjY0IMKgMzYlPGJyPsKg IMKgIMKgIMKgIC0gbWFwYXRvbXMgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAxLDgxNSwyNjQgwqAzNiU8YnI+wqAgwqAgwqAgwqAg wqAtICMmbHQ7bGFtYmRhIC0weGYwYTE4NWUzNTRhZmU0YSZndDsgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgMSw4MTUsMjY0IMKgMzYlPGJyPsKgIMKgIMKgIMKgIMKgIC0gbGV0IMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIDI4NCwwNjQgwqAgNSU8YnI+wqAgwqAgwqAgwqAgwqAgwqAtIGlmIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IDI4NCwwNjQgwqAgNSU8YnI+wqAgwqAgwqAgwqAgwqAgwqAgLSBwcm9nbiDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAyODQsMDY0 IMKgIDUlPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgc2V0cSDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAyODQsMDY0IMKgIDUl PGJyPsKgIMKgIMKgKyBpZiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAxLDIwOCDCoCAwJTxicj7C oCDCoCDCoHByb2ZpbGVyLXN0YXJ0IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIDQ2MyDCoCAwJTxicj48L2ZvbnQ+PC9k aXY+PGRpdj48YnI+PC9kaXY+PGRpdj5BcmUgdGhlc2UgbnVtYmVycyBhcyBleHBlY3RlZD88L2Rp dj48ZGl2Pjxicj48L2Rpdj48ZGl2PlNvbWV0aW1lcywgYWxsIG9mIGEgc3VkZGVuLCByZWdhcmRs ZXNzIG9mIHdoYXQgdmVyc2lvbiBvZiB0aGUgZnVuY3Rpb24gSSB1c2UsIHRoZSBtZW1vcnk8L2Rp dj48ZGl2PmNvbnN1bWVkIGJ5IGFiYnJldi1zdWdnZXN0IGNhbiBiZSBhcyBsb3cgYXMgODAsMDAw IGJ5dGVzLiBXaGF0IGhhdmUgaGFwcGVuZWQgdGhlbj88L2Rpdj48ZGl2PlNvbWV0aGluZyB0aGUg R0MgZG9lcz88L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PlRoYW5rcyE8L2Rpdj48ZGl2Pjxicj48 L2Rpdj48ZGl2Pi9NYXRoaWFzPC9kaXY+PGRpdj48YnI+PC9kaXY+PC9kaXY+PC9kaXY+DQo= --000000000000b1b70305a5d94a3c--