From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#39649: 27.0.60; tab-line doesn't scroll Date: Thu, 27 Feb 2020 01:16:25 +0200 Organization: LINKOV.NET Message-ID: <871rqhj5x2.fsf@mail.linkov.net> References: <87lfp0lsun.fsf@mail.linkov.net> <87imk3a5sa.fsf@mail.linkov.net> <87h7zn4d99.fsf@mail.linkov.net> <87r1yoopgp.fsf@mail.linkov.net> <87d0a8bu5c.fsf@gmail.com> <87y2sup4c2.fsf@mail.linkov.net> <87h7zg7vjx.fsf@mail.linkov.net> <87pne2ilur.fsf@mail.linkov.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="58718"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (x86_64-pc-linux-gnu) Cc: 39649@debbugs.gnu.org To: =?UTF-8?Q?Jo=C3=A3o?= Guerra Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Thu Feb 27 00:20:16 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@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 1j75yR-000FAD-CS for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 27 Feb 2020 00:20:15 +0100 Original-Received: from localhost ([::1]:51516 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j75yQ-0001uj-2u for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 26 Feb 2020 18:20:14 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:49381) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j75yG-0001uX-6z for bug-gnu-emacs@gnu.org; Wed, 26 Feb 2020 18:20:05 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j75yF-0001h5-3H for bug-gnu-emacs@gnu.org; Wed, 26 Feb 2020 18:20:04 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]:51964) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1j75yE-0001gb-1v for bug-gnu-emacs@gnu.org; Wed, 26 Feb 2020 18:20:03 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1j75yD-0003vf-TU for bug-gnu-emacs@gnu.org; Wed, 26 Feb 2020 18:20:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 26 Feb 2020 23:20:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 39649 X-GNU-PR-Package: emacs Original-Received: via spool by 39649-submit@debbugs.gnu.org id=B39649.158275917015039 (code B ref 39649); Wed, 26 Feb 2020 23:20:01 +0000 Original-Received: (at 39649) by debbugs.gnu.org; 26 Feb 2020 23:19:30 +0000 Original-Received: from localhost ([127.0.0.1]:57937 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1j75xi-0003uU-EB for submit@debbugs.gnu.org; Wed, 26 Feb 2020 18:19:30 -0500 Original-Received: from beige.elm.relay.mailchannels.net ([23.83.212.16]:49954) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1j75xf-0003uL-AT for 39649@debbugs.gnu.org; Wed, 26 Feb 2020 18:19:28 -0500 X-Sender-Id: dreamhost|x-authsender|jurta@jurta.org Original-Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id C5EF65A077D; Wed, 26 Feb 2020 23:19:25 +0000 (UTC) Original-Received: from pdx1-sub0-mail-a11.g.dreamhost.com (100-96-206-239.trex.outbound.svc.cluster.local [100.96.206.239]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 37DE15A0E6F; Wed, 26 Feb 2020 23:19:25 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|jurta@jurta.org Original-Received: from pdx1-sub0-mail-a11.g.dreamhost.com ([TEMPUNAVAIL]. [64.90.62.162]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.18.5); Wed, 26 Feb 2020 23:19:25 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|jurta@jurta.org X-MailChannels-Auth-Id: dreamhost X-Well-Made-Company: 17fa6b9d1f2cbb69_1582759165658_407075086 X-MC-Loop-Signature: 1582759165658:2020402184 X-MC-Ingress-Time: 1582759165658 Original-Received: from pdx1-sub0-mail-a11.g.dreamhost.com (localhost [127.0.0.1]) by pdx1-sub0-mail-a11.g.dreamhost.com (Postfix) with ESMTP id 7EA46880B9; Wed, 26 Feb 2020 15:19:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=linkov.net; h=from:to:cc :subject:references:date:in-reply-to:message-id:mime-version :content-type; s=linkov.net; bh=7eskFPFZorhv4uSrg462kJzroW4=; b= Pl3dGXvpcgKlNlqIqiAtQafyjZbaRofw5Ff0Vhu6b5eqNhqhhMo9fLySVTHV5qIg wJ9tTb65knjnGdAZf4nroga0jTE4mODG2SM1ysNC745aEYAmc0TrMxu+zz2QPsGY av8YvLvtszpySkOmvROwhE65s4OKt9TwYqiCNgzeFs4= Original-Received: from mail.jurta.org (m91-129-103-27.cust.tele2.ee [91.129.103.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: jurta@jurta.org) by pdx1-sub0-mail-a11.g.dreamhost.com (Postfix) with ESMTPSA id C619087FE9; Wed, 26 Feb 2020 15:19:17 -0800 (PST) X-DH-BACKEND: pdx1-sub0-mail-a11 In-Reply-To: ("=?UTF-8?Q?Jo=C3=A3o?= Guerra"'s message of "Tue, 25 Feb 2020 22:49:02 +0100") X-VR-OUT-STATUS: OK X-VR-OUT-SCORE: 0 X-VR-OUT-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedugedrleehgddutdcutefuodetggdotefrodftvfcurfhrohhfihhlvgemucggtfgfnhhsuhgsshgtrhhisggvpdfftffgtefojffquffvnecuuegrihhlohhuthemuceftddtnecunecujfgurhephffvufhofhffjgfkfgggtgesmhdtreertdertdenucfhrhhomheplfhurhhiucfnihhnkhhovhcuoehjuhhriheslhhinhhkohhvrdhnvghtqeenucffohhmrghinhephihouhhtuhdrsggvpdhgnhhurdhorhhgnecukfhppeeluddruddvledruddtfedrvdejnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmohguvgepshhmthhppdhhvghlohepmhgrihhlrdhjuhhrthgrrdhorhhgpdhinhgvthepledurdduvdelrddutdefrddvjedprhgvthhurhhnqdhprghthheplfhurhhiucfnihhnkhhovhcuoehjuhhriheslhhinhhkohhvrdhnvghtqedpmhgrihhlfhhrohhmpehjuhhriheslhhinhhkohhvrdhnvghtpdhnrhgtphhtthhopehjohgtrgdrsghtsehgmhgrihhlrdgtohhm X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:176517 Archived-At: --=-=-= Content-Type: text/plain > It does have your patch, but just the latest one in this thread. > Video demonstration: https://youtu.be/xq_JMBO4SyI. > I'm using Emacs from > https://alpha.gnu.org/gnu/emacs/pretest/windows/emacs-27/. It does > have XPM support. Thanks for the recipe. I tried everything possible, but still no bug reproduction. Given the above, may I ask you to run some debugging diagnostics: 1. load the attached file, e.g. with M-x load-file 2. M-x global-tab-line-mode 3. perform all steps from your bug report 4. after the last step, when the tab selection fails, execute M-x test1 RET and make a screenshot. The screenshot should look like on the image attached. I suspect that the problem comes from the tab-line fontified differently by core and when fontified manually in the buffer. --=-=-= Content-Type: image/png Content-Disposition: inline; filename=screenshot1.png Content-Transfer-Encoding: base64 iVBORw0KGgoAAAANSUhEUgAAAkgAAAGOCAIAAADjJWvMAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA HWlUWHRDb21tZW50AAAAAABDcmVhdGVkIHdpdGggR0lNUGQuZQcAACAASURBVHja7N13QNRmHwfw J7k74AZ77z0U98Q6qaNOcEsdddZaR1t9bbWtttjaZV21WltXnW1t3dWqaMWNSpGhbJApIHseN5P3 jwNE4A5EQMDv548WfpyX5Mlz+SZPcgkVGxtLAAAA2gsaTQAAAAg2AAAABBsAAACCDQAAAMEGAAAI NgAAAAQbAAAAgg0AAKCVBJss+uym/aGFLFFEnvpiz/1itqVmUvLggP9fYdKnM/CyvPQZaAC2IOL8 jq83rfvq0LUnTLWf2VbeE1u6U7WOSQNAM+Cq/QuTcW3b9ptZjOo3StBr6icje4zSFupSpGm3ALUn 9OlkF05dr+TZVswAYUsSHhZadLIVUY3a9osf37l4NSgyI6+c1TGy9nxtyEgva4G6t6o2racz0IKY jGvbtt/KJhShONq6xo5d+48Z7mGsbsUpH98KSLGZtnSxA1fJZlw4VPkz3ewzrUy9suXnoFym+m6T 0aBF74y2a+lhASbj2o+HyseuHOlc0Y1kYQe3hXZcPKeXgMJHHuBVDjZCCKXfc8GKEU4cQghFKIqm SEcRIYQomnouak5I3ctEVqoZYPKjrtyQ+3o2KtiU2dcP/hmsN2DCogm2+nTZ4+jLJ/86IH1z4RDz OtO0+rSqZqCFUfo95q8c6Uwrxdkx5w6d/dvUdnYvYd2LriwuLDXqaK1NcQhXVu3n5p9Jjp33ivVD CGHSL+49xo55b6QVreo0AACtJ9gIIRRN05U5o4g89XWQ3Qfzewie/l2eFRxw8kpcjlzbrPPgyWM8 TRq7Ba0+IdVRVWLg2dO30kq5+i5ejkrq6Qy8P1UYePhWSg679/swbbc33pvgynueCcni790q7jB1 Xm9nLUII0XLoPmFS/rZDd6L7+XoknN4YbjqQjr4RVyDjW/f1GTfc6vGZatNa7Bb5fZDdB/N76BFZ RnDA6cD4bCmla915xIQhnYw4isjTmx6YD+bGXI/OFXONO4/0Hd/diMkMPXXydmyulGjp2Q8cO72/ Bafx+cYRmHt0c/r3fGEZS4TlIUc3RHf+ZGZHLUKIIvb3r0Jd3u2VezowXlqWtHXHNdcubvkRFT97 jnpvnG1OrTWliDy9JdZ5nCji9K0MS98lfpYxp19oVimapgghFCGEoijV+mTraKi6i1VdqglbrA6a eqwismYHGOEuQjIDtLdgq2cjkXL9t0DZ4AXLeugX3zty5FiQ5cKBRk0y8CSNvfJnsPbopR901ZMk XPh9v0K/R9XmU9d93Pi0xL91Zi4eYP7cE2NyUjIYR28HrWptYO3sxPknOZPxIGx5VGTeW29+6Cco izq/+68Ai+UTq09LERlZseBJV38LlL8+f1l3Y2XWrZP7f79jsqi/CWHFD8Iypk9fMVlXmhCw6+it uE5vyK9cLew69+P+BkScnyvVfbHGYaW5ceEpfJeJahpZ6DJqtjT366jOy6d00yZEZpRf+bM85d/a a4oQtuzh9TteI9/+2EaXR6L/aMJZJRoayjilztar2PGIvtL0s6G5x1Zv4dodoKsQmwmAdhRsbHHE 4W9juIQQwnUeO39SzRcz6RExpPOE7sZcihh172594V5S6QAjveffxWWLQnZ/GqKaIbeJS+f20UmP SdLuOrmzIYcQobNXZ+t7qU20wKykXKot4D8zj5SOQEdaJGEJIbR5h74uIg4heh59eugfjk1VdBLU kY5pD+M5XSd2M+FShGvp1dfj5uUHT/p5E0KbdezXQY9LCNfR1Z4OKhBzbI2FedFh0S5eHc2NzAWN neni0H2fh1Mso2R17Af5zrR93v2RuteUgBDCd/ce6mTEIYQwhk0xqw1oqL7OalpP1QEMm6bFqrou IYQoJEq7jhrboVLtDtC1AxfbCYD2E2yUbsdJ7w6xpwkhFI/Pp2o+4IYpLSnLizv6zX2KEEIYJTG1 lLCkEcFG6fd8++mpfkKIQiyWiswrTiNRIqGwycaDKB2+trS4nH027MTl2nwdipQRSodfEXqUUCRS ppYrSF3BVlZaLnSonClaqCeQFItZQgglrJpViqZYlqFth0+fdvfG5QM/nzfpPNJncOdGjdVSet3n rRzpzGHlJRl3jp3Yc2ni0jesnytg6lxTAkJoQwPDimOippnVBjSUUl3rNeFsVOu6hBB55LG90Rrb oXr/qNkBCIINoB0FG6G4fJFItzJval0zQguEQouBU5YMNWvq694ovkBbXCJWpSQrkUjq2Cdv3DvT pvZW9JnEZJmrS+VopDw9IZGxHmlJkwTClpWWVky1tLiEKxDw6poWLRTxS4srXkiY0uIyvq6QIlKi OsH0DI7I8bVRb3sNSr5y4vCJUJu3exs2PqQpnq51n24Wl4NSCxlrEUURlmWropnRtNR1rikFeXaG m3JWNTQUR33rNd1sPNN1ZTqcetuhslvV2QEAoC15oUSi7bq6y+/fCsmSMoQoy/Mzcssb/U0AllFh GZYQwrFxsxeH/xdVpCRMecrdh+nKGrnH1y7JeVLemAlpufbprxd96nhIUoFUqZQVpYSePPFQOKCf hzYhhDDZ0XdjS5REWRh5936JvYcdp65p0bZdPaiIO6G5cpaVZt65F6Pr4Vn36T5lQUZWsZwltMDE Ql+LUTIv9lUJZVnGvbDH2mamejThGejzs9PTpYQQRU5YVArzgmuqiWdVfUNxNbZec8zGc7RD7Q6A jQRA+zpiqw/PYfDMYVdOH/npXLGSFhh7vjFhogm/MalWFLJnreocW8X32HQ6DJ36+O9TP2w5wTNw GdC1m2Hqs4ddnQZ5nDi3ect5tzeWTe34fN9O4pgNemuq1oWrJ7b/m1dO+MbWnfpPeauvGYcQBSEc R2eD8D+//6tAxrfuO2VcJwGh+E+ntdizcsHtB80Y/u/JX7efFVNCa88xb/azpOv8FgRTGHnpr6Bs CYerrWf3mm+3xl1aU3GOjRCKJ7Rw95o+ykWLEOLgNdr51Ikfdgn1hfr2Nh0Msl5sTTXNrNacbl0N RTS1XrPMRsPboXYHAIC2hoqNjUUrVA5JRZ76Oshu+fweurjEGx0AANoq3Cuy9uERmgAdAAAQbAAA AK0DhiIBAABHbAAAAAg2AAAABBsAAACCDQAAEGwAAAAINgAAAAQbAAAAgg0AAADBBgAACDYAAAAE GwAAAIINAAAAwQYAAIBgAwAABBsAAACCDQAAAMEGAACAYAMAAFCLiyZooNLS0qysLIVCUdFwXK6F hYVIJELLAAAg2NqkrKwsLy8vIyMj1a/5+fl37txxcXFBy7Ra8dHRrh06YNkB6wXB1todP348KytL 9bOlpeXEiRNbYKIpKSkKhaIq1QghRkZGCoUiJiam7mbF8RxAW5aSknL16lVCyODBgx0cHNAgr0Sw 3b59Ozw8nGGYOv9K03S3bt369evXrKlGCMnMzNyxY0ftlzV54EkkkgEDBtQo+vj4qHt9+z6eCw4O JoRwOBxCSI8ePfApgiYUHR1dWlpa559EIlGHljrcuXr16ogRIxQKxeXLl+fOndt62qe4uDgkJCQl JUUsFguFQnt7+549e+rq6qLnNEGwPXz4UF2qEUIYhgkLC2uOYJs0aVILN1Dyk8irEX+USQovx21/ 3n97K9lgSBc/ezPPdtl1lErlK/IhkUqlKSkpbm5uzTwdxZPwm7nmAz0tOK1hkZOTk8vKykQikb29 vba2dotNWl2qaf5Tkzh58mRGRsYz20cuVywWV+09W1lZTZgw4SWul9TU1AsXLsjl8qoGiYyMjIuL GzVqlK2tLfLsRYNNdQ3FggULavd4qVS6Z88eDbHXaDdv3nzw4EFD3pmm6S5duvTv3//FJ3rtwR9C U8ZIx6gxW4dyxdWIo7OHffGq9i5GnBWf8CirWKKktYT6Nu4eDgacNrUALMtmZGRkZmayLNuwJc5P uJ2g1a23nYhSFeQZocE5ln27WrStBU9OThaLxSYmJnl5ecnJye7u7jU+4zExMTKZrHfv3s00A833 zhrUSLUTJ05ofkHLH6upUs3JyalXr16GhoYFBQXBwcFJSUnnz5/38/PT09NDpL1QsKnUuR/XfDt3 ERERDdy+MAwTHh7eJMFWWl5o2KhUI4Ro87nZ5flN3g7Hjx9nWXb06NECgYAQIhaL//77bw6HM3ny 5NaVCmWpcbElBl28PPU4SklpmZLftjbuhYWFKSkpMplM9atqAJYQQlGUSCSysLAwMDBor9uF0tJS U1NTOzs7Qkh2dnb1P4nF4ri4OLlcbmVl1azz8LLGJJcsWVL7BEedxRYWEhKiSrVRo0apKqampqNH jz537lxycnJISIi3tzci7YWCrXrAsCz7008/URS1ePHi5t59rvq5X79+3bp1o2m6dqSFhYUFBQU1 dBe7LR4HMUx2dvapU6fGjx9PCDl9+nR+fr65uXmrm1GZRKZtYGygzaEIR2igVZV3j6MSUgvEUgXF N7H37GgpFKfeC5U4v+ZmwiGEsMUJIQ+ULv3cdcUZidGP8sQMR2jm0NHNTNBavnPJsmxJSUlJSYml paWNjU2DV1t2zO1skQOdm5IrllN8c1cPDws+ReQFSXExaUUySsfI1qByMEJZ8jgxNjmvVEFp65k5 eziY8Vt44YVCYV5eHiFE9d/CwkJVipeWlsbHxysUChsbG0tLy+YO10b8qamyrRV+8FNSUgghvXr1 qlHv1atXcnKy6q/QBEdsL1Hnzp3v3bsXGhpafWRSddFKnz59goKC2vE6GzNmjCrMTp06RVFUfn6+ iYnJ2LFjW9t8UrqmhsqoR4l6rg6mAi5VVdfStXTs7qGnwxbF/xeVnGvWydTEXPtBdoHSxIRD2NLs XNbUQ48UJj9IUjr06GupI02PiIhK0+1pz6dadP4NDAz09fWrhiKrBsfkcnl+fn5aWlpmZqZIJHqO 4zZ5dmZJ5y79Omop8xP/i0zNM3U3KHj0MIPj2sfLQluRH/8wjNG2JERZkPwgWenYva8lny1Niw57 kC54OrbZMhwdHZOSkrKzs3V0dBQKRUJCgouLi5aWVmxsLMMwtra2FhYWLTMntcckqw6dXzVisZgQ YmhoWLujEkLKy8tZlqUoisCL33nkp59++umnn1S7sTt27Ni5c2fLzDeHw4mIiKhxvk01Aln7MK6d EQgE48ePNzY2LigoUKWar6+vjo5Oc09XoVCEhobW2KwEBwffv3+/arzu2b0mY5eensbS1Ae3bkfE Pi6p+Go7xdMz0tPhEMLVM9KnpVIFS/HNzLXzs4uUhLAlubmssbk+Vfwkl5jZWAhoQvMtLfXK8gpl LyObKcra2rpz5876+vpVRR6PZ25urjpWe/LkyfO8ncDM1kSbJhTPwNiAkpbL2eLcQq65tbkOTSgt Q1szPZoQwhZn51HmNhYCmlAckY21iSznSWkLjz9oa2t7eHj06tWrU6dODg4OLMsmJCRIJBJDQ0MH B4cWSzWo8cEnhBQUFNSoFxYWEkL09PSQam3+iI1UXpU3f/581Ta9+S5aaeUUCkXLLDWXy3V0dIyP j69Rd3Bw0NLSqntLrmNk42lkLSvKiot6GMF2726jQ2RFaYlp2SVyliKKcoWWiBBC8c1MdEJyC5SG Wtn5xNRNj2JzZPLyvIc3MilCCGEZIhQpWKL9cj632tratS+JNDY2TktLq39MjCWkaq4pLS0eVRmZ hGUJq5ArtYRalYmvxSOEEFYuU2hVjdxSWlo8hUz+EjuYqampWCzOzs5OTEx0cnIyNjbGdvOlsLe3 j4qKCg4OHj16dO1DWHt7ezRRkwXb4sWLW+wcW41d6aqNTsUAl5pta7sckVANRRoZGVEUlZeXd/r0 aV9fX9UOXbMyMDAwNjZWnXdRMTIyqv699bpXlpa+pYtN9p2CEtaGmxsXlcHz6NHbUIticiPvpVQE oIk5PyInv5iXS0w9RRQhPC2e0M6zj5Owde+D1txHprR4PJlUVpVmrEwqo3k8dWMIFJfHkcvkhGgT QtiK+7VRPC2uTCpTFQkrk8p52i+zb+fk5GRnZ6uW9NGjRwzDmJqaYtPZ8nr27BkfH5+UlHTu3Lne vXsbGhrm5+cHBwerzq7VuHL1FdeGR+3a8eUhml24cEGVauPHj/f19TU2Ns7Pzz979myL7TZW7UPw eDwN+4lMWX5+kVimYFilpDAjWywQCSjCyOWslkioRRFWmp9dqKg6tDM15xekp+bRJuYiihBKz9yE yUzNLFWwhLCK8hKxopWtBVW6C4XCZ5NKaGymlZuYmCdWsKxSWpia9FhpYm6gLp0pPWMDedbjHAlL WHnR4+xilhBC6VuYUE/SM8UMYZWl6Y9ztUzMWjrfpVJpbGxsSEhIVFRUcnIyRVFOTk5ubm40TScn J9e4ThJahp6e3siRI7W0tJKTk//6669du3YdO3as6pqRS5cuqU7CAWmSoUiKolrmIiKKohoeZu14 uJmiKDMzs7Fjx/L5fEKIr6/vuXPnVPcBaQEcDsfR0TE2NpYQ4uDgwOWq7UKsrDA9Jr2kXM5QPL6B hUsneyFFiJmDdXZs+J3HPC7f0NJMJKl8tbapCT8+Qe7grNqGcwwcujg9io0IjpMyFE9g5tLBo/oF KC+TTCbLz89PT08nhNQ620SJ7Du7KmOTQ25EyQhXYGDm2tXRSP2q4Zo6ehbHxdwNiuboGNmaW+gU EUJofYfOTo9iwu7GywhPz8ytk42opZdc9T02U1PTvLw8iqJcXFxUVyi4u7vHxcWlpKQwDNNMZ9pE IlFzX/TYdtnZ2fn5+d2/fz8lJaW8vFxXV9fOzs7d3f3y5cuqq8nGjx/fAiM37TzYpFJp7W+tSSSS ZprXrl271r5gpO7jUJru2rVre11nNe59wOfzW/gbbHp6emZmZjRNa74gkGPo1KWfU80qz9C+u1fV UZ69dVUiaFt2965+/TgttHTpYdkabkqm7jI8Kyur6heVVM4338Slm0nt+abNPAabVf1i4DFA1XZa Rs6dXnOu0R600NKl58tc9hrfY6ta0SKRyMPDIzY2Ni0tjWXZ5rjivwPuEayRrq7u4MGDaxTHjx9/ +vTpvLy8kydPjh8/vuZAAoKtgWiaZhhmz549Gvbrm3xe+/fvX/s711KpVHXxSHl5edUBzbvvvosP QLOytbV9ZS/Bomla9QXtOlKtvaj+PbYa9yEUCAQdOnSIiYlJT09v7q+yvRQv/YvYjcDn8318fFSn 3s+dOzd16lQEW2N069YtLCxM802QW2D7olQq9+7d29yBCg3/5tBLuRNSc2uXC6WZ6ntsOTk5IpGo 9r3tdXR0WuAD/rx978VZWlpmZmZqfkGrXWUCgUB1VqLdf9+pGYOtX79+zXGP4+fSvXv3+/fv1/6C dtNORcQ3kJYrtPmNaShpuVzEN0QngzZH9T22lzsPGk62NdMDoVrmGVjNmm1TpkxB7yVt+ntsffv2 7du3b3NPZUgXv6sRfzTulo8ivuGQLn44ZAFoBJxsg1cx2FqGvZnn7GFfoh0AANoKSnXdNgAAQPuA 04wAAIBgAwAAQLABAAAg2AAAABBsAACAYAMAAECwAQAAINgAAAAQbAAAAAg2AABAsAEAACDYAAAA Wg9ufn4+WgEAANpPsBkZGbXAZNzc3DQ/mhagzbG0tIyLi6veydEm0LbU6MDtZivdQs9jy8zMxPNx oJ3ZtGnTwoUL1W0mAFq5o0ePTps2rV1upXGODQAA2pU6jtgyMjLUvdrKyup5XwYAANC6jti8vb2v Xbum7q/Xrl3z9vZGOwI8i0ndN2v2wccMKqi0eKXGgUp1CLaKVPP39x88eLC6FwwePNjf3x/ZBgDQ 2tROslck27gvkmo1si0wMFDjC6UpATs2/x5RyuHw7CasWTPWhkYFldZZqeNTcO3aNX9//3o6OVsS umflmj/Ttc1ce1qWky6ooPIyKtUyrHYHzsjIUH+2SJZ2eceWPx4UKhkd5/HL/zfeld8mK9wXTLWG ZxuTfOy735iZW/a9ZkjLS0oYChVUWmmlOv9naf4gKKP3rTvnuO7Ezz3p8M3T5yi6oILKS6g0ugMz KSe2BFi+t2O5g7b00cGPtv3da2Pfm22xojbYAgMDG55tDdiZZQsiwsV9Z/cxpAkhPF1dQtg8VFBp jZU6dtpU6vsssHnhEcoB73fXpSjSecxQp3BUUHkJlcZ34MKIkMTUki2r7lCEEGmppFtuftusaBqK bGC2NWiIBqBtUnXvBm8aCJfHUf3A4XFRQeVlVRrXgVmWiF5btOm9btyqfbUzR9pipZ6LRwIDA/39 /TVfFdmwVKMMu3YV3j1/L58hhMiKiyUsKqi0zkodIzlVu72aO7lx1670f3dSFYQoHwcFJTGooPIS Ko3vwIZdexjcOXUlU0EIYUpSEjNlbbRC1f6qeXN8j01XVzc2NiLl4vZNv4UV01xtx8lr14yxoaWo oNIqKw06mDt79mz1O4+4ubnFxYaE7l713XXW3Eikp4hN8dq5f5ZeOCqotGzl4FvWGrbSVdvnGnce 0dXVjY19mH7l580H7+YSDuGaDV26bnY3XlusUC1zDxVdXV3cUgvamTqCDbfUgtZ9xX/1o466gq2d bKW5WPEAAO3Vq3kfKNwrEgAA2pUWOmKztLTctGkTmhvak40bN9YYezx69CiaBdqKtWvXVu/A7Wkr TRUXF9f5Bz09vTrrLMuiQwAAQJMrKSmpsy4QCJrsiK12hlEUhaYHAIDWDOfYAACgXcFVkQAA0JYw DBMTE5Oenk4IsbW1dXd3p2kawQYAAG1VbGxsQkKC6uf4+HhCSIcOHaq/AEORAADQlqSlpWn4FcEG AABtjEQi0fArgg0AANobBBsAACDYAAAAEGwAAAAINgAAAAQbAAAg2AAAABBsAAAACDYAAIDmpOle kXhIDQAAtJ9gwwNFAQCgLcJQJAAAINgAAAAQbAAAAAg2AAAABBsAACDYAAAAEGwAAAAINgAAAAQb AAAAgg0AABBsAAAACDYAAAAEGwAAAIINAAAAwQYAAAg2AAAABBsAAACCDQAAAMEGAACAYAMAAAQb AAAAgg0AAADBBgAAgGADAABAsAEAAIINAAAAwQYAAIBgAwAAQLABAAAg2AAAAMEGAACAYAMAAECw AQAAINgAAAAQbAAAgGADAABAsAEAACDYAAAAEGwAAIBgAwAAQLABAAAg2AAAABBsAAAACDYAAECw AQAAINgAAAAQbAAAAAg2AAAABBsAACDYAAAAEGwAAAAINgAAAAQbAAAAgg0AABBsAAAACDYAAAAE GwAAAIINAAAAwQYAAAg2AAAABBsAAACCDQAAAMEGAACAYAMAAAQbAAAAgg0AAADBBgAAgGADAABA sAEAAIINAAAAwQYAAIBgAwAAQLABAAAg2AAAAMEGAACAYAMAAECwAQAAINgAAADBBgAAgGADAABA sAEAACDYAAAAEGwAAIBgAwAAQLABAAAg2AAAABBsAAAACDYAAECwAQAAINgAAAAQbAAAAAg2AAAA BBsAACDYAAAAEGwAAAAINgAAAAQbAAAAgg0AABBsAAAACDYAAAAEGwAAAIINAAAAwQYAAAg2AAAA BBsAAACCDQAAAMEGAACAYAMAAAQbAAAAgg0AAADBBgAAgGADAAAEGwAAAIINAADgpdDR0dHwK4IN AADaGFtbWw2/EkK4aCMAAGhD3N3dCSFpaWmqVFP9Wh1VXFxc57/U1dVF8wEAQIspKSmpsy4QCJ7r fTAUCQAA7QqCDQAA2hVuSEgIWgEAANpPsBFC3Nzc0BAAANAOxMXFYSgSAADalXYXbPKgjVN9xy/a H6tAHXXUm7reHBT3dy9ZsGDejMmT/QOK2Prr7Qab++9XS76/Udicy6aI+XXR7O33Fa1w8TWtX3nC kRXLD8ZKmyPY2KIA/ykL98UoKn675D/l7b3RCgIA0MiNecm1b/x8Jyw98khZWeL2eHvHnt3fTHOp sTVSV1e/V3tvs9/U74PktacZ8deGT9+f5zfBd+rG2n9+WcrD/jya039SPwOqoqBMPLJ0gk81k9pe oivCdsxZ2LCY0LR+ec5jfc2vHgzIauTi4wvaANByuVYWFvSQb2qYffduqp+TI6eFBqZ0zDqPmD22 9OIXB1tPSxTePnvLcMgmx2e3wVzPeTv8R5uoso6ieTzq1ewolH7fYd1+3XchftQct0ak1AsEmzLx mP/m61ZvffduX/7L3kvIurV3674rCWKj7hP7KVFHHfWmrDchcVjQA77XgrGpO6/eS5/maN8i50Io odvgUW5EHnydJq1lxIktDbsTZdJtlmmt4OLwtLS0qlfZnL8/WXJv8C9fjDSkiDL59xUfpU45vGqA Fpvz9ydLbthNsH0S/igzq8RoyOLVs3voU4QQWfrVPT8eupEkFjoOfM1ISYQVm+yUS9t3nQlPzi5V ahk595v89rxhDjpEfmfTW/tzO2hnxEo7vuElu3kxkvR4Z/1KbzOKsOKEi7/uOxmUUKAQWvf0fedd Xw8RRdRMl0n/e/1Xf6eXFxcVUxsW3+URjtmID9dNduKomW59dDp29yj4427yLDeX59//eYF+xcqK sh5n5JUxL72L5AX+8uM/0YX6nQb34N74574UddRRb7J6k+Za+J0IbpeeXr172j2+e/cxQ15ZyvTE FNbKzvIFj1mVSY/oMR9/u2Xnhom8iwf/SWEIIUzqmS07Ix3e3fHbka3zjeNDc6qaWcG1Hbnsu91H jh7+cbFL/K5NxyvHgxmH8d9ummESfDl/+OZdi50iLgfnsYTNv/bDl7/n9Fq+/bejB77ypf/ZsPtu Kat2urTNuM927vrpg4H6JsM++mnXrl0710924mierkba1nYmOUnJ4saMRr5AsHE7zN996tia14Uv u4tIY+5HlhODIYs+XvT2hysnOnJY1FFHvanqTXlWKeJOGOPZsyPfolt3i9S7dzNe4WQrKxPzBPxa uaaMPfT+zBkzZsyYMWPmvB3/1XdCkOPYf7CjNiG0TnCAFwAAIABJREFUsYe7SVZ6ppIQ9knIvVS7 ob49jLi0yM1nbI+qgyOOs/fEgW6mAi7FNeg0tJ/1k+RU1d4LbWJtqWNgYSEysbEWCCws9IoLihg2 L+jSff2Rs309DLiUttVA34GCkNtRcrXT1TCT6qZbTzgJBHxSVlbWqHTSeARP1a5Q9Q0cX/SfvyNU Tght5vP1zws6chtXf54DtvLiUiXLMbO24BFCW1hb0lQS6qij3jT1JiR5cCdU5jGnE59w7Hp2Nzp5 517mRBvrV/QrR0KhQJ5brqy5DaadJ/l/NNSIIoRQtLYur97DGh3tin9I0wyjZAlhSopKKAMjQ1W7 8gyN9ejyitDMDT1x6Nj16CflDCHK8gLGTaFkCU/1jwnhcDgcDq16J6WSMPm5+conF79bel210Wfl Yq6bWKr6B3VMV8NhZZ3TJfWdPWTKxeVEIBQ0dbBRWjo6FKOszGJGoaR0+Nqa54YyeGPd8TdevP48 A+h8PRGHYooKChliRRUXFjEs6qij3kT1Jsy1h3fuF8tKf5o3+SdCCKtUkDvB2ROsLajKDSRRKmvv +aurt3EcG2d7KiI1Q9n/2StoKK7A0MTE5JnNLM3hkMoNMSuVSOo50NEz0CXxZWUs4VOEMGUlYoZL CCFs0Y1fvr8setd/2wBLHYpJObriwxiibh2zhNCGRgZcN59vvhhlSNX8m8bDIYqw1V9Sz3TVr19p elquqaODkGriYCNajm52xf9eDc506m0sSfj39iO+i+/TMWFlwl+fbbpq9db3S/oJXmoX0fbo4cm/ fT/wyBH74aLgU9FK1FFHvcnqTXbKIDIoRNLlnd1fjDKmCCGy8J2LvrxzL9vXx5wihFD6VlaCtIeR hW8MNKx+DKeurn4/XyGXySq2mxTN4XI5FCGsUq5QyhUMYRmlXCYnHC6P83IvN6RE3bw67g4Iz/Fz tKhnTig9aythekx86WgTUXnMjf+yGTuNLzfr6WV/7NbN9BHjbTn5dwJDy0hvQggh8jKxQs/DyVSH ImxJ5KWbqUoTje9j0m9412N//fqv+9tDnEREnJ0Qmkh36eem+bEvlK6+qDg2JV/Z0awyKjROV/36 lUSFxhj0Hu/QqLOQGrsKbTN2+dJuWQdXzprit2jDbb3Jq+b0fHoxCysvzs58UlD+0r9nQRl7L1wy 0o0bf2bP4TCLnp6VVxShjjrqL15vIrKoOyHlHQf0Nap4W62OA70MEoPu5VRsQLS6TpnfO3P3O1On +i3ZH/P04kV1dXXxeet7v8mVpizaF6UghChCd8ydPNnvm6ulkpsb/CZPnv9z2Eu/OpIyeG1s/4Kr gUn1zwmv08TZPdN2f/DeR2s239Jytqon4GnbcR8ssL377QfLV67adE/boSIwKGPv2TNNb3z53orV n67ZeoPvaldPZFAm3u+v8dEO/H7xzKl+s9713387S15vn+A4DPcbLDn2vzlz5s5fdTRBWe901axf tujev2FWo0e6Ne7CfSowMBD3igQAaGls7r9ff35/0FcrBxpQaI1nyBOOrNquWPjdbA/t5//HcXFx CDYAAGg/cBNkAABob7iqfENDAABA+0AVFxfX+YfMzMyqnzFWCe1S9V06dHJoe5tvNd8rZtm2+jCE kpKSOusCwfNdes9txCYAoB04evTotGnT0Mmh7XZgNII6OMcGAADtCh5bAwAAbQnDMDExMenp6YQQ W1tbd3d3mqZxxAavioxnNfyDk7pv1uyD1e8+jwoqLVRpig7czsXGxiYkJEgkEolEEh8fHxsbW+MF CDZoz6lWbwUAHbjNSUtL0/AreZ6hSEniqW8+3xNcxOFqOc3YtHGaAwcVVFpn5ekmwNvb29/ff/Dg wdeuXfP39w8MDMzIyLCysqq7j7MloXtWrvkzXdvMtadlOemCCiovo0Ia24FfGZJn7wQtqXVj6IYG mzJ+/8e7le8e+NvbhCMrLmZoVFBppZXq/J9VTyeP3rfunOO6Ez/3pMM3T5+j6IIKKi+h0ugODM87 FMnmhwSXDpo80IRDCNHS09OhUEGldVae6biDBw+u2igMHjxYcyfPC49QDhjdXZeihJ3HDHXioILK S6g0ugMDzrHBq0E1gKNy7dq1el/P5VVsWDg8LiqovKxKozswPFewUUa9+uheP3YjV0kIkRYWlrOo oNI6K3WM5FTt9mru5MZdu9L/3UlVEKJ8HBSUxKCCykuoNLoDQ7UPcwNvqRUXF5Fw8qvPdt0r5PB0 XGdv2TjFniNBBZVWWdF0CVnVifcadx5xc3OLiw0J3b3qu+usuZFITxGb4rVz/yy9cFRQadnKwbes G9iBP/vss7pH1dv7LbXOnDlT4wU+Pj6NCzbcbQjanhqbhuqXk9URbOjk0KY6MIJNXbDhziPQnuHC aEAHfgXh4hEAAGhXGnrEhjtJQzuzdu3aGmOP6OTQtjqwuqFIUHuOTVdXF60DAAAtpqnOsWEoEgAA 2hUEGwAAINgAAAAQbAAAAAg2AAAABBsAACDYAAAAEGwAAAAINgAAAAQbAAAAgg0AABBsAAAACDYA AAAEGwAAAIINAAAAwQYAAAg2AAAABBsAAACCDQAAAMEGAACAYAMAAAQbAAAAgg0AAADBBgAA0DA6 OjoafkWwAQBAG2Nra6vhV0IIF20EAABtiLu7OyEkLS1NlWqqX6ujiouL6/yXurq6aD4AAGgxJSUl ddYFAsFzvQ+GIgEAoF1BsAEAAIINAAAAwQYAAIBgAwAAQLABAACCDQAAoH2gWJbNzMxEQwAAQDtg aWlJZWRkxMbGoi0AAKAdOHv2LIYiWx4rKysuKhbLWTQFAEDTQ7A1IIhKLqwe4T38nSMpTINennNq xQhvb29vb+/Xx6y/Ka/196zTqyePn7z2fH5TJ5si/MdpQ4dO3PSfokWbR83y1tcOLU8R/OOcN/2m +r7xxkfnCtn66+2nB2dfWDPniysFzblsisifZ03aGKxohYuvaf3K4/YtWrg7SorN3KsTbGzhuY9G zfgpUlHx2z+rRk3/6WH9PZfN+OvTzfcUDa43N/ntr8e/fzzr2R7NpBxeONx7xCcXS5r6007p9Xhz 5aoPZ/UxfDX2GtQtb73tUOd6acLdkX8/G/P6sLn74pWVJW7vZft///2HWe6cZ1+qrq6pR40Z9eWN 2vssJaFH1q1YMG3MsNdHr78hby1rSBxy+FD24OmDDKmKgjJ+39xh3tWMaHuJrvhv0+QZDdkcaV6/ PNeJUywv7TmXgfETHLGp3ZbkBe745sCtNAlLiCI/8swP3/0Zq9BQb+791MLA75Z8uudKYjFDiCTz 3tFvlq4+2rCjrheibdd7xMgRfR3V3LWTspzyY0BgwCYfY6p99CF1y6uu3iLrhS0Nvh4uMDfOunUr WdlyIa9j0X3MO2vefk3QetYtW3D9xDWj4SOdn32SB6/L4kMXLlY49/Vog3bSG597lRn0H9Ur9fTf MQoC7ccLPLZGGf/bqq/+tX77x+X9KzZdlLH3wvlh537beeZhkmiX8Zszl45z4GqoN3uXHbhgsfjo r+t+CC2RXfti39A357/na08TedA3kz4NUB2pBX3r8/q3hOu2YM/OGfa0LObEdzvPRCQ/KSonQnP3 AW++t2S0U+Uj7Jisa1sXn76UxFj2eXPlR1M6Cp9/S6AI2eL30Zk8hhDC67H8940V2aYI/3HGilPS HqNfKw0KfCQ17Tvv8zUTnLUIIfKMG/t37L8YllZMDBx6jp6/dGZfs/paji38b/fy7/+OEptUvQ8r jj3z4/Y/b8VlSzhCY2vPiR99McWVozrGiDr1864Tt2KfSLVNHbtPWLZqcgcdQpikQ4sW7kvuNPEt 44enbicVU6bjvjiwrCdXkXlr//Z95++nlfJM3QdMXbzYx0NENdV6aVJlITfCBAOWTEzeEnAr9S1n xxY5eqZEHYb6dCDyoMs0UbaSTzhb+t/NB6Y9F5jVWk8cLS0trepVNvvEB3NuDzv8/TgjiigfHXhn adLMk/5DtNnsEx/MueI4zT4zJP5xRonx8BXrFvY2oAghstRL27/fE5goFjp7DzZWElHFpiHpn40/ HgtJfFKi0DJxGzh92bujnPhEfnP9xF9yPLXTo6Vdxg2QBp6NIH3e27xmhDlF2LK4sz//dPRGXJ5C aNt36vsfTPbUpYia6TKpxz9dcyJVXFhYRK+bfUuL0OZjPv9+ugtHzXTro9O5l2f+wVuPFnRw4yAR cMTGSgsz0tJzy6rtajPFyeHBkQUCYwMjAyY5NDj6iVRjvblHK4oykx49ylLoCGkdEV2QnJiYklPO Eq6rz4pPPl44xIImXNdxKz755JPV8/qbqj6nD+Kojm/MWPK/9/08lZHntm4+nV65eMpHF/9Jd359 gB2TcmPXN4ejGrODx3Ec9f7HHy8eZlPHB4gpiUkW+Syc5Ek/vrnvtztiQogkYvfqL38PkXWcsPCd yR2l9w75f370UX0bTLY4+Faa85DelvL0yvdh0k5u3RHwSH/Ysk8/XTF/bGe+VKwaeGEz//5i9fbz 0QqX4dOmjeltlBWVVF793FPEPwGy3jPeW7nsTS8rLUJk0fvXrPvtbrHdiKkTemgnXNj2yYZ/89gm Wy9NOvp2/2Yot7vXAK++Dum3bqUxr+4nXJkSn8TYOli/4DZbkRhPT/hi266D2/20zu46ncQQQpjk v77ZGuG8Yv+Z07sXm8YEP6lqZgXXfuyH238//c/pfSvcY3786o+Eim7LOE3b9vM806B/8kb/fGS5 y/0LQbksYfP+/e7jA9leH/965p/jW6ZQp9Ztv1V5hqCO6dJ2k745eOTA6tcNzEZ9fuDIkSOHNk93 4WieruZks3Mwe5KQWIbRSByxEUK4nRb/9u/iZ7epifHK/kvWGlz6/A/7jxdbBQfEZSks7Lnq6s29 rypLDYsVjfliF/f3ucfcN692uPfHvdgSLxu+ieeQYR1Sso7tu5pn4jlk2HDdyt1WwcAP9wwXaLEK mUxqm3ntzm+JsY8UxFq1N67n/d76/73Gf2KZPWt71H8hqW97OtFswdUfPv8zTkEIIbTBoGVf+mk8 T0MZeQwc5p5Z8Pfuy09qj2L1njJv1MBy5aU/Q8OfZBWyhBP6z8XHSoOh89/366VNhuil/PfNzctX H/k5uXI0TVer9+xPlg6VnI4P2vrwSVYhSwREoZSzLCMuKJIL3b0mDh3HVy0wk3rlXFgJ7TL3q2/f cuISQlilklTbhaftJ6/9bL4rlxAyghCiCL14MVmp9/p7Xy0fKGCGCRe9/eudf27mDfU1oZpmvTRl rt34j+nyQSeBlXEfq/23bqVPt7d7Va+TKist0xYIanVLRdSeBeMPUKquN2j14f958TTukzkPHuqs TQgx7djRdHfqYyVxojLvBiU7jPy0tzGXJh0mTehzdFvli11H+LmqfjTsOnKQzZmYZClx4RFCm9pa 8w0VViIzC1uhUGylX5RXyLDs9XPBBmO3T/E05BBi8/pU798+uv5ANuA1rbqnq35F1j3deh/kRQuE fFJWWkaIHhLhVQg2iqLqrTw7xtR99EhC2HxLd2cDWsfmNR8bjXVCCFtw9qNpm/6TE0JbTN56aEnn Jkw7StB95v+6E6IIN3e0NhRZ9JqyvJfmvdLMu79u3X/5QVqRlFHtvWlJpZVHZrSptaUOIZSxtTWf elhSVMoQQhN5QUpMdLScEEJoYzfxC+zzUdpCAZcQLpdDCMswDMuW5eWVM4z80rrJl6o+gpxc1bWU 6qdL8Q0MdAhhtbUq3ocQ2tFn6ZyEbX/d2vv11T2UjqXXnM/WTPMQECY/J5+htB1dbCtaneI8s/2j za0tqhVk+XnFDG1na61DCKEtba045FFBbgFDTDjNu16eW3nYjf9knu90ExCOQ59exn/cvJ3hZ2fz iiabUCSU5oiVNT/rHDe/7z4fZUIRQihaR49X30rT4VeMyXNomlEqGUKYksIiYmhipGpXLWNTfUpc cZSY898fe45ceZhZpiREWZ6v7CBXsIRHCKE5NCE0h8NR/Z9WKpWEyc/JU2Sd9Z97harY8SnjdhBL WaJV93Q1HJ3WOV1S334XU15WToQiAeLg1Qg2SpuvQymVlQfzSoWS6PB16t87p4wGvOXbwDplOPb7 gLHNvIxdF2zpWldsE0LYapFQfnvfpuMhUvsRy1YMd9TNvvD9xgu5hFS+gMnNeiIjjtoFmVnlLG2m L6IJIZTZhC0BE+psBC0elyIKiUROCK9Rs00JDQ11KFp/yHsf+1SegaK4Ro4cjdNVs8fRbcYX+6ZL 85MfXD+ydfuV/Ydujl4/Qpc2MjGk2cLkR4+VrzlwCCEswxCarlrDFE1X35HRMjTWpZmc9AwJcRIw WekZSkIbmlRc86hueTW0g5r18uIk4TeDi6Ulm6e+sVnVccnN21nTplpRlRtI8rRXV9vSq6m3cRx7 V0f6fnK6kjg/s/9BcUXGpqamz3ycaQ6HKBUVV0FLyiWa99NoPUN9ElNSyhIBRYiytKiM5RFCCFt4 5Ycvzusu/27vEGsdikk6+M7iKKLurVhCaCMTQ57H5K0ba15OpXnyFEU98/Gtb7rq1680NSXb3MVJ 9IpePtMuadyL1XLu4FAUcinosVghy4+6eC1e6O5hVfXpUMYdWT5rzqYb4ja54JS+kSGHUsYGHD51 /kJA0KMytuJ4lGvo0MHDTpQfGZ3zzAeLLQrcsW7Hnk3rDoYrKIuePesZ2qItHOy1iTz0+M6//rlw MTAyjyVEknov4MKFC9diChnC5EUGXrhwISAkXe1V4drdR7xuSeXfPX3mXsyjR3EP7gb8tuNiCv/5 P35s5rkNa7YeOnMtIr1IoiSE0DweTRFC23qP7ixUxh/+9JNt+w/t+9F/6dcXNVz1ze00fIQdpzhw 25qte3/58ovfExi9viP7V2yM6lpeTfVmJA2/ca+8+/u/XwwICAgICDj7vY9hws3blV8roPRtbAQp 4RH5TM0OUXdd/X6+QlZFrlBWnLVUyuUyuYIlrFIpk8nlypd+3oYS9RrQOSfkfjbbgM+EjY0wLTK2 lCVsWWTgnSzNTUFZ9B3glHTtaqqcECbvZkBIacUkZGVihb6di7kORdji8H+upmjeW6BMB47ukfLX LxcSihWEVZRlRl69Hl3vt3AofUO9ouRHedXeW+N01a9fyYPgSMN+rznjypFXZSiStpv48cqcrbsW T1gn5ho5e03//J2+T0+EsLKiJxmZgvK2eWKe0h8wfdbN7BOhJ7aHKWjXBe59nez7zV0+PnfPpX1L Zh217d7H3JROya225+s0bLjJwzOXHylt+i34cEbHesZMKd2Bc94dlrn/xj87N56lDMZ+N9DTqDjk 943bwiqCLCVgx4YAwuvzYZ8eFmreQ9Dr3e/Winb9dunvfbekXKGRlWuPCdaNGVDjGxvITv3z66W8 UilH16qL7/L5A4SEEEJb+372tfznPaeCzh2+zzGw7zF5iqYjci3PuV+tZbftu3jxj4dcE/c3lixe PLzy/Fody2vM1VBvxlx7cPOuuPOcysQlWp29BxhevBGUPWmiOUUI0e45Y0m/dT/OHL2Bthi/Yc87 nhWzo66ubjJXvxh79emg7cQth5d14SqCN035+HwRQwgh68ZepQ3Hfvfn/3pxX25PNxw0cfChXRcT J8xxqWdOeN383unjv33B/KPWlq4d3Ww4Ms07b/aTVi/N3Pj525cFQpGVnWPFoCRlOmLhvPDNn8y/ ZmgkENl29rDn5teTbCNWrZfu2rVuzvY8Kc03duw2ekHPeo9EnUbPGhayc9GUQ1yepc+XW2e5cTRP V836ZQtvnQ+x8d3SgYs0aEdwr0iA9o7NvrD2o3uvb1n7uiGG254lj/t12Ub5sh8XemqjMdqLs2fP ItgAAKBdBRvuFQkAAO0KxbLsypUr0RAAANAObNy4kSouLq7zb7q6umggAABoMSUlJXXWBYLn+5oh hiIBAKBdQbABAACCrU7Mo80DdEftzWnoN1JlF9/3dHSwNebzR+6p48uj8qAP3Szfvihr8iVmUrcN 1h3+S1ZLf3NW3fLW0w4AANCkwSa79I61y4pbzfHIRK03fohMenR9rZqvr3Icx3/29fR29K1Jdctb Tzs0mDLp1CdT+7tb6vN19G17Tfky4HG9d4cqDds118tOny809/T5PCCTwccBAHDE1pwzZtF/5lxv OwyVNvhINDutrMviXwIiUlND9o7J2Tpl9i9JGqNKfH3t1JUPBu+PK8wK/IC7980Fv6Yj2gCgPQeb MuaHsR4uHef8kZ3667QOLi4u7kO/DVMQQoji4d65r3e2NdYT6Zu5eS/aF1Fa9Y/Y4ntbJnay0Ncz 6zjui3+zG7mdLD7xtqeLi42hjnn1oUgmddtg3dcWr1swamBPV2vHwasuVg7csUUhvywc4mqqKzKw 6fnm5qCC+gf0FEl/LRvkoM/Xtav2PsyTy+vGd7U2MjA0tnDtv/jPp0/xkiSe/GRCD1sjPX0Tu+4T NgZVLnHhQR/d3qv2fz+9f2cPV3u7zisDZYQQJuvyFxO7Whno6pm6DFl8MPJFbqapuP/tcM+u754u qfeVvL7LflgzY0hne1MzlxErFw6S378XpelIW3brt6NZ3u+v8jbX1u04d/VM06tHTj9GsgFA69+N Z5ioqCjVzWCjo6MZhmlosHE83j8bkxC138/Mbu7R6ISEhNh/V3dTjZbJtDou3HMrKa8k98HPvYLf n7khrPLRLvJ7V57M+ielICNwKdk5c/mp/EadM9KbuDsyIfqvBbUP1+ThoZylx2+ExNz6UHvX6p0P lIQQJuO3eWPXpY058DCvOCNwOb1j6vun64s2+d2z0UMPRuc9vjhL/NMq1fsQ+b1NS7ZJF159XFCQ nXhlyxS3ytsNlwauGjUvwMH/amphUVbY/pmONPP0/RVRh4/K3vs7PCY++eGJhR5cwmQceufN3Zz3 rjwuznu4q2/wsmnr7zX+TCFbnp0YG/e46PluOi8OC47i9ezbWcNjBZismJhCG08P5b2fV687merc yZ3ERsYp8JEBgNYuNjY2ISFBIpFIJJL4+PjaN89qxFAft8esD/362unxKJ754DkT3ZIiqo5JuJ3e Wu5rp02LPOcvHUsunr7VxA/K5nad/GYXASEcm35eNkkxCQpCmMcn9lwwW/jt8tfMtWiBq98KP/3z x29I6nmfTjPf83Hgc436TBxhlxyToCCEEIrDoWW5iZEJT8opoW0f724V9/cVX957pHTSl1/5OIto wjXqOmlSX72nd9yjDMat+J+XEU0IpefqZkmT4isnA/WnrXjLQ0jxzL1XLnot+fTpB40ODF7/zY8U 5WfeMniOLMy58OGiozb+m+dpGshly0rLiECknXH98J4DF2KUAgFdVoJnCANA65eWlqbh18YFmyI9 4Ou3vLu4ODg4ODi/sTlSIZPJK59RYmZuqnpHjqm5sSQ3T/UETPbJrjd0KIqiKK7j8psvcCUKJRQJ Kx6qxeEoFQqGECYzPVOetHtKJw8PDw8Pj05vHsnTkpXUM11K39BANZ88LZ7qfQjh9lp1ZNugtM3T ulkY2fedvqViSJMtzMySWDraq7lHKsfK3rb6gRFTkJvHmFmaqZ6BQelZmOvk5+S12BAfm3/103Fv 35/wx7EPOmvX25TiMrnnhzdzH/0yWkcsZqoaFwCgFZNIJBp+JfU8toYQQlEU++zT/HL+WOr3q+HO 8+FTXIS08uGXvbyCql7AZGdlM8ScQ4gy50ke39REoHr0vPnCi5KFdecCh0MUihcYAaMtrMy1+3xw 7dIiy1pbZQ3TrXNZDXrM3fTX3E1seeqFVWMnr9gz9uaHrhzKwNJCJzMpRUo61vnd92oP5iSEENrA xJjOzsxWEmeaELY464nEqIcxXd/yvnA7EEIIm3f1k7Gzrw09dPbLQfXdxp0293DXfxwVU8z2NKKI IjYyjriPcMOjOwCg7avniI02MTPKi3yQ8XSLy0qKiuUmHt3shTRh8q7v/TOq2tZY8fDwD2fSpExZ 1N7tZzmjJw6o71EQtKmrq170tRtZjX5wMW0zcd7QqC0f7Q/LkxNWVpR0+6/jdxt1bk8ZF/BHYFyB jKV4QpEOhyMQqp5NJhg6903h8c/W/P2ojCHKoqjTp4KLNby/vrfv4MI/Nx+KLWPl2Vc3/nzbbty4 Ttx6lldtOyhCvvZ291x4srje2WdyLn80aua/A3YfW+MllEokEqmc0fQ+2v1nTDW/sm3TzVyFOO7Q hsPZQ2b4WOMiVABo98HG7Tx/7fTSb3tbW9vYD1gfoiCEtpn17Zd2R8d16T3Qe9ico7p9OlYbiOP1 fd380Gh7Q8shO+ilhzeNM6h3aIs/7JPNYxLed9UV6XuuCpITQhSh33g7Ozi4TtqVnPPHbDcHB6de H9+Qa0q2t349vVxwaFpHE119c49Rq048kjZqRI0tiz764Uh3U3190w7zg71+3DbXVtU6ukM3nNv9 esLagTb6+madpu+LV9AaJkBbv/XLkXmyrUOsdI06zA/qsfXoWi9tDcuruc5KclMSH2WV1D+WWXLx x+3Bj4M3vmEt4PP5fD5f33d/LqvhfQSD1h/d0OHydGc9s/7fl8/9bXfl8gIAtGm4CTIAALQKDbwJ 8pkzZ2q8wMfH5zmO2AAAANoWBBsAACDYAAAAEGwAAAAINgAAAAQbAAAg2JpAW3nQaJMtb0s9sJRJ 2z++o98fT9iWWS8V2MIb60e5muobGJj57M1k6603LXVrH3XUUX/xeguThqzt3fPjO+IWnCQeNNra lVz+6svUKasnmVM14mqQ6/vX5Yq7qzy9volWNvVU2cw/vthQuOBGTmFh9pn5T+9Wpq4OAO1JUz64 WLvHe8sdD3+yJ7HlHouFB422buyT4z8es5w5u0uNJ9CI799L7OLVlc4MDi7v0deZ0+TdOis9U8ut o6NWA+sA0J406YOLKVPfucNjd+4KlrfU7L/ngYd0AAAWKUlEQVSaDxqt88GhGpZL3YNG635gqab5 afiDQ1VvVXDp1E2bYcNqBrz8wd0I+z49RJKQO3Fd+nWr+dw1RV7kue0rp4z5/Lpc7Xp5ZihVEbGu m+6UP8sJIUzGwekdXDx8f4ovPPlORxcXl46zjjxh1dc1LW/dD2JVu1ZiDi8aYG+oa+gwYNnxZAXq qKPeRHUm7dd5oxZ8deR2mriBpw+a+MHFwgEj+mWdPRPRYk98LFaDZVmWZaUBC62cl9+UsdXIQw5u +P1OSpGMkWX9u7KHqPPaUDnLssrETf21uC7zjqdIlCUPd4y1sJh+PI9hNVM+2jJA9MbuJ7VfJ7u9 0tViwQXp05em/DBIW+D1ZWgZyyqSdgw36OYfrmBZVvn48EQLy5EbbmVJlWVxh6Y72cw6ma9xuiVX 3nM16PnB6YQSJSvPCzt27E4Ro3651L1emfLDIG2+57snksTyvFuf9BJ1bcj8yG4ud+TojDtQwDaI 7OZyJ70pf5ZVq1z/XwdDfT0+l6Mt0tcXaXO4fF19k6E/JChZllXkR53f+dHUPtZGtl5TP9zxT2wx o3a9KFN+GCQa9nMmw7IsKw/37yqafFT8dCUHf9zB5K2/JTVnqHZd0/IWHBinI7AauT4oT8myTFFc bIZS7aIqHn7dW7fDu+ceyxT5d74cqMcxVa191FFH/YXrsow7h9e//UYHUxOPEe9888ed9HK24cqu f+CmN+ynFKWGLXnKtsH8Dh/fy76zc5X/icTcQz4Cq3cvS6ttOUI/6ywcvS+3nkhQl0eKZ52opcYL GhFsz26N1vcQ+R4uqgg2QbcvHihYlmVZyYUFFsZvnSlv2mAT9tuYoGRZlpXfX9tJ3++4hGWVqT8O EXT5PExe0Xz/feJpMvO0WNNaOjnD2HL+P2Wa5qvacql7vTLlh0HC3t9EKyom27Gx86OJ9NxcE7P5 56XPVpncA742M06WKGK+9eqwMkjGsixTdHvrzNfszV28Z3+293JcoeLpfKpZL00UbBqXt+DAOL7V OwEN+Qwp47/vJ/DaEKeazeI/p+qbLbggRR111JuiXqk8I/jYpvd8u1tbeo7+3/FHivo/mUz2+cUd LV/fHCHRuMWM+roXv+dX4WEb+hs7Ljz35LifSH/m6eo7wAkb+wn7b05UtkywvXoPGlX74FA1y6Xp QaN1PLBU0/w0YoH1DfQkxSU1jt/Lb1+53/X11/i5N69neA3pyiOEEFneo4eJUvNOXbt26dLRVv/Z k25q1kuTDMXXs7w1H8Sq9n3yc/IocysL1YzrWFpXPMMOddRRf/F6JR0zl85dunbt4qz9JDrmcWl9 24Gme3AxU1pcSvT09VroerP6gk3Ng0Y5i06EP0pOTk688EEHDqnxoFFC6nrQqCrXk7YMeGYz10QP Gl17LTpGJS458/HRGcbqp/v0waHPrkF1y6Xm9Y2Zn+fH7dCjMx0XGV/ZQLLz7zpbWti+eeTJ9VVd rDyWBWSfmOtoN+XAE2Iy9ofQlPt7Z1gl7Jvdzc5jxIIvDgQmFDMa1guHyyUKuWqfhBWXlrFN3v6q F9ANWnba2MyYFBUUqmZTUZhXMe+oo476i9eJNOv+qR/+N7mPg8vwz/9VDlgbkJhwdllnjVeds3lX Pxkz++pzPriYEFLx4OJO1R9cLI6JSrPr1sWgdQRbe3zQaN0PDlW/XM/3oNF65qfhDw5VpbDh8PED 0i//m1rRO7VG7UxMO7fIudua25mPDky2GvFjzJOs1L9mq74LoG3Za/KHO85FpoQemOfy+Lcl4z6+ IlO7XmgTN1f92KDgQpawRbePnktWtlD7q3kfh9HjOz889meslBBlxqlDlwpZ1FFHvWnqTMovb036 Nog3/MvLCY9uHVm/YJirnuZtfxM/uLjsZkCQ+Vifri31/a16psPtPH/t9Msre1uv19JxXHTi6pqe XJtZ3355fdG4LsfMLXQN3Af06cjLrHYlzevmh0bbz0lhbLzfb/iDRqe+76o7n+O45ELYd/14itBv hk/+JUkpK8jIYWa7XdKhTd48EPTNQI7aLetbv54uX71qWscPMsppkVWnIfO/GqZxmrpDN5zb7b9y 7UCb6aW0geOA93YOpVQPUK17uep8PWEbNT+qB37qljT0glHKfNKyyetXH4xY5l9x7aMi4uQ53rhD HvIb2664+Kwzq6OJdaz7+q3u67daLpPz1K8X7SEffjdyygfdu2x0durh1dOVK2lksj1v+9eN0+H9 /VuT3p7c/TddfX0nj84Vgymoo476C9dpm0VnE97Teo6vBakeXCwJfsN6Y0Vyjdqbfm6eCaVuOyYY tP7ohqWLpjtvKdByGPLuMw8uZnPO/HrJ9d3APrwWyjU8aLQNfKEkbf/ENy74Bf7uZ47vQwNAWyMN +WzA27JtN7/tJ6g3T5voQaMINgAAaBXwBG0AAIA6INgAAKBdUXvxCEXVfULn2Yv/AQAA2kiw1Zlh 6tIOAACglcBQJAAAINgAAAAQbAAAAAg2AAAABBsAACDYAAAAEGwAAAAINgAAgBego6Oj4VcEGwAA tDG2trYafiX1Po8NAACgVXF3dyeEpKWlqVJN9Wt1ah9bo6enV+cttXCvSAAAaA4NfGxNvTAUCQAA 7QqCDQAAEGwAAACtlaaLR/CQGgAAaHOowMBAtAIAALSrIzY3Nzc0BAAAtANxcXE4xwYAAO0Kgg2g sdjcf79a8v2Nwnb01U55wpEVyw/GSrFyob0GG1sU4D9l4b4YRcVvl/ynvL03WqH+M5Fxc8+6/32w /ONNp2PK6viss1mn1v90X9F8n8l7m2d+/Hc2+3RyH0308Rk/b2eEnLBPTq+e6OvjO3NbM85AyyzX y6P4b9sMXx8fHx9f34l+81Z8dzS8gKn/H4XtmLNQU7d5dkn9pn4fJK/Vc0oi/trw6fvz/Cb4Tt34 zJ8ljy7+sHKe3+Qps5as/y20oGXbqDzsz6M5/Sf1M6Cq+pvvpNVnslhCCCm/t3WWr+/sHWFtq7/x nMf6ml89GJCF+zAAjtgIIWzxzQPHlL7+W75b7Hhv39nUaps8Nv/Gni2/330sIYQoCmPO//LDqYQm /LizRTd++HD9wRvJJQwh/2/vzsOaurYFgK+dhEwEkmBkCgICIiogVhBRUVFQpCrP6WpvRSg4a1tb hz7rfa/qVa+AtmoBeU5VW7ReB1R8RRwARRFqBRSlVlAggAIyJUBCcnJy3h+BttcWe+UpDl2/v/g2 fKzsc85e6+x9hmhr8pK3rVqXXGGMTwjTdDOvVN9UkH+fhtfrLs+n9evlJT6/FUeSTxw/tPM//TUp MYlZym5JgCy+pce48BVhQwT/sgu1d76J2Vfuvizx8MFNk9nnt3x5oa778jHTlH3mqnT0mN6/urOY ZW3dkp390ABMa15Wsbmt6PXLCETsG+hVlXq2WA8Iva7+H++KpO8fW/v5Zds50Yt8BcaRDoyBIQAA hDEY37yl16gNAiHXwj88rPDc0X2pP5ab7pdO+8u8Yfac5zkU/eZEaU4kRScWNlPZMUkjp81eMKEX C6oBgGXlYKssyPvJsazY0sHuUbmyfWpQfe3wnsPphVXNRNxrYNDseTO8ZRwARl2Sunv3ydz7dVqW UGrrNun91aHO7M7bdcUp2/edLVLUKjXE1Mpl6NT5UUGOfACm+c7R7XGnCup5LmOGi3NTcnRj/uvA B96cZ4vbWb9ecuIjLDabw5b28fdxSDpTWmMYJWYD03jzSOLe1JvVbRyJ8/BZCyPH2PPAUJmyYWNK pUalVJGYxbkmwLYct3LddCf2s8c0dR01wRWo65dZ8Kt8q//xUlajR8Q0D4kJkQROG31yTWZufeDb sm45f2FaCnKKZF5hPX8djWU5zI/kXK2cHPwgq8JzRL/ctPY/VpekfbUv+VpJo95UPjh0waJQNxEB AKbp5rfxe9Pu1GoJ11zuF7Zq4QjZU9rp8vNxu07fLKttobkWzn7T50UGOvKNiyWX9+44kPlAI3Ia 5d/jRrpg4d6lb3GePS4AAPD7D3Jr/Da3LMzVhY0ZEv3ZChujU1ZXPeS1tk8hiLn/nOkluz/76ADX fmzUe6J76YfTbzzi+cyIGN2L1ay4nf+TUmghlvIZxa38e32svSy5z2+JrLm6vLysluYL2Ww2q0lR WlpR39/KBgCACPp59MzMOZRWJ+g/Ul5jLGxtdw6uiz392GpoaLg768fU5G+j6022RE93IFXf7dyT XuUUMm+OO6/l0U+3tRoGAMDQSTtQlUX3Sd8xMybLhQ3Xjh49l5hgO2DzFFtt3oGth643WXgEjZCV XMyoN4AZdCXu7/fLlv8qTDx1NXkFCr5jsDULgGnIiI89ZxK+cX+gdVvhN+s3xRyx2zbHlWM36b93 TtIXxM9N4K9KiOr3vF+4zTRWVrbK3OwMxakHbkjGT3SQQ4aiigZZt7zZm668X87Yjrb519zPsvAb ZrYz65Z5ac2gqePUuWkGAGAaLm3/+2Ft6Oq49X0FtZfi1sbstt6xbKiI6O+dTDxDTYzdH2LL0daV FKvax0Rn7aDn9Ap+/6+DnWTclsKv123Yetxp27tObEPVmW0Jhb0/jtvgI1Qkb/pbrWFY+0rJM8Zt x5Pbyx6XlKkZFzN8khX92Qobp1/U7pNRv16lkvvP/8yn9vbltIyU/TV9h48LX24vYgEAoyx9QPtG rRBnbD5hvyzSOj+jpMbdstfzyj+MrqKwRDju0y84x5eedtnwof2N5LziZm8bY72VDPCQpx0q4o+a 4EwbH9nTFZ5Pf0ibj5q9YKoXD4abVeZ/kZN5pWyKQ29arwegNUqV3nSw98RRwR0lpLN2gd8H20cL uIye0unk1dk/HC8rKdOD5d2c7+sZ0ch5ny7yE9Tb1C9IvNWluJ30y5b/Mg8Y6oeEeXN2M5S6hbEe +/7aEeYEoPXWtULhiHUBdnwCfI8pE9y+O5lb9u4LP99n2tragCcwabideS7dfkDIWzzSptF221pk a6vaRCh4so8sqe9w6eqEY7yAT505xvkaU3/tfJ44OCbUTcIGsPUP9T+2NruIGjqES1gsQqmqFY+a ZPZSmauHrGOG2kk72zlgqrPxR4n7WD95arFCC06C2uvXyuwDP/KRcQg4hbz91rGELsbt6INQKIDW 1lZoPyFD6I0qbL9988hTX0aiK/nfXcklogH+494Lqzi++5+fZ552CoqYG+wiFHsGjQVgGq37OJqz +LZDJtj+nJya0tZGxedTACzLyZsS5/bvQrUjQs+/LPEE0N/u6WAjNrXy+o9FXgDAVBtHqa13gF+R ucXwfvzLxpCtDQ1tDENlRkdk/vwvGusbGXC2nzD3ndJdp3K++fzK14Rn5f3XlSumuAqA1Um7vuaH pMTDl+5UqXQGYz7lanV60Cmb1AzbTm7LByBiudwMbum6EreTfr1cJp7hse/7cml1ze3TiYn/OGK1 eZZzi6qZkQyQsNv3hlRi0qJqfvEFhvD5fKJt09uHRSdNBVBnnmX4PXjdNscwNRVSdRr6yTFExEOC vNMzbUY6shuNLYaGuga6Ji166WXjZ2MoNcdVrWWAy3aZtny+/tipmA+31ZvYeU+eu3Cym4gAdNZO 1+Wf+PrY5R9rNAYAWtNocNXTDBhUTc0glhpvYQGOWCpiaboWt51Bo9aA0FSI6RG9iYWNcPl8YqDp jsNdTxO+4CmJg+s4fuHKtzkA6qtbNqvGb/jCS5m8fsepfpvfcWQDABDp0JkhT8aQjF93fPxz6ot7 2Eb33zaznSatXD8JgMq+3J55JRIeYZmPmL8suOOKFeFIHdgAROwxY/WX03WNiqLsozv3ZB36Z07g mgAz8vvtJt9/E59SoOsVMG9xgIPo8cUv4y42AACYmJnxCV1fXaMDB15LdXUzAK9rcZ/ar5eEayqR SnkglY6aNjZt8dkcxQwXK3Mz0tTQRIM1B4BRNzZRIudfFrEIIfBCvuuISOzkwvqKSuOSGV2leAjy QfLuuizEtnN2ILcUD+nhvZ8IKfKJ2uADAPrGjkmchYTjOvkf6ydInxw8xNQ5MPKTwEhG9zhv//rN e8/5RE+1ZXXSTpRZ/xN7QbRo7Y4RNnxiKD/y8cq7wACwzCVmUNSkZEBAAPTKphYDr4txjbSVFXU9 ezua4jokel099VYEbm9Xe1VB5vVHGr2u8aeL2Q8ELn1+uaZAlxxds2hJ/DX1L5WFwwEAYGiKIgIB l7D5AhNKq33VbhzmeYwZaUUabqSezSsuL79fdCPj+J70Cj4Bpvrcjo2JR1KvFD1UamkAYJtw2AQ6 bSeEALDF9n37yE2b7t7ruCOP4zZksARUWXu27D+8KzapgGK6GPeVxDAGmqZ1rbV3Ln2v4FhaSllg 6uHr3nrlVGZVG6NX3k5OvdtzyBCHjuOEmIlFKkV5A/3vBjDoKV0HSk8bNx5DU5SO0huAMdCUjqJo BgBM+o0eIbl15mSRitZWZZzIVHqM9u3RXduNiLyG9q8ruPn4Dw9vIvMLGqg4/dXFB816YPTqmrtX s+81MwBgqMrPKqxq0TOEzedz2Swen0ug83aqVa03t3PqySfANN85f0Vh3KbE0tvPUXHhVF6jnmkr Tzub19bVuEZtRfl3JT6+jnjnCHozlyJZdhM/WlqfeHBFWIyGLXX0nv5JxOBfLvAwlKr2UY1A85uB Tcz8ZgZfT1i+RMOWDQlf5vrKfUu30CvysxXCg8cvnU3K1bGFUhsnz7dtWAAgsBBT350/lNHYqmOJ rPuHLJw9VAidt/u8uyik4evMpJULk+Web/WUsSoajKfDvpEfz1TtTMk/812vYb5ekvP5xicNnjnu K4i6tmXmlK2EbSKSOXqGLH9vjAUB6DFmyfLHCV99GrFLwxY7D5u7amZfk59nNo5Bs0bd3Lc84giH axW8etPMP7j0pr0aO+vqz0eg5aSNifMGcPT58e+tu6BiAABiZl0hkvFr9y0ZxOENCFsVkZiwdf6p Fo6V+4TlSwNl3Xc+QCTDJg4/ciCjdOI7Tpw/qGwBH/5Ne2B/7OI99ToisHBwDwobCADAaCuzvkrY 9VBFEa7EadiCBe2fv5P2HgHhs+8k/P2DqxKpwFTev499+2Iny27issXV2+MXz6bMnPz9B8nKjFcM njkuAACj/P5igW3Ipldv2CL074/OjIwMfFfkc2egDSw2CwBAkx0bGX3VLHRzQqQbpoo3DFN3cdNn eSM3rvCXvDITbCovbu5u0Zq4CNcuzbiokqRP4vTzo8PdeLh/0evp3r17mGtfSHL5IXFlCu3lLjdt uX0+Rw1iP08H3NJv4GmhbOya+LGvQIFVl94s5rp6yIV0zZUL+dyBHzh0dR3RxOXdz7fhnkWvOUy3 LyThSazMGs6cPZqhBUEPp5ERERGDBbhV0AtDP75+cNfWGi2weJYDQ5fP9sTpFvpzp2D8PjaEEEJv VGFTqVS/+wszM3w4EyGEUPdpbm5+LvUIv7YGIYTQGwULG0IIISxsCCGEEBY2hBBCCAsbQgghhIUN IYQQFjaEEEIICxtCCCGEhQ0hhBDCwoYQQghhYUMIIYSFDSGEEMLChhBCCGFhQwghhLCwIYQQQljY EEII/an8Hy1HKJRyCnPAAAAAAElFTkSuQmCC --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=tab-line-1.el Content-Transfer-Encoding: quoted-printable ;;; tab-line.el --- window-local tabs with window buffers -*- lexical-bindi= ng: t; -*- ;; Copyright (C) 2019-2020 Free Software Foundation, Inc. ;; Author: Juri Linkov ;; Keywords: windows tabs ;; Maintainer: emacs-devel@gnu.org ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; To enable this mode, run `M-x global-tab-line-mode'. ;;; Code: (require 'seq) ; tab-line.el is not pre-loaded so it's safe to use it here (defgroup tab-line nil "Window-local tabs." :group 'convenience :version "27.1") (defgroup tab-line-faces nil "Faces used in the tab line." :group 'tab-line :group 'faces :version "27.1") (defface tab-line '((((class color) (min-colors 88)) :inherit variable-pitch :height 0.9 :background "grey85" :foreground "black") (((class mono)) :background "grey") (t :inverse-video t)) "Tab line face." :version "27.1" :group 'tab-line-faces) (defface tab-line-tab '((default :inherit tab-line) (((class color) (min-colors 88)) :box (:line-width 1 :style released-button)) (t :inverse-video nil)) "Tab line face for selected tab." :version "27.1" :group 'tab-line-faces) (defface tab-line-tab-inactive '((default :inherit tab-line-tab) (((class color) (min-colors 88)) :background "grey75") (t :inverse-video t)) "Tab line face for non-selected tab." :version "27.1" :group 'tab-line-faces) (defface tab-line-tab-current '((default :inherit tab-line-tab) (((class color) (min-colors 88)) :background "grey85")) "Tab line face for tab with current buffer in selected window." :version "27.1" :group 'tab-line-faces) (defface tab-line-highlight '((default :inherit tab-line-tab)) "Tab line face for highlighting." :version "27.1" :group 'tab-line-faces) (defface tab-line-close-highlight '((t :foreground "red")) "Tab line face for highlighting of the close button." :version "27.1" :group 'tab-line-faces) (defvar tab-line-tab-map (let ((map (make-sparse-keymap))) (define-key map [tab-line mouse-1] 'tab-line-select-tab) (define-key map [tab-line mouse-2] 'tab-line-close-tab) (define-key map "\C-m" 'tab-line-select-tab) map) "Local keymap for `tab-line-mode' window tabs.") (defvar tab-line-add-map (let ((map (make-sparse-keymap))) (define-key map [tab-line mouse-1] 'tab-line-new-tab) (define-key map [tab-line mouse-2] 'tab-line-new-tab) (define-key map "\C-m" 'tab-line-new-tab) map) "Local keymap to add `tab-line-mode' window tabs.") (defvar tab-line-tab-close-map (let ((map (make-sparse-keymap))) (define-key map [tab-line mouse-1] 'tab-line-close-tab) (define-key map [tab-line mouse-2] 'tab-line-close-tab) map) "Local keymap to close `tab-line-mode' window tabs.") (defvar tab-line-left-map (let ((map (make-sparse-keymap))) (define-key map [tab-line mouse-1] 'tab-line-hscroll-left) (define-key map [tab-line mouse-2] 'tab-line-hscroll-left) (define-key map "\C-m" 'tab-line-new-tab) map) "Local keymap to scroll `tab-line-mode' window tabs to the left.") (defvar tab-line-right-map (let ((map (make-sparse-keymap))) (define-key map [tab-line mouse-1] 'tab-line-hscroll-right) (define-key map [tab-line mouse-2] 'tab-line-hscroll-right) (define-key map "\C-m" 'tab-line-new-tab) map) "Local keymap to scroll `tab-line-mode' window tabs to the right.") (defcustom tab-line-new-tab-choice t "Defines what to show in a new tab. If t, display a selection menu with all available buffers. If the value is a function, call it with no arguments. If nil, don't show the new tab button." :type '(choice (const :tag "Buffer menu" t) (function :tag "Function") (const :tag "No button" nil)) :group 'tab-line :version "27.1") (defvar tab-line-new-button (propertize " + " 'display `(image :type xpm :file "tabs/new.xpm" :margin (2 . 0) :ascent center) 'keymap tab-line-add-map 'mouse-face 'tab-line-highlight 'help-echo "Click to add tab") "Button for creating a new tab.") (defcustom tab-line-close-button-show t "Defines where to show the close tab button. If t, show the close tab button on all tabs. If `selected', show it only on the selected tab. If `non-selected', show it only on non-selected tab. If nil, don't show it at all." :type '(choice (const :tag "On all tabs" t) (const :tag "On selected tab" selected) (const :tag "On non-selected tabs" non-selected) (const :tag "None" nil)) :initialize 'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) :group 'tab-line :version "27.1") (defvar tab-line-close-button (propertize " x" 'display `(image :type xpm :file "tabs/close.xpm" :margin (2 . 0) :ascent center) 'keymap tab-line-tab-close-map 'mouse-face 'tab-line-close-highlight 'help-echo "Click to close tab") "Button for closing the clicked tab.") (defvar tab-line-left-button (propertize " <" 'display `(image :type xpm :file "tabs/left-arrow.xpm" :margin (2 . 0) :ascent center) 'keymap tab-line-left-map 'mouse-face 'tab-line-highlight 'help-echo "Click to scroll left") "Button for scrolling horizontally to the left.") (defvar tab-line-right-button (propertize "> " 'display `(image :type xpm :file "tabs/right-arrow.xpm" :margin (2 . 0) :ascent center) 'keymap tab-line-right-map 'mouse-face 'tab-line-highlight 'help-echo "Click to scroll right") "Button for scrolling horizontally to the right.") (defvar tab-line-separator nil) (defcustom tab-line-tab-name-function #'tab-line-tab-name-buffer "Function to get a tab name. Function gets two arguments: tab to get name for and a list of tabs to display. By default, use function `tab-line-tab-name'." :type '(choice (const :tag "Buffer name" tab-line-tab-name-buffer) (const :tag "Truncated buffer name" tab-line-tab-name-truncated-buffer) (function :tag "Function")) :initialize 'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) :group 'tab-line :version "27.1") (defun tab-line-tab-name-buffer (buffer &optional _buffers) "Generate tab name from BUFFER. Reduce tab width proportionally to space taken by other tabs. This function can be overridden by changing the default value of the variable `tab-line-tab-name-function'." (buffer-name buffer)) (defcustom tab-line-tab-name-truncated-max 20 "Maximum length of the tab name from the current buffer. Effective when `tab-line-tab-name-function' is customized to `tab-line-tab-name-truncated-buffer'." :type 'integer :group 'tab-line :version "27.1") (defvar tab-line-tab-name-ellipsis (if (char-displayable-p ?=E2=80=A6) "=E2=80=A6" "...")) (defun tab-line-tab-name-truncated-buffer (buffer &optional _buffers) "Generate tab name from BUFFER. Truncate it to the length specified by `tab-line-tab-name-truncated-max'. Append ellipsis `tab-line-tab-name-ellipsis' in this case." (let ((tab-name (buffer-name buffer))) (if (< (length tab-name) tab-line-tab-name-truncated-max) tab-name (propertize (truncate-string-to-width tab-name tab-line-tab-name-truncated-max nil nil tab-line-tab-name-ellipsis) 'help-echo tab-name)))) (defcustom tab-line-tabs-function #'tab-line-tabs-mode-buffers "Function to get a list of tabs to display in the tab line. This function should return either a list of buffers whose names will be displayed, or just a list of strings to display in the tab line. By default, use function `tab-line-tabs-window-buffers' that returns a list of buffers associated with the selected window. When `tab-line-tabs-mode-buffers', return a list of buffers with the same major mode as the current buffer." :type '(choice (const :tag "Window buffers" tab-line-tabs-window-buffers) (const :tag "Same mode buffers" tab-line-tabs-mode-buffers) (const :tag "Grouped buffers" tab-line-tabs-buffer-groups) (function :tag "Function")) :initialize 'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) :group 'tab-line :version "27.1") (defvar tab-line-tabs-buffer-list-function #'tab-line-tabs-buffer-list "Function to return a global list of buffers. Used only for `tab-line-tabs-mode-buffers' and `tab-line-tabs-buffer-groups= '.") (defun tab-line-tabs-buffer-list () (seq-filter (lambda (b) (and (buffer-live-p b) (/=3D (aref (buffer-name b) 0) ?\s))) (seq-uniq (append (list (current-buffer)) (mapcar #'car (window-prev-buffers)) (buffer-list))))) (defun tab-line-tabs-mode-buffers () "Return a list of buffers with the same major mode with current buffer." (let ((mode major-mode)) (seq-sort-by #'buffer-name #'string< (seq-filter (lambda (b) (with-current-buffer b (derived-mode-p mode))) (funcall tab-line-tabs-buffer-list-function)))= )) (defvar tab-line-tabs-buffer-group-function nil "Function to put a buffer to the group. Takes a buffer as arg and should return a group name as string. When the return value is nil, filter out the buffer.") (defvar tab-line-tabs-buffer-group-sort-function nil "Function to sort buffers in group.") (defvar tab-line-tabs-buffer-groups-sort-function #'string< "Function to sort group names.") (defvar tab-line-tabs-buffer-groups mouse-buffer-menu-mode-groups "How to group various major modes together in the tab line. Each element has the form (REGEXP . GROUPNAME). If the major mode's name string matches REGEXP, use GROUPNAME instead.") (defun tab-line-tabs-buffer-group-name (&optional buffer) (if (functionp tab-line-tabs-buffer-group-function) (funcall tab-line-tabs-buffer-group-function buffer) (let ((mode (if buffer (with-current-buffer buffer (format-mode-line mode-name)) (format-mode-line mode-name)))) (or (cdr (seq-find (lambda (group) (string-match-p (car group) mode)) tab-line-tabs-buffer-groups)) mode)))) (defun tab-line-tabs-buffer-groups () (if (window-parameter nil 'tab-line-groups) (let* ((buffers (funcall tab-line-tabs-buffer-list-function)) (groups (seq-sort tab-line-tabs-buffer-groups-sort-function (delq nil (mapcar #'car (seq-group-by (lambda (buffer) (tab-line-tabs-buffer-gr= oup-name buffer)) buffers))))) (selected-group (window-parameter nil 'tab-line-group)) (tabs (mapcar (lambda (group) `(tab (name . ,group) (selected . ,(equal group selected-group)) (select . ,(lambda () (set-window-parameter nil 'tab-line-= groups nil) (set-window-parameter nil 'tab-line-= group group) (set-window-parameter nil 'tab-line-= hscroll nil))))) groups))) tabs) (let* ((window-parameter (window-parameter nil 'tab-line-group)) (group-name (tab-line-tabs-buffer-group-name (current-buffer))) (group (prog1 (or window-parameter group-name "All") (when (equal window-parameter group-name) (set-window-parameter nil 'tab-line-group nil)))) (group-tab `(tab (name . ,group) (select . ,(lambda () (set-window-parameter nil 'tab-line-gr= oups t) (set-window-parameter nil 'tab-line-gr= oup group) (set-window-parameter nil 'tab-line-hs= croll nil))))) (buffers (seq-filter (lambda (b) (equal (tab-line-tabs-buffer-group-name b) group)) (funcall tab-line-tabs-buffer-list-function))) (sorted-buffers (if (functionp tab-line-tabs-buffer-group-sort-f= unction) (seq-sort tab-line-tabs-buffer-group-sort-fu= nction buffers) buffers)) (tabs (mapcar (lambda (buffer) `(tab (name . ,(funcall tab-line-tab-name-function b= uffer)) (selected . ,(eq buffer (current-buffer))) (buffer . ,buffer) (close . ,(lambda (&optional b) ;; kill-buffer because bury-buffer ;; won't remove the buffer from ta= b-line (kill-buffer (or b buffer)))))) sorted-buffers))) (cons group-tab tabs)))) (defun tab-line-tabs-window-buffers () "Return a list of tabs that should be displayed in the tab line. By default returns a list of window buffers, i.e. buffers previously shown in the same window where the tab line is displayed. This list can be overridden by changing the default value of the variable `tab-line-tabs-function'." (let* ((window (selected-window)) (buffer (window-buffer window)) (next-buffers (seq-remove (lambda (b) (eq b buffer)) (window-next-buffers window))) (next-buffers (seq-filter #'buffer-live-p next-buffers)) (prev-buffers (seq-remove (lambda (b) (eq b buffer)) (mapcar #'car (window-prev-buffers windo= w)))) (prev-buffers (seq-filter #'buffer-live-p prev-buffers)) ;; Remove next-buffers from prev-buffers (prev-buffers (seq-difference prev-buffers next-buffers))) (append (reverse prev-buffers) (list buffer) next-buffers))) (defun tab-line-format-template (tabs) "Template for displaying tab line for selected window." (let* ((selected-buffer (window-buffer)) (separator (or tab-line-separator (if window-system " " "|"))) (hscroll (window-parameter nil 'tab-line-hscroll)) (strings (mapcar (lambda (tab) (let* ((buffer-p (bufferp tab)) (selected-p (if buffer-p (eq tab selected-buffer) (cdr (assq 'selected tab)))) (name (if buffer-p (funcall tab-line-tab-name-function tab tabs) (cdr (assq 'name tab))))) (concat separator (apply 'propertize (concat (propertize name 'keymap tab-line-tab-map) (or (and (or buffer-p (assq 'buffer tab) (as= sq 'close tab)) tab-line-close-button-show (not (eq tab-line-close-button-show (if selected-p 'non-select= ed 'selected))) tab-line-close-button) "")) `( tab ,tab ,@(if selected-p '(selected t)) face ,(if selected-p (if (eq (selected-window) (old-selected-= window)) 'tab-line-tab-current 'tab-line-tab) 'tab-line-tab-inactive) mouse-face tab-line-highlight))))) tabs)) (hscroll-data (tab-line-auto-hscroll strings hscroll))) (setq hscroll (nth 1 hscroll-data)) (append (if (null (nth 0 hscroll-data)) (when hscroll (setq hscroll nil) (set-window-parameter nil 'tab-line-hscroll hscroll)) (list separator (when (and (numberp hscroll) (not (zerop hscroll))) tab-line-left-button) (when (if (numberp hscroll) (< (truncate hscroll) (1- (length strings))) (> (length strings) 1)) tab-line-right-button))) (if hscroll (nthcdr (truncate hscroll) strings) strings) (when (eq tab-line-tabs-function #'tab-line-tabs-window-buffers) (list (concat separator (when tab-line-new-tab-choice tab-line-new-button))))))) (defvar tab-line-auto-hscroll) (defun tab-line-format () "Template for displaying tab line for selected window." (let* ((tabs (funcall tab-line-tabs-function)) (cache-key (list tabs (window-buffer) (window-parameter nil 'tab-line-hscroll))) (cache (window-parameter nil 'tab-line-cache))) ;; Enable auto-hscroll again after it was disabled on manual scrolling. ;; The moment to enable it is when the window-buffer was updated. (when (and tab-line-auto-hscroll ; if auto-hscroll was enabled (integerp (nth 2 cache-key)) ; integer on manual scroll cache ; window-buffer was updated (not (equal (nth 1 (car cache)) (nth 1 cache-key)))) (set-window-parameter nil 'tab-line-hscroll (float (nth 2 cache-key))= )) (or (and cache (equal (car cache) cache-key) (cdr cache)) (cdr (set-window-parameter nil 'tab-line-cache (cons cache-key (tab-line-format-template tabs))))))) (defcustom tab-line-auto-hscroll t "Allow or disallow automatic horizontal scrolling of the tab line. Non-nil means the tab line are automatically scrolled horizontally to make the selected tab visible." :type 'boolean :group 'tab-line :version "27.1") (defvar tab-line-auto-hscroll-buffer (generate-new-buffer " *tab-line-hscro= ll*")) (defun tab-line-auto-hscroll (strings hscroll) (with-current-buffer tab-line-auto-hscroll-buffer (let ((truncate-partial-width-windows nil) (inhibit-modification-hooks t) show-arrows) (setq truncate-lines nil) (erase-buffer) (apply 'insert strings) (goto-char (point-min)) (add-face-text-property (point-min) (point-max) 'tab-line) ;; Continuation means tab-line doesn't fit completely, ;; thus scroll arrows are needed for scrolling. (setq show-arrows (> (vertical-motion 1) 0)) ;; Try to auto-hscroll only when scrolling is needed, ;; but no manual scrolling was performed before. (when (and tab-line-auto-hscroll show-arrows ;; Do nothing when scrolled manually (not (integerp hscroll))) (let ((selected (seq-position strings 'selected (lambda (str prop) (get-pos-property 1 prop str))))) (cond ((null selected) ;; Do nothing if no tab is selected ) ((or (not (numberp hscroll)) (< selected (truncate hscroll))) ;; Selected is scrolled to the left, or no scrolling yet (erase-buffer) (apply 'insert (reverse (seq-subseq strings 0 (1+ selected)))) (goto-char (point-min)) (add-face-text-property (point-min) (point-max) 'tab-line) (if (> (vertical-motion 1) 0) (let* ((point (previous-single-property-change (point) 'tab= )) (tab-prop (when point (or (get-pos-property point 'tab) (and (setq point (previous-single-pr= operty-change point 'tab)) (get-pos-property point 'tab)))= )) (new-hscroll (when tab-prop (seq-position strings tab-prop (lambda (str tab) (eq (get-pos-property= 1 'tab str) tab)))))) (when new-hscroll (setq hscroll (float new-hscroll)) (set-window-parameter nil 'tab-line-hscroll hscroll))) (setq hscroll nil) (set-window-parameter nil 'tab-line-hscroll hscroll))) (t ;; Check if the selected tab is already visible (erase-buffer) (apply 'insert (seq-subseq strings (truncate hscroll) (1+ selec= ted))) (goto-char (point-min)) (add-face-text-property (point-min) (point-max) 'tab-line) (when (> (vertical-motion 1) 0) ;; Not visible already (erase-buffer) (apply 'insert (reverse (seq-subseq strings 0 (1+ selected)))) (goto-char (point-min)) (add-face-text-property (point-min) (point-max) 'tab-line) (when (> (vertical-motion 1) 0) (let* ((point (previous-single-property-change (point) 'tab= )) (tab-prop (when point (or (get-pos-property point 'tab) (and (setq point (previous-single-pr= operty-change point 'tab)) (get-pos-property point 'tab)))= )) (new-hscroll (when tab-prop (seq-position strings tab-prop (lambda (str tab) (eq (get-pos-property= 1 'tab str) tab)))))) (when new-hscroll (setq hscroll (float new-hscroll)) (set-window-parameter nil 'tab-line-hscroll hscroll))))= ))))) (list show-arrows hscroll)))) (defun test1 () (interactive) (with-selected-window (split-window-below -10) (switch-to-buffer "*Messages*") (tab-line-mode 0)) (message "tab-line-hscroll: %S" (window-parameter nil 'tab-line-hscroll)) (message "tab-line-cache: %S" (cdr (car (window-parameter nil 'tab-line-c= ache)))) (tab-line-format-template (funcall tab-line-tabs-function)) (select-window (split-window-below -5)) (switch-to-buffer tab-line-auto-hscroll-buffer)) (defun tab-line-hscroll (&optional arg window) (let* ((hscroll (window-parameter window 'tab-line-hscroll)) (tabs (if window (with-selected-window window (funcall tab-line-tabs-func= tion)) (funcall tab-line-tabs-function)))) (set-window-parameter window 'tab-line-hscroll (max 0 (min (+ (if (numberp hscroll) (truncate hscroll) 0) (or arg 1)) (1- (length tabs))))) (when window (force-mode-line-update t)))) (defun tab-line-hscroll-right (&optional arg mouse-event) (interactive (list current-prefix-arg last-nonmenu-event)) (let ((window (and (listp mouse-event) (posn-window (event-start mouse-ev= ent))))) (tab-line-hscroll arg window) (force-mode-line-update window))) (defun tab-line-hscroll-left (&optional arg mouse-event) (interactive (list current-prefix-arg last-nonmenu-event)) (let ((window (and (listp mouse-event) (posn-window (event-start mouse-ev= ent))))) (tab-line-hscroll (- (or arg 1)) window) (force-mode-line-update window))) (defun tab-line-new-tab (&optional mouse-event) "Add a new tab to the tab line. Usually is invoked by clicking on the plus-shaped button. But any switching to other buffer also adds a new tab corresponding to the switched buffer." (interactive (list last-nonmenu-event)) (if (functionp tab-line-new-tab-choice) (funcall tab-line-new-tab-choice) (let ((tab-line-tabs-buffer-groups mouse-buffer-menu-mode-groups)) (if (and (listp mouse-event) window-system) ; (display-popup-menus-p) (mouse-buffer-menu mouse-event) ; like (buffer-menu-open) ;; tty menu doesn't support mouse clicks, so use tmm (tmm-prompt (mouse-buffer-menu-keymap)))))) (defun tab-line-select-tab (&optional e) "Switch to the selected tab. This command maintains the original order of prev/next buffers. So for example, switching to a previous tab is equivalent to using the `previous-buffer' command." (interactive "e") (let* ((posnp (event-start e)) (tab (get-pos-property 1 'tab (car (posn-string posnp)))) (buffer (if (bufferp tab) tab (cdr (assq 'buffer tab))))) (if buffer (tab-line-select-tab-buffer buffer (posn-window posnp)) (let ((select (cdr (assq 'select tab)))) (when (functionp select) (with-selected-window (posn-window posnp) (funcall select) (force-mode-line-update))))))) (defun tab-line-select-tab-buffer (buffer &optional window) (let* ((window-buffer (window-buffer window)) (next-buffers (seq-remove (lambda (b) (eq b window-buffer)) (window-next-buffers window))) (prev-buffers (seq-remove (lambda (b) (eq b window-buffer)) (mapcar #'car (window-prev-buffers windo= w)))) ;; Remove next-buffers from prev-buffers (prev-buffers (seq-difference prev-buffers next-buffers))) (cond ((and (eq tab-line-tabs-function #'tab-line-tabs-window-buffers) (memq buffer next-buffers)) (dotimes (_ (1+ (seq-position next-buffers buffer))) (switch-to-next-buffer window))) ((and (eq tab-line-tabs-function #'tab-line-tabs-window-buffers) (memq buffer prev-buffers)) (dotimes (_ (1+ (seq-position prev-buffers buffer))) (switch-to-prev-buffer window))) (t (with-selected-window window (switch-to-buffer buffer)))))) (defun tab-line-switch-to-prev-tab (&optional mouse-event) "Switch to the previous tab. Its effect is the same as using the `previous-buffer' command (\\[previous-buffer])." (interactive (list last-nonmenu-event)) (let ((window (and (listp mouse-event) (posn-window (event-start mouse-ev= ent))))) (if (eq tab-line-tabs-function #'tab-line-tabs-window-buffers) (switch-to-prev-buffer window) (with-selected-window (or window (selected-window)) (let* ((tabs (funcall tab-line-tabs-function)) (tab (nth (1- (seq-position tabs (current-buffer) (lambda (tab buffer) (if (bufferp tab) (eq buffer tab) (eq buffer (cdr (assq 'buffer tab))))))) tabs)) (buffer (if (bufferp tab) tab (cdr (assq 'buffer tab))))) (when (bufferp buffer) (switch-to-buffer buffer))))))) (defun tab-line-switch-to-next-tab (&optional mouse-event) "Switch to the next tab. Its effect is the same as using the `next-buffer' command (\\[next-buffer])." (interactive (list last-nonmenu-event)) (let ((window (and (listp mouse-event) (posn-window (event-start mouse-ev= ent))))) (if (eq tab-line-tabs-function #'tab-line-tabs-window-buffers) (switch-to-next-buffer window) (with-selected-window (or window (selected-window)) (let* ((tabs (funcall tab-line-tabs-function)) (tab (nth (1+ (seq-position tabs (current-buffer) (lambda (tab buffer) (if (bufferp tab) (eq buffer tab) (eq buffer (cdr (assq 'buffer tab))))))) tabs)) (buffer (if (bufferp tab) tab (cdr (assq 'buffer tab))))) (when (bufferp buffer) (switch-to-buffer buffer))))))) (defcustom tab-line-close-tab-function 'bury-buffer "Defines what to do on closing the tab. If `bury-buffer', put the tab's buffer at the end of the list of all buffers that effectively hides the buffer's tab from the tab line. If `kill-buffer', kills the tab's buffer. When a function, it is called with the tab as its argument. This option is useful when `tab-line-tabs-function' has the value `tab-line-tabs-window-buffers'." :type '(choice (const :tag "Bury buffer" bury-buffer) (const :tag "Kill buffer" kill-buffer) (function :tag "Function")) :group 'tab-line :version "27.1") (defun tab-line-close-tab (&optional mouse-event) "Close the selected tab. Usually is invoked by clicking on the close button on the right side of the tab. This command buries the buffer, so it goes out of sight from the tab line." (interactive (list last-nonmenu-event)) (let* ((posnp (and (listp mouse-event) (event-start mouse-event))) (window (and posnp (posn-window posnp))) (tab (get-pos-property 1 'tab (car (posn-string posnp)))) (buffer (if (bufferp tab) tab (cdr (assq 'buffer tab)))) (close-function (unless (bufferp tab) (cdr (assq 'close tab))))) (with-selected-window (or window (selected-window)) (cond ((functionp close-function) (funcall close-function)) ((eq tab-line-close-tab-function 'kill-buffer) (kill-buffer buffer)) ((eq tab-line-close-tab-function 'bury-buffer) (if (eq buffer (current-buffer)) (bury-buffer) (set-window-prev-buffers nil (assq-delete-all buffer (window-prev= -buffers))) (set-window-next-buffers nil (delq buffer (window-next-buffers)))= )) ((functionp tab-line-close-tab-function) (funcall tab-line-close-tab-function tab))) (force-mode-line-update)))) ;;;###autoload (define-minor-mode tab-line-mode "Toggle display of window tab line in the buffer." :lighter nil (setq tab-line-format (when tab-line-mode '(:eval (tab-line-format))))) (defcustom tab-line-exclude-modes '(completion-list-mode) "List of major modes in which the tab line is not enabled." :type '(repeat symbol) :group 'tab-line :version "27.1") ;;;###autoload (defvar tab-line-exclude nil) ;;;###autoload (make-variable-buffer-local 'tab-line-exclude) (defun tab-line-mode--turn-on () "Turn on `tab-line-mode'." (unless (or (minibufferp) (string-match-p "\\` " (buffer-name)) (memq major-mode tab-line-exclude-modes) (get major-mode 'tab-line-exclude) (buffer-local-value 'tab-line-exclude (current-buffer))) (tab-line-mode 1))) ;;;###autoload (define-globalized-minor-mode global-tab-line-mode tab-line-mode tab-line-mode--turn-on :group 'tab-line :version "27.1") (global-set-key [tab-line mouse-4] 'tab-line-hscroll-left) (global-set-key [tab-line mouse-5] 'tab-line-hscroll-right) (global-set-key [tab-line wheel-up] 'tab-line-hscroll-left) (global-set-key [tab-line wheel-down] 'tab-line-hscroll-right) (global-set-key [tab-line S-mouse-4] 'tab-line-switch-to-prev-tab) (global-set-key [tab-line S-mouse-5] 'tab-line-switch-to-next-tab) (global-set-key [tab-line S-wheel-up] 'tab-line-switch-to-prev-tab) (global-set-key [tab-line S-wheel-down] 'tab-line-switch-to-next-tab) (provide 'tab-line) ;;; tab-line.el ends here --=-=-=--