pax_global_header00006660000000000000000000000064144602774420014524gustar00rootroot0000000000000052 comment=a1c29c0bbfca3f6778022628b79e7eef2b9f351d emacs-dashboard-1.8.0/000077500000000000000000000000001446027744200145475ustar00rootroot00000000000000emacs-dashboard-1.8.0/.dir-locals.el000066400000000000000000000002331446027744200171760ustar00rootroot00000000000000((emacs-lisp-mode . ((indent-tabs-mode . nil) (fill-column . 80) (elisp-lint-indent-specs . ((when-let . 1)))))) emacs-dashboard-1.8.0/.github/000077500000000000000000000000001446027744200161075ustar00rootroot00000000000000emacs-dashboard-1.8.0/.github/workflows/000077500000000000000000000000001446027744200201445ustar00rootroot00000000000000emacs-dashboard-1.8.0/.github/workflows/activate.yml000066400000000000000000000020771446027744200224750ustar00rootroot00000000000000name: Activate on: push: branches: - master pull_request: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: test: runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] emacs-version: - 26.3 - 27.2 - 28.2 experimental: [false] include: - os: ubuntu-latest emacs-version: snapshot experimental: true - os: macos-latest emacs-version: snapshot experimental: true - os: windows-latest emacs-version: snapshot experimental: true steps: - uses: actions/checkout@v3 - uses: jcs090218/setup-emacs@master with: version: ${{ matrix.emacs-version }} - uses: emacs-eask/setup-eask@master with: version: 'snapshot' - name: Run tests run: make test-activate emacs-dashboard-1.8.0/.github/workflows/test.yml000066400000000000000000000020561446027744200216510ustar00rootroot00000000000000name: CI on: push: branches: - master pull_request: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: test: runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] emacs-version: - 26.3 - 27.2 - 28.2 experimental: [false] include: - os: ubuntu-latest emacs-version: snapshot experimental: true - os: macos-latest emacs-version: snapshot experimental: true - os: windows-latest emacs-version: snapshot experimental: true steps: - uses: actions/checkout@v3 - uses: jcs090218/setup-emacs@master with: version: ${{ matrix.emacs-version }} - uses: emacs-eask/setup-eask@master with: version: 'snapshot' - name: Run tests run: make ci emacs-dashboard-1.8.0/.gitignore000066400000000000000000000002271446027744200165400ustar00rootroot00000000000000# ignore these directories /.git/ /recipes/ /_test/ # ignore generated files *.elc # eask packages .eask/ dist/ # packaging *-autoloads.el *-pkg.el emacs-dashboard-1.8.0/CHANGELOG.md000066400000000000000000000131521446027744200163620ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. ## 1.9.0 (Unreleased) > Released N/A - N/A ## 1.8.0 > Released Jul 26, 2023 * Disable display-line-numbers-mode (#182) * Mute no project removed message (#212) * Align the file icons horizontally (#221) * Fix package count when using package.el and straight.el simultaneously (#233) * Fix fitler agenda by time (#232) * Respect to custom items face instead of widget-button face (#273) * Support for image transforms (#278) * Allow moving point during `dashboard-mode-hook` (#227) * Add truncate style for path (#279) * Add agenda highlight headlines (#281) * Fix mosue click error (#285) * Add flag to refresh instead to kill the dashboard buffer (#290) * Fix wrong recent files when first starting the dashboard buffer (#294) * Add license file (#296) * Fix icon for week agenda items (#300) * Make `page-break-lines` as optional dependency (#315) * Add feature to customize section headings (#316) * Add gif support (#327) * Fix init info reporting with wrong time (#330) * Add new ASCII GNU Emacs logo, `banners/4.txt`. (#337) * Add feature to sort agenda (#335) * Update the CI process uasing Cask (#341) * Add a changelog (#342) * Make shortcut function name respect to shortcut id (#348) * Add capability to custom align agenda widget (#350) * Correct straight.el package count (#354) * Lazy load modules specify in dashboard buffer (#359) * Clean up zombie project for project.el (#363) * Add capability to navigate each section (#365) * Add functionality to delete items (#366) * Fix issue dashboard-banners-directory resolves with two slashes ("dashboard//banners") (GNU only?) (#367) * Add capability to remove item for agenda (#372) * Add CI, activation test (#381) * Fix dashboard not showing up in daemon mode (#382) * Calculate truncate path length in pixel (#402) * Center banner with properties and combine text with image (#407) * Caculate line length in pixel width (#427) * Add ascii option to dashboard-startup-banner (#436) * Agenda tags format (#441) * Make icon display predicate customizeable (#442) * Add support for nerd-icons (#451) * Add custom variables for icon's arguments (#461) ## 1.7.0 > Released Feb 21, 2020 * Update year in Copyright * Fix CI and include emacs 27 (#218) * Disable package-lint checks for now * Fix error when `dashboard--section-starts' is nil (#204) * Smaller icon size for remote files (#211) * Create a custom variable for dashboard-footer (#186) * Replace defvar with defcustom, making customize work properly (#205) * Disable undo history for dashboard buffer (#207) * Avoid loading `all-the-icons` prematurely (#209) * Get elisp-lint path using find * Refactor: use all-the-icons-icon-for-dir (#198) * Update Emacs 26 to 26.3 * Update elisp-lint package * Update circe to 2.1 * Replace if with when (#200) * Fix space after comma for phrase in dashboard-footer (#194) * Fix face description typo (#189) * Fix widget face bug. Fixed some linting issues (#177) * Dashboard return button (#171) * Fix icons for weekly agenda and add an icon final condition (#173) * Added filtering by category for org mode (#167) * Revert "Remove `(require 'seq)` (#165)" * Remove `(require 'seq)` (#165) * Restore seq-take properly * Replace `seq-take` with its code (#161) * Reduce initial requires (#162) * Update screenshot * Vimish bindings (#139) ## 1.6.0 > Released Jun 07, 2019 * Added foot note plus several enhancements and code improvements (#137) @romatthe * Do not require all-the-icons for footer icon, use it only if it is available (#141) @JesusMtnez * Properly use footer icon fallback text (#142) @JesusMtnez * Add face: dashboard-footer (#145) @seagle0128 * Clean up project list before loading it (#144) @seagle0128 * Add the navigator below the banner with the customized buttons. (#143) @seagle0128 * Support `straight.el` properly in `dashboard-init-info` (#147) @JesusMtnez * Support multiple lines for the navigator. (#150) @JesusMtnez * Add newline at the end of insert footer. (#149) @jcs090218 * Update metadata in comments @JesusMtnez * Drop 24.4 support, from now on checking from emacs 25.3 @JesusMtnez ## 1.5.0 > Released May 27, 2019 * Support bookmark/agenda/register/project actions. (#131) * Made heading icons a customizable variable (#135) ## 1.4.0 > Released May 22, 2019 * Update emacs versions used in CircleCI (#124) - Emacs 25.3 - Emacs 26.2 - Emacs master * Added heading and file icons (#123) * Added new init info functionality (#126) ## 1.3.1 > Released Mar 20, 2019 * No need to launch 'projectile-mode (#113) * Use "Applications" group and give a proper description (#114) * Fix error in `dashboard-next-section` (#118) * Make line moving commands behave like `dired` (#117) ## 1.3.0 > Released Mar 03, 2019 * New configuration `dashboard-center-content` to center content (#88) * Handle the case where dashboard lines longer than win width (#101) * Fix shortcut regression bug (#102) * Fix opening org mode "links" (#106) * Add shortcut indicators to sections (#103) * Indicate when a section has no items (#107) * Give section headings a face for easy visual scanning (#109) ## 1.2.5 > Released Feb 25, 2019 * Improve CircleCI badge ## 1.2.4 > Released Sep 23, 2017 * Registers widget - Thanks to [Pedro Silva](https://github.com/pedros) ## 1.2.3 > Released Aug 11, 2017 * Refactored widgets into their own module * Added org-mode agenda ## 1.0.3 > Released Dec 05, 2016 * `g` shortcut refreshes contents of Dashboard. * Stop dashboard from displaying if Emacs is launched with a filename * Fix whitespace-mode banner issue emacs-dashboard-1.8.0/Eask000066400000000000000000000011601446027744200153530ustar00rootroot00000000000000(package "dashboard" "1.8.0snapshot" "A startup screen extracted from Spacemacs") (website-url "https://github.com/emacs-dashboard/emacs-dashboard") (keywords "startup" "screen" "tools" "dashboard") (package-file "dashboard.el") (files "dashboard-widgets.el" "*.org" "banners") (script "test" "echo \"Error: no test specified\" && exit 1") (source "gnu") (source "melpa") (depends-on "emacs" "26.1") (development (depends-on "elisp-lint") (depends-on "page-break-lines")) (setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432 emacs-dashboard-1.8.0/LICENSE000066400000000000000000001045151446027744200155620ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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 this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . emacs-dashboard-1.8.0/Makefile000066400000000000000000000010431446027744200162050ustar00rootroot00000000000000EMACS ?= emacs EASK ?= eask .PHONY: clean checkdoc lint package install compile test ci: clean package install compile package: @echo "Packaging..." $(EASK) package install: @echo "Installing..." $(EASK) install compile: @echo "Compiling..." $(EASK) compile test: @echo "Testing..." $(EASK) test ert ./test/*.el test-activate: package install $(EASK) emacs --batch -l ./test/activate.el checkdoc: @echo "Run checkdoc..." $(EASK) lint checkdoc lint: @echo "Run package-lint..." $(EASK) lint package clean: $(EASK) clean all emacs-dashboard-1.8.0/README.org000066400000000000000000000315121446027744200162170ustar00rootroot00000000000000[[https://www.gnu.org/licenses/gpl-3.0][https://img.shields.io/badge/License-GPL%20v3-blue.svg]] [[https://jcs-emacs.github.io/jcs-elpa/#/dashboard][https://raw.githubusercontent.com/jcs-emacs/badges/master/elpa/v/dashboard.svg]] [[https://melpa.org/#/dashboard][https://melpa.org/packages/dashboard-badge.svg]] [[https://stable.melpa.org/#/dashboard][https://stable.melpa.org/packages/dashboard-badge.svg]] * Emacs Dashboard [[https://github.com/emacs-dashboard/emacs-dashboard/actions/workflows/test.yml][https://github.com/emacs-dashboard/emacs-dashboard/workflows/CI/badge.svg]] [[https://github.com/emacs-dashboard/emacs-dashboard/actions/workflows/activate.yml][https://github.com/emacs-dashboard/emacs-dashboard/workflows/Activate/badge.svg]] An extensible emacs startup screen showing you what's most important. * Features 1. Displays an awesome Emacs banner! 2. Recent files 3. Bookmarks list 4. Recent projects list (Depends on `projectile` or `project.el` package) 5. Org mode agenda 6. Register list 7. Supports both [[https://github.com/domtronn/all-the-icons.el][all-the-icons]] and [[https://github.com/rainstormstudio/nerd-icons.el][nerd-icons]] * Screenshot [[./etc/screenshot.png]] * Dependencies You will need the following packages which are all available on Melpa: 1. (optional) page-break-lines - [[https://github.com/purcell/page-break-lines]] 2. (optional) projectile - [[https://github.com/bbatsov/projectile]] 3. (optional) all-the-icons - [[https://github.com/domtronn/all-the-icons.el]] 4. (optional) nerd-icons - [[https://github.com/rainstormstudio/nerd-icons.el]] * Usage #+BEGIN_SRC shell M-x package-install RET dashboard #+END_SRC ** Open the Dashboard You can set up the dashboard to open automatically at startup using =dashboard-setup-startup-hook=: #+BEGIN_SRC elisp (require 'dashboard) (dashboard-setup-startup-hook) ;; Or if you use use-package (use-package dashboard :ensure t :config (dashboard-setup-startup-hook)) #+END_SRC Alternatively, if you don't want the dashboard to open by default, you can use the interactive function =dashboard-open= to open it when you do want it. By default, the dashboard will show three lists, recent files and bookmarks and org-agenda items. The widget “projects”, which shows a list of recent projects, is not enabled by default since it depends on packages that might not be available. To activate the widget, set the variable =dashboard-projects-backend= to either ='projectile= (projectile, available from melpa) or ='project-el= (project.el, available from GNU elpa), then add an entry like =(projects . 5)= to the variable =dashboard-items=. The function =dashboard-refresh-buffer= (an alias for =dashboard-open=) can be used to visit and refresh the dashboard. ** Emacs Daemon In addition to the above, configure =initial-buffer-choice= to show Dashboard in frames created with =emacsclient -c= as follows: #+BEGIN_SRC elisp (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))) #+END_SRC * Configuration To update the banner or banner title #+BEGIN_SRC elisp ;; Set the title (setq dashboard-banner-logo-title "Welcome to Emacs Dashboard") ;; Set the banner (setq dashboard-startup-banner [VALUE]) ;; Value can be ;; - nil to display no banner ;; - 'official which displays the official emacs logo ;; - 'logo which displays an alternative emacs logo ;; - 1, 2 or 3 which displays one of the text banners ;; - "path/to/your/image.gif", "path/to/your/image.png" or "path/to/your/text.txt" which displays whatever gif/image/text you would prefer ;; - a cons of '("path/to/your/image.png" . "path/to/your/text.txt") ;; Content is not centered by default. To center, set (setq dashboard-center-content t) ;; To disable shortcut "jump" indicators for each section, set (setq dashboard-show-shortcuts nil) #+END_SRC To customize which widgets are displayed, you can use the following snippet #+BEGIN_SRC elisp (setq dashboard-items '((recents . 5) (bookmarks . 5) (projects . 5) (agenda . 5) (registers . 5))) #+END_SRC This will add the recent files, bookmarks, projects, org-agenda and registers widgets to your dashboard each displaying 5 items. To add your own custom widget is pretty easy, define your widget's callback function and add it to `dashboard-items` as such: #+BEGIN_SRC elisp (defun dashboard-insert-custom (list-size) (insert "Custom text")) (add-to-list 'dashboard-item-generators '(custom . dashboard-insert-custom)) (add-to-list 'dashboard-items '(custom) t) #+END_SRC To add an icon to a custom widget, insert it with `dashboard-insert-heading` in your custom function. In this example, there is an icon but no shortcut. #+BEGIN_SRC elisp (defun dashboard-insert-custom (list-size) (dashboard-insert-heading "News:" nil (all-the-icons-faicon "newspaper-o" :height 1.2 :v-adjust 0.0 :face 'dashboard-heading)) (insert "\n") (insert " Custom text")) #+END_SRC To modify the widget heading name: #+BEGIN_SRC elisp (setq dashboard-item-names '(("Recent Files:" . "Recently opened files:") ("Agenda for today:" . "Today's agenda:") ("Agenda for the coming week:" . "Agenda:")) #+END_SRC To use ~all-the-icons~ package: #+BEGIN_SRC emacs-lisp (setq dashboard-icon-type 'all-the-icons) ;; use `all-the-icons' package #+END_SRC To use ~nerd-icons~ package: #+BEGIN_SRC emacs-lisp (setq dashboard-display-icons-p t) ;; display icons on both GUI and terminal (setq dashboard-icon-type 'nerd-icons) ;; use `nerd-icons' package #+END_SRC To add icons to the widget headings and their items: #+BEGIN_SRC elisp (setq dashboard-set-heading-icons t) (setq dashboard-set-file-icons t) #+END_SRC To modify heading icons with another icon from all-the-icons octicons: #+BEGIN_SRC elisp (dashboard-modify-heading-icons '((recents . "file-text") (bookmarks . "book"))) #+END_SRC To modify heading icons with another icon from nerd-icons octicons: #+BEGIN_SRC emacs-lisp (dashboard-modify-heading-icons '((recents . "nf-oct-file_text") (bookmarks . "nf-oct-book"))) #+END_SRC To show navigator below the banner: #+BEGIN_SRC emacs-lisp (setq dashboard-set-navigator t) #+END_SRC To customize the buttons of the navigator like this: #+BEGIN_SRC emacs-lisp ;; Format: "(icon title help action face prefix suffix)" (setq dashboard-navigator-buttons `(;; line1 ((,(all-the-icons-octicon "mark-github" :height 1.1 :v-adjust 0.0) "Homepage" "Browse homepage" (lambda (&rest _) (browse-url "homepage"))) ("★" "Star" "Show stars" (lambda (&rest _) (show-stars)) warning) ("?" "" "?/h" #'show-help nil "<" ">")) ;; line 2 ((,(all-the-icons-faicon "linkedin" :height 1.1 :v-adjust 0.0) "Linkedin" "" (lambda (&rest _) (browse-url "homepage"))) ("⚑" nil "Show flags" (lambda (&rest _) (message "flag")) error)))) #+END_SRC To show info about the packages loaded and the init time: #+BEGIN_SRC elisp (setq dashboard-set-init-info t) #+END_SRC Also, the message can be customized like this: #+BEGIN_SRC elisp (setq dashboard-init-info "This is an init message!") #+END_SRC A randomly selected footnote will be displayed. To disable it: #+BEGIN_SRC elisp (setq dashboard-set-footer nil) #+END_SRC To customize it and customize its icon; #+BEGIN_SRC elisp (setq dashboard-footer-messages '("Dashboard is pretty cool!")) (setq dashboard-footer-icon (all-the-icons-octicon "dashboard" :height 1.1 :v-adjust -0.05 :face 'font-lock-keyword-face)) #+END_SRC To use it with [[https://github.com/ericdanan/counsel-projectile][counsel-projectile]] or [[https://github.com/bbatsov/persp-projectile][persp-projectile]] #+begin_src elisp (setq dashboard-projects-switch-function 'counsel-projectile-switch-project-by-name) #+end_src Or #+begin_src elisp (setq dashboard-projects-switch-function 'projectile-persp-switch-project) #+end_src ** Org mode’s agenda To display today’s agenda items on the dashboard, add ~agenda~ to ~dashboard-items~: #+BEGIN_SRC elisp (add-to-list 'dashboard-items '(agenda) t) #+END_SRC To show agenda for the upcoming seven days set the variable ~dashboard-week-agenda~ to ~t~. #+BEGIN_SRC elisp (setq dashboard-week-agenda t) #+END_SRC By default org-agenda entries are filter by time, only showing those task with ~DEADLINE~, ~SCHEDULE-TIME~ or ~TIMESTAMP~ . To show all agenda entries (except ~DONE~) #+begin_src elisp (setq dashboard-filter-agenda-entry 'dashboard-no-filter-agenda) #+end_src To have an extra filter, ~MATCH~ parameter is exposed as ~dashboard-match-agenda-entry~ variable, by default is ~nil~ #+begin_quote ‘MATCH’ is a tags/property/TODO match. Org iterates only matched headlines. Org iterates over all headlines when MATCH is nil or t. #+end_quote See [[https://orgmode.org/manual/Using-the-Mapping-API.html][Org Manual]] for more information. Once the agenda appears in the dashboard, ~org-agenda-files~ stay open. With ~(setq dashboard-agenda-release-buffers t)~ the org files are close. Note that this could slow down the dashboard buffer refreshment. *** Agenda sort Agenda is now sorted with ~dashboard-agenda-sort-strategy~ following the idea of [[https://orgmode.org/worg/doc.html#org-agenda-sorting-strategy][org-agenda-sorting-strategy]]. Suported strategies are ~priority-up~, ~priority-down~, ~time-up~, ~time-down~, ~todo-state-up~ and ~todo-state-down~ *** Agenda format To personalize the aspect of each entry, there is ~dashboard-agenda-prefix-format~ which initial value is ~" %i %-12:c %-10s "~ where ~%i~ is the icon category of the item (see [[https://orgmode.org/worg/doc.html#org-agenda-category-icon-alist][org-agenda-category-icon-alist]]), ~%-12:c~ gives the category a 12 chars wide field and append a colon to the category. A similar padding but for a 10 wide field is ~%-10s~ that is for the scheduling or deadline information. For more information see [[https://orgmode.org/worg/doc.html#org-agenda-prefix-format][org-agenda-prefix-format]]. Deadline or Scheduling time will be formatted using ~dashboard-agenda-time-string-format~ and the keywords (TODO, DONE) respect [[https://orgmode.org/worg/doc.html#org-agenda-todo-keyword-format][org-agenda-todo-keyword-format]]. *** Agenda tags To customize the tags format there is a variable ~dashboard-agenda-tags-format~. This variable could be any function that receives the tags directly from ~org-get-tags~. By default ~dashboard-agenda-tags-format~ is set to ~identity~. To hide the tags set the variable to ~ignore~: ~(setq dashboard-agenda-tags-format 'ignore)~ or to ~nil~. ** Faces It is possible to customize Dashboard's appearance using the following faces: - ~dashboard-banner-logo-title~ :: Highlights the banner title. - ~dashboard-text-banner~ :: Highlights text banners. - ~dashboard-heading~ :: Highlights widget headings. - ~dashboard-items-face~ :: Highlights widget items. * Shortcuts You can use any of the following shortcuts inside Dashboard |----------------------------+------------------| | Shortcut | Function | |----------------------------+------------------| | Tab Or C-i | Next Item | | Shift-Tab | Previous Item | | Return / Mouse Click / C-m | Open | | r | Recent files | | m | Bookmarks | | p | Projects | | a | Org-Mode Agenda | | e | Registers | | g | Refresh contents | | { | Previous section | | } | Next section | |----------------------------+------------------| * Wish List 1. [X] Center content 2. [X] More banner options 3. [X] Customizing the list of widgets to display 4. [X] Integrate Org-mode's agenda 5. [ ] Listing Perspectives * Contributions To contribute your changes to this package, please do the following: 1. Fork the repo 2. Clone a local copy 3. Make your changes 4. Push and create your PR When working on this package, it's typical to uninstall dashboard, develop your changes and then install this as "development version". This is accomplished with the following steps: #+BEGIN_SRC shell # In emacs: M-x package-delete dashboard- RET #+END_SRC #+BEGIN_SRC shell make package make install #+END_SRC ** Prerequisites * [[https://github.com/emacs-eask/cli][Eask]] emacs-dashboard-1.8.0/banners/000077500000000000000000000000001446027744200161775ustar00rootroot00000000000000emacs-dashboard-1.8.0/banners/1.txt000066400000000000000000000005011446027744200170740ustar00rootroot00000000000000 ######## ## ## ### ###### ###### ## ### ### ## ## ## ## ## ## ## #### #### ## ## ## ## ###### ## ### ## ## ## ## ###### ## ## ## ######### ## ## ## ## ## ## ## ## ## ## ## ######## ## ## ## ## ###### ###### emacs-dashboard-1.8.0/banners/2.txt000066400000000000000000000004771446027744200171110ustar00rootroot00000000000000 _______ .___ ___. ___ ______ _______. | ____|| \/ | / \ / | / | | |__ | \ / | / ^ \ | ,----' | (----` | __| | |\/| | / /_\ \ | | \ \ | |____ | | | | / _____ \ | `----.----) | |_______||__| |__| /__/ \__\ \______|_______/ emacs-dashboard-1.8.0/banners/3.txt000066400000000000000000000007231446027744200171040ustar00rootroot00000000000000 _______ _____ ______ ________ ________ ________ |\ ___ \ |\ _ \ _ \|\ __ \|\ ____\|\ ____\ \ \ __/|\ \ \\\__\ \ \ \ \|\ \ \ \___|\ \ \___|_ \ \ \_|/_\ \ \\|__| \ \ \ __ \ \ \ \ \_____ \ \ \ \_|\ \ \ \ \ \ \ \ \ \ \ \ \____\|____|\ \ \ \_______\ \__\ \ \__\ \__\ \__\ \_______\____\_\ \ \|_______|\|__| \|__|\|__|\|__|\|_______|\_________\ \|_________| emacs-dashboard-1.8.0/banners/4.txt000066400000000000000000000005021446027744200171000ustar00rootroot00000000000000_ ___ _ _ _ ___ __ ___ __ _ ___ __ _ ___ __ ___ _ ___ _ _ _ __ _ ___ __ _ __ _ _ _ _ _ _ _ _ _ _ __ ___ _ _ _ _ _ _ _ _ _ _ _ __ emacs-dashboard-1.8.0/banners/emacs.png000066400000000000000000001253571446027744200200120ustar00rootroot00000000000000PNG  IHDR3LgAMA a cHRMz&u0`:pQ< pHYs B(xYiTXtXML:com.adobe.xmp 1 L'Y@IDATx Uer, /2T2VolnTe--V[[.l -o9de h0s0lwfZYvv-=[kO@d ;YT鯁gu\(? mm ^BiG=T,qKp)@/fDԀ@:i+?w=0ӳӎ ʛ&dpmпmJ-|/77Y5\SEja)muxUJ/n c? oG&Xe;-_{--N5;>Omގ5Ez 7m uLa+oS1w"U${+,vTU5=4o`Զ(i=NcOhMER}t(lܱك_!..s̛ZзzҶycc9%(^T^JG8Jj5x7je'cV_U[+m* u0TVTgVWgq:}aN&X:E ~.k[._Y~Ց@*WeeU)w}ATvXıAVjC;| JF>"ior@ّ }7WUe}{r?o_ $\<ҺLJ]u~`8ybh,A4}Ś+%`^ td*/bRjն # [/]ol]fMV.u{M6/V ` a<'f}Æ$8JgHv9TVuycʯ-qo$.7G2p M[)dZm~´@oǭ܌|M4D 9N&8rl.{SXI8COڡ=AdJA@:`#I|2WӘ..t?tO $m; DZ&Y@Vp] "\ݭ[Ximz֣!NG9P4$kfh,lSF* 䉔siD7qxEm_ctpu,+Nh]ݗ:AF_b&W~n) >vȇȞl`.}OٚGr_si ŊD]r 9Bb*zH 4>Rƌ8Vu6]-辀) +wSr8ΉUbV{^Y3WQ#G~a[/@ TI@oRzFgLZ ;fZAdvloVG=.[v<4SJѝ!iiI~ b%M8B:sVY;TKxYR% <] ELdP>9Ë=|Lzak$&1ƀH3Ȓtȇ)H1c~Q^Uz Q\{D$0ۥ 0נiD<ѭou5mt)C4lw tdژ%cә[ sXDJ?C.A.N^/_AەrӶu;Dۊ\JXWZoxfWElO RA^0_|.4'=6܈C51Ь=<%3iX,kWy~*y"JcF/&SrQO*5o W}+J6rĎV7?dw0SwUPi,WvزKS %Cf=@_D 7)f9,ڳ5~ni![aaMcGcN!ݫ]x&D lPB=rLH.:Hhњaq9p3!ǰz qKA:KOGxU'E]Y>CqLс(ΛDk`W?lzkYƖ.I@2t$VcC ?-xe?h`#J^IݎE߰=*cC.1tFZ7`GDsPΥӹۥ!;I-BsH[ʒ…)T+rީ1:gKߋj}Pߡ>#C%BO"[ߣdT}ܟ#%3}_7a$A !>|vP3} F9%ai(s۟{O,sAk+PԹ,|g.4y/cRm ,ObkmTlӰ,0Xs#[/YzpkLV=XӞX8dj-K/-ӳ2J;t2^z8v$\@?ܔC@t{r=XJ[kЪÍ.79j|rD<. zclTu=dGҒ6|lgp3Q9G)}:+O #}tnqozڛPO`:e5y=(:(F殡lpZ̧mK$~G$i7F2tjчhwf/$C!K]~|Ydr ;V[F͢Uۏ""C:oO]zy7 _s'gnIp9>,}H;t15ٔ2-B<܊1(J \wE脧N^Gf$ {tl@R₆8P,E' 6y"K|T2YIH\¬Э~/m+(QZצJp!@Zk`~N@&.K#V *zv8E.g$MAo>Xf8VzaVZ$ܢ?#/noHĸoPOVn鯍s)%XQa:8'oU+ʵ:\2ztڋ:e^r%Nkl)c'9(@8-1e:-Yyl낿yAD">xOa#Sy*"$&}KY9}1םM<w3 (pG^ztStTd_%ݤfdC\7-Zϕr7<I/ŤzV? 9zQz@Y: nj]5[1Voh×&4QJ˺p"\[tniTj Jjr cR8k"%(›v[3iʧ< FQ$cJ8{+%v+g 8mnep-M RH~1b<z;X>{0oѴpup.?'TpAmvTXT0}?a]ze_A gdBDDYoWh_h*OO'HTTf̞T,g]Z=S%uBUD*k-^fLf߇9:Mz4mbw_v31cϕcƳAt"x#UDE&Q\i#ĝTžҧ @΋ޝR|9H)*ڥyz=A,4fԇ^N%x/`o LY9ͤ ԥ+\pF$?ޞ>,+pι K 'YqSosݳ2&q߼s:IQBDhLND+lYcrE~).7^P\,&\-QP5_y\/ڇ<:Re$NCUMżZq{Y!@Tz_sF:[gѩIOSS3Qhwv$uϐzIp4pq|~wD%q^Ҧ.!?k1@v;'Y{z/z{L;:H-QCjv6s+=S]Sj~BA+8_l)h<+M| 3×0p}{ xa#/xMo,0O}cWXHM>!heN9ЮO6s],Jwʕ:g!r Iv(O1sS$ۡxYF7,N{Yr(:XiKѫFntТ1H2+Scn GyCAי/BDw~_$]1 )s@ jEH:+*WH貿aKVbج̍|%x: ;e:icdGQEr8%db*UUv=U'fpE12qv7Rdi.$J[ӋӖ(a,#/"{k?4q$9 _1W} YǗֻ;EզBS6]]ih`i3Q]:R6qOݖkz#%7oscGȼ:fZd\N bJ/=_Gi,q[Ah^T] =6ÈR)ٿqŠ#H][#$%,:լbz}#mRr$#Ҳ{{O:WŀqTmR!UGpCXM޸8 (]pc2$/\yP]~ ƩJOazcH-tpWȆ^zfٿ)i:RzhG-?Keh;(J{&\VzW.m1Xq!~8hDWU; n^J7q kWyywI TkoTO;bfPھX-Gz7U+7O<q(C 6Nr/ˣtT1 C_6J@Ym)m3y2I5ah(3e& Xْ<֮Va %cVYE^ki-O?x:YK퓖IB(4_O<)Gv]KAA+]PYU8 g[8l~%3ضP⺞G"ʋ%gggMf CA%[)]^d`Q"~T"^NJ/ߓb/uJgYa0Gb.]V #S 8l)ߨ%߰q'׮I2;g[cс3猡OH{Лl #oGQ'ŜCE{h+K C/Q Ql;gET=S  ygT1[Yu>$Z([RViл*F>&-Y&)߶+}H^n"8Ť)+X7ċYtSs*4ɂSoTP`=ѻ; te[b]Esv5^#?z ]K刁1k>Lz|1U] t=ۋ>W1Kp !y}5zWݑvp'J }5?[W84W\AY $y]ֆ#J~k[?[/>U0~J3#F4Gh5|S%!.u GCE Q)+@2ۻte]\r9$:k }Ea'yTHլ'ܶ;cƎsamN#u(u.I+ݑv>;c+OvwWRɠYf+ɊFL3(xٺyR7ڤ8wt'Eb-dR}ӻ.K,K~S⸳ᔚ1KBIVtMFT(z$$/p(İϤKY5RAI񋺹KaUFl*ҰL_Jwʎl0c>JK#bɁMEa'X)O:H:Ig3:e#? Z  1SJ lU zkQ}C~:Лϖfo?LgaԵ! AK1әi?X!>V'K˘OqGIJVa/"':* Ѥ'CwYq850#}N{QRHy5uǒi)極egXK'nh՞z 7pO1E&뽋@)b֝Acȓj+дKg3iI8$ M)]O _|~Ï{ycF z Eheߍ\ ?%D'CYoDk՝LBiO:׮eƣ`I_o-Nd?8Aq8lcQX:bG[^9}?1%U#vkyǖ}?ҋ2 C(-xv}5AGk0ŒKpqayJT}1%}Fi" ZU7.~h]rQ0:i;.Ì)a 3{O^8znD5iGkznLKwI4&D\.\-(ϫ^/u95:_ce6tYM@F74.ĤsIhcO{ hƙ]LEt`U^7=YRދ$s i!ΡO3IUf2~M OS%3/1uIV(U($fрIg@[r -wQL vkŚ ^bDݼ/ Tq>%wIu9-Qyyy.@)]} #yzz:RmSC8@՗k{2o-Oѽyfi5zбd[v D|e|Q^4LF[KHQF} M"ugƬA@,7GQ@Y+֩?kGc Fߓ$&ɡ7@nr#s`GԏRo)^//壭;}6HdEp")ujY$7'f=@ďcziu)X}' |.$7q=b3 GsrpJgVgSU1dV s>-w~H_6[}IMN9^ ЧO N&t#U7C73VKkI4GKTpԞs3V_$$gtqCJG(ɾB5]gjb@vpЈEܳg1xԩE7Ltp)2Q\˟ %J#z2$HN'GextP4>}Lƚ[dq/t*7;O磘JדA ,JlGs捙[gx:/I)Cau+Ϫ3e#$z0t3J$uT yZ)˸~{o!#'p6)Vv Dȥd$ԝ녀sxea@b԰xByrRU.Y y%w]. 4)N֗bW*|o2]F]Q滍(lqX#t20H>u!_>> EfO!zCQRGEpTvԖ25Mr4ܷ8FgN {?+_"5WCX;wT\@Ukhh|!urzH{g$_Hʴ037 qĺMTY8n 4f Y#%h/B&qcNE`ul}`?g0~EM@fwp3/E?1ۻ:u1!R*H:"6p> vşH.ܼ182=8"L6KԴF{}҃{3Wo z9VcQYqx&}H$qOf͉X i閬l<\?Q_%Es3~` {"wfVu涽fhz3/]J[b,[v(gױmq o$ϻH;>VgH.眱e7̊Qa.B/1r|rlz'x⤙kRƺʭxXsh'^^i)ή2TNC񴛖/Y[(5Pߥn9u[H[X_-e^Y^2 vf {tCVÅ:̍3XWn $r/_NzlZ-nJs4d jA>2#N~f ^=eX,3$Dj^|G6k-V6># 乕dU'|bA*Cc转-[c#cϧ!PP'}G$Zvga$^ؐ=wL5a}=S=LAfJɡ"yjЪ(U*VwZ&CsFՆz?F1V_D{CC12iD3:%okTi_= ptxOjvOZ}M?vk#:Z"덗GטiA V}BWu-=\SO܉ۂɨJV΍<>z9&ww[9PY~x!l1rK!Fč-kCYٗRSð|[^wfQa3՗g@aQ`yTl(S!c\eAG4=~2~˺7zIDd:iOůqGǔ *;6Vag`]:5k]7[8;.| zjbErהbk2 W'}CWpA`C=KdR=+i_*?u2o.=j]+dM}avuz0i)'xM}wtSnT;r8w1eY!Zs#l$jP~}cg\X@.Cb0+<^u:WW{"DGxSδMtiK| ޒ/+<>uU*=11eC4Mtt54&x nTc\2^'4Cܓ;gW ͂syBn+zŀ<+w.L$`XW jt=}.PMvq~$#y'K@ݴ`EcȄ+)s耼M?iK& FGKĵR)#S^ʇO"?L VQa$T^RQݼ?+|4b"c?Fן"2sg}A.bE(d8L٭E;kCIVFcM3?(ԇ^nbI; 4T:=PR[3Y|r´js=ʒoHIŸW]lȽd*Rw)݌O9cR(90[gj JUywOgd'aK7v|h’Ty;%5@ͳGّ kO"/~0{m|o5i=}I"Eu]Pղ@QN q={Bݜ#"^.'|Uk3;:mNT/;rq?'?)kά~V'jH5ُk}7`O$ )`(+~HV9E{ᒮJ5o2 3@ODvul7gFp,_s᮴(N/MS'}4" _bO ۚs#-X'a_)4aIf=<[Ypct)'$a ݙgp3DQrj`;L@G3v#ǔԱ$HCi:g&78.ʷr.}ۜOp!nNZ[ M"t嗾{]kgw@D-?7PQM>szLE+]]Gx4*]}}6v1d%n(s3+.*G֞<vY x.+t@rv,X(T b tzF0?R\֬'0EI;l,áoBP{`0go_vC x9 fI2Z"gX>Ij(tۉH+Rv}\/nzjkXNᜊӏ0'~6Ⱦq2芸0W}~Ui& w24{p1W7DKqT✵wFi!6дRd-ۗJ¤6 F6ݖn9{ȜöJQ}pcB,/)v@Aq`Um,l{ԪuS~vݟhtGq#{-ݕz-XSyZb1:UpAPSq(϶9vZȓi0eas%mrZA|OIQ6zlc1W[H;_L=Nu 6zUO?tk Mns}82ёٖH=xeC|JI?qDߔ[]L*/p,)CnHՂۈL dWbղ.\ vZc0~`m gä9WC5๑8͍"#!k:h^L\JtTV@ӟ8ny Jg("ci|ժOhc\}u`g˨U[wi| F}#FfCLK7U1_=k~ma!l$(jxXe&]rmAPR5AP)O]7M);1: Mӄʘܵ/1zv]?n(o1/n_ލ_K8Vp4ўC&ѥx1oKi ϱ}ӞZ5{;fQu]qj{eyjӛLlsMeHcaHXhvض>Wn8pэi] ݙ|]P@.@hqJ6t6D tss}SwKD.<@ jYdgKl{I6ꪜh< /b͹sK>!@}g<8K 8Sǟ`%?SQڲ$@cnӇBA=_(@~:5 6*5Mo cDJu/ݘnZ :A88s!솆7xpu;gO$?LMJ"8FguGÜDI&J6 CX?ANhbIyXDxz*ЗII@v"#h|X%iyǻ8ll^h]6olU"?<KB1<14&=O{J'6OivR0@[!m-1: Æ~Z0.UhL.Sdx|1܈zȸ`ʲFcqt4_EcD5fȌP9ǡ1Bk!Cjv9C;^h*Ӕ:QyR<ր29o&ti*UbKyLۣ*'i7R uY_LnakcJpgKnI\Jx\cfi=4#[#YoAL3h0iPc\ֲk2(sT6&12:و"ϰ#4CXc|![K X(&e4N&1mgG`}Z`[Q<8?¨}Xڐ>F.C7)}$.Lˌ=hڇOj,}ʍ asPg. GPs+s̍<<턣JM9Ǎ4M;?sgKYFuZ0y@KR1ҺXz-L|s4‰1YM`q:8 An|RJ1鳙6&c46uG ma65qk-l,o|tt8p'5}e1)A Wߡvz1xQV4e쏉48؋o;BEK6O+)Q!VMPPlѢ0_A8| OY>}iLEdM\\Ѣs8n䥋y>D&*=hz(nyx$GJeZmH*<^ۭ^ KVF@/uK7=҉pS )K:kpB4;T|6~;GԲzB#ȇۦ0|?̨`VuILz! * ]+FN}0?p5wPCJ qGM .5Ͱw C1=ۘ |eGkO~p^ƅ,af=hgިH&!4Vۡ{o8ם&y_;s1e!䓘|PeE"7_ubRz5IsއE1=/RD?ՅY٬A]cju/AueC@&I>~q4L keQȡ\ 4vc]p>7ZʠsC7{{%L=޴ٽEv 1Jk4xUUĥtf~V;Ex2TJ9TǴwSiZ>~!:>W ʔGSDIKֽɭz tm2r 0 |[ddLipRŎaAʗ=ڿ\2ɰj ݆'KCX W 7@ JD<63&r+r?XۨQRWpK=O@V`H ~8t>>Y@O:kt|ս~&p"B2-{sַ! GUD渮&#wO+/JMױ*5-1wC]=Nj>[4ӱ/ pM}qKHĉvax\]% z\Iq‘ q)Ɲi_TL72܉4 ,fIp-w[#8AdZ-*ο}mŃ?v*NxXSe~y,xτ9t9ӌ 嚙[Y)Mgߛ%38l0f coϯ_2a=c-iP4E\%ϙ3IcwڬEb9c,{*tV^bf]6!2Ե Z,񵸰և A-ڷf/@]4? 9%oDt1txl؇{pK{_vT5p߾/O1튫ym\pwaQMUcQ0rz&'7iDI8縑cXуG\Ϟbۄ%I^ ȫbc)$`iXvkT353#={32UV"ۻT'z'/mVt{ Lhٰez]C)v4}I$`+1 V X}d݀+󗞎l3,C%g`@/0M1]հ3T jH:C0O6}*1e;?k^n."@Δճ~`/0Gf"u!}81gݶ5W*)x)"p ?+=}Nl%^\)yƻ'nItZ^#-HYR?ր8-'M8ayagZ !{8oޔysn;G3۲gnTNN Ǎ%ZV6Nj-h&6lTa^’^7eLE&:+ڔZhbyǖ(O^w(-M /7?|VN}=(wKr+'GqIs +nS#DF39 y1xO© V?rEksnV易ȮŏZn8cdģL/<̟b6( #c|26q'kꌜf8/3ӧNߴtr)"P{05[`-jvs+FN蓀s83 4)L؀|խC` GO\\|u2a@sDa<9z61좧PT 8‚1#NtNEɀ\ZxG㓏pEqNpA=n3̃Ok3:-2Ț}\^zX[q \5OW]oǝ>}Ќ?W5 ǩyK=X`NĿ^S Ml.a[NG BY]ܼiRR]]0 W~bPL dFet-Q;VB tׄQ$~;7WYȟ[ҍ+puiUt[}Dī,pX\==$r  :G7zo3s*Fr<`l:Pta,kդ>So'@wsʷhB .DXąYF*t_VRF󔗞m/:ayڰ C7{!W9p*ls֩BqNY5vx>O`xK5)hOݴyؘ,q{vSfYV?oVQWǎC})Vpp߫UĞ*΋M[77h)ccty8 G#?YXC'E1A?Œ$@qn`?Vj }Byn@]zt$cu.~^:Wh$婫g8: bZl`Ht pq 1B2p9߿޳Q?4@ݚeދnmg:~rN9qf2MNw_5Qܳ!=?.B gx*UN}R<4?_Zp6>js)b8k6Ȳ[j4JዪoC Hy<#t?͸`g[#0h%TK|}0x0M# WVEG3Θvsǎ@zl(l[F%c;YŦYp3ʽHĊYc;tWUu?qa.5Ijj9E`/f+{i?sMJSFug9V»[O:^8/g? O_4,vή̙eҲ#9V{"3yNk8}k#$iO[I<[7匽|WfOA}v{^ɼ5;hedL6"ۉBowEb{&=S;k +-æ MbŒXd ,ZklU|P6oy:\i%+V3mÉIK3&_-D]jqo0f4\DA^W-fuq}>zPI@\;oزl֠r4Tg*#/GlE64PrBB>GYe-1qGH.*`@N"po&\i"i®rBlh2|lEs ,%5:ʬ;q\HYZkw=tG,xVqO;7\N?cq6 WqC#P{U{MJRFZ q}F1p.#;z%wi-]}@:cPPMq)}A x Yw>/RZc=jz` }D%SMMz{^ ,r22RfM}y SM񳤉;.eWwJ*97ay RmޘiB|@!|.hycG~n|&)#:eWdNpr˺bd )IYCxupb*P|pvV,g=ٙeމve}{9m_% p}[4 g:{676S?yeGrNpE!ZgaC:@ 8I0} 5fqȜOrjgjLk?43>u9?7f$&;gZmr%ϲ{\#x PC../:rg5IvMm Nc?r Ent0466}@ɝ9n`] WӆK GݯO]_% V{Ff[pTTYnةak ۅ4&j76pbG'p{<(ԠL)G˛ ZCyuzt ggB|7'~:~-W0O}ļm} `V i._!iǔ}682=) 뛽Tϻ|>>S~^k>!1Rۻ4Hs)PG]nBeϮ\1"y WWշw;?%ne짮\E+z:2k5IR0<.͡_{lͩ{}em HL-Dq)q,逌rZe_7l;Q~xȐ#Fl.nZ~lS"IT܉MWٝ_6M%(EBcrZ +:Av7#y4\M'$2 c]qhN2Wgtݢ쎊]|P{'n³6L|r[ uxVjf?U#;$21nվo߶(ȣ3'Cس0t9,6tiO+&p"dR/Xs=蒨 =K{(SJL!8t1!=}ՃUU9G6uU}Х>o`,ҎARpw\= ޵E'3K˦Yt ǏiTFNp@L̇t ybUײ֝_{t$/8E$أ"7h ,F$ly 03cڑ]BE+DRHdz7q)[Cbں%W7,wŻ3)\CG10f}H&Z@Fِ he1޵c#=UZ KrhFSKh:,"ipL^NW>艏֌ x84%haʁbxY'@rEȩVUVs7w_ hS|9tFY/T6돸]޴t$Q{c@pPd$K;y~KI!,xI 5C'4HGӹXyUn4 |vO~$WWm}|=`N;!&N.ca Y&pEc0yqn&MFDO^:>sYA ##ծ;lmZt֟ސ&M8FH{>i33#'>oP7`18knaCm_t͆{b(voŌAn 2L5` 4 !صwM_^4\;7/pτ[UIUQaR]'vʑ&"$5Ju;+3ѭqÜx'n;9jWUWOa!:(O!dXB* (–! 0 $!$l,I6KOwuߪ̐ H_HwO-=SUl)lw;̬Y3ߘ5 +PNc8ri?V6%J*gA#Җҩ}JH: )^`xB1 t4diH G^s4ͧN6er٧tCFoNʄGN*rfdtb2mtS3-ypا!&E6݃d[PyS2c$E3)z;Vz9W8W#MN{h,}ɺĎN>^\c`Fq {S;ߪk]ccH^dZ/qԡbx&H4olWM|'.>n3<&J.Lf"-L%(T9/G^EMM pB(9>@L3r=SVa ՇW!Bb_6}FyTHM49|gxvBZ!떻˞Ui$zf^FB(xM?{yoAv?%bAQ`[ v:ϚŢSuZ Ml9 #-(6]B~Q! 09ݮR2?< ;F"Tܗ5U CιBOhĮ6vKL +8A3ߡ̶N7n`Uحuh!?@UN58K9c]OEў7C*:xV-w5 mT6\1uWS":$Saq`¤J];YB\NbANF <jZRufoPQWFX nnv6 2k_}ߐ+!%h'58YH0$zR* 6Zx=螴gɖKnQ$ypOnϏͽ~ob46(*^^>ɚV:d8`ԗboYp?e&Gj*3C(|@B^ԍfbI);wivSč_L\Ml?hdM9\mW)=쥒_յq<ި[G!/e'4* Ř៭ 32Jɉι۾~r@59hL=dm.4G\ Xز2Z/>5Yo鏜NU ͬ][4EDsh$c^`p71d xfBP95@xؼ$Bx%B#, 9qS0]ƲsTDHm1uB1v~@Wm&is/j>!WA-/blFK H}ۆGR8aIho㷷x>CĹ"v@>q,SS2G#OyEX^+2O[YwxU]aZau筅nٖז:CY؟0Bd#R;ϑ(׼@ JPbރV_dgk+bݼM+v!ta!I=)D1e3psR.9T ,l£XU.Rye`;?\>}L;4Q}(Hq=ru6({[^:?j (:.:kCvW3ȟ%+--rT5/l~1YOp)'l&f5XC|'*Ao峐 q5yC? K\1AZbe|;wu9k~‚1BfQri !,/CnSI ->vA<4Ǫ _nbgݫv|MSkREa֯Y 랊2䐑߶r/i=/?9"_&` (# }5eK)ߤvZ^vvn_vϷsl[~,ЏgΤ"klg1ıkBLyaIm*\:/7O{+[>5 ;Թ*;~g$.֖G^v{N)`KGv{plnr^Sn7c]zzz˟Uzo1POiNYEe4ugFZ_`v :Bk0FkMVJ@-TȘp\cFU"wuf]/_ g@ %Qן%{ܪG :&֛Xơ6*l 7]T:h:kx6s^ F1?9r:hwó^K= i].˾ZÙVY $3 GpV8nv)]=6n7骼3kɀPM`{DL?su\i iOɜREBI23ǍKk*JЖaFc!MTB==A Ǝ9f]f:3)Gw>㡪r$M -@BuBgaC .>w jK;XO\U{BŌ1$o$nX 52֢H&K9elAҧI}Z\;&;j"DDfSu91GZrkoby4w5J!C<A{AM1`I+ku#Hs E]Ia7uƤVi+U@:] m&m heKŁYE*r-7=?n+&Y>V,H$~hMdk{*ۻH};7ZOT pmK,/jS#`g/o9Qw+@p 78:ն/jA2;ʟɚ7pβ˭veZ"6 vL^5#-E6plTa~2i9R"ʹirmN[3v'sGH0H1H]h_kciRiu8jq=7kQ" enGQ1|{ iQP8wRdF-sӜ=>-ig6%fgK;.r־̘yuj>aF]$ P'2 7Iҡ q A`"q܍<|?9,1 6.roT^Y2QVAqƄW}=^aSȌ8zN*ckK %q^D M/#݈{d( &RVmw8' +"MLY /}Y蟟e| !`ޠ?HNa#Aԣ̲vBN?gQZrڝ/eɷN)7" m`K[{z`Ƴʑx=QykJ1 0DRP.^SҶʪ+yn5g^yL(&] wE)Ǽ$ q dC FlPݗ@q yw] ¾cVh";BwMJc=LŖP XknVgkBSAEm?Fؓz:1.r[!:Vnc(Բb%>Oa١d𑠤P*9>tw  H7L9Q@JmÞm{MsJCWopA0E=1@nkU//V!/N$7k$-p\c.C}3[A6FCTϫv _bJ#amaJ[gUhb! L(`W˄EEΣsiHc4L}0JXA#c_Z>Փt4 zX\H25*7٤mFU(q[CHI@a g+mwzRveL߽怜xBt[ "G69l -KOVZ}gh},h2CcN2 tǗ#{Jf͇8EBM|:_[@京ҭ9ΚZR[Q7WOmZv g\@o|}?9:.z顲473S&Hs/b;j~F=- ]p0!T A}.#2|(Bąw͇|˂g>Uan2o ׅNd)U.CkڔVR Xs,EKMLHi&q(p͟:tPvVv]_]~<nQ7UC@C= yt~KBG( |fS{ɀ 2mOvPe8x6/C rS rr5m|/&u GL؂0lK惍T Si촛Ho4h(V$U9n.JT~ 7avO4Xy 9{崺Ō:Uщq,QЖHԗTVrjI_oTRߛu ϴ[s-k  AMFAN%fy8ܸ59[/ӄ3s܄8W4HmOmvG?5k/F*[Q5'溧G2i~9׭l0L4p̄:JW&/:w;hJS'N=Fi9]͗-~_~̀ڻnl@aH~&Q V q=z3qa %rT} b%$`+% s}mEu7RpQlQ L@#uل(H-(;xܓx_ ;g: F8Y1v(՞zژYџV6H ;aj{_aOt˺9l0C5ڇmQvctD#vfp.".EGfߴ>'kSYy 6Q8ճaCw 2 b!-E~^Lg$`65f@v2ڐ ."`@&Sfi(M Es 'ID%$es*s1j_n>㷈Vti*iux-&ӘV";s2e9 LK&|Nvknp=)m0)xY|MӊII +6j¤J5(뭽UC6t_x@v79`ǀYJdP _CO1Hb( pY7i*30)?k5u&Qه#ipɷidl2dI[mn\Y?`?Uػ$g[49hԴӖʲ{OГ=Ri'dVʪ c*4BnvC&7՞(- ՗ *Ux}G?o~"Kx&* 6՝۹ vbªG9wS'xOW/:W/i>c![Id ./%LeO{{ d_/N c=Sd1ZQKX,u{wgws϶J_͵!@/(`q[5 t"܎yeä%dSO7֡@,?^=θعl4$u E맞DmKa KV%`܍n$@=K3L͛_ak}DݭEeD~taKy᷃+%encOTC;;c߁=UJ ӟcC-;QsA7Y9A }1+ߍD4!_kWI݄{ 3gs0@ҢϡB2qBTb\{{mc-R&:'H76kUA4K8L|Pqb+UK cog72 ˦_0wr 98V-b"6 C-k^MvWy 2Q|/G}cv;Dn`,"Gd[^`+p8{g7hwx5&K!O9 S7U,dDx j!CQ_^ oI^Ԥgkq}ݚXrT6mhPnNP'tBv99 }jՏT%U8"U [+6|%an{7)&> UJvJZ= O<\(6)hE4XqZ3IT;lv5`TAT\tZ?L3|]|ٯ %u ÷g9Jfo o>tܔaw]/Vp!rvZkA:f5&.LF\~zqO{a fC ,sGI3~F8eMQ5TL+YyWba!-PvҶ4`uZ2lu%jt|XS$CB˧0/QE.ٜA;Wkw>v]Zop(@_u#zy.VQds8ܛAU`sLWecQ\{ZL*&K.l'қUP#8k@I6IE< ΰF4FPӏ|0ppEN+e(aeJRɒb]y#֬@6۽š)ǙLYry2wsTPPvi |fGB@QI)iY~ڢď#ș&` f11"-yԙ>{#oeJjcIlX<.9k!FMY(TRԙ;T$7SZKskYׂ\&rsdbUV C'&Al"lh0w ==AP%.Z3U,IŽ$fLBЌo;ڄl ITMu!cN;M9~%[w1h.&("0m<6,˨#sRԼg(W,!-Q(Uڐ.޿!GuN9"#sx>A+T3̭ٵ5'x)D+*7M|GaHqQ3WyF/|!T'cGis[cMV8J܉5nI` kHHBT/)w$ y'EW}dwaZ wةW<VzCIYG]n3dS熳?+( > 61$.g .*|QE+zirw^.k_&5b M@Dv;h-hbACe:/ϵvicCn/##vh+$>-:%#\w;O5FsI X3$ s0C9l2Z3`0F^sosG W0-yߏNֳƆxi.u8y¹2h| 2|ϙzuE-~q-v*4%[P귿 %7ӎB5B%ՀO+v:+A~S-K"3@Wͩyr^}"0jzQ:|!t:ei.hI{+ ӅpzDcƮCBcX:8?**R}G]=\y4Zn{ZaJ)R P_mD_ocHqHحFd#M:~Men gVjcfV0_-yOW!1pBۼ5,?w5V;MαFڂU'7%߾$W U7l1/. ғt%GD?v8%CRy _'Zf{-0|T?wy%Q9KֵpzFE·i DXV.8j {ּ?JsDPƎnxJx@e7aoCm}I9;v(W:-- !\M_(Vy%'CkGѹ0GL_ Ro쀛:zIes1˶Bٕv ⎯EQMw B]3"oϵ7WC|bT FC/ѷ2L\"7ͭǘic1WV͵[v,?gu 3[yvߵ7D]FDU/qtyo &:ddeY=HeEi4ळ/`kJ Е5=ԭC!lz )fvY ^DzSf/(&lrt"B=74n: Q{^\ɒ[4P/BE(ιmfwҡާ5-aVײŮ+WܣNN*jhJ 눨sjRH͂M77?{9_קP{5sJx!3k$qbc6!nK5T,g65zu>.%Iv^0yK-ꔞ&xT'<^[ciiw}=K8WOk|Ti4;CE/ #Vo=X(-B9$I;ϿK+Ue1J}ǍÙ<o[SD.}DKו BsamɈI 4S7y Kq>c+OQ I_j%| _AF=bMJR<+VVuqPPjWz\9+^cKG#Eʶo ǿOCAvO豭=uԈ=ReDܨG$;,$FJ:rݷiCȶl>zes)y?\Xl/ y;v-ѯU,{tG+*'CN&TXJeOpJ`A`47lu{H$!og_i;*R4WŒu.MRuObXVY-l?^ZWڰ >%zwӨE38L*N8o:P~+s%70T]j,+#u9/BkyIecwilwFmWfrj\|.L)bs˖Ko5.(A \oOpu(έ囚#h_R=9M:;J(A鸽a*Yx|_DY|ռk_GZ %m prK8J^uӋ_~坷 Z{JG)B㈻wť\aJ>!]#g`?b^۾]ʞc]j% 'Lc⓳K&>^eXүW5v}2z0x.Щ]{Ix>Ʉ?YDn`S(Adׄ%I_ -%".%7AR+AJ(A?JbIENDB`emacs-dashboard-1.8.0/banners/logo.png000066400000000000000000000770611446027744200176600ustar00rootroot00000000000000PNG  IHDRAsRGB pHYsJoJolbiTXtXML:com.adobe.xmp www.inkscape.org 1 UX@IDATx ]Y&ϝoUݚ$`l' f&j オ5,VԌ ĎĶ,y,ɚU*|{sJdKv=g?{>.%?0wq0taO(L3.lwTl5KC/nYA\`'{"љ Wʍzz*7!Nֆɳq/ uiwJ˜hw>&`ќ7c4e::nvS{k-u%RIIdI$R&F&)̘0Mب&ac6|=Tj:R]>|dqaX*%koNt#ad4[OEso> Oa\:`\VJ:Z'f* KOVAW/=ޜOnOa"=aɶ"GсPho+$1G1#00aQi1e[L ZMŤr?j2P~ȱLPnb4FF{ZlʋlES_5eS[A2 㥑 <[r԰a"q We4Oj+[9&, d~j"8ãR50 騗m59ҹ;MGŞM$2Lv`EC ParI&ӝ7-&?i--&ϙT>+ˇ5:0 <*"!JQ;kU`l*%ʪY7sP2Ų r0L2D- lxMD߀UNWONW?ٿx BL׊K5N4_=(u"R36tmf3x۶'?T"t"7>T#¼ j,KN6mr&Y04F4thX6kk7׀޳yEh$% CDSqY ꦴlVY7 +$j h"֛K)NW ۋ~d:^؁mbMkF2VIz2SGd~ u*= z&#ܖS5mzM5oR rFy <~,ǮɉѨgabu0g܎O&JŔQ-ONŋS8چ<8Hc|0CiSA?v/{bнJyjjf 7\mw9n3wgӉ;c~(6Vu̚}}ˀwupєVsA YklԧIQ(AZZo,c:.X]EhTŅJX8S(Mu%zvo<*hmp1cۇ Doo6ݝٜE?mmgh_(Dcn}-cfh&ކEh`\9Hh9b ݆xb-]Ǔ9# VV< o̬D>i$*w0<*ҙ̉KD.=]^LO}1h>Gal}rs҅[} }&Rd7MahdlJ.Ȥuqb,rl#8*!Sɼ"A>"`eqb̝3EtyL$FmangPH wŊG'ht,sjVT2פ36ܵjt~W$jqj-$˨ /U17]M&ւ2|d^/CcrxC܌N6`/W<* "ytgeu̍c)d^ǃeۥT.Ww|ilbYko6565)Lz|@~M# L6V1jCFw:dwm5V)q%z!I[7+i#y(j1`:C.tIS;s;~( .)Dr&;ɹr|s]Y 12_kipؚËOzﮟT1֎v+uӶnuOsjh+I ݿϴcP@Ni>1_%hd7{F_Tސ<ʖɸ-{17جR mVZ-"G nLkovBn8qO.+G t#ݍ68v6o$ݝts/]|?.G.պ~8!:%f{L Oi>9;̽hTx֋6ƸF58ct#`tq#oȎ~\:3&ْ,WSR`^kd-lS?`ޜɬbbtrEt}F 6Τ'.}]?Bm{XI֗҇tm}5VCc&jFe#N0`E[O2xSH|.yýi,LF{s#'{(::)@-&hxU ԋa\X7.c [ _Eko?Q12MRܝ)D.!NrCֆY&Qjȩn=}ҧN&Z[R6ntخ_HR!ǟ4:|Bj*k.LRb`a4jzwHFrz#k5(H ]T` ̋j*fsJ@PFDߩ?g6 MyLs@%L>Me3~~ޞ޸!>n'7Gkx#<}Y"3d ?Wk˿vT:77u3ܙJϫs}Lt|[ka 6+|ߴWk2m̫KT-_D1C{bRao Teyljǯ`2& {͎e^c3ss;b0S׸Mk9y ,?>yZssK ' ;( oDԤ9s yuZ_Ϝm#/S+]el䷿Q, ,v'on~ÅtoKVcGL}n @c x?VX6A6pd[xf`lZ0wvh"sm'!yZCQ:Sփ_0h<AblT ݂۴S0q҄m\0_@ǕRؿ HNJfkJq?xݽZc6=?m]?B0Tq fflr լ@XAddЁflpӅڬ5,ذjfڌ]mw1|!קFDqF&_5 v5k#/~\HkߒB|سN-uLl53m7[nLͦ.~h2'0ϑ!;[@6e;$R]771НA6QmJ<06VGkӤ8f.<8; QQ$ұ>7ѭ$-:eN$\MZ4|8klK./c[HM`[ T}j߸adu}56FUiL YX]s8?c34l1Kqԡ$ c>B{i+dMj "]ͅ537}y)sil icI_(e50dr8qI&=L'[fGlǶ8xvkw%?W"TҷM(.,?|ϞhUtX1wm5.*&s N=6[$bqr#OdM-*=N2 SَAn6{nFktzYӽ)!TQ=\?Qԗ4O73ghu,V~ᓿsw, ]u-uRÝ[1Hx?L/<ۋڶoƋko=x>nW3 RhżWk[ZR!&N&L4;=,Y[E-KΜ-cEMϦ,L( 3B'VB ^Nbvw u;ܹ|fk `|k58y!ƖMmؖ;5HmK_~w8HF"FualC6Uq~w`Cc,"?NB6~ &\ǝ86X.-{|Y5&g͹cKqtCCc3b&/0UA+tPG%0Kݑƿ85ҹ39_ClK 皜5$C5&i-򣿀u~aQh6ݷG^<拾7X6΀JmґHx$0>S4 x\Ϝ4wlJ2'QZeeCج ,4XBKiR4#C-]0GAI}`ZLR_M'(]eJTk18'QyooqsՅ|T  O,z5jI&oG,6{F@ ^*±b-$265fa^&6v9&U-r8zP\Cq4>` r0lށvemFP+̓4ªUMJEAMU$ F\DQn Wչ NOZ~-'s#gܺ3dgO'Իj Ȧ} nĺ~ S =cGeKL'J74jl!x$76-I_q~TAA*5kvl_WONz}Np=57sɋ[Q` ՘$ďi0`Pdϑ!d*mg ygtO_WɐGqLMB|beWcp9[HgeO}џx_&}/R{7=)rɾ|f԰`<4xg>(aWcJe1"a[Gm1RgϹNZ3& ,sZJyԱtW럟] XٔXy!=|k5A5Nӳu$%q[K-Ze[ݪ d.5^14>hL|ع]º'S9LMpz"OGB#4GNy:)YLR1Iшj`df\}ȜɡCQՋy/6(07t(bzܴ)..do%[m~f{{Sӣ(dF iR7'3=}z>InfJnYMǾ#x#f6 S{`Z~YgJie[tbОKSXpׇQk*utj]ԇ} sS,oċO%_'BaWBc>T:kGsGcY#ܶ9_{MGfڌqk^H !*!?3l 5:m2mxdR$j}.q5Yk5QB{w ;q٫NlvZC]&Y%`avz<|PHDhf^x?ÓHHim1fe!k?|>ç_/_]XWJi| UCLy7d }=xα9X*'wL_q]Y]߻ܼ7$KԴ9X܈iap:_"ucZΊ\6Ifk35G79sgӶpyv up[s_ ӳ[P"wR@cCٗ&3;{3[~cvֻXnbFCn<'w H.ЙQB6|7;1ZT04~WuI}B}i9z.?h5Ngle< (ZgxM!4hZFnVgS,Tg^l<6zSP,Q2Hʊp?B2Ue[lʓi;CT+>>^UpԙG'wo+ fxA/)ɏפkj΢(ɕΚ?s^N ʮ xEOr'|sSJ|1wM~XoX_uXĩ -$ri4wâG2D xU:kXq( vH^=Y@T11;4*f[_ ^䄭 f4iHU) yGʼ!'"Q ʯ.un]@ M>V;D 弆NFGב <ЀG}||:u3Nji[TяٙU3u GέŅS:?Uƚ) ?` ,KdPU2q*PZ{p V#ӓ~olW[[fkyL :mŋA"+Qx8ut1sdo8955F(ԫ׍ G*])tg[I;2Ix%Vq(|8xg]e\f\l&..V9wjL^\1hvZxIvr /t$M[f&Yl 2FqQSK5 bzL24;TMbI'xxXwvq1︭{9Cw(arn#Crs$΋ݤҝQkɶrP|Ir OM3u~nqzh&M ӱ]?ladbkKGg&< B,$lC:5ȰdN rxǗ^?ucsJ !5h*;p8ޥZ^ xVx#*I(im`^]_,u N%s"Wa3\k "SV~% '9Xo#R"3l+wlBaǪ"^D*Ťa@(؀1Oc󩯎]dWaqޜ6{s/7ίj+]M؏"q3;Hd#X$pEb $q.xPhWit4"jbAl7ê5 `:s)^YڋXu p铒rgb|KZwH0F?;k;4ncsF~uagl0G/,ưΊCCiDn.@<Q5gi7q!TFxi;FRR~tr 1iZ9EB Q g4 9QJ .npgcK/b`1 Ұ )h1i| 9¢l\(7%hW/ c8(͠:VܨQ$?98cz7{[XqNQxcDU ' lyEcVpr,JeXU<<Ox(Az<_y$Va$G4XouD`L{9*|A 8/nӆ@mJ97j>p`mvk! rv` }M褊94X՜ R3"qK*Ϗ`/ W`'fϱBQa;@wybhZ)(+#<|PP/ XK[eV B w<߄!ioEI/OW ^ynUqA D^0|xUq4mrd+8 -,/\u%^i(fŽ<X[:&Wm̒'k}4+^]e?m-*o^A`#=TSC^S0mC(~}ܔIFD"i|(B}%Fʯ`$,kŠ~|wWњ~"i9pW:m6E6hy#?ύpmCs3d9r$N 0q@+Ц3deOUhO_zݵ4m1wW^niCDz„ȒnT|Z xq2$6,xǯ8顛(.VWr4yxEWغr' rM8 ։[@??3]3 2̱/ 77c)){VyKzp%;E1.-2ұF;ϛ">|sWht:d_΂mܙYs쪼 Mn^q@OS_:xU4[\# `J&%DHy(x@s<tqAw%\K7KӰ<6i왹0 O&D/S؃#D$V$.릌8ZX,5,ƒP);ΞyЧ{}5\Sb>w{߼ gkCX)Teu#F]WfDRoJa\$Ex< ,aJ#N[-\kV"^⳺sN%_|i4 VvlmQ Zôۨ(lWS4ΖH .,O-@ YF]d. U&}:x }\W gt]Bla"M4?ILvBt -r@G4,ɓiє"VAR|-H6 iw,cɤYYD-g괙d i$D-$KMj0hvby*w[~s+;1&6tߊ!uxK 4 stx?anh^88iz1]E댎#ޡֻ7֎9cFʕ^aPhhR/B aJ TS/$g(ǺE %Gb[}؏涑[}(uq'("yx12^6yNyAFHACúSS\7nk 3~fY^dNby+]JK?$*2鳤[YO]$|))cfģPXL?'x#冣 P%^d.6=8WWVED݉wݛOFui@ҝ{gbpdU,Ur(x]UsA[ DPEDFP|R\{Ys4Z(TWQ km˚ѽfݛLGoL_Oe~"jڬVu*ܡ1"B|R1x>]GVuDqr7z3{x<)xG#06-gu^& Ux`Ȣ7<z`0rS;"xu_*'v%@">T<naB1Xpjxt\ӎx 22{@9>.)|d\^TE )JU7^I+&H"܈?tM#V#v% ? X{;'ރii#IGѯ=ixaF"@P5p+x8GMO 9҄Eǀ@~@wQ^ESv\njxbWO߾|۠iÑ[iy4kJjE]:JhOM#Gτ_}x / I֖{AB\WI+"DbGքa`o>oY\VH F08.qUke<57'"r;TxjO*Ǡ /' h}kٻӻ.kυn:mngs0K)~W9"~qӏ x]p2&29QesZB*)%Z' ^ʿ2}A$N&2mY(ifNe@ OGaEM=q  r57$R2V#ws a`dq u ї>q:^~le 6Eb]q0X;w~3xݛC_;>3fSZр OPVfnqHbėSgƯ(HfD|jyCmvrkRk3cN!ɠആ30b%3!]bL$:*a.> U=!(r0b NW*h;Zx٘q|3^Y蓱 ̓_4O|r j Gv}X 0=.hla578vuKp}̳0G?}\< Kyo *Bf =p^ '{.ꥹ+Y+!p)d *QHpEX x@*#&R(6s {ȱ`th\%@a{ dOiR0bKNoR% Q{!c @ 9yﰖ%R鴚q OŠNUy--6cElG] dˋyTdƨg6'w1:k_<>gGh 1.`Vx$ {|\X\fdHXO 2fu!=a8VEM*qUVHDS%.Ä!Xx#GBӄG@D4w^je|s>OMrf269>N"hn"fzi<,^K+%3vzg,EVp%oX=Bk:=l"LP%/a I<:+(DA>`X_b0?cDqk5E\T>1Xda upA|_^{ 3wnN{&PnEK#N]Zv%+q'Y4El(Mc:?X l 3IJ ߤ,Z9Aƌ!26GCB:^R$&~m5&o3)Z+j3(ʧgc2GY6Tkc {ߥ]("j-4ܳpHl)EN%zAj H.;45\UXQ):gXLPByx4 q4ȩϙ?2bzl+[_+#sF]ζy9wb6;;k`3-*,Dع5 .Bxc$>o $fW<ߨxXs,ugjfk-atŊN+ppC+v㭒 $ci^ =FfҮM $8";:o1|L+mDq72th&s'gͱgE5 w!ñLV8] &[u׀b Њ ^p/9KSNq:ܼ] v뵝۶|s5䅘 SZ8|vZ9G@2*Aل`j k55'7Th` 92OZ9M}Bv08>"ƻuLUZ<TKes̻?p<_Mvv#czb\0y9v`L/jU![~&mpك{3Lj(6[EIVL%~Zj>XXV's8*0n91MZПKj@JӤ>FvG Vl4mibyr^ A@(-1# |PapTTޭVYyqÎB|? %̟֘5|@[s Z\j h SKA͹4S5_;cCV%td;j}qR:Bpw* 6z謱( RG5Eˬ-. ,hD#s0WkQW*j- z痻$ H3 >.VLOMe1-$VNt$kpD2H `vZ *Ek1GxwӰ{O .q6e'c7jls9!eЁK$ Iצ䏌M$j+$+ƣ/Y,= b*7/ RÔÐ+ɓi<8+2}6٦tWĴN973Ba߉4?9%R +mf_>qOA6iX~{kl4dƊgWSXnيv\6X5Xl4V .[<`y%VE<k*<<>;mYP @3_ ɕ  s)NIFloVZ Kb1 Տ>O㍍EI5R dH ,ȳ<,VMZ B-O]NEz9 WQ78ޡ{S/Y>^0qiՅEQey.nl<ŋ$K_ @8S0e sYt Ɲ^_c*I0# <"gBs)tBKz3[(5$G'CH!<^UZR"U+)1Fhk04%Bӓ*ܛ|5y_,uu>Z+ȢD/OѪF"Ȧr ìXMC_y.4$в!2iFI116_bi(x 8Ry<|6} Hb Ht^ w h!?qՔRKd5&?x(! oGƱMo6Q Gֵ62:X=,BqҚ , RVύ: ZГ6_P<2uL7 >37 !0: {C#He-qZjo LxIW 11 'X#C9qPRJRN,_NuCy8l ډ5ՔYzUTen4^9j2]rUcb:x #=Fc DL60$4*R7+EToBtMW->+½B8OJZ7Dz&Vi&}f1iЉj2658 V[0T)sls3ބfu?UdXmj61kP Ne$ז0/>9c=]s  '/{pgp[n~C_37-]tnl̟,"C2QA0QJLK'rd̵b1V/|GYi߂C/^/XRx#x r&T08U>T"IESG/-<TUg.~φ2{KݺМol]-¼CQ4dZ[.~*}8| :LEa3Mq*O^PJ)7yO~L_ ?ۃH IԴ++ 1ր-GCL-K+>l榋ؚU{X7R!:&q<7ķTxיq)-!)h~Yu85Vi i4,: KȆi$4O5/x-jΕdiܤp\,V> j|6d cka1׷/;U9Ʃ]o_gR;!k]R3+T $XJSl[h,}LJv2Ýi(}iR7I9L2Y+t,2>&WɠR5%#$ְk@ASK Ә>k? AjTg릆$0IIۑ,aӘA5EF%@crK3Mq-U($rs hNVg-<=8g/3\:$DL>]S©2,48qI 61i|M4_NZ s&$XxmPpr[>d( _-,<75 [: "D:=mdpđDf-K鱕ڕGЦn瘲V,''&r8fw˜u@ һ-/ݟ卽߳e IPBj. \!ˉ(vWM$j=r/f/9s3f+i{]<0[j9C"Z$E1ePBDu!H) [#fb<y77sd]wucj|l,Fٔy5?'fr-%cijͥwּ8>v3`{f|q,D9gtYcAq JC[R۰pRЧ0'E,t x˯ߟa ܙqUV|ŨF[ yy!ђkOǡ#vD`gKx&h6+7h ,'̓0fdV/BwK#_TDxK@Q^_<Gldo00'}hhj^ō~:ثo30mp*֨T: TgXLaZ]dp5b`vޙ=2]kZDJ.^NAn\ɐM*W[5>4[60a>>fNq;qy=ABXjq#a;qܙ!MzG'?6dk5(#N+qp4\e<7UpB.3|#5Qg/}SC{S l3Z]]b:RAbt\XG\F [* :HԸX\hU2Gdy fSъS =>=;Q*> xQG߫iAp,2RLD̐.pgl $\U`{:LSLadҥ89m^,-+/cМ_}9cpf4{ {g<=y{b4%3Z`l-Q],LD;c0xOZN5HƂ}to=`K1NOyé|k]ym`91 wN+`Nc(o?7^$6߄Z"ۘ4C8/@^U_=t Y_Uƴ8bVLQ;џzS:݌o$"j^4q"P[`>'r"~B|rLaěYL^2?}<Ę9rȟ1*(k6l_C#o#W4 霹K+ӿ|K4X*oxMz*R@9Hֱ]G^?I ^[ɫ(Vc4NkߒǼ\F>]LA`};w[FP pm \, Gψ\,[i(a2I,!9/X89kZ0v%÷NMB/2qr@e2wd"tǓVʦ\Y+8ZhD0'{)S;4L0yov}_jl1Ly4b%BΩ ]" n_dҥ\n|@rQ@;\v[ޅBaѺ ,&8B:¨ zxKW=Y&0{ϏOvb#c 睅ʗp0ˣX]X; XA@ʖO/[aPSÙ+c87wc_F3m>x/=ofq  A bHWNPzgt/'f4a|I:`rŏ j.]2Ha)u9wߍ!pcjj6ҙ5+۶=vZb`ͷ\bayCktT8J0nUD "<9|{犐 cUKNj0,p#Ts y$ZJ8ڔ yŸQ됆zQbN [[@plARsƣ Nϛ'?}*|3 Q/MCcsۭiϐBq ș3>$͙24';A.'-ޡ O9o~%hw fY{06ٜ15XLjMq\K# O/,0-V"xL'>;|_>kٔv~yû^gص&D-TM mJ  *Z(hJmZ(iK[4vI۱׻ާwgfg~9ΝIqrvsC^'TNtOxdMƚ[h{/U+]BC JX" كbT1xZb:O@H|6s ӯ_Dp,:ډTَ80nǸ>0Ne `۫^0`AF?\Z/{O=4窪a؝<9!G :13Im@I8+zj|Q[Nqf\"Tk־/|pWǜ*¸^MJJ&7&[3\ccjs/8у80DE2jhhz l2%)3`o c4( ]4GY:#& hJm;ھ{D<0~>ܤ@+iKLLӊ4ldEu芚|Aɰk<6zƁH,u 6mۀPϪSTe[+]ז!UPz his*I(+k0 $0dU{噖 Bj[jAg!^\b3(=:6fXo.m*WYoeuXV+cL=uV`X~+-:DO+‰(azbru^Bq,$_ҨJ|eYh:m_^WH$^ t"؂?~v:&>B2/JJ.@JP;]5?&v:;:L?ΰpؙP o,) EAė֋2[pr⺷1^W nt4l.UqBZL/$~qלJ5 GǹW$m^gT,fVc(kkWj=Y ؗ8p+z`Y$sKe$Kj,Jwf4l0Vd8P[YC=ƸD{ CjXZm1GA}%B X}M4pa UJ%FX"yt8;ŦR oy` Rp+NIj^MoDkГ8UbcXt |F/~{J# elAOx5)5@ os'gN4G?D@Lk HI1h][kw2Ahs@kjA m/ R,3:K~c2 ̋*4XQVTv^c~3U}Oհ)'F>.7`a %F +ӶĞ0wlhUTaPUOf0%xh @{f#ۖ?BN ) 4P{0hڻv~c䧹Yڨ%۶LcJ:R4⊄L+PTaACjj0aL8C[z2TEh! /qne 5Ӣ*'i;_Q HK6YD a!CmEjBn૫^ DLY=H^> ~&OfJ39qVMOWUZ??6όkIOŤy+nj0$cKœ_?~[ɐHV[w楌c@D`}kox_v}جv0*rcl+ wc%vdaj_cj}SRb*za,LW 8m4HȘ*4,mMp‡CHfY AI4XT3xac$Zw_ գ; Ӑn_t}};Fksv}q7D s)P"{W8N iЉdvgv8YGA"ҀFs(I{g\hQgm2dmê[bSp1LA tBJXZJ5`> krB 6S:~{T&!}ɆջptKHf^2XF>7qvW*n nGH\ 6OD./Ib>MP p-`#m/^f%l@bbx])HVt◄6‡v}d\c?Q'֏?ِMAKylKJ&aV˵J3\0צdⵑx87kS9::ѝۘK^\ +k"X//34M2#RI˝aFҐxl&ʞPډht@-5&K =xy̳pCqdXlV}^;ذtFͰ#.FItԥytjPh6ֳNVDqPErw(X'7!p +tmQ|idI()h;Uh@Xhybbya*܋kô[>U?=p=kQU}'?PgK)ߏ^ >P8Uc=N52YX!+M(YJ.M|7nO4{'QZn;*%TXs"eGu8[T`_0چF$ MϺ۰R`C^~&|aiÜԜq5^Dqrz2}rmQfo[U.}s{˜>r%"PY{ՍJ%EM;Щ۞/"nl+L\V>09IZ0b`AOm4N"ׅRB+o1h>-=zjM^` z:8?$Jua0߇D>ËG"JSYfRnҼڽT<`r}qcrۿw^l,o|XTF OyrCv ta1" vluLгdliZbʂ􅺀݆xKMz@@.ז VuCBXb'wL&)R'**FIYK7u%MIj ]{xd"7':iH\&!땲Sȯ8U,{,J;A%.. G' gXIX-1ЁAiwM] ߚy5zkjSONal1̩>,3'!jGsGN,|'77W91'U>7E|)HyjxEj3'*Nߛy]1/ 8-|}*34T,zA rtOD`ڭvp0X6UYSǯ;@Ox{ 0HfQ͖_P3NY `El(f^ix?UKhX^Tպ'd%hD9*v*5˵]sW:2/a-bĒlSN2m^:9 ax,(Q/8t1/ A]T/=Ml6 +z-9NX`\T1mhDĩ>w7ٿⷎ'BP{vk]U()?onZ1~pM])v PpPl/ćKNpb/[T<ƃ9MZd'k[/]Mj?A)6/1ulaF3yĒOTU'׭͔_pQuفBӃ@$7(V.%B;Rtk٘R?M|yx썊ciZX#*ʌ-4tYD; gy`v +O$#PR- 3~U(ST6AKO^̣vh?6TAL-H7pKp(,0# e%MRRSTK h +Nv_ .86qB8O, ӥ#cG3Â~ CsrS 5IVU/R׷To:9ͷ3C SCC}xc(2qԝtxWx ,đeD!W 3*?cj?6(gfH zCܟ :k#HR7,ێ i?K E\ȖxA|` ^(+90[^=+=wx/ږDlN}yJ H9Ö_̸U&lg>^d=Wˈ>+sgz:2DXlAK%0~7lE+ԖUZuEek+ijwbZ (`7"m8NWYp܊8[D~H@پeԭ 8f̀}G՚.η8t֞{&~>އ0G]ɘ6kσhq[R&ɈG=$I/P1PR8U$*Ӷ"_[)5)|ꫨ&K*8ezF7t\c5)qhq -ˆ@Vcvs٣,r>ФƟ|)w[] Y|/6N4C8qf4xdt;Qu1(  q~R@aқ?Tmxp+GiEz,NPʔ@uhWF,[z5z^0DR] nBm 'a~US|Ǘ/nGg)u[W¼u9pfy%n%^C)Dc4jWKRoN۟pYÒla"WE3) ^$D@B9jÒ!3H`lx)}=[.Il ǫ#ssHoXÏK[]B gy<\C{z!H<V}۝KrpȽZ!#0?,JVvG]-ȟRJP]cց!aObbӋ8((BX8Nz;p;d,JhFk_-s){w:tXՎ_QNm8P .#ۉ;8h%)lX[>,E߀ .ywa{3ءIts֔ I$zh-dd$NQQ#|2YFa%d:lZUn%_iwq^)uU-)#̖T" Y[Qch%j1`0 l^4DPS6`WG~R  kmXZrsR_]O@z*dh=˘q>W/Y8xl!6MJjhB9ؕJfpYۗZΥ -ElxGՔ th}Oo#TisVD2MY~> ^. iKGE A8Bі3䥝F z @jҊQ]N ]ve4Â]Rf/4ꪙINMҖzk6#@U{R5Sj ǯS~{2Mƫ%7l k ckI8?hIENDB`emacs-dashboard-1.8.0/dashboard-widgets.el000066400000000000000000001672131446027744200204760ustar00rootroot00000000000000;;; dashboard-widgets.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*- ;; Copyright (c) 2016-2023 emacs-dashboard maintainers ;; ;; Author : Rakan Al-Hneiti ;; Maintainer : Jesús Martínez ;; Shen, Jen-Chieh ;; URL : https://github.com/emacs-dashboard/emacs-dashboard ;; ;; This file is not part of GNU Emacs. ;; ;;; License: GPLv3 ;; ;; Created: October 05, 2016 ;; Package-Version: 1.8.0 ;; Keywords: startup, screen, tools, dashboard ;; Package-Requires: ((emacs "26.1")) ;;; Commentary: ;; An extensible Emacs dashboard, with sections for ;; bookmarks, projects (projectile or project.el), org-agenda and more. ;;; Code: (require 'cl-lib) (require 'image) (require 'subr-x) ;; Compiler pacifier (declare-function all-the-icons-icon-for-dir "ext:all-the-icons.el") (declare-function all-the-icons-icon-for-file "ext:all-the-icons.el") (declare-function all-the-icons-fileicon "ext:data-fileicons.el") (declare-function all-the-icons-octicon "ext:data-octicons.el") (declare-function nerd-icons-icon-for-dir "ext:nerd-icons.el") (declare-function nerd-icons-icon-for-file "ext:nerd-icons.el") (declare-function nerd-icons-sucicon "ext:nerd-icons.el") (declare-function nerd-icons-octicon "ext:nerd-icons.el") (declare-function nerd-icons-codicon "ext:nerd-icons.el") (declare-function bookmark-get-filename "ext:bookmark.el") (declare-function bookmark-all-names "ext:bookmark.el") (declare-function calendar-date-compare "ext:calendar.el") (declare-function projectile-cleanup-known-projects "ext:projectile.el") (declare-function projectile-load-known-projects "ext:projectile.el") (declare-function projectile-mode "ext:projectile.el") (declare-function projectile-relevant-known-projects "ext:projectile.el") ;;; project.el in Emacs 26 does not contain this function (declare-function project-known-project-roots "ext:project.el" nil t) (declare-function project-forget-zombie-projects "ext:project.el" nil t) (declare-function org-agenda-format-item "ext:org-agenda.el") (declare-function org-compile-prefix-format "ext:org-agenda.el") (declare-function org-entry-get "ext:org.el") (declare-function org-entry-is-done-p "ext:org.el") (declare-function org-entry-is-todo-p "ext:org.el") (declare-function org-get-category "ext:org.el") (declare-function org-get-deadline-time "ext:org.el") (declare-function org-get-heading "ext:org.el") (declare-function org-get-priority "ext:org.el") (declare-function org-get-scheduled-time "ext:org.el") (declare-function org-get-tags "ext:org.el") (declare-function org-get-todo-face "ext:org.el") (declare-function org-get-todo-state "ext:org.el") (declare-function org-in-archived-heading-p "ext:org.el") (declare-function org-map-entries "ext:org.el") (declare-function org-outline-level "ext:org.el") (declare-function org-release-buffers "ext:org.el") (declare-function org-time-string-to-time "ext:org.el") (declare-function org-today "ext:org.el") (declare-function recentf-cleanup "ext:recentf.el") (defalias 'org-time-less-p 'time-less-p) (defvar org-level-faces) (defvar org-agenda-new-buffers) (defvar org-agenda-prefix-format) (defvar org-agenda-todo-keyword-format) (defvar org-todo-keywords-1) (defvar all-the-icons-dir-icon-alist) (defvar package-activated-list) (defvar elpaca-after-init-time) (declare-function string-pixel-width "subr-x.el") ; TODO: remove this after 29.1 (declare-function shr-string-pixel-width "shr.el") ; TODO: remove this after 29.1 (defcustom dashboard-page-separator "\n\n" "Separator to use between the different pages." :type 'string :group 'dashboard) (defcustom dashboard-image-banner-max-height 0 "Maximum height of banner image. This setting applies only if Emacs supports image transforms or compiled with Imagemagick support. When value is non-zero the image banner will be resized to the specified height in pixels, with aspect ratio preserved." :type 'integer :group 'dashboard) (defcustom dashboard-image-banner-max-width 0 "Maximum width of banner image. This setting applies if Emacs supports image transforms or compiled with Imagemagick support. When value is non-zero the image banner will be resized to the specified width in pixels, with aspect ratio preserved." :type 'integer :group 'dashboard) (defcustom dashboard-set-heading-icons nil "When non nil, heading sections will have icons." :type 'boolean :group 'dashboard) (defcustom dashboard-set-file-icons nil "When non nil, file lists will have icons." :type 'boolean :group 'dashboard) (defcustom dashboard-set-navigator nil "When non nil, a navigator will be displayed under the banner." :type 'boolean :group 'dashboard) (defcustom dashboard-set-init-info t "When non nil, init info will be displayed under the banner." :type 'boolean :group 'dashboard) (defcustom dashboard-set-footer t "When non nil, a footer will be displayed at the bottom." :type 'boolean :group 'dashboard) (defcustom dashboard-footer-messages '("The one true editor, Emacs!" "Who the hell uses VIM anyway? Go Evil!" "Free as free speech, free as free Beer" "Happy coding!" "Vi Vi Vi, the editor of the beast" "Welcome to the church of Emacs" "While any text editor can save your files, only Emacs can save your soul" "I showed you my source code, pls respond") "A list of messages, one of which dashboard chooses to display." :type 'list :group 'dashboard) (defcustom dashboard-icon-type (and (or dashboard-set-heading-icons dashboard-set-file-icons) (or (require 'nerd-icons nil t) (require 'all-the-icons nil t))) "Icon type used for dashboard. The value can be one of: `all-the-icons', `nerd-icons'." :type 'symbol :group 'dashboard :set (lambda (k v) (pcase v ('all-the-icons (unless (require 'all-the-icons nil t) (setq v nil))) ('nerd-icons (unless (require 'nerd-icons nil t) (setq v nil)))) (set k v))) (defcustom dashboard-heading-icons (pcase dashboard-icon-type ('all-the-icons '((recents . "history") (bookmarks . "bookmark") (agenda . "calendar") (projects . "rocket") (registers . "database"))) ('nerd-icons '((recents . "nf-oct-history") (bookmarks . "nf-oct-bookmark") (agenda . "nf-oct-calendar") (projects . "nf-oct-rocket") (registers . "nf-oct-database")))) "Association list for the icons of the heading sections. Will be of the form `(list-type . icon-name-string)`. If nil it is disabled. Possible values for list-type are: `recents' `bookmarks' `projects' `agenda' `registers'" :type '(repeat (alist :key-type symbol :value-type string)) :group 'dashboard) (defcustom dashboard-heading-icon-height 1.2 "The height of the heading icon." :type 'float :group 'dashboard) (defcustom dashboard-heading-icon-v-adjust 0.0 "The v-adjust of the heading icon." :type 'float :group 'dashboard) (defcustom dashboard-agenda-item-icon (pcase dashboard-icon-type ('all-the-icons (all-the-icons-octicon "primitive-dot" :height 1.0 :v-adjust 0.01)) ('nerd-icons (nerd-icons-octicon "nf-oct-dot_fill" :height 1.0 :v-adjust 0.01))) "Agenda item icon." :type 'string :group 'dashboard) (defcustom dashboard-remote-path-icon (pcase dashboard-icon-type ('all-the-icons (all-the-icons-octicon "radio-tower" :height 1.0 :v-adjust 0.01)) ('nerd-icons (nerd-icons-codicon "nf-cod-radio_tower" :height 1.0 :v-adjust 0.01))) "Remote path icon." :type 'string :group 'dashboard) (defcustom dashboard-show-shortcuts t "Whether to show shortcut keys for each section." :type 'boolean :group 'dashboard) (defconst dashboard-banners-directory (concat (file-name-directory (locate-library "dashboard")) "banners/") "Default banner directory.") (defconst dashboard-banner-official-png (concat dashboard-banners-directory "emacs.png") "Emacs banner image.") (defconst dashboard-banner-logo-png (concat dashboard-banners-directory "logo.png") "Emacs banner image.") (defcustom dashboard-banner-logo-title "Welcome to Emacs!" "Specify the startup banner." :type 'string :group 'dashboard) (defcustom dashboard-banner-ascii "EMACS" "String to be shown in place of the startup banner if `dashboard-startup-banner' is set to `ascii'." :type 'string :group 'dashboard) (defcustom dashboard-navigator-buttons nil "Specify the navigator buttons. The format is: `icon title help action face prefix suffix`. Example: `((\"☆\" \"Star\" \"Show stars\" (lambda (&rest _) (show-stars)) warning \"[\" \"]\"))" :type '(repeat (repeat (list string string string function symbol string string))) :group 'dashboard) (defcustom dashboard-init-info (lambda () (let ((package-count 0) (time (emacs-init-time))) (when (bound-and-true-p package-alist) (setq package-count (length package-activated-list))) (when (boundp 'straight--profile-cache) (setq package-count (+ (hash-table-count straight--profile-cache) package-count))) (when (fboundp 'elpaca--queued) (setq time (format "%f seconds" (float-time (time-subtract elpaca-after-init-time before-init-time)))) (setq package-count (length (elpaca--queued)))) (if (zerop package-count) (format "Emacs started in %s" time) (format "%d packages loaded in %s" package-count time)))) "Init info with packages loaded and init time." :type '(function string) :group 'dashboard) (defcustom dashboard-footer (nth (random (1- (1+ (length dashboard-footer-messages)))) dashboard-footer-messages) "A footer with some short message." :type 'string :group 'dashboard) (defcustom dashboard-display-icons-p #'display-graphic-p "Predicate to determine whether dashboard should show icons. Can be nil to not show icons and any truthy value to show them. When set to a function the result of the function will be interpreted as the predicate value." :type '(choice (function :tag "Predicate function") (boolean :tag "Predicate value")) :group 'dashboard) (defun dashboard-replace-displayable (str &optional rep) "Replace non-displayable character from STR. Optional argument REP is the replacement string of non-displayable character." (if (stringp str) (let ((rep (or rep "")) (results (list))) (dolist (string (split-string str "")) (let* ((char (string-to-char string)) (string (if (char-displayable-p char) string rep))) (push string results))) (string-join (reverse results))) "")) (defun dashboard-display-icons-p () "Assert whether to show icons based on the `dashboard-display-icons-p' variable." (if (functionp dashboard-display-icons-p) (funcall dashboard-display-icons-p) dashboard-display-icons-p)) (defun dashboard-icon-for-dir (dir &rest args) "Get the formatted icon for DIR. ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties." (dashboard-replace-displayable (pcase dashboard-icon-type ('all-the-icons (apply #'all-the-icons-icon-for-dir dir args)) ('nerd-icons (apply #'nerd-icons-icon-for-dir dir args))))) (defun dashboard-icon-for-file (file &rest args) "Get the formatted icon for FILE. ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties." (dashboard-replace-displayable (pcase dashboard-icon-type ('all-the-icons (apply #'all-the-icons-icon-for-file file args)) ('nerd-icons (apply #'nerd-icons-icon-for-file file args))))) (defun dashboard-octicon (name &rest args) "Get the formatted octicon. ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties." (dashboard-replace-displayable (pcase dashboard-icon-type ('all-the-icons (apply #'all-the-icons-octicon name args)) ('nerd-icons (apply #'nerd-icons-octicon name args))))) (defcustom dashboard-footer-icon (if (dashboard-display-icons-p) (pcase dashboard-icon-type ('all-the-icons (all-the-icons-fileicon "emacs" :height 1.1 :v-adjust -0.05 :face 'font-lock-keyword-face)) ('nerd-icons (nerd-icons-sucicon "nf-custom-emacs" :height 1.1 :v-adjust -0.05 :face 'font-lock-keyword-face))) (propertize ">" 'face 'dashboard-footer)) "Footer's icon." :type 'string :group 'dashboard) (defcustom dashboard-startup-banner 'official "Specify the startup banner. Default value is `official', it displays the Emacs logo. `logo' displays Emacs alternative logo. If set to `ascii', the value of `dashboard-banner-ascii' will be used as the banner. An integer value is the index of text banner. A string value must be a path to a .PNG or .TXT file. If the value is nil then no banner is displayed." :type '(choice (const :tag "no banner" nil) (const :tag "offical" official) (const :tag "logo" logo) (const :tag "ascii" ascii) (integer :tag "index of a text banner") (string :tag "a path to an image or text banner") (cons :tag "an image and text banner" (string :tag "image banner path") (string :tag "text banner path"))) :group 'dashboard) (defcustom dashboard-item-generators '((recents . dashboard-insert-recents) (bookmarks . dashboard-insert-bookmarks) (projects . dashboard-insert-projects) (agenda . dashboard-insert-agenda) (registers . dashboard-insert-registers)) "Association list of items to how to generate in the startup buffer. Will be of the form `(list-type . list-function)'. Possible values for list-type are: `recents', `bookmarks', `projects', `agenda' ,`registers'." :type '(repeat (alist :key-type symbol :value-type function)) :group 'dashboard) (defcustom dashboard-projects-backend 'projectile "The package that supplies the list of recent projects. With the value `projectile', the projects widget uses the package projectile (available in MELPA). With the value `project-el', the widget uses the package project (available in GNU ELPA). To activate the projects widget, add e.g. `(projects . 10)' to `dashboard-items' after making sure the necessary package is installed." :type '(choice (const :tag "Use projectile" projectile) (const :tag "Use project.el" project-el)) :group 'dashboard) (defcustom dashboard-items '((recents . 5) (bookmarks . 5) (agenda . 5)) "Association list of items to show in the startup buffer. Will be of the form `(list-type . list-size)'. If nil it is disabled. Possible values for list-type are: `recents' `bookmarks' `projects' `agenda' `registers'." :type '(repeat (alist :key-type symbol :value-type integer)) :group 'dashboard) (defcustom dashboard-item-shortcuts '((recents . "r") (bookmarks . "m") (projects . "p") (agenda . "a") (registers . "e")) "Association list of items and their corresponding shortcuts. Will be of the form `(list-type . keys)' as understood by `(kbd keys)'. If nil, shortcuts are disabled. If an entry's value is nil, that item's shortcut is disbaled. See `dashboard-items' for possible values of list-type.'" :type '(repeat (alist :key-type symbol :value-type string)) :group 'dashboard) (defcustom dashboard-item-names nil "Association list of item heading names. When an item is nil or not present, the default name is used. Will be of the form `(default-name . new-name)'." :type '(alist :key-type string :value-type string) :options '("Recent Files:" "Bookmarks:" "Agenda for today:" "Agenda for the coming week:" "Registers:" "Projects:") :group 'dashboard) (defcustom dashboard-items-default-length 20 "Length used for startup lists with otherwise unspecified bounds. Set to nil for unbounded." :type 'integer :group 'dashboard) (defcustom dashboard-path-style nil "Style to display path." :type '(choice (const :tag "No specify" nil) (const :tag "Truncate the beginning part of the path" truncate-beginning) (const :tag "Truncate the middle part of the path" truncate-middle) (const :tag "Truncate the end part of the path" truncate-end)) :group 'dashboard) (defcustom dashboard-path-max-length 70 "Maximum length for path to display." :type 'integer :group 'dashboard) (defcustom dashboard-path-shorten-string "..." "String the that displays in the center of the path." :type 'string :group 'dashboard) (defvar recentf-list nil) (defvar dashboard-buffer-name) ;; ;; Faces ;; (defface dashboard-text-banner '((t (:inherit font-lock-keyword-face))) "Face used for text banners." :group 'dashboard) (defface dashboard-banner-logo-title '((t :inherit default)) "Face used for the banner title." :group 'dashboard) (defface dashboard-navigator '((t (:inherit font-lock-keyword-face))) "Face used for the navigator." :group 'dashboard) (defface dashboard-heading '((t (:inherit font-lock-keyword-face))) "Face used for widget headings." :group 'dashboard) (defface dashboard-items-face '((t (:inherit widget-button))) "Face used for items." :group 'dashboard) (defface dashboard-no-items-face '((t (:inherit widget-button))) "Face used for no items." :group 'dashboard) (defface dashboard-footer '((t (:inherit font-lock-doc-face))) "Face used for widget headings." :group 'dashboard) (define-obsolete-face-alias 'dashboard-text-banner-face 'dashboard-text-banner "1.2.6") (define-obsolete-face-alias 'dashboard-banner-logo-title-face 'dashboard-banner-logo-title "1.2.6") (define-obsolete-face-alias 'dashboard-heading-face 'dashboard-heading "1.2.6") ;; ;; Util ;; (defmacro dashboard-mute-apply (&rest body) "Execute BODY without message." (declare (indent 0) (debug t)) `(let (message-log-max) (with-temp-message (or (current-message) nil) (let ((inhibit-message t)) ,@body)))) (defun dashboard-funcall-fboundp (fnc &rest args) "Call FNC with ARGS if exists." (when (fboundp fnc) (if args (funcall fnc args) (funcall fnc)))) ;; TODO: Use function `string-pixel-width' after 29.1 (defun dashboard-string-pixel-width (str) "Return the width of STR in pixels." (if (fboundp #'string-pixel-width) (string-pixel-width str) (require 'shr) (shr-string-pixel-width str))) (defun dashboard-str-len (str) "Calculate STR in pixel width." (let ((width (frame-char-width)) (len (dashboard-string-pixel-width str))) (+ (/ len width) (if (zerop (% len width)) 0 1)))) ; add one if exceeed ;; ;; Generic widget helpers ;; (defun dashboard-subseq (seq end) "Return the subsequence of SEQ from 0 to END." (let ((len (length seq))) (butlast seq (- len (min len end))))) (defun dashboard-get-shortcut-name (item) "Get the shortcut name to be used for ITEM." (let ((elem (rassoc item dashboard-item-shortcuts))) (and elem (car elem)))) (defun dashboard-get-shortcut (item) "Get the shortcut to be used for ITEM." (let ((elem (assq item dashboard-item-shortcuts))) (and elem (cdr elem)))) (defmacro dashboard-insert-shortcut (shortcut-id shortcut-char search-label &optional no-next-line) "Insert a shortcut SHORTCUT-CHAR for a given SEARCH-LABEL. Optionally, provide NO-NEXT-LINE to move the cursor forward a line." (let* (;; Ensure punctuation and upper case in search string is not ;; used to construct the `defun' (name (downcase (replace-regexp-in-string "[[:punct:]]+" "" (format "%s" search-label)))) ;; remove symbol quote (sym (intern (replace-regexp-in-string "'" "" (format "dashboard-jump-to-%s" shortcut-id))))) `(progn (eval-when-compile (defvar dashboard-mode-map)) (defun ,sym nil ,(concat "Jump to " name ". This code is dynamically generated in `dashboard-insert-shortcut'.") (interactive) (unless (search-forward ,search-label (point-max) t) (search-backward ,search-label (point-min) t)) ,@(unless no-next-line '((forward-line 1))) (back-to-indentation)) (eval-after-load 'dashboard (define-key dashboard-mode-map ,shortcut-char ',sym))))) (defun dashboard-append (msg &optional _messagebuf) "Append MSG to dashboard buffer. If MESSAGEBUF is not nil then MSG is also written in message buffer." (with-current-buffer (get-buffer-create dashboard-buffer-name) (goto-char (point-max)) (let ((inhibit-read-only t)) (insert msg)))) (defun dashboard-modify-heading-icons (alist) "Append ALIST items to `dashboard-heading-icons' to modify icons." (dolist (icon alist) (add-to-list 'dashboard-heading-icons icon))) (defun dashboard-insert-page-break () "Insert a page break line in dashboard buffer." (dashboard-append dashboard-page-separator)) (defun dashboard-insert-heading (heading &optional shortcut icon) "Insert a widget HEADING in dashboard buffer, adding SHORTCUT, ICON if provided." (when (and (dashboard-display-icons-p) dashboard-set-heading-icons) (let ((args `( :height ,dashboard-heading-icon-height :v-adjust ,dashboard-heading-icon-v-adjust :face dashboard-heading))) (insert (pcase heading ("Recent Files:" (apply #'dashboard-octicon (cdr (assoc 'recents dashboard-heading-icons)) args)) ("Bookmarks:" (apply #'dashboard-octicon (cdr (assoc 'bookmarks dashboard-heading-icons)) args)) ((or "Agenda for today:" "Agenda for the coming week:") (apply #'dashboard-octicon (cdr (assoc 'agenda dashboard-heading-icons)) args)) ("Registers:" (apply #'dashboard-octicon (cdr (assoc 'registers dashboard-heading-icons)) args)) ("Projects:" (apply #'dashboard-octicon (cdr (assoc 'projects dashboard-heading-icons)) args)) ("List Directories:" (apply #'dashboard-octicon (cdr (assoc 'ls-directories dashboard-heading-icons)) args)) ("List Files:" (apply #'dashboard-octicon (cdr (assoc 'ls-files dashboard-heading-icons)) args)) (_ (if (null icon) " " icon)))) (insert " "))) (insert (propertize heading 'face 'dashboard-heading)) ;; Turn the inserted heading into an overlay, so that we may freely change ;; its name without breaking any of the functions that expect the default name. ;; If there isn't a suitable entry in `dashboard-item-names', ;; we fallback to using HEADING. In that case we still want it to be an ;; overlay to maintain consistent behavior (such as the point movement) ;; between modified and default headings. (let ((ov (make-overlay (- (point) (length heading)) (point) nil t))) (overlay-put ov 'display (or (cdr (assoc heading dashboard-item-names)) heading)) (overlay-put ov 'face 'dashboard-heading)) (when shortcut (insert (format " (%s)" shortcut)))) (defun dashboard-center-text (start end) "Center the text between START and END." (save-excursion (goto-char start) (let ((width 0)) (while (< (point) end) (let* ((line-str (buffer-substring (line-beginning-position) (line-end-position))) (line-length (dashboard-str-len line-str))) (setq width (max width line-length))) (forward-line 1)) (let ((prefix (propertize " " 'display `(space . (:align-to (- center ,(/ width 2))))))) (add-text-properties start end `(line-prefix ,prefix indent-prefix ,prefix)))))) (defun dashboard-insert-center (&rest strings) "Insert STRINGS in the center of the buffer." (let ((start (point))) (apply #'insert strings) (dashboard-center-text start (point)))) ;; ;; BANNER ;; (defun dashboard-get-banner-path (index) "Return the full path to banner with index INDEX." (concat dashboard-banners-directory (format "%d.txt" index))) (defun dashboard--image-supported-p (img) "Return non-nil if IMG exists and is a supported image type." ;; In Emacs 29.1 we could use `image-supported-file-p'. However: ;; - We need to support Emacs 26. ;; - That function will only look at filenames, this one will inspect the file data itself. (and (file-exists-p img) (ignore-errors (image-type-available-p (image-type img))))) (defun dashboard-choose-banner () "Return a plist specifying the chosen banner based on `dashboard-startup-banner'." (pcase dashboard-startup-banner ('nil nil) ('official (append (when (image-type-available-p 'png) (list :image dashboard-banner-official-png)) (list :text (dashboard-get-banner-path 1)))) ('logo (append (when (image-type-available-p 'png) (list :image dashboard-banner-logo-png)) (list :text (dashboard-get-banner-path 1)))) ('ascii (append (list :text dashboard-banner-ascii))) ((pred integerp) (list :text (dashboard-get-banner-path dashboard-startup-banner))) ((pred stringp) (pcase dashboard-startup-banner ((pred (lambda (f) (not (file-exists-p f)))) (message "could not find banner %s, use default instead" dashboard-startup-banner) (list :text (dashboard-get-banner-path 1))) ((pred (string-suffix-p ".txt")) (list :text (if (file-exists-p dashboard-startup-banner) dashboard-startup-banner (message "could not find banner %s, use default instead" dashboard-startup-banner) (dashboard-get-banner-path 1)))) ((pred dashboard--image-supported-p) (list :image dashboard-startup-banner :text (dashboard-get-banner-path 1))) (_ (message "unsupported file type %s" (file-name-nondirectory dashboard-startup-banner)) (list :text (dashboard-get-banner-path 1))))) (`(,img . ,txt) (list :image (if (dashboard--image-supported-p img) img (message "could not find banner %s, use default instead" img) dashboard-banner-official-png) :text (if (and (file-exists-p txt) (string-suffix-p ".txt" txt)) txt (message "could not find banner %s, use default instead" txt) (dashboard-get-banner-path 1)))) (_ (message "unsupported banner config %s" dashboard-startup-banner)))) (defun dashboard--type-is-gif-p (image-path) "Return if image is a gif. String -> bool. Argument IMAGE-PATH path to the image." (eq 'gif (image-type image-path))) (defun dashboard-insert-banner () "Insert the banner at the top of the dashboard." (goto-char (point-max)) (when-let (banner (dashboard-choose-banner)) (insert "\n") (let ((start (point)) buffer-read-only text-width image-spec) (insert "\n") ;; If specified, insert a text banner. (when-let (txt (plist-get banner :text)) (if (eq dashboard-startup-banner 'ascii) (save-excursion (insert txt)) (insert-file-contents txt)) (put-text-property (point) (point-max) 'face 'dashboard-text-banner) (setq text-width 0) (while (not (eobp)) (let ((line-length (- (line-end-position) (line-beginning-position)))) (if (< text-width line-length) (setq text-width line-length))) (forward-line 1))) ;; If specified, insert an image banner. When displayed in a graphical frame, this will ;; replace the text banner. (when-let (img (plist-get banner :image)) (let ((size-props (append (when (> dashboard-image-banner-max-width 0) (list :max-width dashboard-image-banner-max-width)) (when (> dashboard-image-banner-max-height 0) (list :max-height dashboard-image-banner-max-height))))) (setq image-spec (cond ((dashboard--type-is-gif-p img) (create-image img)) ((image-type-available-p 'imagemagick) (apply 'create-image img 'imagemagick nil size-props)) (t (apply 'create-image img nil nil (when (and (fboundp 'image-transforms-p) (memq 'scale (funcall 'image-transforms-p))) size-props)))))) (add-text-properties start (point) `(display ,image-spec)) (when (dashboard--type-is-gif-p img) (image-animate image-spec 0 t))) ;; Finally, center the banner (if any). (when-let* ((text-align-spec `(space . (:align-to (- center ,(/ text-width 2))))) (image-align-spec `(space . (:align-to (- center (0.5 . ,image-spec))))) (prop (cond ;; Both an image & text banner. ((and image-spec text-width) ;; The quoting is intentional. This is a conditional display spec that will ;; align the banner at redisplay time. `((when (display-graphic-p) . ,image-align-spec) (when (not (display-graphic-p)) . ,text-align-spec))) ;; One or the other. (text-width text-align-spec) (image-spec image-align-spec) ;; No banner. (t nil))) (prefix (propertize " " 'display prop))) (add-text-properties start (point) `(line-prefix ,prefix wrap-prefix ,prefix))) (insert "\n\n") (add-text-properties start (point) '(cursor-intangible t inhibit-isearch t)))) (when dashboard-banner-logo-title (dashboard-insert-center (propertize dashboard-banner-logo-title 'face 'dashboard-banner-logo-title)) (insert "\n\n")) (dashboard-insert-navigator) (dashboard-insert-init-info)) ;; ;; INIT INFO ;; (defun dashboard-insert-init-info () "Insert init info when `dashboard-set-init-info' is t." (when dashboard-set-init-info (let ((init-info (if (functionp dashboard-init-info) (funcall dashboard-init-info) dashboard-init-info))) (dashboard-insert-center (propertize init-info 'face 'font-lock-comment-face))))) (defun dashboard-insert-navigator () "Insert Navigator of the dashboard." (when (and dashboard-set-navigator dashboard-navigator-buttons) (dolist (line dashboard-navigator-buttons) (dolist (btn line) (let* ((icon (car btn)) (title (cadr btn)) (help (or (cadr (cdr btn)) "")) (action (or (cadr (cddr btn)) #'ignore)) (face (or (cadr (cddr (cdr btn))) 'dashboard-navigator)) (prefix (or (cadr (cddr (cddr btn))) (propertize "[" 'face face))) (suffix (or (cadr (cddr (cddr (cdr btn)))) (propertize "]" 'face face)))) (widget-create 'item :tag (concat (when icon (propertize icon 'face (let ((prop-face (get-text-property 0 'face icon))) (if prop-face `(:inherit ,prop-face :inherit ,face) `(:inherit ,face))))) (when (and icon title (not (string-equal icon "")) (not (string-equal title ""))) (propertize " " 'face 'variable-pitch)) (when title (propertize title 'face face))) :help-echo help :action action :button-face 'dashboard-items-face :mouse-face 'highlight :button-prefix prefix :button-suffix suffix :format "%[%t%]") (insert " "))) (dashboard-center-text (line-beginning-position) (line-end-position)) (insert "\n")) (insert "\n"))) (defmacro dashboard-insert-section (section-name list list-size shortcut-id shortcut-char action &rest widget-params) "Add a section with SECTION-NAME and LIST of LIST-SIZE items to the dashboard. SHORTCUT-CHAR is the keyboard shortcut used to access the section. ACTION is theaction taken when the user activates the widget button. WIDGET-PARAMS are passed to the \"widget-create\" function." `(progn (dashboard-insert-heading ,section-name (if (and ,list ,shortcut-char dashboard-show-shortcuts) ,shortcut-char)) (if ,list (when (and (dashboard-insert-section-list ,section-name (dashboard-subseq ,list ,list-size) ,action ,@widget-params) ,shortcut-id ,shortcut-char) (dashboard-insert-shortcut ,shortcut-id ,shortcut-char ,section-name)) (insert (propertize "\n --- No items ---" 'face 'dashboard-no-items-face))))) ;; ;; Section list ;; (defmacro dashboard-insert-section-list (section-name list action &rest rest) "Insert into SECTION-NAME a LIST of items, expanding ACTION and passing REST to widget creation." `(when (car ,list) (mapc (lambda (el) (let ((tag ,@rest)) (insert "\n ") (when (and (dashboard-display-icons-p) dashboard-set-file-icons) (let* ((path (car (last (split-string ,@rest " - ")))) (icon (if (and (not (file-remote-p path)) (file-directory-p path)) (dashboard-icon-for-dir path nil "") (cond ((or (string-equal ,section-name "Agenda for today:") (string-equal ,section-name "Agenda for the coming week:")) dashboard-agenda-item-icon) ((file-remote-p path) dashboard-remote-path-icon) (t (dashboard-icon-for-file (file-name-nondirectory path) :v-adjust -0.05)))))) (setq tag (concat icon " " ,@rest)))) (widget-create 'item :tag tag :action ,action :button-face 'dashboard-items-face :mouse-face 'highlight :button-prefix "" :button-suffix "" :format "%[%t%]"))) ,list))) ;; Footer (defun dashboard-random-footer () "Return a random footer from `dashboard-footer-messages'." (nth (random (length dashboard-footer-messages)) dashboard-footer-messages)) (defun dashboard-insert-footer () "Insert footer of dashboard." (when-let ((footer (and dashboard-set-footer (dashboard-random-footer)))) (insert "\n") (dashboard-insert-center (dashboard-replace-displayable dashboard-footer-icon) (if (and (stringp dashboard-footer-icon) (not (string-empty-p dashboard-footer-icon))) " " "") (propertize footer 'face 'dashboard-footer) "\n"))) ;; ;; Truncate ;; (defcustom dashboard-shorten-by-window-width nil "Shorten path by window edges." :type 'boolean :group 'dashboard) (defcustom dashboard-shorten-path-offset 0 "Shorten path offset on the edges." :type 'integer :group 'dashboard) (defun dashboard-f-filename (path) "Return file name from PATH." (file-name-nondirectory path)) (defun dashboard-f-base (path) "Return directory name from PATH." (file-name-nondirectory (directory-file-name (file-name-directory path)))) (defun dashboard-shorten-path-beginning (path) "Shorten PATH from beginning if exceeding maximum length." (let* ((len-path (length path)) (slen-path (dashboard-str-len path)) (len-rep (dashboard-str-len dashboard-path-shorten-string)) (len-total (- dashboard-path-max-length len-rep)) front) (if (<= slen-path dashboard-path-max-length) path (setq front (ignore-errors (substring path (- slen-path len-total) len-path))) (if front (concat dashboard-path-shorten-string front) "")))) (defun dashboard-shorten-path-middle (path) "Shorten PATH from middle if exceeding maximum length." (let* ((len-path (length path)) (slen-path (dashboard-str-len path)) (len-rep (dashboard-str-len dashboard-path-shorten-string)) (len-total (- dashboard-path-max-length len-rep)) (center (/ len-total 2)) (end-back center) (start-front (- slen-path center)) back front) (if (<= slen-path dashboard-path-max-length) path (setq back (substring path 0 end-back) front (ignore-errors (substring path start-front len-path))) (if front (concat back dashboard-path-shorten-string front) "")))) (defun dashboard-shorten-path-end (path) "Shorten PATH from end if exceeding maximum length." (let* ((len-path (length path)) (slen-path (dashboard-str-len path)) (len-rep (dashboard-str-len dashboard-path-shorten-string)) (diff (- slen-path len-path)) (len-total (- dashboard-path-max-length len-rep diff)) back) (if (<= slen-path dashboard-path-max-length) path (setq back (ignore-errors (substring path 0 len-total))) (if (and back (< 0 dashboard-path-max-length)) (concat back dashboard-path-shorten-string) "")))) (defun dashboard--get-base-length (path type) "Return the length of the base from the PATH by TYPE." (let* ((is-dir (file-directory-p path)) (base (if is-dir (dashboard-f-base path) (dashboard-f-filename path))) (option (cl-case type (recents 'dashboard-recentf-show-base) (bookmarks 'dashboard-bookmarks-show-base) (projects 'dashboard-projects-show-base))) (option-val (symbol-value option)) base-len) (cl-case option-val (`align (setq base-len (dashboard--align-length-by-type type))) (`nil (setq base-len 0)) (t (setq base-len (length base)))) base-len)) (defun dashboard-shorten-path (path type) "Shorten the PATH by TYPE." (setq path (abbreviate-file-name path)) (let ((dashboard-path-max-length (if (and dashboard-path-style dashboard-shorten-by-window-width) (- (window-width) (dashboard--get-base-length path type) dashboard-shorten-path-offset) dashboard-path-max-length))) (cl-case dashboard-path-style (truncate-beginning (dashboard-shorten-path-beginning path)) (truncate-middle (dashboard-shorten-path-middle path)) (truncate-end (dashboard-shorten-path-end path)) (t path)))) (defun dashboard-shorten-paths (paths alist type) "Shorten all path from PATHS by TYPE and store it to ALIST." (let (lst-display abbrev (index 0)) (setf (symbol-value alist) nil) ; reset (dolist (item paths) (setq abbrev (dashboard-shorten-path item type) ;; Add salt here, and use for extraction. ;; See function `dashboard-extract-key-path-alist'. abbrev (format "%s|%s" index abbrev)) ;; store `abbrev' as id; and `item' with value (push (cons abbrev item) (symbol-value alist)) (push abbrev lst-display) (cl-incf index)) (reverse lst-display))) (defun dashboard-extract-key-path-alist (key alist) "Remove salt from KEY, and return true shorten path from ALIST." (let* ((key (car (assoc key alist))) (split (split-string key "|"))) (nth 1 split))) (defun dashboard-expand-path-alist (key alist) "Get the full path (un-shorten) using KEY from ALIST." (cdr (assoc key alist))) (defun dashboard--generate-align-format (fmt len) "Return FMT after inserting align LEN." (let ((pos (1+ (string-match-p "%s" fmt)))) (concat (substring fmt 0 pos) (concat "-" (number-to-string len)) (substring fmt pos (length fmt))))) (defun dashboard--align-length-by-type (type) "Return the align length by TYPE of the section." (let ((len-item (cdr (assoc type dashboard-items))) (count 0) (align-length -1) len-list base) (cl-case type (`recents (require 'recentf) (setq len-list (length recentf-list)) (while (and (< count len-item) (< count len-list)) (setq base (nth count recentf-list) align-length (max align-length (dashboard-str-len (dashboard-f-filename base)))) (cl-incf count))) (`bookmarks (let ((bookmarks-lst (bookmark-all-names))) (setq len-list (length bookmarks-lst)) (while (and (< count len-item) (< count len-list)) (setq base (nth count bookmarks-lst) align-length (max align-length (dashboard-str-len base))) (cl-incf count)))) (`projects (let ((projects-lst (dashboard-projects-backend-load-projects))) (setq len-list (length projects-lst)) (while (and (< count len-item) (< count len-list)) (setq base (nth count projects-lst) align-length (max align-length (dashboard-str-len (dashboard-f-base base)))) (cl-incf count)))) (t (error "Unknown type for align length: %s" type))) align-length)) ;; ;; Recentf ;; (defcustom dashboard-recentf-show-base nil "Show the base file name infront of it's path." :type '(choice (const :tag "Don't show the base infront" nil) (const :tag "Respect format" t) (const :tag "Align the from base" align)) :group 'dashboard) (defcustom dashboard-recentf-item-format "%s %s" "Format to use when showing the base of the file name." :type 'string :group 'dashboard) (defvar dashboard-recentf-alist nil "Alist records shorten's recent files and it's full paths.") (defvar dashboard--recentf-cache-item-format nil "Cache to record the new generated align format.") (defun dashboard-insert-recents (list-size) "Add the list of LIST-SIZE items from recently edited files." (setq dashboard--recentf-cache-item-format nil) (dashboard-mute-apply (recentf-mode 1) (recentf-cleanup)) (dashboard-insert-section "Recent Files:" (dashboard-shorten-paths recentf-list 'dashboard-recentf-alist 'recents) list-size 'recents (dashboard-get-shortcut 'recents) `(lambda (&rest _) (find-file-existing (dashboard-expand-path-alist ,el dashboard-recentf-alist))) (let* ((file (dashboard-expand-path-alist el dashboard-recentf-alist)) (filename (dashboard-f-filename file)) (path (dashboard-extract-key-path-alist el dashboard-recentf-alist))) (cl-case dashboard-recentf-show-base (`align (unless dashboard--recentf-cache-item-format (let* ((len-align (dashboard--align-length-by-type 'recents)) (new-fmt (dashboard--generate-align-format dashboard-recentf-item-format len-align))) (setq dashboard--recentf-cache-item-format new-fmt))) (format dashboard--recentf-cache-item-format filename path)) (`nil path) (t (format dashboard-recentf-item-format filename path)))))) ;; ;; Bookmarks ;; (defcustom dashboard-bookmarks-show-base t "Show the base file name infront of it's path." :type '(choice (const :tag "Don't show the base infront" nil) (const :tag "Respect format" t) (const :tag "Align the from base" align)) :group 'dashboard) (defcustom dashboard-bookmarks-item-format "%s - %s" "Format to use when showing the base of the file name." :type 'string :group 'dashboard) (defvar dashboard--bookmarks-cache-item-format nil "Cache to record the new generated align format.") (defun dashboard-insert-bookmarks (list-size) "Add the list of LIST-SIZE items of bookmarks." (require 'bookmark) (dashboard-insert-section "Bookmarks:" (dashboard-subseq (bookmark-all-names) list-size) list-size 'bookmarks (dashboard-get-shortcut 'bookmarks) `(lambda (&rest _) (bookmark-jump ,el)) (if-let* ((filename el) (path (bookmark-get-filename el)) (path-shorten (dashboard-shorten-path path 'bookmarks))) (cl-case dashboard-bookmarks-show-base (`align (unless dashboard--bookmarks-cache-item-format (let* ((len-align (dashboard--align-length-by-type 'bookmarks)) (new-fmt (dashboard--generate-align-format dashboard-bookmarks-item-format len-align))) (setq dashboard--bookmarks-cache-item-format new-fmt))) (format dashboard--bookmarks-cache-item-format filename path-shorten)) (`nil path-shorten) (t (format dashboard-bookmarks-item-format filename path-shorten))) el))) ;; ;; Projects ;; (defcustom dashboard-projects-switch-function nil "Custom function to switch to projects from dashboard. If non-NIL, should be bound to a function with one argument. The function will be called with the root directory of the project to switch to." :type '(choice (const :tag "Default" nil) function) :group 'dashboard) (defcustom dashboard-projects-show-base nil "Show the project name infront of it's path." :type '(choice (const :tag "Don't show the base infront" nil) (const :tag "Respect format" t) (const :tag "Align the from base" align)) :group 'dashboard) (defcustom dashboard-projects-item-format "%s %s" "Format to use when showing the base of the project name." :type 'string :group 'dashboard) (defvar dashboard-projects-alist nil "Alist records the shorten's project paths and it's full paths.") (defvar dashboard--projects-cache-item-format nil "Cache to record the new generated align format.") (defun dashboard-insert-projects (list-size) "Add the list of LIST-SIZE items of projects." (setq dashboard--projects-cache-item-format nil) (dashboard-insert-section "Projects:" (dashboard-shorten-paths (dashboard-subseq (dashboard-projects-backend-load-projects) list-size) 'dashboard-projects-alist 'projects) list-size 'projects (dashboard-get-shortcut 'projects) `(lambda (&rest _) (funcall (dashboard-projects-backend-switch-function) (dashboard-expand-path-alist ,el dashboard-projects-alist))) (let* ((file (dashboard-expand-path-alist el dashboard-projects-alist)) (filename (dashboard-f-base file)) (path (dashboard-extract-key-path-alist el dashboard-projects-alist))) (cl-case dashboard-projects-show-base (`align (unless dashboard--projects-cache-item-format (let* ((len-align (dashboard--align-length-by-type 'projects)) (new-fmt (dashboard--generate-align-format dashboard-projects-item-format len-align))) (setq dashboard--projects-cache-item-format new-fmt))) (format dashboard--projects-cache-item-format filename path)) (`nil path) (t (format dashboard-projects-item-format filename path)))))) (defun dashboard-projects-backend-load-projects () "Depending on `dashboard-projects-backend' load corresponding backend. Return function that returns a list of projects." (cl-case dashboard-projects-backend (`projectile (require 'projectile) (dashboard-mute-apply (projectile-cleanup-known-projects)) (projectile-load-known-projects)) (`project-el (require 'project) (dashboard-mute-apply (dashboard-funcall-fboundp #'project-forget-zombie-projects)) (project-known-project-roots)) (t (display-warning '(dashboard) "Invalid value for `dashboard-projects-backend'" :error)))) (defun dashboard-projects-backend-switch-function () "Return the function to switch to a project. Custom variable `dashboard-projects-switch-function' variable takes preference over custom backends." (or dashboard-projects-switch-function (cl-case dashboard-projects-backend (`projectile 'projectile-switch-project-by-name) (`project-el (lambda (project) "This function is used to switch to `PROJECT'." (let ((default-directory project)) (project-find-file)))) (t (display-warning '(dashboard) "Invalid value for `dashboard-projects-backend'" :error))))) ;; ;; Org Agenda ;; (defcustom dashboard-week-agenda t "Show agenda weekly if its not nil." :type 'boolean :group 'dashboard) (defcustom dashboard-agenda-time-string-format "%Y-%m-%d" "Format time of agenda entries." :type 'string :group 'dashboard) (defcustom dashboard-match-agenda-entry nil "Match agenda to extra filter. It is the MATCH attribute for `org-map-entries'" :type 'string :group 'dashboard) (defcustom dashboard-agenda-release-buffers nil "If not nil use `org-release-buffers' after getting the entries." :type 'boolean :group 'dashboard) (defcustom dashboard-filter-agenda-entry 'dashboard-filter-agenda-by-time "Function to filter `org-agenda' entries." :type '(choice (const :tag "No filter" dashboard-no-filter-agenda) (const :tag "Filter by time" dashboard-filter-agenda-by-time) (const :tag "Filter by todo" dashboard-filter-agenda-by-todo) (function :tag "Custom function")) :group 'dashboard) (defcustom dashboard-agenda-sort-strategy nil "A list of strategies to sort the agenda. If nil agenda is not sorted." :type '(repeat (choice (const priority-up) (const priority-down) (const time-up) (const time-down) (const todo-state-up) (const todo-state-down))) :group 'dashboard) (defcustom dashboard-agenda-prefix-format " %i %-12:c %s " "Format for each entry in the agenda. When the dashboard-agenda is created this format is inserted into `org-agenda-prefix-format' as `dashboard-agenda' and compiled with `org-compile-prefix-format' previous calling `dashboard-agenda-entry-format' for each agenda entry." :type 'string :group 'dashboard) (defcustom dashboard-agenda-tags-format 'identity "Function to format the org agenda tags. Any custom function would receives the tags from `org-get-tags'" :type '(choice (const :tag "Show tags" identity) (const :tag "Hide tags" ignore) (function :tag "Custom function")) :group 'dashboard) (defun dashboard-agenda-entry-format () "Format agenda entry to show it on dashboard. Also,it set text properties that latter are used to sort entries and perform different actions." (let* ((scheduled-time (org-get-scheduled-time (point))) (deadline-time (org-get-deadline-time (point))) (entry-timestamp (dashboard-agenda--entry-timestamp (point))) (entry-time (or scheduled-time deadline-time entry-timestamp)) (item (org-agenda-format-item (dashboard-agenda--formatted-time) (dashboard-agenda--formatted-headline) (org-outline-level) (org-get-category) (dashboard-agenda--formatted-tags))) (todo-state (org-get-todo-state)) (item-priority (org-get-priority (org-get-heading t t t t))) (todo-index (and todo-state (length (member todo-state org-todo-keywords-1)))) (entry-data (list 'dashboard-agenda-file (buffer-file-name) 'dashboard-agenda-loc (point) 'dashboard-agenda-priority item-priority 'dashboard-agenda-todo-index todo-index 'dashboard-agenda-time entry-time))) (add-text-properties 0 (length item) entry-data item) item)) (defun dashboard-agenda--entry-timestamp (point) "Get the timestamp from an entry at POINT." (when-let ((timestamp (org-entry-get point "TIMESTAMP"))) (org-time-string-to-time timestamp))) (defun dashboard-agenda--formatted-headline () "Set agenda faces to `HEADLINE' when face text property is nil." (let* ((headline (org-get-heading t t t t)) (todo (or (org-get-todo-state) "")) (org-level-face (nth (- (org-outline-level) 1) org-level-faces)) (todo-state (format org-agenda-todo-keyword-format todo))) (dashboard-agenda--set-face org-level-face headline) (dashboard-agenda--set-face (org-get-todo-face todo) todo-state) (concat todo-state " " headline))) (defun dashboard-agenda--set-face (face text) "Add FACE to TEXT but inherit height from `dashboard-items-face'. If not height is found on FACE or `dashboard-items-face' use `default'." (let ((height (face-attribute 'dashboard-items-face :height nil 'default))) (add-face-text-property 0 (length text) `((:height ,height) ,face) nil text))) (defun dashboard-agenda--formatted-time () "Get the scheduled or dead time of an entry. If no time is found return nil." (when-let ((time (or (org-get-scheduled-time (point)) (org-get-deadline-time (point)) (dashboard-agenda--entry-timestamp (point))))) (format-time-string dashboard-agenda-time-string-format time))) (defun dashboard-agenda--formatted-tags () "Apply `dashboard-agenda-tags-format' to org-element tags." (when dashboard-agenda-tags-format (funcall dashboard-agenda-tags-format (org-get-tags)))) (defun dashboard-due-date-for-agenda () "Return due-date for agenda period." (if dashboard-week-agenda (time-add (current-time) (* 86400 8)) (time-add (current-time) 86400))) (defun dashboard-filter-agenda-by-time () "Include entry if it has a scheduled-time or deadline-time in the future. An entry is included if this function returns nil and excluded if returns a point." (let ((scheduled-time (org-get-scheduled-time (point))) (deadline-time (org-get-deadline-time (point))) (entry-timestamp (dashboard-agenda--entry-timestamp (point))) (due-date (dashboard-due-date-for-agenda)) (now (current-time))) (unless (and (not (org-entry-is-done-p)) (not (org-in-archived-heading-p)) (or (and scheduled-time (org-time-less-p scheduled-time due-date)) (and deadline-time (org-time-less-p deadline-time due-date)) (and entry-timestamp (org-time-less-p now entry-timestamp) (org-time-less-p entry-timestamp due-date)))) (point)))) (defun dashboard-filter-agenda-by-todo () "Include entry if it is todo and not done. An entry is included if this function returns nil and excluded if returns a point." (unless (and (org-entry-is-todo-p) (not (org-entry-is-done-p)) (not (org-in-archived-heading-p))) (point))) (defun dashboard-no-filter-agenda () "No filter agenda entries." (when (org-entry-is-done-p) (point))) (defun dashboard-get-agenda () "Get agenda items for today or for a week from now." (if-let ((prefix-format (assoc 'dashboard-agenda org-agenda-prefix-format))) (setcdr prefix-format dashboard-agenda-prefix-format) (push (cons 'dashboard-agenda dashboard-agenda-prefix-format) org-agenda-prefix-format)) (org-compile-prefix-format 'dashboard-agenda) (prog1 (org-map-entries 'dashboard-agenda-entry-format dashboard-match-agenda-entry 'agenda dashboard-filter-agenda-entry) (dashboard-agenda--release-buffers))) (defun dashboard-agenda--release-buffers () "Release agenda buffers buffers. This is what `org-agenda-exit' do." (when dashboard-agenda-release-buffers (org-release-buffers org-agenda-new-buffers) (setq org-agenda-new-buffers nil))) (defun dashboard-agenda--sorted-agenda () "Return agenda sorted by time. For now, it only works when dashboard-agenda has been filter by time and dashboard-agenda-sort is not nil." (let ((agenda (dashboard-get-agenda)) (sort-function (dashboard-agenda--sort-function))) (sort agenda sort-function))) (defun dashboard-agenda--sort-function () "Get the function use to sorted the agenda. Depending on the list `dashboard-agenda-sorting-strategy' use this strategies to build a predicate to compare each enty. This is similar as `org-entries-lessp' but with a different aproach." (dashboard-agenda--build-sort-function dashboard-agenda-sort-strategy)) (defun dashboard-agenda--build-sort-function (strategies) "Build a predicate to sort the dashboard agenda. If `STRATEGIES' is nil then sort using the nil predicate. Look for the strategy predicate, the attributes of the entry and compare entries. If no predicate is found for the strategy it uses nil predicate." (if (null strategies) (lambda (_dont _care) nil) (let ((predicate (dashboard-agenda--build-sort-function-predicate (car strategies))) (attribute (dashboard-agenda--build-sort-function-attribute (car strategies)))) (if (null predicate) (lambda (_dont _care) nil) (lambda (entry1 entry2) (dashboard-agenda--compare-entries entry1 entry2 (cdr strategies) predicate attribute)))))) (defun dashboard-agenda--build-sort-function-predicate (strategy) "Return the predicate to compare two entryes depending on the `STRATEGY'." (cl-case strategy (`priority-up '>) (`priority-down '<) (`time-up 'org-time-less-p) (`time-down (lambda (a b) (org-time-less-p b a))) (`todo-state-up '>) (`todo-state-down '<))) (defun dashboard-agenda--build-sort-function-attribute (strategy) "Return the argument to compare two entries depending to the `STRATEGY'." (cond ((memq strategy '(priority-up priority-down)) 'dashboard-agenda-priority) ((memq strategy '(time-up time-down)) 'dashboard-agenda-time) ((memq strategy '(todo-state-up todo-state-down)) 'dashboard-agenda-todo-index) (t nil))) (defun dashboard-agenda--compare-entries (entry1 entry2 strategies predicate attribute) "Compare `ENTRY1' and `ENTRY2' by `ATTRIBUTE' using `PREDICATE'. If both attributes are nil or equals the next strategy in `STRATEGIES' is used to compare." (let ((arg1 (get-text-property 0 attribute entry1)) (arg2 (get-text-property 0 attribute entry2))) (cond ((or (and (null arg1) (null arg2)) (equal arg1 arg2)) (apply (dashboard-agenda--build-sort-function strategies) (list entry1 entry2))) ((null arg1) nil) ((null arg2) t) (t (apply predicate (list arg1 arg2)))))) (defun dashboard-insert-agenda (list-size) "Add the list of LIST-SIZE items of agenda." (require 'org-agenda) (dashboard-insert-section (if dashboard-week-agenda "Agenda for the coming week:" "Agenda for today:") (dashboard-agenda--sorted-agenda) list-size 'agenda (dashboard-get-shortcut 'agenda) `(lambda (&rest _) (let ((buffer (find-file-other-window (get-text-property 0 'dashboard-agenda-file ,el)))) (with-current-buffer buffer (goto-char (get-text-property 0 'dashboard-agenda-loc ,el)) (switch-to-buffer buffer)))) (format "%s" el))) ;; ;; Registers ;; (defun dashboard-insert-registers (list-size) "Add the list of LIST-SIZE items of registers." (require 'register) (dashboard-insert-section "Registers:" register-alist list-size 'registers (dashboard-get-shortcut 'registers) (lambda (&rest _) (jump-to-register (car el))) (format "%c - %s" (car el) (register-describe-oneline (car el))))) (provide 'dashboard-widgets) ;;; dashboard-widgets.el ends here emacs-dashboard-1.8.0/dashboard.el000066400000000000000000000436151446027744200170310ustar00rootroot00000000000000;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*- ;; Copyright (c) 2016-2023 emacs-dashboard maintainers ;; ;; Author : Rakan Al-Hneiti ;; Maintainer : Jesús Martínez ;; Shen, Jen-Chieh ;; URL : https://github.com/emacs-dashboard/emacs-dashboard ;; ;; This file is not part of GNU Emacs. ;; ;;; License: GPLv3 ;; ;; Created: October 05, 2016 ;; Package-Version: 1.8.0 ;; Keywords: startup, screen, tools, dashboard ;; Package-Requires: ((emacs "26.1")) ;;; Commentary: ;; An extensible Emacs dashboard, with sections for ;; bookmarks, projects (projectile or project.el), org-agenda and more. ;;; Code: (require 'ffap) (require 'recentf) (require 'dashboard-widgets) (declare-function bookmark-get-filename "ext:bookmark.el") (declare-function bookmark-all-names "ext:bookmark.el") (declare-function dashboard-ls--dirs "ext:dashboard-ls.el") (declare-function dashboard-ls--files "ext:dashboard-ls.el") (declare-function page-break-lines-mode "ext:page-break-lines.el") (declare-function projectile-remove-known-project "ext:projectile.el") (declare-function project-forget-projects-under "ext:project.el") (declare-function linum-mode "linum.el") (declare-function dashboard-refresh-buffer "dashboard.el") (defgroup dashboard nil "Extensible startup screen." :group 'applications) ;; Custom splash screen (defvar dashboard-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-p") 'dashboard-previous-line) (define-key map (kbd "C-n") 'dashboard-next-line) (define-key map (kbd "") 'dashboard-previous-line) (define-key map (kbd "") 'dashboard-next-line) (define-key map (kbd "k") 'dashboard-previous-line) (define-key map (kbd "j") 'dashboard-next-line) (define-key map [tab] 'widget-forward) (define-key map (kbd "C-i") 'widget-forward) (define-key map [backtab] 'widget-backward) (define-key map (kbd "RET") 'dashboard-return) (define-key map [mouse-1] 'dashboard-mouse-1) (define-key map (kbd "}") #'dashboard-next-section) (define-key map (kbd "{") #'dashboard-previous-section) (define-key map (kbd "") #'dashboard-remove-item-under) (define-key map (kbd "") #'dashboard-remove-item-under) (define-key map (kbd "DEL") #'dashboard-remove-item-under) (define-key map (kbd "1") #'dashboard-section-1) (define-key map (kbd "2") #'dashboard-section-2) (define-key map (kbd "3") #'dashboard-section-3) (define-key map (kbd "4") #'dashboard-section-4) (define-key map (kbd "5") #'dashboard-section-5) (define-key map (kbd "6") #'dashboard-section-6) (define-key map (kbd "7") #'dashboard-section-7) (define-key map (kbd "8") #'dashboard-section-8) (define-key map (kbd "9") #'dashboard-section-9) map) "Keymap for dashboard mode.") (defcustom dashboard-after-initialize-hook nil "Hook that is run after dashboard buffer is initialized." :group 'dashboard :type 'hook) (define-derived-mode dashboard-mode special-mode "Dashboard" "Dashboard major mode for startup screen." :group 'dashboard :syntax-table nil :abbrev-table nil (buffer-disable-undo) (when (featurep 'whitespace) (whitespace-mode -1)) (when (featurep 'linum) (linum-mode -1)) (when (featurep 'display-line-numbers) (display-line-numbers-mode -1)) (when (featurep 'page-break-lines) (page-break-lines-mode 1)) (setq-local revert-buffer-function #'dashboard-refresh-buffer) (setq inhibit-startup-screen t buffer-read-only t truncate-lines t)) (defcustom dashboard-center-content nil "Whether to center content within the window." :type 'boolean :group 'dashboard) (defconst dashboard-buffer-name "*dashboard*" "Dashboard's buffer name.") (defvar dashboard-force-refresh nil "If non-nil, force refresh dashboard buffer.") (defvar dashboard--section-starts nil "List of section starting positions.") ;; ;; Util ;; (defun dashboard--goto-line (line) "Goto LINE." (goto-char (point-min)) (forward-line (1- line))) (defmacro dashboard--save-excursion (&rest body) "Execute BODY save window point." (declare (indent 0) (debug t)) `(let ((line (line-number-at-pos nil t)) (column (current-column))) ,@body (dashboard--goto-line line) (move-to-column column))) ;; ;; Core ;; (defun dashboard--current-section () "Return section symbol in dashboard." (save-excursion (if (and (search-backward dashboard-page-separator nil t) (search-forward dashboard-page-separator nil t)) (let ((ln (thing-at-point 'line))) (cond ((string-match-p "Recent Files:" ln) 'recents) ((string-match-p "Bookmarks:" ln) 'bookmarks) ((string-match-p "Projects:" ln) 'projects) ((string-match-p "Agenda for " ln) 'agenda) ((string-match-p "Registers:" ln) 'registers) ((string-match-p "List Directories:" ln) 'ls-directories) ((string-match-p "List Files:" ln) 'ls-files) (t (user-error "Unknown section from dashboard")))) (user-error "Failed searching dashboard section")))) ;; ;; Navigation ;; (defun dashboard-previous-section () "Navigate back to previous section." (interactive) (let ((current-position (point)) current-section-start previous-section-start) (dolist (elt dashboard--section-starts) (when (and current-section-start (not previous-section-start)) (setq previous-section-start elt)) (when (and (not current-section-start) (< elt current-position)) (setq current-section-start elt))) (goto-char (if (eq current-position current-section-start) previous-section-start current-section-start)))) (defun dashboard-next-section () "Navigate forward to next section." (interactive) (let ((current-position (point)) next-section-start (section-starts (reverse dashboard--section-starts))) (dolist (elt section-starts) (when (and (not next-section-start) (> elt current-position)) (setq next-section-start elt))) (when next-section-start (goto-char next-section-start)))) (defun dashboard--section-lines () "Return a list of integer represent the starting line number of each section." (let (pb-lst) (save-excursion (goto-char (point-min)) (while (search-forward dashboard-page-separator nil t) (when (ignore-errors (dashboard--current-section)) (push (line-number-at-pos) pb-lst)))) (setq pb-lst (reverse pb-lst)) pb-lst)) (defun dashboard--goto-section-by-index (index) "Navigate to item section by INDEX." (let* ((pg-lst (dashboard--section-lines)) (items-id (1- index)) (items-pg (nth items-id pg-lst)) (items-len (length pg-lst))) (when (and items-pg (< items-id items-len)) (dashboard--goto-line items-pg)))) (defun dashboard-section-1 () "Navigate to section 1." (interactive) (dashboard--goto-section-by-index 1)) (defun dashboard-section-2 () "Navigate to section 2." (interactive) (dashboard--goto-section-by-index 2)) (defun dashboard-section-3 () "Navigate to section 3." (interactive) (dashboard--goto-section-by-index 3)) (defun dashboard-section-4 () "Navigate to section 4." (interactive) (dashboard--goto-section-by-index 4)) (defun dashboard-section-5 () "Navigate to section 5." (interactive) (dashboard--goto-section-by-index 5)) (defun dashboard-section-6 () "Navigate to section 6." (interactive) (dashboard--goto-section-by-index 6)) (defun dashboard-section-7 () "Navigate to section 7." (interactive) (dashboard--goto-section-by-index 7)) (defun dashboard-section-8 () "Navigate to section 8." (interactive) (dashboard--goto-section-by-index 8)) (defun dashboard-section-9 () "Navigate to section 9." (interactive) (dashboard--goto-section-by-index 9)) (defun dashboard-previous-line (arg) "Move point up and position it at that line’s item. Optional prefix ARG says how many lines to move; default is one line." (interactive "^p") (dashboard-next-line (- arg))) (defun dashboard-next-line (arg) "Move point down and position it at that line’s item. Optional prefix ARG says how many lines to move; default is one line." ;; code heavily inspired by `dired-next-line' (interactive "^p") (let (line-move-visual goal-column) (line-move arg t)) ;; We never want to move point into an invisible line. Dashboard doesn’t ;; use invisible text currently but when it does we’re ready! (while (and (invisible-p (point)) (not (if (and arg (< arg 0)) (bobp) (eobp)))) (forward-char (if (and arg (< arg 0)) -1 1))) (beginning-of-line-text)) ;; ;; ffap ;; (defun dashboard--goto-section (section) "Move to SECTION declares in variable `dashboard-item-shortcuts'." (let ((fnc (intern (format "dashboard-jump-to-%s" section)))) (dashboard-funcall-fboundp fnc))) (defun dashboard--current-index (section &optional pos) "Return the idex by SECTION from POS." (let (target-ln section-line) (save-excursion (when pos (goto-char pos)) (setq target-ln (line-number-at-pos)) (dashboard--goto-section section) (setq section-line (line-number-at-pos))) (- target-ln section-line))) (defun dashboard--section-list (section) "Return the list from SECTION." (cl-case section (`recents recentf-list) (`bookmarks (bookmark-all-names)) (`projects (dashboard-projects-backend-load-projects)) (`ls-directories (dashboard-ls--dirs)) (`ls-files (dashboard-ls--files)) (t (user-error "Unknown section for search: %s" section)))) (defun dashboard--current-item-in-path () "Return the path from current dashboard section in path." (let ((section (dashboard--current-section)) path) (cl-case section (`bookmarks (setq path (bookmark-get-filename path))) (t (let ((lst (dashboard--section-list section)) (index (dashboard--current-index section))) (setq path (nth index lst))))) path)) (defun dashboard--on-path-item-p () "Return non-nil if current point is on the item path from dashboard." (save-excursion (when (= (point) (line-end-position)) (ignore-errors (forward-char -1))) (eq (get-char-property (point) 'face) 'dashboard-items-face))) (defun dashboard--ffap-guesser--adv (fnc &rest args) "Advice execution around function `ffap-guesser'. Argument FNC is the adviced function. Optional argument ARGS adviced function arguments." (cl-case major-mode (`dashboard-mode (or (and (dashboard--on-path-item-p) (dashboard--current-item-in-path)) (apply fnc args))) ; fallback (t (apply fnc args)))) (advice-add 'ffap-guesser :around #'dashboard--ffap-guesser--adv) ;; ;; Removal ;; (defun dashboard-remove-item-under () "Remove a item from the current item section." (interactive) (cl-case (dashboard--current-section) (`recents (dashboard-remove-item-recentf)) (`bookmarks (dashboard-remove-item-bookmarks)) (`projects (dashboard-remove-item-projects)) (`agenda (dashboard-remove-item-agenda)) (`registers (dashboard-remove-item-registers))) (dashboard--save-excursion (dashboard-refresh-buffer))) (defun dashboard-remove-item-recentf () "Remove a file from `recentf-list'." (interactive) (let ((path (save-excursion (end-of-line) (ffap-guesser)))) (setq recentf-list (delete path recentf-list))) (dashboard-mute-apply (recentf-save-list))) (defun dashboard-remove-item-projects () "Remove a path from `project--list'." (interactive) (let ((path (save-excursion (end-of-line) (ffap-guesser)))) (dashboard-mute-apply (cl-case dashboard-projects-backend (`projectile (projectile-remove-known-project path)) (`project-el (project-forget-projects-under path)))))) (defun dashboard-remove-item-bookmarks () "Remove a bookmarks from `bookmark-alist'." (interactive)) ; TODO: .. (defun dashboard-remove-item-agenda () "Remove an agenda from `org-agenda-files'." (interactive "P") (let ((agenda-file (get-text-property (point) 'dashboard-agenda-file)) (agenda-loc (get-text-property (point) 'dashboard-agenda-loc))) (with-current-buffer (find-file-noselect agenda-file) (goto-char agenda-loc) (call-interactively 'org-todo)))) (defun dashboard-remove-item-registers () "Remove a registers from `register-alist'." (interactive)) ; TODO: .. ;; ;; Confirmation ;; (defun dashboard-return () "Hit return key in dashboard buffer." (interactive) (let ((start-ln (line-number-at-pos)) (fd-cnt 0) diff-line entry-pt) (save-excursion (while (and (not diff-line) (not (= (point) (point-min))) (not (get-char-property (point) 'button)) (not (= (point) (point-max)))) (forward-char 1) (setq fd-cnt (1+ fd-cnt)) (unless (= start-ln (line-number-at-pos)) (setq diff-line t))) (unless (= (point) (point-max)) (setq entry-pt (point)))) (when (= fd-cnt 1) (setq entry-pt (1- (point)))) (if entry-pt (widget-button-press entry-pt) (call-interactively #'widget-button-press)))) (defun dashboard-mouse-1 () "Key for keymap `mouse-1'." (interactive) (let ((old-track-mouse track-mouse)) (when (call-interactively #'widget-button-click) (setq track-mouse old-track-mouse)))) ;; ;; Insertion ;; (defmacro dashboard--with-buffer (&rest body) "Execute BODY in dashboard buffer." (declare (indent 0)) `(with-current-buffer (get-buffer-create dashboard-buffer-name) (let ((inhibit-read-only t)) ,@body) (current-buffer))) (defun dashboard-maximum-section-length () "For the just-inserted section, calculate the length of the longest line." (let ((max-line-length 0)) (save-excursion (dashboard-previous-section) (while (not (eobp)) (setq max-line-length (max max-line-length (- (line-end-position) (line-beginning-position)))) (forward-line 1))) max-line-length)) (defun dashboard-insert-startupify-lists () "Insert the list of widgets into the buffer." (interactive) (let ((inhibit-redisplay t) (recentf-is-on (recentf-enabled-p)) (origial-recentf-list recentf-list) (dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0)) (max-line-length 0)) (when recentf-is-on (setq recentf-list (dashboard-subseq recentf-list dashboard-num-recents))) (dashboard--with-buffer (when (or dashboard-force-refresh (not (eq major-mode 'dashboard-mode))) (erase-buffer) (dashboard-insert-banner) (insert "\n") (setq dashboard--section-starts nil) (mapc (lambda (els) (let* ((el (or (car-safe els) els)) (list-size (or (cdr-safe els) dashboard-items-default-length)) (item-generator (cdr-safe (assoc el dashboard-item-generators)))) (push (point) dashboard--section-starts) (funcall item-generator list-size) (goto-char (point-max)) ;; add a newline so the next section-name doesn't get include ;; on the same line. (insert "\n") (when recentf-is-on (setq recentf-list origial-recentf-list)) (setq max-line-length (max max-line-length (dashboard-maximum-section-length))))) dashboard-items) (when dashboard-center-content (dashboard-center-text (if dashboard--section-starts (car (last dashboard--section-starts)) (point)) (point-max))) (save-excursion (dolist (start dashboard--section-starts) (goto-char start) (delete-char -1) ; delete the newline we added previously (insert dashboard-page-separator))) (progn (delete-char -1) (insert dashboard-page-separator)) (dashboard-insert-footer) (goto-char (point-min)) (dashboard-mode))) (when recentf-is-on (setq recentf-list origial-recentf-list)))) ;;;###autoload (defun dashboard-open (&rest _) "Open (or refresh) the *dashboard* buffer." (interactive) (let ((dashboard-force-refresh t)) (dashboard-insert-startupify-lists)) (switch-to-buffer dashboard-buffer-name)) (defalias #'dashboard-refresh-buffer #'dashboard-open) (defun dashboard-resize-on-hook (&optional _) "Re-render dashboard on window size change." (let ((space-win (get-buffer-window dashboard-buffer-name)) (frame-win (frame-selected-window))) (when (and space-win (not (window-minibuffer-p frame-win))) (with-selected-window space-win (dashboard-insert-startupify-lists))))) ;;;###autoload (defun dashboard-setup-startup-hook () "Setup post initialization hooks. If a command line argument is provided, assume a filename and skip displaying Dashboard." (when (< (length command-line-args) 2) (add-hook 'window-setup-hook (lambda () ;; 100 means `dashboard-resize-on-hook' will run last (add-hook 'window-size-change-functions 'dashboard-resize-on-hook 100) (dashboard-resize-on-hook))) (add-hook 'after-init-hook (lambda () ;; Display useful lists of items (dashboard-insert-startupify-lists))) (add-hook 'emacs-startup-hook (lambda () (switch-to-buffer dashboard-buffer-name) (goto-char (point-min)) (redisplay) (run-hooks 'dashboard-after-initialize-hook))))) (provide 'dashboard) ;;; dashboard.el ends here emacs-dashboard-1.8.0/etc/000077500000000000000000000000001446027744200153225ustar00rootroot00000000000000emacs-dashboard-1.8.0/etc/screenshot.png000066400000000000000000002436061446027744200202200ustar00rootroot00000000000000PNG  IHDR5T, pHYs+ IDATxi\Yvs}/ 4n͞C $EHS4p6%+vX!#-[VaK5sq} Wns-^f.tU3ݨ2s/}8A_@  8,O?uE?w{H 'pX a| 'pX a| 'pX a| A_0UO  ))ѝ1B+p['?$IPR""֣1ɇy$*|4*pUUa%VU[U'ߣGE_ yLlX,q"B jӮɐ2&qEPUPQ')#%ĬlTH1IU+SU*LbaAD_hR[QQ"%Uz=j.:˛=1dRe&(:6  Gp2o YITԬXj4YoZQQ!Q%&&"%R5RQ&&@EJu3l:-vK ,l$AJ!|O&q!fbUrU٠:OU^6 &#$,HDԩ:P%J\Ǣ%Q ]'p0luvu=P4"eHERƘ Kk[t}nҺa|) ҨdLƐ: Rx%S%PBAhj (V zaRjQJc,cac0tkqRTE9QD$t[Nj6Z՝pG>)6cfn M7wUɰfSR~h!|dILEC"-RmJOb͌10^`8툭Zef<;VTr+9oNԹkS4(z{DT+cD"a{fǭwd`C ”96 rWvٰ@JADa|a20I7WHmNئ:E.J+@Mɫ.NԎNX>[CD*"iHcAL "IfJ\5f%t BL%+Hjƪ<6%Kz&]6Y}H)m'ٲ2!4 5gI^غ .&! ѩTZ(wO/|KFw"g6N&'vn]^TSBO#xxt\IK=h3bR~( | 5t!QУ,Q2Qɩ scW,J%iN5g :֓bGtV x^٨5'kmln-l]lwLɪLqL#*_j9;:B G a2i(f9S7aOD=q-W4-5jǒ'If='H)+F2T}b|ı啍˽l''oJ И̭;kzl5.d> D+7MTŠ5&Q" LmŹǎfղ CX-唡p2u\gOl{cʞqVDOё}EDlMωQ|pH N1;Bْҍyw[Aa<b".Z{n$=]^'?[4kOQR>q9;V˖}G!)M#57vYH԰O$HB>8 RXֱE~tszeC S.U"uajMmJbNm?+LDD4fgo^%U1E'QpM&ћbi,ADHA>8tJjJ:M'ђecة驩STrw6 '=]|2uXDHX9{9;sw.0%Ok^7nE&I #pIT: %~b&/LNʵ~ t^fکJ;۲ȩ9Q%~50-Cq4~n(b'ޯhФ%~f{j/$O?8y'3/L4T٠=NFMr5l(*$FcnN\;Jj|N̯m C3 @DB>8ᄙTMq~Şvg^q:줪Jw2Iv:\^=]ٲɭ^|+α1KKW_lxBݲG6*7@DC>8xTE,>Ώ6!&\L?sXJs?,mQxs~o dmF&V!ON~b7/߰?О%Nã18rL,sK3=` ~ebJeGWjמּyOP儜GPbb%qypFNN(otځ Z)Nϕ1NY|iZ+u)- \/+8g;y ^}Uy>M+%C  Ҩrr<JHL*J'T\g&ì*aQ9../4ZPɾu;v7n~7^^}*U=q3R/:P9~PU;-ADB>89'fUn^4a cUN)u\kiGK'K5h$:ڝr/W3{?Wz}܋O(W^'lI0ϧUief"EDA>8@t :hw ;<:'.${|=={Nd7Eۑ^WTP0 j<؜=ژXI2OAQi9z`zd?1UMι#|9i8k|ɨ!('l璲Zp.'U8/|$#*`8a"cw i_sGJ'N]ljJ=Dw;Ө>;;_gDj ڿ[nƤBט>裗0驐{[|ͨ,>TOEᤡ3'39#{xthڻZ_8֘6J, Q>+rx/Uf~UJݎl+YѪ8טY8, a;uk yJP!|ʎbAA+KC1 ~<9هpH= y|lqlD}vv|i,|;<4wN.zuqM|v*=?BH\TPstΟyxWEj_Ri/:^dzx|W*m9ypż "e5J$7gC鱵nW{`r)fV{J^7P,r˵W =CE=ZєݝwGynz| e@58bTyfdwggwmPI:ڢZ1jIytyjmK4(jy̐QV ,=s֖{ ':OWr>2-^Ή Յ[|u8u.:=R剩b_^Э0MNNng[>Bt ̤l5 $_>K^B )9+Sgԉ; ˦>NJ YjB^7ͱrdͻvCkep"g* Nee/ >O G2tݛuv 4tQ=F;u"IEUT#f P0WjͫJůT՚_KZYϷ?zv1zLwvcZqe ʅO6&-thv[oMV ǡR'9 Xy:c 8NX9>>qj1gÛ[M1J"iKe[.Rٔ^Z W*R+WR Zc<l˾G_ "dF?۽w^[/լ8'L;Xu%YY_momk {⮷.6M 20O*3|if1:_*EgW uaO+Ucccz46^j4gp<~DLl>y|sl֗ppj_ctW$p밈,]x]IavU~WT3!GZM2szy>;Z8%"r}lf~n5g{(B'/mMRՎڣPb&e>(|Kr_zhf*=h檘/Yjzpwv_4ģDeN\'te+*uU6<>udsuŹޔ5s%C>bbGG)ZfrJ͚[vv2DF#uU54Y;bN|PalouVlۯ_yq$:^i0d e:8)kKJCg73[M~Q%P5Nj(̋&oGlI+᱉eRuQF[7  4:%pzУS{n5g)"(Jϫ7LTBont.{o._ܺ~yk}*/rd4%3 ID!'!$ ̷G`2j)WM3~M&[f5+AA>Oi& Z3sNCf4IIf<~d8I[~%򃧧QLpnů}ҵK^xJfb@J"QD&̥?诳C!37>5wKʵF)91vxVUujə!VpO_:ߤ2ҕZujLU`o`'VhɳX ׏L>D~DQ< [mmv;vL19/ (%Ǜeֳ(|%zh{2'AUjp8p'L:OLY4třZQMo]6 'هIj/_zuwQqϳgTI)FS\zNhl$W6I.X5pI|=F?jT-NI=.h>8JڠY˖ NX;>JȲɈrD(%"jPы щSO~bjz&wYIRv=)Dg3ӬI d-$%sJ|~f%g/?ʗM260B$"-֚.tdT |?jC4\)D gƺ)ӕiU{U&5X JsWΘGU)|OJB\S"L Ձ18(')bbr+M]SlTj MhV~*}f~;Z\(톿_ZD{R9*43~~ٵkݠ'&J)ɋjxL> FlfȾ? ~ K5òmgx=[\,FQHHZ1+9FD8h8?`ʤ\H(T/U$9-& <딿}yΩ\?{3'OONJgtOg>qo]Ο_zUib٨\|.,j_zG[HP$Ϧ>2#1^/{A2 Z2s?%~JLAH˅JIE3c}Օo|߹VM$p(i{[В<~: iɮksTVZ2h+8`'IDF2U JTWso8#S3R(zP'EU Y Tr,*}YO&^'۔M-S"=U}7^sN>ɣ=:_27SBDSgg>kWo)z,NU2PHH6 'z暓ɈHvӰùF{)Y ĪgȺ@!+&OX!Qq^l͵4Iz[(ОHQ/|囫'>#F1~(qw"&"5NM.|3Kw7)/q 9\z/UGGcQ>=OzE{DAe6U/h<AC>'}DžxũW)c~Lh{#s6뤪ꈈuz?_>G~dѧiz>E f)^<9xr?ݿ?~]QG*:Ҩ00>0UǕODW%f6l|$D/c/|ȣ"G[y9E/5ΔGG^4Z2&WR.UrV.W~M}|ĩzyIm%ڪx>{o]{oB:KF@d d)+\98kM!Cƚ231[L Hom=-PtC/j>nW6 'ÍRC^?LĆc@î NUDT٪[R^Ɨg,;lTGg4sNX@OW=ibH8.A V2z 0%{7}fPbO5Q6=N{r̊D"Tvbxyt^/7JFi Kv3g.sRZk!=]*P$}Ϸ/e;fbF(8`'ݕ!N?9<.{vab^۹fUѥcKӳ5߷ loq|^2 fn?~䷾kNȆ{Ϛ}lG+%tiZ$夗,_`ʞ9MOW? &gc&6,N[A#T83ȓs JTU Bt6='ﴂݝ7m\2>kK\gT٤d>}'G\< %Mgٲ kz &5%f%E!3qP7yǛ0 +3O~ȉcWC~tes܍k;7/uVjT>WUҞQ nt{+KI;rdp|,~ 3a%DDQoj7t RГ`j;ijG6=oܒ}K$Ӫ1-nuwv:W/m֯oo)Ke 2f|U @$Y&N{ΌlO(< l.M)P`[%:Dw韺:NFcYD6Wҏ%XnOk^|akシJ\SQUaik8 tq6e͟vOoBQ8O{(j&zۯ  >߆Krɡ,l5}vijZ$u_ݺu7qA'lKqp$7W)nӕ]~Lk:xN^g8B q#%xD ^`9rD"D$"ث$[rᓟ:uq̼_-Jۯ87_e_M+p}cũ:u"z@V?(e$V`IEsS%J+^8jcr∢ U!f:ԞD^qٞ.ߐ/xgWk~?~9xe?KThk}oxw_pXK 3q@DT:IRYl<2kTI|;8dl4YUEerÇ H#BHڰ*B̷YvLk׺b~&%d_IzVIε+=]qq)[%$54lˁ^i2}ʌ`OWZQ:TC%{p<3DN{JluqeʅUWN}'Nos&ްn'߸V`PbV&ڴ/K@y$-Xh1< 1&$% }\?~h>ӕS a|OHBo8lDG&{F# nӥĆ\(._="wCWTVG[k*Z' *$B4tV$TɄSIeoO1wP6>]_A%f#6haR\ #%NBcZZGYIG3vv=c$ z7g|b. faKMG3Jݢ= G=BȊ "h]9  `030Nv EyS(t'=]׆o?D ;_yů^/5Ls'%$B!!7/sHs&(|T=8ddOW1kR?ѰvJ9|_TQK"Չ:kKjrDtE7ly{=ON>V?Ue|B6\u NR@8IMؓGܾ+5@$sbNnwI:(Ll Q'u*>L'_ Q2lB6HS3w{tEtLs?y:ߗpU.sw׾:P``$[ B4~hMȁ4T@rͅ$I/&~nvDI-Ga/` %5l]iwܢvA{M( lxg=_<39]ݧp?~7nr|@C¨ޭ~OW&p 2SR]6!uǛܢ+<6(%fj;is5pR |o3lpՒ oU6\ cųϕi0}O|/I2ezr#NϖMFt%gl<2}Cd(^cٲIi8qpInc8H/#ITM;m{!$4TCCOMMT}/؂g=eե$+d{[ J^&&_p8;G'JN4>rH}_I8.2۲2Sn( `pIDJm l NE7Y i[˪>{ή!e  q6HIo90XtEuG8DqyN?bD !sVo۲GĎt1| >R"fzmڊoEۻ*w '\.)Eї~놾oI?elU_in_ Q<8G(}*E''$$D]ڧfQ/XYIwz[B3I '%ebf CFUݛ"B4ӕ9!yL"w߼4 .pٲ>]K5b3K5_IQ.L4EQسIYE6 [!L]f2 陹mcf;]Tnڛ|Ei!aOwwp=DK+eJiNET OGCd}l2;$w4(|T-L;6LJx-pP?W񈼶iۖ=t[&'epu*T{[a ?uEBY( C+ '91jL#;̝o2= ϣ&)`$+ 6H}DdtTu6 >KOblzO;̞nvvw8j*VaUIŅ3==3{rW궷B1~."̑h1+h2k&Sf=]ЈQb2voݰ=vnQ58 OVfnZ)n__=]i8IBZvݝ1QIN7/vzmg-{>ΆM/.ͬk?w Hg2LMx0&)&l'ӕ?&FJteخ Ō.`GP [k6&fwnA=] 'ѓHզW7_vDGfն{7Ϸ@ƲdFzBK]={ +2ھjc,ICH* ?NՎLY=n67f$O߾wh {:>WJcUQ6w}ͽ(iZN?oz_^ŚK&eqP'$rJ{&qDSWηgӏz<o65n7߷M Uܸy7__pg|k܈-PZ}e[!殶&!Hz!wx(m^ڜ+U$~q"'/BؓRՖj߽׿'&GcW~T(o-$u٪3WO>C?__}/OAQ_}LBKfoΛSPRCfx8DO_DDJ|e- ڝ˳J ̒QT)Qkߺ—-=|G<6wti/<-܇A&ٓ/4}عzfGB IDAT{_;z&=v* ^yDœvZ) DR9 m߸ܜ)7ddn/2cEjZuIlOzƮuW^%GŽ]ȖP yy-uΜ#ܿ+Ep2̮P/٩ W_N<̙&ꥊ^X4{8q?5NMTܘی'(FD|5nɔ-ۭF3' }ƤQ:m-hlLNk&C$S6~t%KT2iU~s/r駦:vrR+2sB\t=}zSF܁IOe7Ȱھxv7(Z'KW2W)YyJa=_Eix_ '^a*N1[ "qw?{WksC=lU;Kq$?ǯapBomlԲm֎]g(2'*Y*jgZkkW[R# ݎknpCSX0n_|e[s&٣X-eÆ _{?{gWY±lpm :`cpQ&42hKaJLm2P.E2gg|p|B0%N,!)&C]mU sQj.:( w )|I#]a@f{Q;!ff%2դX[*kKK=$)ljK(Ll}to]d$F\coo}#mQڕh.Lۢ iPON Ƥ1F_2v6!9ٿǶawz=EJyTw-&X/лwY0SFDb]9UV9\ޒlHn&I|WI`,~gK]K^u52C63+ʰT BD S320s##*)!߅"/,٫oˈqn=-/22Zk:]G.EcFepjCqqΤ aLH<ͫ[㛽jJoYp2#cLdDDFƌSvx0*ޠa'NtXM8<#E*q#jNIzM>̐TxIaza$'.I oIu$SeZHM*!N*q pP̐ON8 )=|]J ]TT5[Ō$ [ ]mB3fLWA2T\F2c&t'L\oj\TV?iAtm5BʑMN2E, :vwG_N$eT{Yt)31 [h1>߅‰qRD쎽 '(z91JN ''NZ^ى({4b^CMkmVTNJpNۛdzYҔFFFr陭/tΘ囵r֒JhOBHH_Sa}pH+ၗL#ɴjhR]s\Ґ$HfHJWAH.l8Nh̠ܵDR[c7_ΉW+T8'E*BRJTҽ|OX2bS{[qEV iTS徒3I=-Ffd*Srue3WU6TU"fPQ썌 %bTcppA>Jc"dL!u*-`D\U: =]Y=SQT2f1ۛdNd9'{[j^k+=M&4j,q3z*Ȋù4]fvE6u);*JF$|0(4j9d:s ͳ\وR}F[4H!*--5ڃ3 Tf7ïH[ɉɀS9)' ;hcL *]&ӫ͹PmX8БR]7-2;֋(r&(5jǨpZ['L˅& ?>ˆ&;փnnhJ=hN!+ I(Q><"*Iwli*\BP~9Qw O#R ICu_s8]7׎Ae.m׈(Cm)ۻSJϷHcS X(DTPs}B81jN&BUNBh,\kx2 Y\r( eYP?1]Q9RJNx03#=.FL2-NdN Ěf +L%TV;w8SP/ 19S$ax.O3J_G+>V)HH2MGHt$DC:BEcM&?Ƅ g$bR!1-]{ۅ4%IH S,JJ!U24=E O/r9ҩ2d 0Έ'؁Dqp'g6AB6LވqRa`B>(R#JvRFv]T:Jځ^2b WIRˆv%[;;\-IcxaG$9qƘ$ B!L/'ŋM/]cIf.uOԔ3o)*zz%OK)=ѨVbLfLפ7ɽ! R$N3UH;m=a#hcv7w 2%#NjQm nu`:B>(v)u$8*q,>4io vx+K5n_Ulʦd*|tИ.)g< 6SLow#ٖ06fwq$)̖ɘiCTm1]@AG48qXG Jpp) bBΡP{*} {nѨ8a5Wt.8iBuFLA>Mev""W4I2 F{~ww}*8W$)LgqddK"F S8q"R`_@WNm8#S2bӔݝ2;MN%''Q3R QZ[HzEǬt07cLHS*IHb(Cs{^GCsUMq( (?rGʇ͂N!Ʋ3 '1Ƙ"e&SF2aFRtD\e4d"2TC -lP? MN1'')^™B 2>(K9) +$)RNije:5Cul^+8gNsΉBR))"ez$nDF4GBz # )qN&bc"P 5qɍl%  )4#EHP&Eŀ]z]~y8i Lʾ6I2 ED1SjWviMkܦqg8$!23TLDL4ɔ$UR5i#ds!fJ,2<2?τJŽ$S I*H_ 1 <}vr SxUi1)$IM0)dD̄g"RHSr+$Isb1N cLed\e6^0kEe2#SJ4g#!Rp4 gRGBFF2<BN;lAnU9*SJ&\dĘn*)I(7>&d(4.iH]it'ts)cҔk  `3u u2םBD qMB#tjTM64l*s$p~|$~ܾRdd6I7N2(É$e$2 OVJF6M.0.MJ'Y&"RJIQ쎊$$Ą$4!\7d2}$AgKfNe'AAexWE z^K0SH]nr"eȭDGz(#NFcXC>ED42c$pĉ|֌xe^MS*1ON y n?ݬ]=ᝳ'l.?&`8 '19alJ6Qb|  ('P,OX @@>b|  u e_e]wCԔAxX,55i 'Sn w}ʙ7,O_'GNH,/s]Zw?ޑ>x5p#g9#XC /m,&r|ej|u4yl}~}-L1pA>rR*]o\=Et_+Yz׿eN[o9*q[H'߿9c j+L]Gb8EY5fW{ۇ8䕫t3<~?xr_B$D e弡i3xWU~ns₏|gCwMWɝjNr"|?8am>7t񭿹߻{mƿG'KtͮQmMF/uSZ߸{6,ɗ^v}[t[ze侑ph0S ` {VuRƪDY?SzMӞ~9d>k^~Ÿ yDFoy-½{by\>"2BcxPDO*LAVue7~}}9"лgVy5R].êDβڒ'E3`pb|0pYR)7ee_cҷ/'""fD:}DV֡>NZI:I""ABJA9}%Qb+0MEYJÑrNc2_FtZVM +R F_& |cTQWo}:j}cjj?H+__G"/[pFE 7 cmd4shhӫ_rR3Szz=sUϵhZ|5Lqծ;+Z}f"z_Wd%S]~"x{_u}˝\RwKﮕzv\M]s{珴DO&Sdʘ4Pd¥߼/:ՅSxX @@>b|  ('P,OX @@>b|  ('P,OX @@>b|NiLјMu) GL%[?[^f3TL|tڹXŚKX^}"E;{嚲]57եX~F)8 Sxo /]qb|%LƍHaUDdb*vpK/,{=_υ"S[0S qo˽>ND4ӻD?MutUZo))DʒsOOCK~kjJyĹu:!!o^wuf෿Hui_]p[s9Ije&nuWx[UF";%O8r9AN'pr✱pz@gZoEUo19c˾Xyེ7m/-O> ]#|ይ+D˪>I;cjJYye7~j0;L7(]YG mD?oŝ 934J̇G_)տ_{?'CǤ+RȼvG)o6|EJD#97]I#n]筣/?8I KŒa[v#\ͣ{Hfy_7z784ׁ1"R'*m#_e:|+=CDgspUFԹ78BT 7Pƶ. &nj- k.upg7̓xO4o}_3?8?ʳ?_~C.W6u4^V{;Ω z}E*Q\Yܳ/%vg =lm-W͋Dkbw.6:K?O^m["u^؉j/pW`~<qO'9=$FD$I-c=Wj[InU%D Dͽ³Y}z.uLѸ7n" vJGD=;:gٽ tĴkʪ7z ˽2pMXBXVS%@҃]D3nYVw̎DtѸm~]㪍H #CT_ mIĭ6۟JT)!n]WV\ H~W/Z$AzӃ~0 !2f)Dj]?n*_[7|Ff)zjŌW@ xPjzYYȈYaFx1;CbDD+Tzͨh/Uo<TV\ˉH q[Y5Q|FT=@f`>NuljnQWU*=kW?F29 ZREC%U*"wp5Xȩ9d/Wꞿ NDZD|FuIL%>1lg~j*){֞6}q{yqiفV-]pk[J68kQ D0 7.O`zwT/ b/u|c hFlii00L$vaɺj%}LhLʫ&|5|-DDpc5UKmi±JO{Ō<|ZkueD<լꊊy׽/IDr6g/0ޔdƶo x2mkfMoQ?Ғ 7>!>ﶚ>ǚ\J4,}ˈw9&$W݉Dq""DӍWh5?dv##Ξ 7¦ҫέ<-9xp+(1Q{ͧKcG. Bx}jn ?7rUsox{kNs~qs({~&S+D_i_o'z ' 89q5"hr{+.tzurR߾vu#d8N_ﱛfǟZ qVkVʴl)vNX{WG]FcVLz۝D'JY '  }ݝMg4\:z¿wnɝ=OXL뙮׏Q"1EUpB>i-y} X @@>b|  ('P,OX @@>b|  ('P,OX GsW/Ѧe˖X:ުdEUctV`rht2|{rNT]3kNE@g[W -Hih"mi鏋.ܶSlTd 3מIGt?8(klQ)fjcok8|ӛfv#{85-ט4ҦeƁ]CJs[T!]9{7{ڢ|' W&7%Pv"WVj xҭ}MTufNCۡ23 %1GiC T}_F~l} \7̛YPoDa]D+<6ζ@F1{iH.x~V}[`[{OTFU4֯{"YiIj{1Wik(2B&  rp{ZV#jOY} LopWzqVRC "Β[UiR)6޵kga"w0Cze 1%W^PufBQK⩛?=w@B1˕scJ(DDd;4Ѻ{opTY42?wŤb 39<};y[CUkJߞma<.)cy5cy`5U;}];[ÖUgwX"S2oBb&CqZɲ=[#nOe+ 0 !ft.8m#3ѷoTqEB# $'X,DD:exS x6*'2i'J+ԡΨ.d 4|=wͫnOd'KH˓Ж.H7xehϞ`F%#~ߔR*vӖLd2a/F I_\PȪHT}I(H13 Dũapp WXIyS7oqze,Ӻu{ZHn4#ָaa`{gϛWsW0MJ҆59dm06MSq~hݻ+iX1q"iZ:ݷ% "+ =7 IuRȦiStY]"Jd;4-dcTUF!g[S{-52LeT3' d$?8S, eQw(Q*d=%_Ze5-?bu+Y=P0!)ɌRu~;J #ӷUFh1)fDH4fr9E=D:Lun3:ey3g鬆I妡KMHU6g2i3ؽ-2z5G^4֌PHШ/n0DdlB7 "شx#f#W$ՙ$Nj JM1I\gҙG0"bru˫e{imNΉ)L$#Z>\^]]b&W5UN) w$NUϭi*PCzycWcTGY+XJIz=^22 9*jc)P_[1Ƙ{D].g$4ln&R^G4F8VzUmeZ8HP(tpzj+<4~,ϜSI9nɪV䷚@P+iOU;U{ZGlٞ[0?MSO`Z3͎i$#Ddڛs)SDȄcY@K`WLl#0ip&޵75-;]c"m -HGْ;/\7fa F"jhiSHdb-0ݝS;v$3--3T)4ǫQgNkHgN `pάe+fh:}Hf眙KVBOZZǙ|BiYMi[%V:O.]MD_]}֩. @ԯE{دg{v!'w #R%2w[7k,EXsg8) `N̓dk疮,]P,OX @@>b|š|s!缹wKAAAAAqغ[t5<,LQiG|PUaナͣ|Jyy tu?9~ƙGWܧE<?CNIWO|qr'KGYigQ*{ ?ɌsGc OX @@>b|ű'^^w^f;7Sơr;>[fFsn ?WԴRf#pdǠ\p9V>URS̾`ё=v5oU^~lvSNEGOE7|5 xC}IŻv]#soZd?m{',pXgOkFrrgJ.8VL/̫]KO""ee跣'Dj&IOᮛJkkiW5}lʼnޝ+Wl"eV]~_zv=GwIQq忖4UPl_wD.D4̴??fgkrο0w^hkщj?w=-WΊkf~/<4a-\{Sf_76ͫs2y^i}/jݭn*S ڥU2ҰeR/ѵsOX:Om&?s͕eo+m4Quϻڿ]|gnx{߈z~;jnod]pJ> ) Q;{n'#Uݿ'Mlx195߿Kj5jTCOu}RhE~bs}_ WMIbFI2c1}$r(gmrjn/43߆o53,lƖ$ 5-*9~gN"rjIa*s>'ez "Vo[vՁ}LRcfvzT Fo)r\-)'ε-+fz{z=z~@O E"! {[b= RUܔ!#bsxD1yT㿪b媧/Lb|f~W֮rI1ID^8h<}z*^h8J&cs>}x֯wH) 'Ddd&(apù_8~{L={sQ2Y"mC1XFgυ?Զn(9ϵúBcսdp29?|SmK߾fwp;ҝczZhpED뫓:1_~ p;|s]'>/]J7E i?#'Mb BtQ 'om8aィd|p 9OӧP$dXO[|}nrpʚv'қ{VMCe]z^}z\M3Dx;oc/u 6KιƷֳ׷k. 0MmI~XpZy?}U_Hoo!""%^gsbܫߺ!wW|#M{ xgڬŻoZHgG6}uzoz>:]G:ZUEdQblB@NBǘ|>sssLJ5:3J/> fwɉ ;-!g?GJ=a'Ҟ~ZjӪT6VUHys!P/C`0(N?So)F&U^Rg nVeztJ$ =1:49;Q0HD@x'B!bIufB/Z u-gziK0 flz`{~?-hr4DT9~u-PS>sa/P\ZuGRoojԕf2U) h4ѵE%Qf}0HB!׍qxo{׫QuMYaM#${?T- :h:m8B b^xaEIlm9,#C>(MJhk ?Yd ώK66 ~oqA3'tyk{6f+_go0gl:+Ѥ[r}3CӵkB!Bӌrdx;~^n~^n~^9*2+rhmd?F.Ѣ'>5uu͍qSŸ\.r:.:wԻ}DVD!BHf'ChrZ٣%;߰Se(3ysۊ!Bόt+&&t9YTܫ~oL%-%nD{|Σˤwfr,3,%ǝo14v+du"P˵z&Z:ucBywyN7wp73+3iExK-:=q7zQ!B!> @bϴY#0?GKӢղ޶ZXZjjGJr~H4zE\nM PzxӻnlMKwxLt]Pk-w&gfW*G7G{VqK9<)K4+6%F-;RD\vq#]!B!#OtIs2MZ=mK/ג ʲ_t9@R(cw7P c#Bwl6N0ϋNojoe({]ltJP[7hJ;opȻ^Qc7]e7\|,`?q()["S;3|>8 snY)!By t h*h|FX[NUկ>]€SϨf|OuP!ʫ:vC9 W^\f8%nTVbՕUpRb8~ m]sN £|g 6̛ョ|LQ$fk<+,(5XB3ߪʮR+oPV( v^vn_] "ܯnݧ4+.ZMy\EӾ@EB!ey9EVX~]#$'>վJP~w]qduZ#{bg)-GEN5]?:/OjE.]]bڜ* Β:V~.8p13ИuxסɘiѿB 45Dw{S\RB!W?شq :h&3:u-÷1u]%1VOϾ:' i}QzB!C 視Oaւ괃2_SW"B!Bz`®&rs[^EB!Q'nYmuGzx!B!Ow,N]o4\e5 >!B!5bwYGn4QFMB!OO1W):~grSXDn]= <{8eYcm ]ϼkݫqO"ByrOLlߵ<[~\ܡSnG?;or.ć#lhxG^߇{J!BHojO,qџ)2Ѝޠf͟]4MB!>˫7Jߘ{J\~; _w|lj󛶤M~g(71j2Rދ^Zvh Gc[}aV6!X}_jkڢyRKNq3~O܍ۨ[晤(vqK_ 7cfhmi*N?rT^t #Gz 5U%;Sys9 wN'> 0L=:{leֲ2u:Jcvchl ~M0Pf0T&(,"9v\9@zzӎ `16"D}fMzT'";$P'P7锠@;v{d7c͚ӿץXsoJya RѨ~)rLZIPl ] \B& 5(2쭱c=a(ГeG7YVm@\QM9),eVgOoQzo(&gY!L}͍67g=6ng k>t2YߺXo :bml zLEZ&KEZ+QjiQ6Zf7NmӔOKƒ{2ݠ)0y"Xa!"uF_y~| 3Ĭ{ݥQ7'$ܚ8rQmIUnSWFT<.Тi`+P0<(]Qcý\-y2F)ǁ |/eAgU]V( WWfֲʢu Ի!BȀfWGFY^N)+,7~b߃Ƕ7u<^Kɝ{\W3=9eפov(3pHC扳2CTl9MqˎKvj$Ϻ$ۓ8łf 'i/1@SW9N*ShƬûeHLݴ7ZR&[t}b Q2P&T~.8p13 $Z&( |!m(e !B!\?85eԲ#z[Sů?]|9oQݻztɢ^^ KWG.SPB7"f;{Gɳ\%B!Ḧ́Wo0+s|#]N_}_+{g!W?koXz~ӖI&FmYfY6{kB.mhҜl˿=*`? KxM[4/[j)n`~<.!{iqK=cfq8UGk {{aHO[}gJ02oT1n֩gVf]ٱEKt>ʬe duF^w0{s`Q>[z% & nQݩ4^hnЄPq,3uʜGyOtIP+I sw'! O )UJ&-]3ÕÁ,@t>Yd $08J#,ȄS挷25yaC+r̽c7e?5%1]̊S&޴B-X_u@Sh(ձ ȭ .TqM6:%(-9'tOs3۬9] |>9vG/ 牜r-~pI E!֐ݕP ,d?q()["S;3=Y&{t3klev a%ݔR; @Rfa gISrzKN-`t=53%;Ѕ*&XB!@Ќƪ@0g^_5^% :i<*`TBcCcXpm\q RaVVjG}ueFܬĝ}WW*\n&+(xӂ` IDAT%Oӫee4ujuuȒ7ev-yuUe=jAd. R*T+ ["B!'f}SZ;9d%$lUsVU7,"ܾDe\`Trn8S( d-uZp%@5Av0]oTsrq?Y+d /d%IS[eoGe2s;6h+c?-%Vno2z4B!ƾ?ey9EVXz~ OYZJT 6X,)C8&}GYDOi$nMv>̗99p93 ЏӾ/Cc B!=chb]W>ZPvZ~>:|!ɛX7sI1{!B^{v5yK0|!TmQ#ƪȣD!3dPڍ2 ._8Tsa it#oɋ7vB!e}%ڛ9GB! O#b7=?M7&޿WuC~ׄ-۱-)fߙ9Mڲ̄dzmׄ]8;#Ѥ9ؖ_{اUmߗZ!h^ԒS܌w6jy&i']"Buz͘;Zqӏ>@ ȑBMUΔja9eܩ.bNݬSϬh̺b)]Vf-k S4:f*[?Ɔpeh cڷkt@ :=O2?-Tߺ1:Qz`ޒQ-B!0U{yն/{8 y Dv \Idr9$ bV.o^tsSΥKzϰekvje~8wC0 & nQݩ4^hnЄPq,3uʜGyOtIP+I sw'! O )UJ&-]3ÕÁ,@t>Yd $08J#,ȄS挷2xL]Fkq8x]֋a?u{\>YTd6EOsN;֖lbkWG!"MDg%^d)ɱ;zӛv\!n6hP=m<>^:>~!b=Ѕ*NO%4g|dޓ7Dm֜.o>œ|;|Vʣu SpRտFDDNc?fzҤM"`kOJr`2_8AgoPC,=R2mntOxg)=QaIgT3W:(jU[P†+n.h(r hsR+d-V>+0Je5f%컺RiMB>m>yZsZiz,}ZV pYG=_~,uA|6|d?A3z=+߂m[t? T`.fLVbҢLumn%^SټuOivϞZ@4dIlsOyЙWHMͽSA>Bm;{eEהZ!K }!(7U PV( v^v\m(`p0澺0WZAqE}.FYEoUeW7J~Dt: `kKji`!B^"v߮84ruMYa#$'>vF\Q㵔ܩ*+q 9mYJQSp~Mf׏2Y12OϜjfۀ.oK]v|\JugW%A~M%Iߞ0ʼn/4F.^8I|-:9tjVB4fu(F2fZ尿-.@ 2٢[2*sās-oM%W~\ݥKB{7 ,r/>)SsO弡Y33{w9hR{PKCG!"p|lێM׽nWoyc%{;tO$bXF26 q/6k/-s2ߌ&B!/QwU$}a]> |!m(jۗw=ZO ԥ__ey17'w4YMB!-ﲎ}D1Rwr&oَծ7mI1QnbԖe&8l}&A&Ƕ>mC ?n ״E"|mf Q3I;Q⨻3>o7ڌ\U~鸷FjJ.wT 3)NwsfO|fE`5KgO2kYt1W1E46̅{?e&(GsٛVox5K[ñ069hT/Qr:9#Sj'Y,2<]o#AhwlWpDv#YvFLtWdw'u< !Bw}S' Q\CWulq  1~^:JX(ՀJeB PYvk^<|iAxԒղ{kZ5:Ydbh~գa+y|XX:P b8~ m]Socd(Se-O2Y*Z RK0յ<\2<0 0rM npXS"B!bɘ #{''ރ촄ğ-jJ*X~EH|c\`Trn8S( d-uZp%@5Av0]o?srq?x DŽEbֽԨnMX(*+#͊ dVSht2_j[>IҦy#|\GTWL綟[ 22T3Weiۛ{=9/$W}0rw@]d)e퓵B@BQbY4U PV( v^v\m(}@<+,(Et^'!B1^? \'`W,/1ꚲ‡O oW,WJT+rc f5雃?ʘglpEl' !B!pGxB!B^kƽWݫZ3ZMZu ';34hB!敻~bd?xe:?} hx !B^Oj/=?]SuWnJ؞@d'u~*ɹZ rH8sAb!B\zx禜KaLwHpa0S. MjEܢ),=SirФݠ 7/xMY>g)9I'9L 钰&W2NB@4nɟ+RNOLZf+=Y}H`pLGXfO =oevYd^y˞Gg:c: N1!Bk¸Ol"b?]BuMBHǜ| =iDžZf3 E=uQcA[({]ltJP[b@swOfYst|>8 snY)(E4* z'rʵ1å&n9[C~2vWB%. B&ġl L}>{kXτr dD}i5ׇuwSN'soDxJ$=KUƓubm6ʫ:'~{` Tap !B^]z.aIgT3W:(jUw†+n.h(r hsR+d-V>+0Je5f%컺Ruh7A^@G-x^-K߿'.}GV pYG=_~,uA|6|d3z=+߂m[t? T`.fLVbҢLumn<J]ÜLF豿,ɳ`2R~F{]gnRz04ńB! cOJt+pEl5}J[n}{Ss4DT9~u[kl5}VH_:J,듦 2 ߎ56Εْg+mz(p˞>G,wSsL)&ByMvu=8QSlk M} 94:NUY=.PhsRZ2k7~:y}!YoVhk eǥTwFyXgT\ SxbAk⅓Xr)ɿCFNpk)4@c]2j$cEn - b)->Y((R?@8wҘVg-ez=uzYsL)&ByMp|lێM׽nW/c%{Ʌ;tO$bF26 q/6k/-s249(B!^eWE&@B݆ƒWkAuk)݀.s@'(B!ge?܇.<e]Nì]NQ"Bk(f{e\5F'O By>FY8Xd˾+pEl' !B!]>`Q B!ƽWݫZ3ZMZu ';3 <{γ7o3[6}=!|!!Cu3ty:!By5rOLlߵ<|LuѹC5ܢs\}%#lhxG^ُ$By^'Su_eyJFLtgoГ%|:-M=B!/q'Q{y՞C}_+{g!W?koXz~ӖI&FmYfY6{kB.mhҜl˿=*`? KxM[4/[j)n`~<.!{iqK=cfq8UGk {{aHO[}gJ02oT1n֩gVf]B.d+5KQ{߭SDc\Sm2{4G :SVysB;oݘPܠ?\>}{M\kH]g?:D|IW=y!BywWU۾+-Il,Q?<2Ts%;p86BZ7zM9.=Ö9 e`?\,,Ԋ6E-;RXz.nwzIgABo?_|S)sN9r6_=>@3%aCMׯ$e(ݝhܒ?-W:V)t W zLd--(:"zN3ɛ΍—ggV 2"yO)ܹgLv-n ]SbC|2d谡nP1yI!:3"zKR(cw7P c#BwlT{8xx}.Jul} (r+CŸ{b U|͟N tK,hnɼ'v3۬9] |>9vGL^JU"=9ZRKSW7 C!?+@ˁY!PRE>5vgB9 zLf">Kʴ:J)97"{m6z>t9w}[BaBYP78B!3OTD0u yU̕=ZyUǰʫ 9ꥮ Y*RY Y;Tvy,uh7A^@G-x^-K߿'.}V pYG=_~,uA|6|d?3z=+߂m[t? T`.fLVbҢLumnY+d /d%IS[eoGe]*ԍZ>T:kZVUvZ@CC08xVs_]YQ6t ԓ5a\լ9[pI!:3+b{p@,/H Qה˛$m?1Arrci4u<^Kɝ{\W3=9eפov(3tPC扳2CTl9MqˎKvj$Ϻ$ۓ8łf 'y\8ga *aP\jڽoo?Srmimk[ uAe4 *$!IH2? u3yǙ3x+4m0VTڿ#.N0bRIc}5UZ0bTэI*Pg0䩿.]|K#(+HQnw`ЊNVA`٪a6qBxez4^L߼r(zwB!WF`g7yuGxv5:R]g|y Ýiol:& 60[D}n_,gϹ_ E!25cI諸.s708CѾ'V&m̗:&uW76^P]qI_8l"BӮW'Q 'zv]gUB:y]B2*fǠ^8?k }6B!iIPXdof[?Z9ރiw?yB)7ּ2mؿ-ʱX3LOڧŨ ݕܗGN~v*z">SWeK3Ξ^o4o3B!0]tqk6Lsbj32_{?Z]58v_eJ|{__{Wlrf1 sC}yfGdz_^|H7%؞\pxWiF ؓZxG A+>[iiƱ laF D)bvށDݰ|&ѹs%oLv" *ڢ́?Ng|ћ>8% _ZטsrN=p)IetC,\s<&m FٝG&,"P[̐dVyM jZvbq+|y}]ၽjyB!lMׂh#_'mtUNMSǽ9͏8G^<\xbzB ;rJpv|gcD;Uqr彉AIw9wusʇ|U0 s3Z-љoR7xc}=@T%FLhl:vq@QV 9sGb5$hpC8dѸ 9(f >kH 0aRG(,M@4!,'.^!c'x8 j ,?O_Yy$Xpd]r -ܘ}T٨91ܑ`tB!гe.'9*\fE? eNr!  I=vbĝ۟ޱ]Rf; j񕽻sھ(iW@cC@7ϒZE]̠3ڊ:IK>4X[\30*:OaRHk7:K--jN@3F9ntNj>fzޒ @LFc(Wfa/p*p!YMf!B=[Yr;ở7We:`M~i8ˁvNNڜĤVhP.н'+<&ko\ ?)B +46hfk'! 44b9Iv]Tp#6o;nޤ˟khOر83xƪ؈9I-{>lwhnRqvf%Wќޛ:t(F#uʼn&u\62bm:EWr]%ьrhX,R$O1L),,_ Yr?xi8dõK(|A"+~OA ԭ~n(]EܕtT,q~ҤEʈɡ*- D1LFDdzddO.^jj)I1K=MK}\Ѣv<5؜ypu:Qw.}G!B! -mFS'h^+HpgZ l:& 60[dsD` Ik{KUB!^l }Ybդ_;sC_xBi3t%FnB!^N/E}R>9</0ceTA%/phz1yBKQV]_l !B=ĄB!B&2mbѢ=g))G!\9O'փCtwpڕ\*n )prSޘ-@^ܻdhvݧn_?r"wf/19MW}~Dqܦo.>_{B~$O|g ݈ qhg73`;VqIgCm{{h{#y#EyYek_h4ZG@]|:׽wEtD}RyavYI G&xl}BB!?x:a3 @ЙtzEqҡNJ{otWlIfY.Z`c-?ꎯd2 Y9<QI9/ٽgxӧExHSO&Ϛr:'!B?0x7$Šqi=n^8v_eJ|'9BuF࢜<&va|/LH 7G@ү,ވ{&@cʗ'YsQbEwq=&Λ'wYzNZxko|AWpIu'Kw>7bؠ_ \kX_IcB!^N^_yݻv|s$NmjeziKKN[,~RRX8̙vS2ƿ}#/vDΕ<"W1مFxPG|5~oܯ-ɿM4|4S=8/dٛ UIY5fܡ{O8̇xtDҫ?z;|P[ p:O" *ڢ́?Ngˌ}*7Ip||\A]WL Z =Y6}lo)II~B!^R&~7fH6٤5X,RR}vm8>ҋ;9>Olޞ\`>rB!}Gnp,oO:y+qo*7gMćGw%ˉ&&Q4JB:Iͪd?X}E<}Ѹmah܅ 5rGb0@f[3Yp4"U(؃fg{0z\S8VPK'YK9Lù4oBo}U%6p ,<۹T ްX_t=GF;c7%94q$@sƁwd9Cww,G(zTYUب|> ,. IDATZXU6}ߟ|hFB!2OtfPɋZX!VcxR]}5AzR8uJ>;G+?&d+0Ԩ@V-%j92Y %/j@/|-kkkgvZ8>f; j񕽻sꍎ^Zƌ?ʌTV:y,W$$ @@0APƆ< .9K nR-!TT9*yr _+G_,*ԂaRѕbkH{FmVը8 P뭄]Y%ڎ=?G!B/'܁vvN=kmDIKLnkE={x£iNG[e&@R x*[[A[ uchvb@Cc3IzFc>:bhuʼn&u\y6!?aI B!0B!B'!BB!P B!B!B!_`}B!/~AN^oߖ7F܈q#nč7Fht#@(z|izF=ƿHtM߳>{N=OSg_l|_>r}q{y/R_E#'4؟ۯw}ߐooӞ~juM`yB!B'!BB!P B!B!B!_`}B!/>A!BC8AN sA%T(Eg_aA!B{|}bUmUyFSfY4zVGrZE!B_XΒ~M;upgޏa!B^֟,gl}8M?l,uoֲ0'?7o DŽ~=1 z'Sz0!~yߧB!'*QUץ&dIpW^ɐS,J6SEgwKj&1C}@\%l)FmRVsO~K7>3t?H oژAGpB!z9<>?Ms۟XLFV]ZHȲ%*6Md? k\憖OcNekƦym& }ZùJXeE7F!BW_(ypb=AQ^Uօ2/Խ`Г ͓VrlA H׭*i?U$ZƼ)$ZwJ㏨Iʖs3eAk{0pL-`/-_4v*j=1|{pey+ H9-4C&?wRnvԺno1~>ՏlWZ_w<͜mӑY]q&ʻ!Bk'N7J:o76մT 0*kن`>if>۔GEXVm-Mg3(霨9z\ܱ $%TN25KxT;cfr;wYkH7M?L3McqͶ@4'%M4(J&>ʻB!zA<>7k 촽wHZBxq2?HEtϿUHӍ_ZcYyY*\Y6CЪɻ`%4H e[}{h[5>SHTAOd[Q7T5{} { ̌Vn'.&4 uuh53!B _e+W! .vZϐ|q#f 7)$-lD qvm} Yh(ʖtMS[mwER*uQ ֭e.\'[@ss ۊu{cM Sjl6Z{:B!B/U7`L+suN34N4Ȗړ mok_鑗OYT,k<\P44ѣ򤶡fiAzlN @%=*s{nn~jk'J1ρE )%byB!^Ά.w_nag)Oԕنy) QÙ M0†ɯ@84Fu'K̍ȶ{ssێr:%6w ǂEԵj~'[^^wPx +z!B~En^綔->|ʧٌkNc=||cÕ?]ZiS׺}JJ?o9q-7|S4J_[7%U_~S:=p/WM'T\khI9fG5)S"N3짿d>_ÃWp 4\>cL7;'vʽ-|0B!zY€`mmENYks+ab6xMq*ˆZm7ڸd}죱w]!BEcrN o0~Z'm<.+ ^ij3A!BKwS70q@>(B!޿5m!B!O+B!z>A!BX B!~St:NgB!B/'Y ̅A V[mb+K.._8̐ _v~NP8u)Iy"!ŽMC!B=fav锉H]sK+k+.ei_ϗ<љ:ট;sK~"+gYq~Va;f; j񕽻sꩢYXhjjT `IJ çΒղ3M YAsbt*彜-$"/'J*6Y2a/Owj&E ;{;X#"#""#">m !A]S'yR)p$J8Zđkti 6z~4wUS,!B5B [>۾/,C8uQ'[J/(qOzGc?syt ~5뻂wUNsK%B!0V?O@s:%`Ђ'n>%yLo-փCtwtˍ7m7B!07^6 kniex}eWxb,b z4y@eˡ˶x=YO7nD!B艙ϛNIRarl YTI:%_yrρRd0z_N!ݐUnOB!Bf6mR{qW7+:zr[HA,5wz]e8W_f \F8 ݬ$dV9زѯ֘{C4/_Wdo%%W?cȜEC=l8yC{Ni9i > m47aW|:8~3GΈ'` ?ĊW}柗y##iNkjI 7G@ү,ވ{8!B=;Ole?=|h30?VRǷb@ ǒFųdKjot@Gjeo.o;{4^)` ebɄG䝭hI{7R^.ń$VF'!Ba'^ A\KOS 2Ο}̻v/.0O^ hg>rB!\nYw!#4#=ķE5`ɾ#x<.݈ -Y2+ԅ.IOᄁ܌,[j,oO:y+qowOZ˳䉩V߽| 9vd+@Qu%#=B!e'v?Jn].tt6ς3)AV }i'0j$"pڕ}wV"o>2WviKa7'Y ?߶# kk I H$Fcƾ:c8ҡYRȵ t[[1@'ߠ! ?p|̲w&+{wPfȪev r IDATv--jN@?9B!;'z}}?#7x~όIghVSy\u62cFvNNڜĤVhP.н'+<&tѺU&k2+M.(% A JK5rC9$i&E< Hvl>s *6"6bN"zR x*[[Cj4pt,_1>F8)vo(POݰuV((߳;-jm4Phei- utmqAaulk?f$:YO%ϑeeFKzP*FM$+ExdBnIdURẺr$jB!zj&Y**@،}*GZ4 ߪ}ӗgw"VEŲV uE%`_{bQ;cI*k:I3'TTi)%K-lv^hrllվuã\[R 454F_zD熜5Fקv ]B[dzdƒ׊NVA`٪aVʖ)\P;G.^|Yh=y jAs/_55!B==B [>۾/,C8uQO [J/(qOzGc?syt ~5뻂w5Y}N!B^2V?O@s:%`ЂuǮO\:yB!'&75L(hf;4W4wB!Kɔ ͸7MB!B?0B!B!Pa]w`MkA*׺غHM2E 3d×+]_6/߈B!deӍ6pG7ב0wx>a,̃~oc@Zu”RZh#|6e7}u^3 *Sʧo iЪe7.jqڧMsҋ~ܴ+f'3 ~`z>B!zLR \f|2]ԐClh`h@ICÃTBL&stC>H=K-ݎ!B2]}z#OV\ zKϖUh`5m]a4%TjgkT+MmߚgF DV=ͅygL\Fts.݉Qv iݩO .*bd 7iL-~`S8eԔ;Zʴ1+5dQrƢ[E,ZTvS2&N -@S]ms&nzɥZޱ7æx Uy53ܜ]\K})i~>'%Yg͈B!9?;9AWWb(ǿ s|b7=w~s0}?9ؼ=|PCf#p8dѸ 9(f >kHV&mXwؼJq%FLhl{UCGYH`0 hͷDg.wr}AC;)NNN,x{t7'j>4u YP(y8jss n;NIIXK2DZtB!'{$2mhTl_tJ{:5F&  I=vbĝ]R7ْ'_[ P @@$I}upFťCVk3 0bN,nA $ieL2WϩnfaQZB.Ft4 @ѴTіd4(#jӹO:͒E7#B!B7Lx&K`o " t#45x;''zmNZbu^+4(RMu:eh*5uʼn&ub vf%W4@^[@h ;69zX~1'ILY` <xɫ/JQ13\^Dy[ */\W)ieJ@}o2,M6>TSG !B1]}b [ߡdBʓm[g[¡ȊSP#u롭fj*J%h2m5l=QtQs?]x܆p:GJ5I4$P a/NPPgwj[hnIXʦZ4R0iֺH#M J׊@͵?2|Aq.jn9FxӤCfv:Aˍ˙u0kܭS2:"B!z$IY'|bҢ-A#H jM^U|Q۟Hu]yQ]vhڋu^o+Z505gIТViɒ}gG/]T}l ՅO(zhx 454ی?+%9 kDO3kN^ >6ʌLpkE*a **@wB |S4q RqH){oHImI)B!BE`g7dYpo-VZ ߞkwILk|=/t!BĄORP?m'V}W3_:yB!Q<uL{G!B:B!j B!B!B!_itz7eD!BL>f. ]'jF^Yt!tY#@^&̐ _v6yv1o[$w<=B!LX0l|.2і`kniex}%,ݓ Xי7t$<= D]`gn7F]|:׫"L B!zj&{W'&Iu\JP}z}'TuI磢tWRr_9&P ~5uC]#,?#:SB!?M}%|WGO[nkc\5&6Q/ǎL/3c⼹Q|By7/ U3l)y5P nEU3B[qfyɕ+2gQPF^zОeZzNZo:2ɠ[ ~3Ε#h{Uon2jδ~e[F-\`e-βΛO^sU^7D7ro_v0Q)^o;Kvnx#R֮^*Oo>N$|/,4l7rkz뎼U5lE0OAK4Kss+]";Qu:wd͎Ǻ>ikk9HJsf_|[K**'i^ko.i":q;N̙;y!"- sߐq.z3L0>-(ks/'S+^m w^z#2hكu'xu'>ީcj~ Ƨښ G]U]:{uv&$u}<0%W8]rJzz kL^B:_i+>u`CKDQ^}pd1C  e5upk{ND$dkVuJ37e] 2mp}]M? ]|թf_׫]qoYfoˆm"ݎ㹇{$!e>^[|} \|@+.p٨םkRngK)WjчW~6xwƾ"w|pJbyxRD$U?U>e""iO<~b EZ**˪<,A!ctR~)+~T+R+} 5Z6gHh ցF^/?kW̨WkFu A=x]}UMmߴFfkUoKIk*zUxD߷tְ ƗofFw>8o7_x:򝑇?e7̮^xG!7S%vV}}ѨVg}wǪ'G l:u[tiꋜ|Cwk>g6 $Yˬ|?:꣛b߽|͉G7Z--<mktL 2tFIe+%8Qa <3NlO9BM+9p=~Fӈŏ?0)%Nx Jgo(*ݻ|=T|msNH_[yW}ۃb_e!wwm߽5^'2`޷l)ض7]]ǥ3 3}HUVNu@̇J1w39妠wwZg/Osꒇf7e2{rhwuvgXclWԄwҫMWS}EotW|?<хɾn\nzjunJ^Ӈgl"< !қ{~//SDbYe ˰O`FxO \b>xED͚X}g# /ޜ~"ED<15D7jQU?:`˦57՝s܌ڈ 8'{uCG0M:%w%tSZƑtv#"-'sJeJcGֈQ7/E:uc<RV[QҩT6.:UGϏ8!T{i*24O.2jδ~e[F-\`e-βΛjO^sUAA"YD**E"EbZDJȀQ|pHNt#e-ް0-vy+ctk/ˮ=F"Q לὸOKHIU"bT$w^>"""("SE>DOcd7C\f4,P]KKRQJFB.-xpE\$26P{C?΢޺wzDD Cg͌۴И0WeeWDIlYE#"l[768Ei뢢l" 癊trUt8"&I!"R_W+>.88KE!w߷$⩋RsFU)Ԩ]M>-^l"5QQW |ԙ֡;G3/nt+EE^zNĹE|zX:̪iU-I1q69hĖ IDAT >I]ֺ5G3F8JN9DDfN{y_'Mcizq==ǖF %c}'MXC-Y;$2hmӕ3U2 |y)icU]^ytATV+2hMi5r:F%d99++s z6Gɷ)>|oXݠQҚ[ctU^ҧ71^b.1ѡ^M"V5Krգ;gYlԶlVݛY:e[\ɶ578p|5WDDi-73t ӂ|;/U4z_Su`D9s>x@amxɝVhMHxhaJ4gzmfmwοeX)>j=? w7Mmk=kqt3Tlw('LI(>K>,rbi*S]OK׫ѻ1#_q7e\=]rJzzZ `^E5]?moSai^٪rϳ?mK{՘z:N""S~GX||>Z%Vq;kzvLɾnp"WgF}O|ፇJM!>'κ3u~7o{ђ1#> u nxF\Jsn|6wc_W\x>Vh& 2>~D:#,luT9 ~ȍoxp}kӧu/O#k̾lA-y5FhY^?1wǎ ?Nwk>d7=_='1qfL'^dNJ]Sqظaϳ&&4yx`ׁn}7?(:_Z}b7mSϽ91>5[ 4 7nI+syC7ǩd?m G}nVGOix홧n '-xiN-UW9pXEϷEP\?_I7}ܷ?o A(!>ld;7;Ŗ=+,5bM{໷Dk,ؒJPNzU7+sxou[d)yVLWX %7[ {wy-~Fu%O]W)4bLkx}}^t7#-թJxzUx^ !I.jO36ooS"i|R@mҁe'0#FwG.c1<""fMf>sxQS,MkvH9wx%Rz24Y4/ DlS9v̘ 6ɏ8!T{i*٬Dh4No=Q.L2(7VzsϋII7HW~\;GR|RM K4U鑋tvЏP;pjX=G,SȰy[N>Dy`V'sf޹rD^mJT 5XF͙֯,}kݨ+{lYVyM+wvF.Ζ&U"""":EQ?rc odN_,h0J`XQܥWOl1^絗e׫$ۛERst⻔bZDJȀ&}3V'"CUoN\^ɐܭE+vx=Gzt9Yzlf#%Gjwor(Y2[Qa謙yvWv檬lՊo Ξ`7J%t{Ki8"(^iwKRLMEDtzJCOoIJSOّTe֦&fi$GcS6.*&XާDdpL&_3Z̗ͼU\!V-{'|RY[`HLlȒ/tW&[DD5g.}Q]ֺ5G3F8JNuB͜.[Lcizqi5r:F%d9gjT5KrգEEo^ff]ꔅ?n*rE$ ׼ޘ0g\yu.A/p?z;zm-xK|߅ؾ&,x~K^!J>F%Y~grxHPQȠws77> |HsuVځۭzFeO~::nWkOo>N$|/,4l7rkz뎼U5lE0OAKKss+]";Qgk:wd͎Ǻ>ikk9Dsf_|[K**'i^ko.i":q;N̙;y!"- sߐq.z3L0>-(ks/'U|W#FVe蹳N~OJ} w̨Q5!K{ࡅ)>D}FګSj*!V-{uF.9%MDV=O=y5&/| !/5:qԗˋw.]t`AD-U?ghv7^~c^^ }c|%(^>8Kɲ:S= '"j~}yRR'O}" oY|Â~0{=y_W71;jjs?ruj⯗:p}|""-Mpr@DZ<{{5w7'""kq?KOhVOhVOhV\OJ?dpɓe 4H#4H#4HFܜ#4Y O?&EѨw=] s{1Q黒zިZg/v:cto=*]q6j ߊli\׿iGM_AW{5}*f(k&mDPԥ/}ץa}N/?KЉT<Qm,h-8RhyO1>G>pc3Xf=N<fD#FH?jٳ3N|qЂo:HoC9 78h9Ԫ7I Q-!s93Fac-k}*&7/9+7[.1wܹhɒnLUӣ_y-sgexUp imE-m#|rĜ1tu"jx~M!"Puem9ZWo>8u\r\x\_^(""3+۽~A軧^z^IY̍4)'n`!I/Z:=ve4w[͊;?5${ջ*b%|ȄY5nYOÙ Wu3&Kέ{,!Qtgc4Z+"00p=F>p u{u9۪k="/wneO9agom(alM"uks̨9 09*u+zۈ)l!f^p@Ni""QSO ))vÇN<"]wG|f>rMi=sVD$"e-L&E13N{|3iG˽AΊGhH]ώԈZacM2Ej>k  H|s|u$ͅSu8cQ[N9!m:/peHؘEu雲"5m[7JOW^DO]܄E1Fɤ̽{"[;UEY4ðU"۳)Z:FB>pӉND[WiEEnuo;_zNtshR~QDT⧭z&gL>UcH|[,QmmtD.9<3Z~[rkM; ]""6tXO7U;tхtMcm:1z,W}#FN/kuwQ 8]G4q&?}ւ#55> ٺ+4#N=L_u=ne⽏^C`d;:XoٖO}O:)zjH{wЋW4R4G5c` Ett;&NO "HqX/ǦIykb>E|"mg|ngd*uMq9=QJ Ңx"2."l ظEDiml fw)R{>"geycp:'+xJGm.Ѣ[6>]g"RoQDzy^PRYH颚Ɠ:nx=ͱ#_T9(- >JwZ!=^y>{~E1k`r VzQ'X'n`u%a@_a?ҞLo׋( ~X? EQpce{(6'O2$8ۮ~ @oi7_zbl|cq3z2xɣD[2Ew&Z,NG{mݞJL/Rg N2j˶=t"^ݧWW1{Rom_>+1Y˩X,"M"mo-UZ=_y>{qc~*< ]5n,մġGF5 gw,Z5{?Ue 2('tߛQ7yT6EQt/(mmVNmYCC姊<9$_^t&f2Y:mAߢ[*N+^ }pz(UGnλ[MJ]怀Hdu=zW#x\"Go[o6:ʫEE-b">ߠ#}\0/rhRxeIaeg#DT)"Q~zCb:ʫ+ͅc%8{Y'X ɯb`qr)f!b1 Jmz{gMg9F2%.i?P0mNUd~hǾqTqW]3c̺kZ0x@)oQR=#wyKR5 O;}u'c5\-uM\Β#/X,R_{Ys0~ꭋo64ё^ܘ׋hM/e==!Cm- hqhSm6k9{o /5+էvd8E]s(iUNjf읖↱CEg_:ƢKNIUϽSOu1pu gQ7 Ћ44yO]?Oq8s^>foFROn`.i{Rj7o;ו5+p׀n} Rޱ'wDi+m=a߿ꋯSZ0t!Cck ''&<-UE[Dzs^'^;Bd3tOu)'n^l|kʪ.4w  _Ie`ܵ-OhVOhV/IK̠[|]SZ^r(W2_7'C~ueV~mzm>DXeS߯?ȧ |JQUOHz~ym!IDAT\[i7C~bz?&\~zHRr-Zߵu贩suik9uD1NN|7 O]yķ̊no/Y/3-}]Uqubq#T}I8:y*2닚M×&~و*OZw;SM Fi#-V]ƽ/n1$H0vhuO # ~m{9iogc`Z*:ۚww1.RkŊrϧC'-{6dwy22Awf )†1s/%/Sj4Ӟ!7DĠwxY *nAdX3甽Lіڔ)!iP":ی7# _ƧXϒ>is$΁˯9MGO̩?S~Ҷ{gOo/)"1camkߔhZ[[l x%.bIg 1^q~ҷ zs]DD zͷ\1?Y2|N5 1P*׹Aa"N{U |bg]5Aw::ʞW1ϸǒfuUh?eI!"(ҲkuDEW㿚}K7Lnd\bD,nw7xEoŊoq5} $""^‚N$d ہ}/+kdro.o =NoG>) 0ȕIc ]U+E.8К9t"("1|S2Ρ3EZ=~pҒ(GR4(ڦy'7^-,>WHdfgzȂ$N]WOܥ{O{EDisk*o蘟e򐚍ǝ}Re yMɿ}去o=5+b 맓FWkT&>X{Vtg{kqۚw>Sr]{O[{Uxج{/+R@j+|V݈a5}^ǫKNIUϽ3~0g%jozat/bvgnuZSO^'E[DKN46;>WE8zIAǬ5td8k=}Wފm, {]5'\\p'|@+'yO=kp-OhVOhVOhVOhVOhVOhVOhVks/aKNI@hVOhV% #IENDB`emacs-dashboard-1.8.0/test/000077500000000000000000000000001446027744200155265ustar00rootroot00000000000000emacs-dashboard-1.8.0/test/activate.el000066400000000000000000000017411446027744200176530ustar00rootroot00000000000000;;; activate.el --- Test dashboard activation -*- lexical-binding: t; -*- ;; This file is NOT part of GNU Emacs. ;; This program 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. ;; This program 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 this program. If not, see . ;;; Commentary: ;; ;; Test dashboard activation. ;; ;;; Code: (dashboard-setup-startup-hook) (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))) (message "Done activation test.") ;;; activate.el ends here