From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2.migadu.com ([2001:41d0:303:e224::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms13.migadu.com with LMTPS id sGhhJuBDSmflswAAe85BDQ:P1 (envelope-from ) for ; Fri, 29 Nov 2024 22:44:48 +0000 Received: from aspmx1.migadu.com ([2001:41d0:303:e224::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2.migadu.com with LMTPS id sGhhJuBDSmflswAAe85BDQ (envelope-from ) for ; Fri, 29 Nov 2024 23:44:48 +0100 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=yavin4.ch header.s=mail header.b=ckodOwvC; dmarc=none; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id C9E8286963 for ; Fri, 29 Nov 2024 23:44:47 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tH9dd-0006vG-Iy; Fri, 29 Nov 2024 17:39:01 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tH9db-0006us-Kh for emacs-orgmode@gnu.org; Fri, 29 Nov 2024 17:38:59 -0500 Received: from peart4prez.yavin4.ch ([81.4.103.105]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tH9dY-0001OD-7j for emacs-orgmode@gnu.org; Fri, 29 Nov 2024 17:38:59 -0500 Received: from petrucci4prez (c-68-56-88-201.hsd1.mi.comcast.net [68.56.88.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) (Authenticated sender: ndwar@yavin4.ch) by peart4prez.yavin4.ch (Postfix) with ESMTPSA id 0C745200A4 for ; Fri, 29 Nov 2024 17:38:40 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yavin4.ch; s=mail; t=1732919925; bh=nIR3Ibj9MGIxLaRBdFydKNJdAaCCnUekKBmpwHxWKvg=; h=From:To:Subject:Date; b=ckodOwvC1BOUTs4WHbhTjgnBovj7BXLpPTR7p3qZj/MRrBG6AoazQHw6s7hfnvyf/ nOmlRR5JQZH3BdiITac/Z30KLt3nkpb9zOSWr4d1BNUHKKH+ReTjMxsaKYoajCvrlh IGJJb3HG3L/h1HFb+2aD2uIIuc3t6i575a+iNeNs= From: "Dwarshuis, Nathan J" To: org-mode-email Subject: [PATCH] org-element.el; significant optimizations for org-element--interpret-affiliated-keywords User-Agent: mu4e 1.12.7; emacs 29.4 Date: Fri, 29 Nov 2024 17:38:25 -0500 Message-ID: <87v7w5pswu.fsf@yavin4.ch> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=81.4.103.105; envelope-from=ndwar@yavin4.ch; helo=peart4prez.yavin4.ch X-Spam_score_int: 0 X-Spam_score: -0.1 X-Spam_bar: / X-Spam_report: (-0.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, FILL_THIS_FORM=0.001, FILL_THIS_FORM_LONG=2, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-Migadu-Spam-Score: -2.84 X-Spam-Score: -2.84 X-Migadu-Queue-Id: C9E8286963 X-Migadu-Scanner: mx12.migadu.com X-TUID: /tvphTZVY9Z+ --=-=-= Content-Type: text/plain Hi all, I noticed that calling `org-element-interpret-data' on objects is generally 5-10x faster than when calling on elements. The reason seems to be that `org-element--interpret-affiliated-keywords' (which is only called on elements) does alot of unnecessary work. Namely, it runs on all elements (including those that should never have an affiliated keyword) and also loops over :standard-properties which should not be relevant here. The attached patch addresses this. I also attached some benchmarks pre and post-patch and accompanying code, which shows many elements (specifically those without children) approaching the execution time of objects. For the graphs, just pay attention to the 'org-element' bars (red); the others were from me trying to optimize the `org-ml` package. Thank you, Nate --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-org-element.el-Make-affiliated-keyword-interpreter-f.patch >From 1b4fb607bd6e233a15a569960517a9388a80974b Mon Sep 17 00:00:00 2001 From: ndwarshuis Date: Mon, 25 Nov 2024 22:04:09 -0500 Subject: [PATCH] org-element.el: Make affiliated keyword interpreter faster * lisp/org-element.el (org-element--interpret-affiliated-keywords): Optimize performance by bypassing unnecessary types and reducing loop complexity. Added new constant `org-element-elements-no-affiliated` which stores the types to be bypassed. This function was doing redundant work on several levels which dramatically reduced performance of interpreting element nodes relative to object nodes. First, all types were interpreted regardless of if they could possibly contain affiliated keywords. Skipping these types dramatically speeds up typical use cases since many of these skipped types are common (headline, item, etc). Second, the loop was much more complex than needed. The loop included :standard-properties which should not be necessary here. It also duplicated some work between calls to `org-element--properties-mapc` and `mapconcat` (the code was moved entirely under the former). The result should be faster and more readable. TINYCHANGE --- lisp/org-element.el | 82 +++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index 9f8f52745..3b90dce2a 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -335,6 +335,11 @@ specially in `org-element--object-lex'.") (append org-element-recursive-objects '(paragraph table-row verse-block)) "List of object or element types that can directly contain objects.") +(defconst org-element-elements-no-affiliated + '(org-data comment clock headline inlinetask item + node-property planning property-drawer + section table-row)) + (defconst org-element-affiliated-keywords '("CAPTION" "DATA" "HEADER" "HEADERS" "LABEL" "NAME" "PLOT" "RESNAME" "RESULT" "RESULTS" "SOURCE" "SRCNAME" "TBLNAME") @@ -5517,49 +5522,46 @@ to interpret. Return Org syntax as a string." (make-string blank ?\n))))))))) (funcall fun data nil))) +(defun org-element--keyword-to-org (key value) + (let (dual) + (when (member key org-element-dual-keywords) + (setq dual (cdr value) value (car value))) + (concat "#+" (downcase key) + (and dual + (format "[%s]" (org-element-interpret-data dual))) + ": " + (if (member key org-element-parsed-keywords) + (org-element-interpret-data value) + value) + "\n"))) + (defun org-element--interpret-affiliated-keywords (element) "Return ELEMENT's affiliated keywords as Org syntax. If there is no affiliated keyword, return the empty string." - (let ((keyword-to-org - (lambda (key value) - (let (dual) - (when (member key org-element-dual-keywords) - (setq dual (cdr value) value (car value))) - (concat "#+" (downcase key) - (and dual - (format "[%s]" (org-element-interpret-data dual))) - ": " - (if (member key org-element-parsed-keywords) - (org-element-interpret-data value) - value) - "\n"))))) - (mapconcat - (lambda (prop) - (let ((value (org-element-property prop element)) - (keyword (upcase (substring (symbol-name prop) 1)))) - (when value - (if (or (member keyword org-element-multiple-keywords) - ;; All attribute keywords can have multiple lines. - (string-match-p "^ATTR_" keyword)) - (mapconcat (lambda (line) (funcall keyword-to-org keyword line)) - value "") - (funcall keyword-to-org keyword value))))) - ;; List all ELEMENT's properties matching an attribute line or an - ;; affiliated keyword, but ignore translated keywords since they - ;; cannot belong to the property list. - (let (acc) - (org-element-properties-mapc - (lambda (prop _ __) - (let ((keyword (upcase (substring (symbol-name prop) 1)))) - (when (or (string-match-p "^ATTR_" keyword) - (and - (member keyword org-element-affiliated-keywords) - (not (assoc keyword - org-element-keyword-translation-alist)))) - (push prop acc)))) - element t) - (nreverse acc)) - ""))) + ;; there are some elements that will never have affiliated keywords, + ;; so do nothing for these + (if (member (org-element-type element) org-element-elements-no-affiliated) + "" + (let (acc) + (org-element-properties-resolve element t) + (org-element--properties-mapc + (lambda (prop value) + (when value + (let ((keyword (upcase (substring (symbol-name prop) 1)))) + (when (or (string-match-p "^ATTR_" keyword) + (and + (member keyword org-element-affiliated-keywords) + (not (assoc keyword + org-element-keyword-translation-alist)))) + (push (if (or (member keyword org-element-multiple-keywords) + ;; All attribute keywords can have multiple lines. + (string-match-p "^ATTR_" keyword)) + (mapconcat (lambda (line) (org-element--keyword-to-org keyword line)) + value "") + (org-element--keyword-to-org keyword value)) + acc))))) + element nil t) + (apply #'concat (nreverse acc))))) ;; Because interpretation of the parse tree must return the same ;; number of blank lines between elements and the same number of white -- 2.47.0 --=-=-= Content-Type: application/pdf Content-Disposition: attachment; filename=org-ml-postpatch.pdf Content-Transfer-Encoding: base64 JVBERi0xLjQKJYHigeOBz4HTXHIKMSAwIG9iago8PAovQ3JlYXRpb25EYXRlIChEOjIwMjQxMTI1 MjIyMzI1KQovTW9kRGF0ZSAoRDoyMDI0MTEyNTIyMjMyNSkKL1RpdGxlIChSIEdyYXBoaWNzIE91 dHB1dCkKL1Byb2R1Y2VyIChSIDQuMy4xKQovQ3JlYXRvciAoUikKPj4KZW5kb2JqCjIgMCBvYmoK PDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDMgMCBSID4+CmVuZG9iago3IDAgb2JqCjw8IC9UeXBl IC9QYWdlIC9QYXJlbnQgMyAwIFIgL0NvbnRlbnRzIDggMCBSIC9SZXNvdXJjZXMgNCAwIFIgPj4K ZW5kb2JqCjggMCBvYmoKPDwKL0xlbmd0aCA2MjgwIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlCj4+CnN0 cmVhbQp4nL1dS3MkN3K+81f0cebAduGNumrDdoQi7Ah7FeHD7sYGh9OjocQixyS1WvnXO18AEj1k T/IhHdScD8hKVAGJRGYCSLnd9zu3+2n3v2f/cv/f//7d7vL+zO2XZdnp3/vLm7Nlt+xSyXssdMnj 37vD7tPZf8Gjv+N/uwVbop+vW/+f3c23Xpur//TnR6r//Kf/xNKy+/XsL3+Dr/t45nbfw38/nTlq 7z/O6M/5442f7b7r71jd3q27Nad98Luwxn0OO5fDfl2/estlv3q/07/4licZnEEvf+Mzln0K4zOW o89wIe9rbuy3hp3z6z643fXZn8+881jXSQRPJLXsy6pIGGuSAK/s0yARrEliqPuiGhKsSeYx4a5x SyxYDw+UtK++F+AD67p3iiXDiWOJ+6ReXfD0dQk6S/WR4OnrfNon1Y7g6euWBcdsfB1jTQIFJcDQ x0y/vpAAyCdU+rayd2GX3T4tMvoLDfSyL3HF37yqZ1pH1L1fHn1o/JLAL5mGCB6OFbuCsVtC2OfE vdWKXN6nomm4QNGcZlNIhJYMn8w0UrCmvTuiKRV7ezsusPKZJ2KBh3N8xUR8gsFbTURh3yfiGj22 o+Zhp2jzUlHwtBsUMi0Hhcy6TtFm5aCQSdcp2qQcFI/NwQLSSfIgU1AwkgvBCpKr5qjgQVAXaDAP AsGKwC97rzgIVgTBgfwrAsaKIIZJTwhWBClinw8Cxoog533UHBgrglL2q+bAWBHUdZ80B8aDYF2g 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 BzpJ3bz2w2Z+mM5Z5bUbn2hOHLqN+Nv5tz/wjeW7HVPUhxZVmEdOKeozi6O2H1Kcziyq+nZGcTqy aJWdl225HB9Ym2TMuXlMGHv4akzsjTZKi5Tu/vpuu//r+5dsE33j/9qLt/Lxf1OHSf4wzoihZt7w 583cN/+8uFLW7oR7fmwJf/rl5vLh6vbmqa/T533puOD4pS8Qhpw6AXdwq/zOX6DZPHJgEdmghV4o BSifkeTfp9mceJtEezimt3nsJGR7m0RHuZ5+mxcMy+MbFHSiLxVKe0FnFe5+/PvXh2NeK/Gn2ubs YK3t7frN9kTP/h8nTwRnZW5kc3RyZWFtCmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlcyAv S2lkcyBbIDcgMCBSIF0gL0NvdW50IDEgL01lZGlhQm94IFswIDAgNTc2IDExNTJdID4+CmVuZG9i ago0IDAgb2JqCjw8Ci9Qcm9jU2V0IFsvUERGIC9UZXh0XQovRm9udCA8PC9GMiAxMCAwIFIgPj4K L0V4dEdTdGF0ZSA8PCA+PgovQ29sb3JTcGFjZSA8PCAvc1JHQiA1IDAgUiA+Pgo+PgplbmRvYmoK NSAwIG9iagpbL0lDQ0Jhc2VkIDYgMCBSXQplbmRvYmoKNiAwIG9iago8PCAvQWx0ZXJuYXRlIC9E ZXZpY2VSR0IgL04gMyAvTGVuZ3RoIDI1OTYgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFt CnicnZZ3VFPZFofPvTe9UJIQipTQa2hSAkgNvUiRLioxCRBKwJAAIjZEVHBEUZGmCDIo4ICjQ5Gx IoqFAVGx6wQZRNRxcBQblklkrRnfvHnvzZvfH/d+a5+9z91n733WugCQ/IMFwkxYCYAMoVgU4efF iI2LZ2AHAQzwAANsAOBws7NCFvhGApkCfNiMbJkT+Be9ug4g+fsq0z+MwQD/n5S5WSIxAFCYjOfy +NlcGRfJOD1XnCW3T8mYtjRNzjBKziJZgjJWk3PyLFt89pllDznzMoQ8GctzzuJl8OTcJ+ONORK+ jJFgGRfnCPi5Mr4mY4N0SYZAxm/ksRl8TjYAKJLcLuZzU2RsLWOSKDKCLeN5AOBIyV/w0i9YzM8T yw/FzsxaLhIkp4gZJlxTho2TE4vhz89N54vFzDAON40j4jHYmRlZHOFyAGbP/FkUeW0ZsiI72Dg5 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 rWbtptrXu3m7r+zx2NNWp1VXWvdur2DvzXq/+s4Go4aKfZh9OfseNkY39n/N+rq5SaOptOnDfuF+ 6YGIA33Njs3NLZotZa1wq6R18mDCwcvfeH/T3cZsq2+nt5ceAockhx5/m/jt9cNBh3uPsI60fWf4 XW0HtaOkE+pc3jnVldIl7Y7rHj4aeLS3x6Wn43vL7/cf0z1Wc1zleNkJwomiE59O5p+cPpV16unp 5NNjvUt675yJPXOtL7xv8GzQ2fPnfM+d6ffsP3ne9fyxC84Xjl5kXey65HCpc8B+oOMH+x86Bh0G O4cch7ovO13uGZ43fOKK+5XTV72vnrsWcO3SyPyR4etR12/eSLghvcm7+ehW+q3nt3Nuz9xZcxd9 t+Se0r2K+5r3G340/bFd6iA9Puo9OvBgwYM7Y9yxJz9l//R+vOgh+WHFhM5E8yPbR8cmfScvP174 ePxJ1pOZp8U/K/9c+8zk2Xe/ePwyMBU7Nf5c9PzTr5tfqL/Y/9LuZe902PT9VxmvZl6XvFF/c+At 623/u5h3EzO577HvKz+Yfuj5GPTx7qeMT59+A/eE8/tlbmRzdHJlYW0KZW5kb2JqCjkgMCBvYmoK PDwKL1R5cGUgL0VuY29kaW5nIC9CYXNlRW5jb2RpbmcgL1dpbkFuc2lFbmNvZGluZwovRGlmZmVy ZW5jZXMgWyA0NS9taW51cyA5Ni9xdW90ZWxlZnQKMTQ0L2RvdGxlc3NpIC9ncmF2ZSAvYWN1dGUg L2NpcmN1bWZsZXggL3RpbGRlIC9tYWNyb24gL2JyZXZlIC9kb3RhY2NlbnQKL2RpZXJlc2lzIC8u bm90ZGVmIC9yaW5nIC9jZWRpbGxhIC8ubm90ZGVmIC9odW5nYXJ1bWxhdXQgL29nb25layAvY2Fy b24gL3NwYWNlXQo+PgplbmRvYmoKMTAgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5 cGUxIC9OYW1lIC9GMiAvQmFzZUZvbnQgL0hlbHZldGljYQovRW5jb2RpbmcgOSAwIFIgPj4KZW5k b2JqCnhyZWYKMCAxMQowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMjEgMDAwMDAgbiAKMDAw MDAwMDE2MyAwMDAwMCBuIAowMDAwMDA2NjQ0IDAwMDAwIG4gCjAwMDAwMDY3MjggMDAwMDAgbiAK MDAwMDAwNjg0MCAwMDAwMCBuIAowMDAwMDA2ODczIDAwMDAwIG4gCjAwMDAwMDAyMTIgMDAwMDAg biAKMDAwMDAwMDI5MiAwMDAwMCBuIAowMDAwMDA5NTY4IDAwMDAwIG4gCjAwMDAwMDk4MjUgMDAw MDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSAxMSAvSW5mbyAxIDAgUiAvUm9vdCAyIDAgUiA+PgpzdGFy dHhyZWYKOTkyMgolJUVPRgo= --=-=-= Content-Type: application/pdf Content-Disposition: attachment; filename=org-ml-prepatch.pdf Content-Transfer-Encoding: base64 JVBERi0xLjQKJYHigeOBz4HTXHIKMSAwIG9iago8PAovQ3JlYXRpb25EYXRlIChEOjIwMjQxMTI0 MjE0NTI5KQovTW9kRGF0ZSAoRDoyMDI0MTEyNDIxNDUyOSkKL1RpdGxlIChSIEdyYXBoaWNzIE91 dHB1dCkKL1Byb2R1Y2VyIChSIDQuMy4xKQovQ3JlYXRvciAoUikKPj4KZW5kb2JqCjIgMCBvYmoK PDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDMgMCBSID4+CmVuZG9iago3IDAgb2JqCjw8IC9UeXBl IC9QYWdlIC9QYXJlbnQgMyAwIFIgL0NvbnRlbnRzIDggMCBSIC9SZXNvdXJjZXMgNCAwIFIgPj4K ZW5kb2JqCjggMCBvYmoKPDwKL0xlbmd0aCA2MjQ3IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlCj4+CnN0 cmVhbQp4nL1dS28kN5K+61fUsfug2uQzyasHMwsY2AV23cAeZgYDtbraLVsl9UryeLy/fuNFMlgq VYce9sElf2RkMJMMBiOCZLTbfL9xm582/3v2b/f//e/fbS7vz9x2WZaN/r2/vDlbNssmrXmLhS55 /Hu323w++y949Hf8b7NgS/TzuPX/2dx867W5+k8/HKn+4U//iaXr5tezv/4dvu7Tmdt8D//9dOao vf84oz/nxxs/23zX37G4raubmtM2+E2ocZvDxuWwrfXRWy7b6v1G/+JbnmRwBr38jc9YtimMz1gO PsPFtF1SY79v2Dlft8Ftrs9+OPMhb6sbJII1SfBlu66DRLAmiX7BN+8kgjXJ3OH83W6JK9bDA2va Ft8L8IFat84PlgwnjhX6saivYzx9XfHbEtXXMZ6+bo3bdVFfx3j6upy3KauvY6xJoOU1wLjGTL9+ pdGVTyj0bRG7PrttWmRoFxrFZbvGir+5qmdaR8RtOf7Q+CVpXsLWQVfAw7FgVzCGP2GbE/dWK3Lw 8qum4QJF8y022MlLps7ej4Katu6AZi3bJWsaLrDymWfZCg/n+IpZ9gSDt5plwr7Psho9tqMmWado k25QyJzqFG3ODQqZUp2iTblBcWyGrSB7NNoywQQjuRDUdevUDBQ8CMoCDeZBIFgRwIt4xUGwIggO pFsRMFYEMUxaQLAiSDAPNAfGigBmZNQcGCuCdd1WzYGxIih1mzQHxoOgLg5HtRMIVgQORmJRBIwV gY8o2YOAsSIICVXPIGA8lGEffFEsauxZ9w0ZFN2oZJBV35BBUY1KBlnzDRkUzahkkBXfkEFRjIPi lB5cy7IN6wamHayqW29RgyKuiRZi/ciJVqqDeQ+KEyTI2grLPGj3YG2lgLaK9GLV2opMnIyz1NqK gwY8UBdzj8nsy6ivra14GkWQNXOPyRSGVry5lVCwkx3ItH1kRBPgQrtEc0uxYkeHbbGPDSsU6W1b K7AqQ0fD+0VzK6yVHovmiVZWjx0dcTGwtsKqLeH8t7ZS6J0CP2drhfUj9Jh9zsDKXvBbDifA062I kgXqam2lLit2sgeVZBYzUdXePZoCJ9pxZVsTtWPuNNH4+Gv/nrCg9Re33pub4XUD+iEde+Sx6Qhj uMISlLzYYYRjW0F7iYfX1BSEJ4oTPOCbsSRvV6YQXHGYJgpQE1lTELbyAK0Ma1wNKGP7gVNb7HtJ HG86sJUHfBasgrVs/SrvAbiArLoDiooCtT/Adh4eV42ISnY/8Nrskl6S25tqbOWR2MiraHDsO4YJ sc4UDtRd1hSErTzitgYoyVvX3pRwHe6AlKw4lvsDbOWRUE0WmMZhlfcgDB+dZgowfZymIGzlAUsF tOvXIYWIYZqqNyWKOiR5YCsPaDdBiUdjZj8w2QITBajurCkI23h4IAbZLqGyFDYM9py8aS9ZWJJn bOQBvgwMWYkRTab9wODhppkioVu0P8A2HqRzHKzkS5NCwaHZ0L3EN0nW2MqDNHhJGSv2Axe0aieK FSf0/gBbeXj8zJJ9k0LBaUihlIQmyRpbeYBmA6nLK5p/+47XBReOiaK2N9XYzqOgAxZ4bDvOQ5Kl JDVJ1tjKA3TOAiWVvdmGCwXtNAU4ISlrCsJWHgEN/gJeSewShLhMUoglebzpwFYeLA/gwmUtQbAi pQMKjy+4P8BWHgFNgwK+Tx9bwnVIoZSU8aYDW3mQCVBB+HxfCREn/aZUQiGm/QE28kDLLUBJkbEV DGtUk8JWQjGb/QG28ljIY3aBwxkd5/6mrYSsrv0BtvKAdsFzhwqWwobD9KZY4nAs9wfYyoMcq+oT R146Lrh0TxQZF439ATbyWMg9quAt5iZBhKOWQioJTZI1tvKgAGYNmYNEHYO1FWcKmGOLpiBs4zEH IxNGGfIrgpFPMHirYKSw78HINSX0VlQwslO04OSgkOBjp2jByUEhwcdO0YKTg+JYMDKDdasjZIJH ACyjuVcUAWNFEMIUShSsCMD3L1ERMFYEWWyMRpC7jSEE8AeGYhAwVgSg/xYVUhWsQqpujvMJVgRg 53mvCBgrgphZUBsB4xEI7B0vASzV7xz4G+MvgUE1/hz4G+MvgUE1/hz4G+MvgUE1/hz4G+MvgcFB ccqlTSD0YJPkrYdmtz4YXFoRlZW+RT/ydCsZpgQYohljB9ZWWN4KTn1rKxg8gxHYhmJuhYW2kvNq bCVSgCJjhNLaCkt+odlvbAUs0IxbMGjCWZvh+QO+XrF/DcoTRg9hObc2w7PwWV8Dkk/vtNhHhqcy 2TfGVtaFtGemKWRrRfRBIY1pbAU81Fqf9S2iVCoFYoytwGq34LyM3twKayZyxo48chhqIos+YSil OdeEa9OwvWRtm4IaTxQneFA0P6MtyuaiYHq/iSKxGp6xlUdCIzSD4C9J3oOwCr5ISWyboBpbeayo ebOrqMX2Hfu+QdZLXDNtNLbyyBgPymi4hWb8AA5+7OhKCRiUUVMQtvIo6Hlm3ADgkRNcUXdOFOsB BWErD/Krcoxt5ASXaeSwJLfR19jKY8WN8ZwcLjH7gdNwjaQkoPuwP8BWHhVt3JyXNnKC4xg5KfFt 9DU28gAPp2LJKiFRwSu4E3GmqGh67g+wkcdC22sZXPYerkKMe4Jlpigj9DawlQf3YQlsaHa8YgB0 okgt0KixlQctXRnc7dhmA+E8Rk5KYht9ja08oDOhXdBsuch7AF4XFYySErCNqqYgbOVBce0V3d42 GxCDTlIjRyWLjP6ErTxWXPFXl8SZbLiiYzFRrOIYT9jKI6OfvfrYRk5wmUYOS3IbfY2tPAqqtBUc 0hJEBxFOeFZnogjsi8zYyiPhPF0jOFZtNhCOY2ylxLex1djKYyXzOK4tXMUYdFINM0VtQWSNbTxm 1zniMru+wnV+gsFbuc7CvrvOKVNkW7nOnaK50oNCXOVO0VzpQSGucqdorvSgOOY6R1Coq/IpBQ+X MXqabIPA98knBCB9ISgCxooAxEKfBBKsCFLEsN4gYKwIwBfIynUWrAhAc0fl3wtWBKBkvfKtBSuC KkfKGkHtJ8okrgIzqaiOEqwIQF9k1VGCFUEg/2cQMFYE0U3uu2BFwEdFB0HqEWQhgPV5VR0lePj3 XTrEYVbCwf78EFLx95WQsj8/hFT8fSWk7M8PIRV/Xwkp+/NDSMXfHxSn/IgIOrPUjeMQHZ2s+LYn IRLtAu2KTA+daIkddhcKbkdZW+KpgQ95e0swkeO6wVPAcTG3xHPMgdGXs7kl3EnLG1gK4CWtDfFc DbQzbm0nLXQYGGw2n80N8Zx3ueCcsLaUKcjtPG2yW1ti5eF8wiXS2hIYnLgmrLA62TuPtZAr/lGP n2gJqMFNdoFC7NaWWJ05cIrWYm6p0qaKAxul2FtivYgHp0CxGFtKCy2lDuZHMPeeKFjnV1o8jS2B Eww9gA9Vs4YQTY1dnszzNnk6QehARx8K7ImWWOWjhgDXw9pSILcExeiwI060xGuHW2l32NoSmFpg LQbSstaGeA2CL7LPppRWnEa+RLSOrQ3xWuZBQ4Sjk32OCXk8Wo7r2crxnIYd2axsdAlFbTcUNJ4o TvBIGKiIHKbcD5zasZ9eEvl4yYytPFZaeV1hH6Zh75pP10tkY27Gdh6wqEQf+FBPx3nc6ZCS2HZ4 NDbySHSWK/rKm4wNg+qS4wO9ZGGrcMZWHqwJ8cwI8xC8tu2/XiJe34xtPNAQAUGI4AcF8scaDniq dKJonvSErTzIeYuRTj/tB15xmk4UmU31Gdt4eLDEAnwddCXF2ToOaEhOFJ5t7RlbeaxkuqXEcdiO S/Mte8nKXsWMjTxQ/EC2s2PfsuPYvPFeEvjIzoytPCItMvCRKx8dElzRoJsoCiqw/QE28ljpHFpc vRyUajihVE4UkaO9MzbyAP8BpW6V4zYNl6X3R6MocpRqwkYeMGE9aIMStrHS1wrObWO/l0SOcMzY yCM4cqb54Mu+49rvVXSKytciZmzkAes/moI1bj1JYcO57Sj0koSm4/4AW3kUunSASyD3B+G0uNEf UrK0/tDYyoMWgQRe2cJSKHhtEbBeQns4+wNs5UEnLBOsr5X7gzGekfYTBR4BLZqCsJUHbWYll/jA RcelHcfqJStH4Wds5VEpuALr6+pFCgmHdjC5l3iOK8zYyAMWBdBsyWc+wtRx7QccW0nhwMCMjTxg QYsYnnB8Uanj2A4X9RLPIZAZG3lghAJGCiuiaAfEse/0dIrCMYwZG3mAy5VgpKLnXYmOY9vF6yVB ritN2MaDYgloLtO+zb5jcHxbdLNRVHx0f4CtPMiJSbB6LsxDcEIzZKKIHFiasY1HAEW6Riip2Py+ 4+zaQdxesvD+yYyNPDINWcJjpMSj4X5FtJfI3umMbTzmeLDH6VpfEQ9+gsFbxYOFfY8HB4wTtCWM 4r+dQrCikPhvpxCsKCT+2ykEK4pj8WBaTlUEUfAIMfo43+sUrAjAQqoqDipYERQ/nbUSPAgCrF1J vYNgRQDfpG9lClYEgc4ADQLGiiDFKdwrWBGsDi3jQcB4RFJ7vzLU3cqR0zG8jPXwcuR0DC9jPbwc OR3Dy1gPL0dOx/AyVhSnPHBcnTFgxDeTCk7bb3vgIgsOt+Lj/NCJlvDsB8ZsA2oLa0ssVA6UMl4s MLaUMto1Dhc4b26JpdNFClZaW8LRgPHy6JBaG2Ipp0CqtZnqKcSEEeJkbUcmCzp4vlpbCqCaAjwE DmO1t8SzzsHUsYsD6imMS/Efa0s8fVGGlmBuCT5miRT3t4uD6AGK6q3mlnhFIjVulgdRKA585XJ0 XhyEszwdOkMvlJ28hle8xMfmpJSkZjxrPFGc4EFxZPR2xIgXnNqWfC8JfDBkxkYeMHGgQbREC4fE BKfu4rcSOb09YyMPsN+gysciYSTBYAp141lKnLjnEzbyCBQ79qk0V5IxiES/6SQli7gsEzbywNNw uLTKDcWGQYZcmSno8uj+ANt44PYBzC+yd2lLXnBZ+iG5RlHkqMSEjTwWCj1h8De1w2mEq75RQyUS FJmxjQcJNYwUnghOIoWES7vH1Esym+gzNvLA2CDqXLkL1XHGiTVRyLGPGRt5oCYDAwKcXFdk5Ajn HkhoJS1UOWEjDxBqPP2A9/w53Ck4thskvcRLEGDCRh7QhwGWziD3ZTqOPQzdSjw7RjM28gh0STCE wg5Jw3GEKlvJgiHj/QG28kiU9wWDqC1wjxjv/c0UvCO6P8BGHpEW9JCSON+C0f1aZorCTt6MrTzo znPAzVGmYLyODYRGAW9aFAVjI4/kaLNoDXxwqGM63DlRpBH8H9jGY3YDOXL3ci/w+PNv5QQy9+4D ujq+U3w+IWj5swZBc/mEoGXPGgTN4xOCljtrEBxzAEFEgj7FQnD4RagL1UEbhqMaTTR9xkWwIlj9 dFJH8PCr2ttKuir1suJGtQ6TpFyqw8SLah0mKblUh4kT1TpMEnKpDhMfqnWYpOMaBCetQAp04s4z OBKOVgrL7il2r0NbKR48dOI4PW3YYxgXU5gYW+KRQqsMvQNjS44joKhJVvtHyaDjU+i+WNvCEyAg 72Tjm5ti8QlkGRx76NCKJpsnOlEdDJNrMtrqs+wraqjrn3weT23gBTeOPgjMwyqRgigGp4aW54On kFeRiLFAmAkyhVp9YmNjgqbnA9Vg8giKOjDEQ6SyXPWSwLvZMzaxwJ28gtn0qkSBBPt+6LuXRDlQ N2E7DzzlE2QbseHYN297iZdDdxO28XB8C8GlIrflBefSM9+1ktA2gDW28iAF5NbMurdh3PKKE0Vp uTQmbOMxr5qi9NqyR1sjj1fNktxG/45V8/jzODO/+wAPugUX2vFLiTX/AnKy+fB5Q+I+snQSRHsV Fl6/0FbQh/3m3Y93u4uH3d1md73b724e3m8+/HT25w+2T3hTIm1rcPTtxb12/PlX9BouShhYpMxN 2GvSW5tfrx6+bG4//rS7fLh/3HUnvuNNifTFZz4C+uKuO/78K7ouU0AhraR0VNc97q0Tr/6mRDpn JV+IfXFvHX/+NdOTArZrdnh2Cnrrr+/udpe/3N1f/fP9BhyqdzsRtvd/33z4fu6+E9/ypkQ6sS4n Fnxx9x1//jXCllHYaqRtWxQ26a1Hsnbizd+USGs/SUf78rXgOIPXdBf9cXRWileDr9cXVzdH1oAT 7/7GVG/yX3cpMYCCnzx+HyeXPnQp264Bm2bandLbUlI9uVN6U0rqJ29Kb0lJ/eRM6Q0pqZ98KWVf 4JArqQk06uP3m2NfKTekpz0eHPilDTryPfWgwxNDRT0JnWp91q/kp41no/1ZDJD4RT2b7c/GRAe1 xrNlPPvWqdFfOS6wXC6UXjpi0IlWgIfd+01YNu/+NWn9t5H1lfbERp7vOe+3lrff8ZtTRusK8xUG NhEubz/trGML7u6aKB1gYRUGtsXVw29mcc74XMEbxIG7u/X219u795vzCP/7cH5/c/X16270/7e4 VtqVc3T+DN/p6ub66mZ3/vHi4+76/PLi+tr8ejTviy/okNHrCav7u8vzj2ATwOtd317+bH6zyBmg 4tLF62fmsuM/v/36HoYfFs67T2aegbIrwGKF+px4Xl90oT3/fMccL360M4x46gmTpTnuP+498FR+ NouFwwB0Qe1K7/Ruf3F5d2tWNgklErOCgRmJT98/XDxc3t7+fGWXy4DBB0y9VVjnPFzc/bh7ML8B iXXFQ/T8Bg9X+x28xf6rWXQopIM5pqqfOZxf3978aNadDg/t10DZ6Whwmyl69/ECWP5eOqlnRp8S paNGkvqWGH3Kkz7qe170KU26qm9p0acs6aq+ZUWfkqSr+pYUfcqRrupbTvQpRbqqbynRpwzpqr5l RJ8SpKv6lhB9yo8+6ns+9Ck9uqpv6dCn7OiqvmVDn5Kjq/qWDH3Kjf5HrRgVZ3eqpc2Oj7fXn6wS nfkEiaO7/rTc7OwKGQ9cREqs0RTyZ1Z0t7cPN7cPu/O73WeznksF40qY2SKzu3L1cHF9dfnMD8m+ We+gJs0K0lMqHczesGbxNEVPf7q6PRdlZVbYlDoV0yeUyMzuH3D1BIl5d9UWmIcvregX+3JFe16Y y6CKP3z/y8f7y8776zPe0RMrTwEwYfV1d/dCZhVjl2ukJMTE7JebT7vGCZer30sv9iRtU862MS97 jrYpZZuqbynapoxtqr5laJsStqn6lqBtytem6lt+tildm6pv6dmmbG1Kr7tJ76jkbFLfkrNNudpU fcvNNqVq+4P0UiDtEDnRBukltPg2z7H4El2cio58ZNJOZN9ZzQa6zoF3vJY6nn7Wgh9It+JFKjGo L2/3OmD3TbuD9jDw8lKWqSEMXmSvot2BW0cezyQQt09XFzjPUOf+dn7frXUzR7DK8abpGvAzJ4sf TKPr3Yve0tNtDbxes8SnvYgXfT9tPeDVltLWm6t/Me/dp/Nfrz49fLF/eUVVgVdLsijTL7dd+f0f aH/4e3sDS9CmK+rr3XNUdcZNPLJjDr2Aze6GP/6fdn4e51Ly5PZLbOrm5souyPC5lW851DIxeNZ0 SJTBCu8XrGxqfL27Ndvg+G9qFDrQn0R6n/Lb3niV6PlIpvQkQ0v2dCRTdhJV37KRTMlJVH1LRjLl JlH1LRfJlJpE1bdUJFNmElXfMpFMiUlUfUtEMuUlUfUtD8mUlmTU9zQkU1YSVd+ykExJSVR9S0Iy 5SRR9S0HyZSSRNW3FCRTRhJV3zKQTAlJ/qhVbOF/oSNjn5HUfr3oTnz7n69fFrsSY4axxWieYBie y5AvxjzNMD9nmQkYn6zdrH+4aNMUbPpbVo6/PuOTmSF4pSGfYPiMTyaGwSWJiTzB0P7JmF8Qr3hQ Cv3Zsb+fVkH7RwvLtPTF6gmW9s8Wlpm891Ms8++lSvtVnulmz5iq/SbPdLFH1beLPNO9HlXf7vFM 13pGfb/GM93qUfXtFs90qUfVt0s8050eVd/u8ExXelR9u8Iz3ej5g1QRryuJXDe2/trs5pGXaOXu 7hkzk3KEVoduBa7nX3YXn9BhM+8mcPAB05z45rXv9uaHKZVNrt34RHNi123E386//YFvLN/tpKI+ t6jCPHJQUR9bHLX9nOJ0bFHVt2OK06lFq+y8bMvl8MDaJGPOzWPC2MNXJ0zfW5ceKd387d3+/m/v X7JN9I1/+Rbv2K+FLrHiLSG648kb/ryZ++afFyv9CyoJ9/zYEv78y83lw9XtzVNfp0/00nHB8Utf IAw5EQLu4Bb5nb9AszlyYBHZoIUOrhimaqIzkvz7NJsTb5NoD8f0NsdOQra3SXSU6+m3ecGwHN+g 4H/NbqUkFnRW4e7Hfzw+HPNaiT/VNuf9am3vr99sT/Ts/wGTqeInZW5kc3RyZWFtCmVuZG9iagoz IDAgb2JqCjw8IC9UeXBlIC9QYWdlcyAvS2lkcyBbIDcgMCBSIF0gL0NvdW50IDEgL01lZGlhQm94 IFswIDAgNTc2IDExNTJdID4+CmVuZG9iago0IDAgb2JqCjw8Ci9Qcm9jU2V0IFsvUERGIC9UZXh0 XQovRm9udCA8PC9GMiAxMCAwIFIgPj4KL0V4dEdTdGF0ZSA8PCA+PgovQ29sb3JTcGFjZSA8PCAv c1JHQiA1IDAgUiA+Pgo+PgplbmRvYmoKNSAwIG9iagpbL0lDQ0Jhc2VkIDYgMCBSXQplbmRvYmoK NiAwIG9iago8PCAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL04gMyAvTGVuZ3RoIDI1OTYgL0ZpbHRl ciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCnicnZZ3VFPZFofPvTe9UJIQipTQa2hSAkgNvUiRLiox CRBKwJAAIjZEVHBEUZGmCDIo4ICjQ5GxIoqFAVGx6wQZRNRxcBQblklkrRnfvHnvzZvfH/d+a5+9 z91n733WugCQ/IMFwkxYCYAMoVgU4efFiI2LZ2AHAQzwAANsAOBws7NCFvhGApkCfNiMbJkT+Be9 ug4g+fsq0z+MwQD/n5S5WSIxAFCYjOfy+NlcGRfJOD1XnCW3T8mYtjRNzjBKziJZgjJWk3PyLFt8 9pllDznzMoQ8GctzzuJl8OTcJ+ONORK+jJFgGRfnCPi5Mr4mY4N0SYZAxm/ksRl8TjYAKJLcLuZz U2RsLWOSKDKCLeN5AOBIyV/w0i9YzM8Tyw/FzsxaLhIkp4gZJlxTho2TE4vhz89N54vFzDAON40j 4jHYmRlZHOFyAGbP/FkUeW0ZsiI72Dg5ODBtLW2+KNR/Xfybkvd2ll6Ef+4ZRB/4w/ZXfpkNALCm ZbXZ+odtaRUAXesBULv9h81gLwCKsr51Dn1xHrp8XlLE4ixnK6vc3FxLAZ9rKS/o7/qfDn9DX3zP Ur7d7+VhePOTOJJ0MUNeN25meqZExMjO4nD5DOafh/gfB/51HhYR/CS+iC+URUTLpkwgTJa1W8gT iAWZQoZA+J+a+A/D/qTZuZaJ2vgR0JZYAqUhGkB+HgAoKhEgCXtkK9DvfQvGRwP5zYvRmZid+8+C /n1XuEz+yBYkf45jR0QyuBJRzuya/FoCNCAARUAD6kAb6AMTwAS2wBG4AA/gAwJBKIgEcWAx4IIU kAFEIBcUgLWgGJSCrWAnqAZ1oBE0gzZwGHSBY+A0OAcugctgBNwBUjAOnoAp8ArMQBCEhcgQFVKH dCBDyByyhViQG+QDBUMRUByUCCVDQkgCFUDroFKoHKqG6qFm6FvoKHQaugANQ7egUWgS+hV6ByMw CabBWrARbAWzYE84CI6EF8HJ8DI4Hy6Ct8CVcAN8EO6ET8OX4BFYCj+BpxGAEBE6ooswERbCRkKR eCQJESGrkBKkAmlA2pAepB+5ikiRp8hbFAZFRTFQTJQLyh8VheKilqFWoTajqlEHUJ2oPtRV1Chq CvURTUZros3RzugAdCw6GZ2LLkZXoJvQHeiz6BH0OPoVBoOhY4wxjhh/TBwmFbMCsxmzG9OOOYUZ xoxhprFYrDrWHOuKDcVysGJsMbYKexB7EnsFO459gyPidHC2OF9cPE6IK8RV4FpwJ3BXcBO4GbwS 3hDvjA/F8/DL8WX4RnwPfgg/jp8hKBOMCa6ESEIqYS2hktBGOEu4S3hBJBL1iE7EcKKAuIZYSTxE PE8cJb4lUUhmJDYpgSQhbSHtJ50i3SK9IJPJRmQPcjxZTN5CbiafId8nv1GgKlgqBCjwFFYr1Ch0 KlxReKaIVzRU9FRcrJivWKF4RHFI8akSXslIia3EUVqlVKN0VOmG0rQyVdlGOVQ5Q3mzcovyBeVH FCzFiOJD4VGKKPsoZyhjVISqT2VTudR11EbqWeo4DUMzpgXQUmmltG9og7QpFYqKnUq0Sp5Kjcpx FSkdoRvRA+jp9DL6Yfp1+jtVLVVPVb7qJtU21Suqr9XmqHmo8dVK1NrVRtTeqTPUfdTT1Lepd6nf 00BpmGmEa+Rq7NE4q/F0Dm2OyxzunJI5h+fc1oQ1zTQjNFdo7tMc0JzW0tby08rSqtI6o/VUm67t oZ2qvUP7hPakDlXHTUegs0PnpM5jhgrDk5HOqGT0MaZ0NXX9dSW69bqDujN6xnpReoV67Xr39An6 LP0k/R36vfpTBjoGIQYFBq0Gtw3xhizDFMNdhv2Gr42MjWKMNhh1GT0yVjMOMM43bjW+a0I2cTdZ ZtJgcs0UY8oyTTPdbXrZDDazN0sxqzEbMofNHcwF5rvNhy3QFk4WQosGixtMEtOTmcNsZY5a0i2D LQstuyyfWRlYxVtts+q3+mhtb51u3Wh9x4ZiE2hTaNNj86utmS3Xtsb22lzyXN+5q+d2z31uZ27H t9tjd9Oeah9iv8G+1/6Dg6ODyKHNYdLRwDHRsdbxBovGCmNtZp13Qjt5Oa12Oub01tnBWex82PkX F6ZLmkuLy6N5xvP48xrnjbnquXJc612lbgy3RLe9blJ3XXeOe4P7Aw99D55Hk8eEp6lnqudBz2de 1l4irw6v12xn9kr2KW/E28+7xHvQh+IT5VPtc99XzzfZt9V3ys/eb4XfKX+0f5D/Nv8bAVoB3IDm gKlAx8CVgX1BpKAFQdVBD4LNgkXBPSFwSGDI9pC78w3nC+d3hYLQgNDtoffCjMOWhX0fjgkPC68J fxhhE1EQ0b+AumDJgpYFryK9Issi70SZREmieqMVoxOim6Nfx3jHlMdIY61iV8ZeitOIE8R1x2Pj o+Ob4qcX+izcuXA8wT6hOOH6IuNFeYsuLNZYnL74+BLFJZwlRxLRiTGJLYnvOaGcBs700oCltUun uGzuLu4TngdvB2+S78ov508kuSaVJz1Kdk3enjyZ4p5SkfJUwBZUC56n+qfWpb5OC03bn/YpPSa9 PQOXkZhxVEgRpgn7MrUz8zKHs8yzirOky5yX7Vw2JQoSNWVD2Yuyu8U02c/UgMREsl4ymuOWU5Pz Jjc690iecp4wb2C52fJNyyfyffO/XoFawV3RW6BbsLZgdKXnyvpV0Kqlq3pX668uWj2+xm/NgbWE tWlrfyi0LiwvfLkuZl1PkVbRmqKx9X7rW4sVikXFNza4bKjbiNoo2Di4ae6mqk0fS3glF0utSytK 32/mbr74lc1XlV992pK0ZbDMoWzPVsxW4dbr29y3HShXLs8vH9sesr1zB2NHyY6XO5fsvFBhV1G3 i7BLsktaGVzZXWVQtbXqfXVK9UiNV017rWbtptrXu3m7r+zx2NNWp1VXWvdur2DvzXq/+s4Go4aK fZh9OfseNkY39n/N+rq5SaOptOnDfuF+6YGIA33Njs3NLZotZa1wq6R18mDCwcvfeH/T3cZsq2+n t5ceAockhx5/m/jt9cNBh3uPsI60fWf4XW0HtaOkE+pc3jnVldIl7Y7rHj4aeLS3x6Wn43vL7/cf 0z1Wc1zleNkJwomiE59O5p+cPpV16unp5NNjvUt675yJPXOtL7xv8GzQ2fPnfM+d6ffsP3ne9fyx C84Xjl5kXey65HCpc8B+oOMH+x86Bh0GO4cch7ovO13uGZ43fOKK+5XTV72vnrsWcO3SyPyR4etR 12/eSLghvcm7+ehW+q3nt3Nuz9xZcxd9t+Se0r2K+5r3G340/bFd6iA9Puo9OvBgwYM7Y9yxJz9l //R+vOgh+WHFhM5E8yPbR8cmfScvP174ePxJ1pOZp8U/K/9c+8zk2Xe/ePwyMBU7Nf5c9PzTr5tf qL/Y/9LuZe902PT9VxmvZl6XvFF/c+At623/u5h3EzO577HvKz+Yfuj5GPTx7qeMT59+A/eE8/tl bmRzdHJlYW0KZW5kb2JqCjkgMCBvYmoKPDwKL1R5cGUgL0VuY29kaW5nIC9CYXNlRW5jb2Rpbmcg L1dpbkFuc2lFbmNvZGluZwovRGlmZmVyZW5jZXMgWyA0NS9taW51cyA5Ni9xdW90ZWxlZnQKMTQ0 L2RvdGxlc3NpIC9ncmF2ZSAvYWN1dGUgL2NpcmN1bWZsZXggL3RpbGRlIC9tYWNyb24gL2JyZXZl IC9kb3RhY2NlbnQKL2RpZXJlc2lzIC8ubm90ZGVmIC9yaW5nIC9jZWRpbGxhIC8ubm90ZGVmIC9o dW5nYXJ1bWxhdXQgL29nb25layAvY2Fyb24gL3NwYWNlXQo+PgplbmRvYmoKMTAgMCBvYmoKPDwg L1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9OYW1lIC9GMiAvQmFzZUZvbnQgL0hlbHZldGlj YQovRW5jb2RpbmcgOSAwIFIgPj4KZW5kb2JqCnhyZWYKMCAxMQowMDAwMDAwMDAwIDY1NTM1IGYg CjAwMDAwMDAwMjEgMDAwMDAgbiAKMDAwMDAwMDE2MyAwMDAwMCBuIAowMDAwMDA2NjExIDAwMDAw IG4gCjAwMDAwMDY2OTUgMDAwMDAgbiAKMDAwMDAwNjgwNyAwMDAwMCBuIAowMDAwMDA2ODQwIDAw MDAwIG4gCjAwMDAwMDAyMTIgMDAwMDAgbiAKMDAwMDAwMDI5MiAwMDAwMCBuIAowMDAwMDA5NTM1 IDAwMDAwIG4gCjAwMDAwMDk3OTIgMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSAxMSAvSW5mbyAx IDAgUiAvUm9vdCAyIDAgUiA+PgpzdGFydHhyZWYKOTg4OQolJUVPRgo= --=-=-= Content-Type: text/plain Content-Disposition: attachment; filename=benchmark.el (defmacro time-stringy (class what thing) `(progn (let ((reps 5000) t0 t1 t2 t3) (garbage-collect) (setq t0 (float-time)) (--dotimes reps (org-element-interpret-data ,thing)) (setq t1 (float-time)) (garbage-collect) (setq t2 (float-time)) (--dotimes reps (org-ml-to-string ,thing)) (setq t3 (float-time)) (format "%s, %s, %f, %f" ,class ,what (- t3 t2) (- t1 t0))))) (defun run-tests () (let* ((text "abc") ;; value objects (code (org-ml-build-code "abc")) (verbatim (org-ml-build-verbatim "abc")) (target (org-ml-build-target "abc")) (ibcall (org-ml-build-inline-babel-call "abc")) (isblock (org-ml-build-inline-src-block "abc" :value "xyz")) (break (org-ml-build-line-break)) (macro (org-ml-build-macro "abc")) (stat (org-ml-build-statistics-cookie '(1 2))) ;; recursive objects (bold (org-ml-build-bold "abc")) (radio-target (org-ml-build-radio-target "abc")) (strike (org-ml-build-strike-through "abc")) (italic (org-ml-build-italic "abc")) (underline (org-ml-build-underline "abc")) (subscript (org-ml-build-subscript :use-brackets-p t "abc")) (superscript (org-ml-build-superscript :use-brackets-p t "abc")) (cell (org-ml-build-table-cell "abc")) (link (org-ml-build-link "https://downloadmoreram.com" "abc")) (fnref (org-ml-build-footnote-reference "abc")) ;; other objects (latex-frag (org-ml-build-latex-fragment "abc")) (keyword (org-ml-build-keyword "thing" "abc")) (timestamp (org-ml-build-timestamp! '(2024 1 1 0 0))) (timestamp-long (org-ml-build-timestamp! '(2024 1 1 0 0) :end '(2024 1 1 1 0) :collapsed nil :repeater '(cumulate 10 day) :deadline '(14 day) :warning '(all 2 day) )) (entity (org-ml-build-entity "Agrave")) (export-snip (org-ml-build-export-snippet "abc" "xyz")) ;; leaf elements (comment (org-ml-build-comment "abc")) (comment-block (org-ml-build-comment-block :value "abc")) (example-block (org-ml-build-example-block :value "abc")) (horz (org-ml-build-horizontal-rule)) (export-block (org-ml-build-export-block "abc" "xyz")) (fixed-width (org-ml-build-fixed-width "abc")) (clock (org-ml-build-clock! '(2024 1 1 0 0))) (clock-long (org-ml-build-clock! '(2024 1 1 0 0) :end '(2024 1 1 1 1))) (bcall (org-ml-build-babel-call "abc")) (diary-sexp (org-ml-build-diary-sexp :value '(poop))) (latex-env (org-ml-build-latex-environment (list "abc" "xyz"))) (node-prop (org-ml-build-node-property "abc" "xyz")) (plan (org-ml-build-planning! :closed '(2024 1 1))) (plan-long (org-ml-build-planning! :closed '(2024 1 1) :scheduled '(2024 1 1) :deadline '(2024 1 1))) (src-block (org-ml-build-src-block :value "abc")) ;; elements with objects (para0 (org-ml-build-paragraph)) (row0 (org-ml-build-table-row)) (verse0 (org-ml-build-verse-block)) (para3 (org-ml-build-paragraph text text text)) (row3 (org-ml-build-table-row cell cell cell)) (verse3 (org-ml-build-verse-block text text text)) (para6 (org-ml-build-paragraph text text text text text text)) (row6 (org-ml-build-table-row cell cell cell cell cell cell)) (verse6 (org-ml-build-verse-block text text text text text text)) ;; greater elements (item (org-ml-build-item! :bullet '- :checkbox 'on :paragraph "abc")) (hl0 (org-ml-build-headline! :title-text "abc" :todo-keyword "TODO" :tags '("poopy" "butthole"))) (hl3 (org-ml-build-headline! :title-text "abc" :todo-keyword "TODO" :tags '("poopy" "butthole") :section-children (-repeat 3 para3))) (hl6 (org-ml-build-headline! :title-text "abc" :todo-keyword "TODO" :tags '("poopy" "butthole") :section-children (-repeat 3 para3))) (pd0 (org-ml-build-property-drawer)) (pd3 (apply #'org-ml-build-property-drawer! (-repeat 3 '("abc" "xyz")))) (pd6 (apply #'org-ml-build-property-drawer! (-repeat 6 '("abc" "xyz")))) (pl3 (apply #'org-ml-build-plain-list (-repeat 3 item))) (pl6 (apply #'org-ml-build-plain-list (-repeat 6 item))) (drawer0 (org-ml-build-drawer "abc")) (drawer3 (org-ml-build-drawer "abc" pl3)) (drawer6 (org-ml-build-drawer "abc" pl6)) (table3 (apply #'org-ml-build-table (-repeat 3 row3))) (table6 (apply #'org-ml-build-table (-repeat 6 row6))) ) (->> (list (time-stringy "plain" "text" text) (time-stringy "object" "code" code) (time-stringy "object" "verbatim" verbatim) (time-stringy "object" "target" target) (time-stringy "object" "inline-babel-call" ibcall) (time-stringy "object" "inline-src-block" isblock) (time-stringy "object" "entity" entity) (time-stringy "object" "keyword" keyword) (time-stringy "object" "timestamp" timestamp) (time-stringy "object" "timestamp-long" timestamp-long) (time-stringy "object" "latex-frag" latex-frag) (time-stringy "object" "export-snippet" export-snip) (time-stringy "object" "line-break" break) (time-stringy "object" "macro" macro) (time-stringy "object" "statcookie" stat) (time-stringy "recursive object" "bold" bold) (time-stringy "recursive object" "strikethru" strike) (time-stringy "recursive object" "italic" italic) (time-stringy "recursive object" "underline" underline) (time-stringy "recursive object" "superscript" superscript) (time-stringy "recursive object" "subscript" subscript) (time-stringy "recursive object" "cell" cell) (time-stringy "recursive object" "link" link) (time-stringy "recursive object" "footnote-ref" fnref) (time-stringy "recursive object" "radio-target" radio-target) (time-stringy "element" "babel call" bcall) (time-stringy "element" "comment" comment) (time-stringy "element" "comment-block" comment-block) (time-stringy "element" "clock" clock) (time-stringy "element" "clock-long" clock-long) (time-stringy "element" "diary-sexp" diary-sexp) (time-stringy "element" "export-block" export-block) (time-stringy "element" "example-block" example-block) (time-stringy "element" "fixed-width" fixed-width) (time-stringy "element" "horizontal rule" horz) (time-stringy "element" "latex env" latex-env) (time-stringy "element" "prop" node-prop) (time-stringy "element" "planning" plan) (time-stringy "element" "planning-long" plan-long) (time-stringy "element" "src-block" src-block) (time-stringy "element with objects" "paragraph0" para0) (time-stringy "element with objects" "table-row0" row0) (time-stringy "element with objects" "verse-block0" verse0) (time-stringy "element with objects" "paragraph3" para3) (time-stringy "element with objects" "table-row3" row3) (time-stringy "element with objects" "verse-block3" verse3) (time-stringy "element with objects" "paragraph6" para6) (time-stringy "element with objects" "table-row6" row6) (time-stringy "element with objects" "verse-block6" verse6) (time-stringy "greater element" "headline0" hl0) (time-stringy "greater element" "headline3" hl3) ;; (time-stringy "greater element" "headline6" hl6) (time-stringy "greater element" "drawer0" drawer0) (time-stringy "greater element" "drawer3" drawer3) ;; (time-stringy "greater element" "drawer6" drawer6) (time-stringy "greater element" "item" item) (time-stringy "greater element" "property-drawer0" pd0) (time-stringy "greater element" "property-drawer3" pd3) ;; (time-stringy "greater element" "property-drawer6" pd6) (time-stringy "greater element" "plain-list3" pl3) ;; (time-stringy "greater element" "plain-list6" pl6) (time-stringy "greater element" "table3" table3) ;; (time-stringy "greater element" "table6" table6) ) (s-join "\n")))) ;; (run-tests) (--> (-repeat 5 (run-tests)) (s-join "\n" it) (f-write-text it 'utf-8 "/tmp/runs_interpret.out")) --=-=-=--