diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..7e1b0c9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,78 @@ +name: Bug Report +description: File a bug report +# labels: ["bug"] +# assignees: +# - alphapapa +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: input + id: os-platform + attributes: + label: OS/platform + description: What operating system or platform are you running Emacs on? + validations: + required: true + - type: textarea + id: emacs-provenance + attributes: + label: Emacs version and provenance + description: What version of Emacs are you using, where did you acquire it, and how did you install it? + validations: + required: true + - type: input + id: emacs-command + attributes: + label: Emacs command + description: By what method did you run Emacs? (i.e. what command did you run?) + validations: + required: true + - type: textarea + id: org-provenance + attributes: + label: Org version and provenance + description: What version of Org are you using, where did you acquire it, and how did you install it? + validations: + required: true + - type: input + id: package-provenance + attributes: + label: org-ql package version and provenance + description: What version of org-ql are you using, where did you acquire it, and how did you install it? + validations: + required: true + - type: textarea + id: actions + attributes: + label: Actions taken + description: What actions did you take, step-by-step, in order, before the problem was noticed? + validations: + required: true + - type: textarea + id: results + attributes: + label: Observed results + description: What behavior did you observe that seemed wrong? + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected results + description: What behavior did you expect to observe? + validations: + required: true + - type: textarea + id: backtrace + attributes: + label: Backtrace + description: If an error was signaled, please use `M-x toggle-debug-on-error RET` and cause the error to happen again, then paste the contents of the `*Backtrace*` buffer here. + render: elisp + - type: textarea + id: etc + attributes: + label: Etc. + description: Any other information that seems relevant + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..7e36d80 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Support questions + url: https://github.com/alphapapa/org-ql/discussions + about: Please ask and answer support questions here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..7b14c94 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,45 @@ +name: Feature Request +description: File a feature request +labels: ["enhancement"] +body: + - type: input + id: os-platform + attributes: + label: OS/platform + description: What operating system or platform are you running Emacs on? + validations: + required: true + - type: textarea + id: emacs-provenance + attributes: + label: Emacs version and provenance + description: What version of Emacs are you using, where did you acquire it, and how did you install it? + validations: + required: true + - type: textarea + id: org-provenance + attributes: + label: Org version and provenance + description: What version of Org are you using, where did you acquire it, and how did you install it? + validations: + required: true + - type: input + id: package-provenance + attributes: + label: org-ql package version and provenance + description: What version of org-ql are you using, where did you acquire it, and how did you install it? + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: Describe your request. + validations: + required: true + - type: textarea + id: etc + attributes: + label: Etc. + description: Any other information that seems relevant + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2de58b4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,81 @@ +# * test.yml --- Test Emacs packages using makem.sh on GitHub Actions + +# URL: https://github.com/alphapapa/makem.sh +# Version: 0.3 + +# * Commentary: + +# Based on Steve Purcell's examples at +# , +# . + +# * License: + +# 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 . + +# * Code: + +name: "CI" +on: + pull_request: + push: + # Comment out this section to enable testing of all branches. + # branches: + # - master + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + emacs_version: + - 27.1 + - 27.2 + - 28.1 + - 28.2 + - 29.1 + - 29.2 + - 29.3 + - 29.4 + - snapshot + steps: + - uses: purcell/setup-emacs@master + with: + version: ${{ matrix.emacs_version }} + + - uses: actions/checkout@v2 + + - name: Initialize sandbox + run: | + SANDBOX_DIR=$(mktemp -d) || exit 1 + echo "SANDBOX_DIR=$SANDBOX_DIR" >> $GITHUB_ENV + ./makem.sh -vv --sandbox=$SANDBOX_DIR --install-deps --install-linters + + # The "all" rule is not used, because it treats compilation warnings + # as failures, so linting and testing are run as separate steps. + + - name: Lint + # NOTE: Uncomment this line to treat lint failures as passing + # so the job doesn't show failure. + continue-on-error: true + run: ./makem.sh -vv --sandbox=$SANDBOX_DIR lint + + - name: Test + if: always() # Run test even if linting fails. + run: ./makem.sh -vv --sandbox=$SANDBOX_DIR test + +# Local Variables: +# eval: (outline-minor-mode) +# End: diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9355658 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.elc +.#* +/scratch.el +.cask +/sandbox/ +/.sandbox/ +/scratch.org +/scratch/ +/worktrees/ +/worktree/ +/NOTES.org diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + 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 +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..64c4516 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +# * makem.sh/Makefile --- Script to aid building and testing Emacs Lisp packages + +# URL: https://github.com/alphapapa/makem.sh +# Version: 0.5 + +# * Arguments + +# For consistency, we use only var=val options, not hyphen-prefixed options. + +# NOTE: I don't like duplicating the arguments here and in makem.sh, +# but I haven't been able to find a way to pass arguments which +# conflict with Make's own arguments through Make to the script. +# Using -- doesn't seem to do it. + +ifdef install-deps + INSTALL_DEPS = "--install-deps" +endif +ifdef install-linters + INSTALL_LINTERS = "--install-linters" +endif + +ifdef sandbox + ifeq ($(sandbox), t) + SANDBOX = --sandbox + else + SANDBOX = --sandbox=$(sandbox) + endif +endif + +ifdef debug + DEBUG = "--debug" +endif + +# ** Verbosity + +# Since the "-v" in "make -v" gets intercepted by Make itself, we have +# to use a variable. + +verbose = $(v) + +ifneq (,$(findstring vvv,$(verbose))) + VERBOSE = "-vvv" +else ifneq (,$(findstring vv,$(verbose))) + VERBOSE = "-vv" +else ifneq (,$(findstring v,$(verbose))) + VERBOSE = "-v" +endif + +# * Rules + +# TODO: Handle cases in which "test" or "tests" are called and a +# directory by that name exists, which can confuse Make. + +%: + @./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(INSTALL_DEPS) $(INSTALL_LINTERS) $(@) + +.DEFAULT: init +init: + @./makem.sh $(DEBUG) $(VERBOSE) $(SANDBOX) $(INSTALL_DEPS) $(INSTALL_LINTERS) diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..b869aeb --- /dev/null +++ b/NOTES @@ -0,0 +1 @@ +Note: Notes are kept in the file "NOTES.org" in the "meta/notes" branch. diff --git a/README.org b/README.org new file mode 100644 index 0000000..457dedd --- /dev/null +++ b/README.org @@ -0,0 +1,1130 @@ +#+TITLE: org-ql + +# NOTE: Using =BEGIN_HTML= for this causes TeX/info export to fail, but this HTML block works. +#+HTML: + +# NOTE: To avoid having this in the info manual, we use HTML rather than Org syntax; it still appears with the GitHub renderer. +#+HTML: + +This package provides a query language for Org files. It offers two syntax styles: Lisp-like sexps and search engine-like keywords. + +It includes three libraries: The =org-ql= library is flexible and may be used as a backend for other tools. The libraries =org-ql-search= and =helm-org-ql= (a separate package) provide interactive search commands and saved views. + +* Contents +:PROPERTIES: +:TOC: :include siblings :depth 0 :ignore this :force depth +:END: +:CONTENTS: +- [[#screenshots][Screenshots]] +- [[#installation][Installation]] +- [[#usage][Usage]] +- [[#changelog][Changelog]] +- [[#development][Development]] +:END: + + +* Screenshots + +[[images/org-ql-search.gif]] + +[[images/org-ql-view-dispatch.gif]] + +[[images/helm-org-ql.gif]] + +[[images/org-ql-view-sidebar.gif]] + +* Installation +:PROPERTIES: +:TOC: ignore-children +:END: + +The package =org-ql= may be installed directly from [[https://melpa.org/#/org-ql][MELPA]] or with other tools like [[https://framagit.org/steckerhalter/quelpa][Quelpa]]. + +After installation, you can use the commands without additional configuration. To use the functions and macros in your own Elisp code, use libraries =org-ql= and =org-ql-view=. + +** Quelpa + +Installing with [[https://framagit.org/steckerhalter/quelpa][Quelpa]] is easy: + +1. Install [[https://framagit.org/steckerhalter/quelpa-use-package#installation][quelpa-use-package]] (which can be installed directly from MELPA). +2. Add this form to your init file: + +#+BEGIN_SRC elisp + (use-package org-ql + :quelpa (org-ql :fetcher github :repo "alphapapa/org-ql" + :files (:defaults (:exclude "helm-org-ql.el")))) +#+END_SRC + +** Helm support + +The command =helm-org-ql= is available in the package =helm-org-ql=. It may be installed from MELPA, or with Quelpa, like so: + +#+BEGIN_SRC elisp + (use-package helm-org-ql + :quelpa (helm-org-ql :fetcher github :repo "alphapapa/org-ql" + :files ("helm-org-ql.el"))) +#+END_SRC + +* Usage +:PROPERTIES: +:TOC: :include descendants :depth 1 +:END: +:CONTENTS: +- [[#commands][Commands]] +- [[#queries][Queries]] + - [[#non-sexp-query-syntax][Non-sexp query syntax]] + - [[#general-predicates][General predicates]] + - [[#ancestordescendant-predicates][Ancestor/descendant predicates]] + - [[#datetime-predicates][Date/time predicates]] +- [[#functions--macros][Functions / Macros]] +- [[#dynamic-block][Dynamic block]] +- [[#links][Links]] +- [[#tips][Tips]] +:END: + +# These links work on GitHub's Org renderer but not in Org. + +Feedback on these APIs is welcome. Eventually, after being tested and polished, they will be considered stable. + +# TODO: Find a way to get these examples included in the info manual. +Lisp code examples are in [[examples.org]]. + +** Commands +:PROPERTIES: +:TOC: ignore-children +:END: + ++ *Jumping to an entry:* + - [[#org-ql-find][org-ql-find]] and related commands + - [[#helm-org-ql][helm-org-ql]] ++ *Showing an agenda-like view:* + - [[#org-ql-search][org-ql-search]] + - [[#org-ql-view][org-ql-view]] + - [[#org-ql-view-sidebar][org-ql-view-sidebar]] + - [[#org-ql-view-recent-items][org-ql-view-recent-items]] ++ *Showing a tree in a buffer:* + - [[#org-ql-sparse-tree][org-ql-sparse-tree]] + +*** org-ql-find + +/Note: These commands use [[#non-sexp-query-syntax][non-sexp queries]]./ + +These commands jump to a heading selected using Emacs's built-in completion facilities with an Org QL query: + +- ~org-ql-find~ searches in the current buffer. +- ~org-ql-find-path~ searches outline paths in the current buffer. +- ~org-ql-find-in-agenda~ searches in ~(org-agenda-files)~. +- ~org-ql-find-in-org-directory~ searches in ~org-directory~. + +Note that these commands are compatible with [[https://github.com/oantolin/embark][Embark]]: the ~embark-act~ command can be called on a completion candidate (i.e. a search result) to act on it immediately, without having to visit the entry in its source Org buffer, and ~embark-export~ may be called to show the results in an ~org-ql-view~ buffer. + +[[images/org-ql-find.png]] + +*** org-ql-open-link + +This command finds links in entries matching the input query and offers them for selection; the selected link is then opened with ~org-open-at-point~. + +The input is matched using the default predicate, which means it searches both entry content and outline paths. This is helpful when a collection of links are kept in Org files: rather than having to first visit the entry containing the desired link, then locate it within the entry, and then open it, the user can simply select the link and open it directly. For example, if an entry with the heading =Emacs= contained a link named =mailing list=, one could search for =Emacs list= and open the link to the mailing list directly. + +*** org-ql-refile + +This command refiles the current Org entry to one selected by searching with Org QL completion. It searches files listed in ~org-refile-targets~ as well as the current buffer. + +*** org-ql-search + +/Note: This command supports both sexp queries and [[#non-sexp-query-syntax][non-sexp queries]]./ + +Read ~QUERY~ and search with ~org-ql~. Interactively, prompt for these variables: + +~BUFFERS-FILES~: ~A~ list of buffers and/or files to search. Interactively, may also be: + ++ ~buffer~: search the current buffer ++ ~all~: search all Org buffers ++ ~agenda~: search buffers returned by the function ~org-agenda-files~ ++ A space-separated list of file or buffer names + +~GROUPS~: An ~org-super-agenda~ group set. See variable ~org-super-agenda-groups~. + +~NARROW~: When non-nil, don't widen buffers before searching. Interactively, with prefix, leave narrowed. + +~SORT~: One or a list of ~org-ql~ sorting functions, like ~date~ or ~priority~. + +*Bindings:* Keys bound in results buffer. ++ =r=: Refresh results. With prefix, prompt to adjust search parameters. ++ =v=: Show =transient= view dispatcher (like Magit's popups). ++ =C-x C-s=: Save query to variable ~org-ql-views~ (accessible with command ~org-ql-view~). + +*Note:* The view buffer is currently put in ~org-agenda-mode~, which means that /some/ Org Agenda commands work, such as jumping to entries and changing item priorities (without necessarily updating the view). This feature is experimental and not guaranteed to work correctly with all commands. (It works to the extent it does because the appropriate text properties are placed on each item, imitating an Agenda buffer.) + +*Note:* Also, this buffer is compatible with [[https://github.com/oantolin/embark][Embark]]: the ~embark-act~ command can be called on an entry to act on it immediately, without having to visit the entry in its source Org buffer. + +*** helm-org-ql + +/Note: This command uses [[#non-sexp-query-syntax][non-sexp queries]]. It is available separately in the package =helm-org-ql=./ + +This command displays matches with Helm. + ++ Press =C-x C-s= in the Helm session to save the results to an =org-ql-search= buffer. + +*** org-ql-view + +Choose and display a view stored in ~org-ql-views~. + +*Bindings:* Keys bound in view buffer. ++ =g=, =r=: Refresh results. With prefix, prompt to adjust search parameters. ++ =v=: Show =transient= view dispatcher (like Magit's popups). ++ =C-x C-s=: Save query to variable ~org-ql-views~ (accessible with command ~org-ql-view~). + +*** org-ql-view-sidebar + +Show a sidebar window listing views stored in =org-ql-views= for easy access. In the sidebar, press =RET= or =mouse-1= to show the view at point, and press =c= to customize the view at point. + +*** org-ql-view-recent-items + +Show items in ~FILES~ from last ~DAYS~ days with timestamps of ~TYPE~. ~TYPE~ may be ~ts~, ~ts-active~, ~ts-inactive~, ~clocked~, ~closed~, ~deadline~, ~planning~, or ~scheduled~. =FILES= defaults to those returned by the function =org-agenda-files=. + +*** org-ql-sparse-tree + +Arguments: ~(query &key keep-previous (buffer (current-buffer)))~ + +Show a sparse tree for ~QUERY~ in ~BUFFER~ and return number of results. The tree will show the lines where the query matches, and any other context defined in ~org-show-context-detail~, which see. + +~QUERY~ is an ~org-ql~ query sexp (quoted, since this is a function). ~BUFFER~ defaults to the current buffer. When ~KEEP-PREVIOUS~ is non-nil (interactively, with prefix), the outline is not reset to the overview state before finding matches, which allows stacking calls to this command. Runs ~org-occur-hook~ after making the sparse tree. + +** Queries +:PROPERTIES: +:TOC: :include descendants :depth 1 +:END: +:CONTENTS: +- [[#non-sexp-query-syntax][Non-sexp query syntax]] +- [[#general-predicates][General predicates]] +- [[#ancestordescendant-predicates][Ancestor/descendant predicates]] +- [[#datetime-predicates][Date/time predicates]] +:END: + +An =org-ql= query is a Lisp expression which may contain arbitrary expressions, as well as calling certain built-in predicates. It is byte-compiled into a predicate function which is tested with point on each heading in an Org buffer; when it returns non-nil, the heading matches the query. When possible, certain built-in predicates are optimized away to whole-buffer regular expression searches, which are much faster to search for than testing the predicate on each heading. + +*Notes:* ++ Bare strings like ~"string"~ are automatically converted to ~(regexp "string")~ predicates. ++ Standard numeric comparator function symbols (~<~, ~<=~, ~>~, ~>=~, ~=~ ) need not be quoted when passed as an argument to predicates which accept them. The resemblance to infix notation is coincidental. + +*** Non-sexp query syntax + +The command =org-ql-search= also accepts, and the command =helm-org-ql= only accepts, an alternative, non-sexp query syntax. The syntax is simple, and a few examples of queries in both syntaxes should suffice. By default, when multiple predicates are used, they are combined with boolean =and=. + +| Sexp syntax | Non-sexp syntax | +|-------------------------------------------------+----------------------------------------------| +| ~(todo)~ | ~todo:~ | +| ~(todo "SOMEDAY")~ | ~todo:SOMEDAY~ | +| ~(todo "SOMEDAY" "WAITING")~ | ~todo:SOMEDAY,WAITING~ | +| ~(ts :on today)~ | ~ts:on=today~ | +| ~(ts-active :from "2017-01-01" :to "2018-01-01")~ | ~ts-active:from=2017-01-01,to=2018-01-01~ | +| ~(clocked :on -1)~ | ~clocked:on=-1~ | +| ~(heading "quoted phrase" "word")~ | ~heading:"quoted phrase",word~ | +| ~(and (tags "book" "books") (priority "A"))~ | ~tags:book,books priority:A~ | +| ~(src :lang "elisp" :regexps ("defun"))~ | ~src:defun,lang=elisp~ or ~src:lang=elisp,defun~ | +| ~(and (tags "space") (not (regexp "moon")))~ | ~tags:space !moon~ | +| ~(priority >= B)~ | ~priority:A,B~ | + +Note that the =effort=, =level=, and =priority= predicates do not support comparators in the non-sexp syntax, so multiple arguments should be passed instead, as seen in the last example. + +*** General predicates + +Arguments are listed next to predicate names, where applicable. + ++ =blocked= :: Return non-nil if current heading is blocked. Calls ~org-entry-blocked-p~, which see. ++ =category (&rest categories)= :: Return non-nil if current heading is in one or more of ~CATEGORIES~ (a list of strings). ++ =done= :: Return non-nil if entry's ~TODO~ keyword is in ~org-done-keywords~. ++ =effort (&optional effort-or-comparator effort)= :: Return non-nil if current heading's effort property matches arguments. The following forms are accepted: ~(effort DURATION)~: Matches if effort is ~DURATION~. ~(effort DURATION DURATION)~: Matches if effort is between DURATIONs, inclusive. ~(effort COMPARATOR DURATION)~: Matches if effort compares to ~DURATION~ with ~COMPARATOR~. ~COMPARATOR~ may be ~<~, ~<=~, ~>~, or ~>=~. ~DURATION~ should be an Org effort string, like =5= or =0:05=. ++ =habit= :: Return non-nil if entry is a habit. ++ =heading (&rest strings)= :: Return non-nil if current entry's heading matches all ~STRINGS~. Matching is done case-insensitively. + - Aliases: =h=. ++ ~heading-regexp (&rest regexps)~ :: Return non-nil if current entry's heading matches all ~REGEXPS~ (regexp strings). Matching is done case-insensitively. + - Aliases: ~h*~. ++ =level (level-or-comparator &optional level)= :: Return non-nil if current heading's outline level matches arguments. The following forms are accepted: ~(level NUMBER)~: Matches if heading level is ~NUMBER~. ~(level NUMBER NUMBER)~: Matches if heading level is equal to or between NUMBERs. ~(level COMPARATOR NUMBER)~: Matches if heading level compares to ~NUMBER~ with ~COMPARATOR~. ~COMPARATOR~ may be ~<~, ~<=~, ~>~, or ~>=~. ++ =link (&optional description-or-target &key description target regexp-p)= :: Return non-nil if current heading contains a link matching arguments. ~DESCRIPTION-OR-TARGET~ is matched against the link's description and target. Alternatively, one or both of ~DESCRIPTION~ and ~TARGET~ may be matched separately. Without arguments, return non-nil if any link is found. ++ =outline-path (&rest strings)= :: Return non-nil if current node's outline path matches all of ~STRINGS~. Each string may appear as a substring in any part of the node's outline path. For example, the path =Food/Fruits/Grapes= would match ~(olp "Fruit" "Grape")~. + - Aliases: ~olp~. ++ =outline-path-segment (&rest strings)= :: Return non-nil if current node's outline path matches ~STRINGS~. Matches ~STRINGS~ as a contiguous segment of the outline path. Each string is compared as a substring. For example the path ~Food/Fruits/Grapes~ would match ~(olps "Fruit" "Grape")~ but not ~(olps "Food" "Grape")~. + - Aliases: ~olps~. ++ =path (&rest regexps)= :: Return non-nil if current heading's buffer's filename path matches any of ~REGEXPS~ (regexp strings). Without arguments, return non-nil if buffer is file-backed. ++ =priority (&rest args)= :: Return non-nil if current heading has a certain priority. ~ARGS~ may be either a list of one or more priority letters as strings, or a comparator function symbol followed by a priority letter string. For example: ~(priority "A") (priority "A" "B") (priority '>= "B")~ Note that items without a priority cookie never match this predicate (while Org itself considers items without a cookie to have the default priority, which, by default, is equal to priority ~B~). ++ =property (property &optional value &key inherit)= :: Return non-nil if current entry has ~PROPERTY~ (a string), and optionally ~VALUE~ (a string). If ~INHERIT~ is nil, only match entries with ~PROPERTY~ set on the entry; if t, also match entries with inheritance. If ~INHERIT~ is not specified, use the value of ~org-use-property-inheritance~, which see. ++ =regexp (&rest regexps)= :: Return non-nil if current entry matches all of ~REGEXPS~ (regexp strings). Matches against entire entry, from beginning of its heading to the next heading. + - Aliases: =r=. ++ =rifle (&rest strings)= :: Return non-nil if each string is found in either the entry or its outline path. Works like =org-rifle=. This is probably the most useful, intuitive, general-purpose predicate. + - Aliases: ~smart~. + - *Note:* By default, this is the default predicate used for plain-string query tokens (i.e. given without a specified predicate). This can be customized with the option ~org-ql-default-predicate~. ++ ~src (&key lang regexps)~ :: Return non-nil if current entry contains an Org Babel source block. If ~LANG~ is non-nil, match blocks of that language. If ~REGEXPS~ is non-nil, require that block's contents match all regexps. Matching is done case-insensitively. ++ =tags (&rest tags)= :: Return non-nil if current heading has one or more of ~TAGS~ (a list of strings). Tests both inherited and local tags. ++ =tags-inherited (&rest tags)= :: Return non-nil if current heading's inherited tags include one or more of ~TAGS~ (a list of strings). If ~TAGS~ is nil, return non-nil if heading has any inherited tags. + - Aliases: ~inherited-tags~, ~tags-i~, ~itags~. ++ =tags-local (&rest tags)= :: Return non-nil if current heading's local tags include one or more of ~TAGS~ (a list of strings). If ~TAGS~ is nil, return non-nil if heading has any local tags. + - Aliases: ~local-tags~, ~tags-l~, ~ltags~. ++ =tags-all (&rest tags)= :: Return non-nil if current heading includes all of ~TAGS~. Tests both inherited and local tags. + - Aliases: ~tags&~. ++ =tags-regexp (&rest regexps)= :: Return non-nil if current heading has tags matching one or more of ~REGEXPS~. Tests both inherited and local tags. + - Aliases: ~tags*~. ++ =todo (&rest keywords)= :: Return non-nil if current heading is a ~TODO~ item. With ~KEYWORDS~, return non-nil if its keyword is one of ~KEYWORDS~ (a list of strings). When called without arguments, only matches non-done tasks (i.e. does not match keywords in ~org-done-keywords~). + +*** Ancestor/descendant predicates + ++ =ancestors (&optional query)= :: Return non-nil if current heading has ancestor headings. If ~QUERY~, return non-nil if an ancestor heading matches it. This selector may be nested. ++ =children (&optional query)= :: Return non-nil if current heading has direct child headings. If ~QUERY~, return non-nil if a child heading matches it. This selector may be nested, e.g. to match grandchild headings. ++ =descendants (&optional query)= :: Return non-nil if current heading has descendant headings. If ~QUERY~, return non-nil if a descendant heading matches it. This selector may be nested (if you can grok the nesting!). ++ =parent (&optional query)= :: Return non-nil if current heading has a direct parent heading. If ~QUERY~, return non-nil if the parent heading matches it. This selector may be nested, e.g. to match grandparent headings. + +*** Date/time predicates + +These predicates take optional keyword arguments: + ++ ~:from~: Match entries whose timestamp is on or after timestamp ~:from~. ++ ~:to~: Match entries whose timestamp is on or before timestamp ~:to~. ++ ~:on~: Match entries whose timestamp is on date ~:on~. ++ ~:with-time~: If unspecified, match timestamps with or without times (i.e. HH:MM). If nil, match timestamps without times. If t, match timestamps with times. + +Timestamp/date arguments should be either a number of days (positive to look forward, or negative to look backward), a string parseable by ~parse-time-string~ (the string may omit the time value), the symbol ~today~, or a ~ts~ struct. + ++ *Predicates* + - =ts= :: Return non-nil if current entry has a timestamp in given period. Without arguments, return non-nil if entry has a timestamp. + - =ts-active=, =ts-a= :: Like =ts=, but only matches active timestamps. + - =ts-inactive=, =ts-i= :: Like =ts=, but only matches inactive timestamps. + +The following predicates, in addition to the keyword arguments, can also take a single argument, a number, which looks backward or forward a number of days. The number can be negative to invert the direction. + +These two predicates interpret a single number argument as if it were passed to the ~:from~ keyword argument, which eases the common case of searching for items clocked or closed in the past few days: + ++ *Backward-looking* + - =clocked= :: Return non-nil if current entry was clocked in given period. Without arguments, return non-nil if entry was ever clocked. Note: Clock entries are expected to be clocked out. Currently clocked entries (i.e. with unclosed timestamp ranges) are ignored. + - =closed= :: Return non-nil if current entry was closed in given period. Without arguments, return non-nil if entry is closed. + +These predicates interpret a single number argument as if it were passed to the ~:to~ keyword argument, which eases the common case of searching for items planned in the next few days: + ++ *Forward-looking* + - =deadline= :: Return non-nil if current entry has deadline in given period. If argument is =auto=, return non-nil if entry has deadline within =org-deadline-warning-days=. Without arguments, return non-nil if entry has any deadline. + - =planning= :: Return non-nil if current entry has planning timestamp (i.e. its deadline, scheduled, or closed timestamp) in given period. Without arguments, return non-nil if entry has any planning timestamp. + - =scheduled= :: Return non-nil if current entry is scheduled in given period. Without arguments, return non-nil if entry is scheduled. + +** Functions / Macros +:PROPERTIES: +:TOC: :include descendants +:END: +:CONTENTS: +- [[#agenda-like-views][Agenda-like views]] + - [[#function-org-ql-block][Function: org-ql-block]] +- [[#listing--acting-on-results][Listing / acting-on results]] + - [[#caching][Caching]] + - [[#function-org-ql-select][Function: org-ql-select]] + - [[#function-org-ql-query][Function: org-ql-query]] + - [[#macro-org-ql-deprecated][Macro: org-ql (deprecated)]] +- [[#custom-predicates][Custom predicates]] + - [[#macro-org-ql-defpred][Macro: org-ql-defpred]] +:END: + +*** Agenda-like views + +**** Function: ~org-ql-block~ + +For use as a custom agenda block type in ~org-agenda-custom-commands~. For example, you could define a custom series command like this, which would list all priority A items tagged =Emacs= with to-do keyword =SOMEDAY=, followed by the standard agenda view, in a single buffer: + +#+BEGIN_SRC elisp + (setq org-agenda-custom-commands + '(("ces" "Custom: Agenda and Emacs SOMEDAY [#A] items" + ((org-ql-block '(and (todo "SOMEDAY") + (tags "Emacs") + (priority "A")) + ((org-ql-block-header "SOMEDAY :Emacs: High-priority"))) + (agenda))))) +#+END_SRC + +Which would be equivalent to a ~tags-todo~ search like this: + +#+BEGIN_SRC elisp + (setq org-agenda-custom-commands + '(("ces" "Custom: Agenda and Emacs SOMEDAY [#A] items" + ((tags-todo "PRIORITY=\"A\"+Emacs/!SOMEDAY") + (agenda))))) +#+END_SRC + +However, the ~org-ql-block~ version runs in about 1/5th the time. + +The variable =org-ql-block-header= may be bound to a string to use as the block header, otherwise the header is formed automatically. + +*** Listing / acting-on results + +**** Caching + +Org QL uses a per-buffer cache to speed up subsequent searches. It's keyed on query expressions and match actions, which means that, for the same query and same match action in the same buffer, if the buffer has not been modified since the last time the query was run, the cached match-action result will be returned, and the query will not be evaluated in that buffer again. + +Therefore, since neither query expressions nor match actions are guaranteed to be evaluated when the following functions are called, they should be free of side effects. Or, if a side effect is required, the cache should be invalidated (e.g. by incrementing the buffer's modified tick, or by using a query expression or match action that has yet to be cached). /Note: Future improvements will allow the cache to be more easily disabled or cleared./ + +**** Function: ~org-ql-select~ + +/Arguments:/ ~(buffers-or-files query &key action narrow sort)~ + +Return items matching ~QUERY~ in ~BUFFERS-OR-FILES~. + +~BUFFERS-OR-FILES~ is a one or a list of files and/or buffers. + +~QUERY~ is an ~org-ql~ query sexp (quoted, since this is a function). + +~ACTION~ is a function which is called on each matching entry with point at the beginning of its heading. It may be: + + - ~element~ or nil: Equivalent to ~org-element-headline-parser~. + + - ~element-with-markers~: Equivalent to calling ~org-element-headline-parser~, with markers added using ~org-ql--add-markers~. Suitable for formatting with ~org-ql-agenda--format-element~, allowing insertion into an Org Agenda-like buffer. + + - A sexp, which will be byte-compiled into a lambda function. + + - A function symbol. + +If ~NARROW~ is non-nil, buffers are not widened (the default is to widen and search the entire buffer). + +~SORT~ is either nil, in which case items are not sorted; or one or a list of defined ~org-ql~ sorting methods (~date~, ~deadline~, ~scheduled~, ~closed~, ~todo~, ~priority~, or ~random~); or a user-defined comparator function that accepts two items as arguments and returns nil or non-nil. + +Examples: + +#+BEGIN_SRC elisp + ;; Return list of to-do headings in inbox file with tags and to-do keywords: + (org-ql-select "~/org/inbox.org" + '(todo) + :action #'org-get-heading) + ;; => ("TODO Practice leaping tall buildings in a single bound :personal:" ...) + + ;; Without tags and to-do keywords: + (org-ql-select "~/org/inbox.org" + '(todo) + :action '(org-get-heading t t)) + ;; => ("Practice leaping tall buildings in a single bound" ...) + + ;; Return WAITING heading elements in agenda files: + (org-ql-select (org-agenda-files) + '(todo "WAITING") + :action 'element) + ;; => ((headline (:raw-value "Visit the moon" ...) ...) ...) + + ;; Since `element' is the default for ACTION, it may be omitted: + (org-ql-select (org-agenda-files) + '(todo "WAITING")) + ;; => ((headline (:raw-value "Visit the moon" ...) ...) ...) +#+END_SRC + +**** Function: ~org-ql-query~ + +/Arguments:/ ~(&key (select 'element-with-markers) from where order-by narrow)~ + +Like ~org-ql-select~, but arguments are named more like a ~SQL~ query. + ++ ~SELECT~ corresponds to the ~org-ql-select~ argument ~ACTION~. ++ ~FROM~ corresponds to the ~org-ql-select~ argument ~BUFFERS-OR-FILES~. ++ ~WHERE~ corresponds to the ~org-ql-select~ argument ~QUERY~. ++ ~ORDER-BY~ corresponds to the ~org-ql-select~ argument ~SORT~, which see. ++ ~NARROW~ corresponds to the ~org-ql-select~ argument ~NARROW~. + +Examples: + +#+BEGIN_SRC elisp + ;; Return list of to-do headings in inbox file with tags and to-do keywords: + (org-ql-query + :select #'org-get-heading + :from "~/org/inbox.org" + :where '(todo)) + ;; => ("TODO Practice leaping tall buildings in a single bound :personal:" ...) + + ;; Without tags and to-do keywords: + (org-ql-query + :select '(org-get-heading t t) + :from "~/org/inbox.org" + :where '(todo)) + ;; => ("Practice leaping tall buildings in a single bound" ...) + + ;; Return WAITING heading elements in agenda files: + (org-ql-query + :select 'element + :from (org-agenda-files) + :where '(todo "WAITING")) + ;; => ((headline (:raw-value "Visit the moon" ...) ...) ...) + + ;; Since `element' is the default for SELECT, it may be omitted: + (org-ql-query + :from (org-agenda-files) + :where '(todo "WAITING")) + ;; => ((headline (:raw-value "Visit the moon" ...) ...) ...) +#+END_SRC + +**** Macro: ~org-ql~ (deprecated) + +/Arguments:/ ~(buffers-or-files query &key sort narrow markers action)~ + +Expands into a call to ~org-ql-select~ with the same arguments. For convenience, arguments should be unquoted. + +/Note: This macro is deprecated and will be removed in v0.7./ + +*** Custom predicates + ++ See: [[file:examples/defpred.org][Custom predicate tutorial]] + +**** Macro: =org-ql-defpred= + +/Arguments:/ ~(name args docstring &key body preambles normalizers)~ + +Define an ~org-ql~ selector predicate named ~org-ql--predicate-NAME~. ~NAME~ may be a symbol or a list of symbols: if a list, the first is used as ~NAME~ and the rest are aliases. ~A~ function is only created for ~NAME~, not for aliases, so a normalizer should be used to replace aliases with ~NAME~ in queries (keep reading). + +~ARGS~ is a ~cl-defun~-style argument list. ~DOCSTRING~ is the function's docstring. + +~BODY~ is the body of the predicate. It will be evaluated with point on the beginning of an Org heading and should return non-nil if the heading's entry is a match. + +~PREAMBLES~ and ~NORMALIZERS~ are lists of ~pcase~ forms matched against Org ~QL~ query sexps. They are spliced into ~pcase~ forms in the definitions of the functions ~org-ql--query-preamble~ and ~org-ql--normalize-query~, which see. Those functions are redefined when this macro is expanded, unless variable ~org-ql-defpred-defer~ is non-nil, in which case those functions should be redefined manually after defining predicates by calling ~org-ql--define-query-preamble-fn~ and ~org-ql--define-normalize-query-fn~. + +~NORMALIZERS~ are used to normalize query expressions to standard forms. For example, when the predicate has aliases, the aliases should be replaced with predicate names using a normalizer. Also, predicate arguments may be put into a more optimal form so that the predicate has less work to do at query time. NOTE: Normalizers are applied to a query repeatedly until the query is fully normalized, so normalizers should be carefully written to avoid infinite loops. + +~PREAMBLES~ refer to regular expressions which may be used to search through a buffer directly to a potential match rather than testing the predicate body on each heading. (Naming things is hard.) In each ~pcase~ form in ~PREAMBLES~, the ~pcase~ expression (not the pattern) should be a plist with the following keys, each value of which should be an expression which may refer to variables bound in the pattern: + +~:regexp~ Regular expression which searches directly to a potential match. + +~:case-fold~ Bound to ~case-fold-search~ around the regexp search. + +~:query~ Expression which should replace the query expression, or ~query~ if it should not be changed (e.g. if the regexp is insufficient to determine whether a heading matches, in which case the predicate's body needs to be tested on the heading). If the regexp guarantees a match, this may be simply ~t~, leaving the query expression with no work to do, which improves performance. + +For convenience, within the ~pcase~ patterns, the symbol ~predicate-names~ is a special form which is replaced with a pattern matching any of the predicate's name and aliases. For example, if ~NAME~ were: + +~(heading h)~ + +Then if ~NORMALIZERS~ were: + +~((`(,predicate-names . ,args) `(heading ,@args)))~ + +It would be expanded to: + +~((`(,(or 'heading 'h) . ,args) `(heading ,@args)))~ + +** Dynamic block + +Org QL provides a dynamic block that lists entries in the current document matching a query. In the header, these parameters are supported: + ++ ~:query~: An Org QL query expression in either sexp or non-sexp form. ++ ~:columns~ A list of columns, including ~heading~, ~todo~, ~property~, ~priority~, ~deadline~, ~scheduled~, ~closed~. + - Each column may also be specified as a list with the second element being a header string. For example, to abbreviate the priority column: ~(priority "P")~. + - For certain columns, like =property=, arguments may be passed by specifying the column type itself as a list. For example, to display a column showing the values of a ~property~ named ~milestone~, with the header being abbreviated to ~M~: ~((property "milestone") "M")~. ++ ~:sort~ One or a list of Org QL sorting methods (see ~org-ql-select~). ++ ~:take~ Optionally take a number of results from the front (a positive number) or the end (a negative number) of the results. ++ ~:ts-format~ Optional format string used to format timestamp-based columns. + +The heading column is formatted as a link to the heading (not shown in the following example). + +For example, this dynamic block shows the first seven headings that are to-do items with priority A or B, sorted by deadline then priority, with certain columns (including the value of the =agenda-group= property with a custom header) and timestamp format: + +# NOTE: These results are edited manually because the Org links don't display well in the Info manual. + +#+BEGIN_SRC org + ,#+BEGIN: org-ql :query "todo: priority:A,B" :columns (todo (priority "P") ((property "agenda-group") "Group") deadline heading) :sort (deadline priority) :take 7 :ts-format "%Y-%m-%d %H:%M" + | Todo | P | Group | Deadline | Heading | + |------+---+-------+------------------+---------------------------------------| + | TODO | A | | 2017-07-07 00:00 | Take over the world | + | TODO | B | | 2017-07-10 00:00 | Renew membership in supervillain club | + | TODO | A | plans | 2017-07-15 00:00 | Take over the universe | + | TODO | B | | 2017-07-21 00:00 | Internet | + | TODO | A | bills | 2017-08-01 00:00 | Spaceship lease | + | TODO | A | | | Skype with president of Antarctica | + | TODO | B | | | Take over Mars | + ,#+END: +#+END_SRC + +** Links + +Org QL View searches may be accessed by opening ~org-ql-search:~ links in an Org file. + +In an Org QL View buffer, the command ~org-store-link~ (i.e. ~C-c l~) stores a link to the current search, and it may be inserted into an Org buffer with the command ~org-insert-link~ (~C-c C-l~). The stored link records all of the view settings, like title, sorting, and grouping. + +Simple links may also be written manually in either sexp or non-sexp form, like: + +#+BEGIN_SRC org + [[org-ql-search:todo:NEXT priority:A]] + [[org-ql-search:(and (todo "NEXT") (priority "A"))]] +#+END_SRC + +** Tips + ++ Org QL View buffers can be bookmarked with Emacs bookmark commands, e.g. =C-x r m=. This also integrates with [[https://github.com/alphapapa/org-sidebar][org-sidebar]] and [[https://github.com/alphapapa/burly.el][Burly]]. + +* Changelog +:PROPERTIES: +:TOC: ignore-children +:END: + +/Note:/ Breaking changes may be made before version 1.0, but in the event of major changes, attempts at backward compatibility will be made with obsolescence declarations, translation of arguments, etc. Users who need stability guarantees before 1.0 may choose to use tagged stable releases. + +** 0.9-pre + +*Additions* ++ Face ~org-ql-view-query~, applied to view queries in header line. ++ Face ~org-ql-view-title~, applied to view titles in header line. ++ Option ~org-ql-view-relative-deadline-prefix~. + +*Changes* ++ Command ~org-ql-find~ respects narrowing of the current buffer by default, allowing searching within the narrowed region. (Using one ~C-u~ argument widens the current buffer, and using two ~C-u~ arguments prompts for the buffers to search.) ++ Function ~org-ql-completing-read~ accepts a new ~NARROWP~ argument, which is passed to ~org-ql-select~. + +*Fixes* ++ Customization group for face ~org-ql-view-due-date~. ++ Apply Org syntax font-locking to items in ~org-ql-view~ buffers. + +*** helm-org-ql + +Tagged v0.6.2, fixing a compilation warning. + +** 0.8.10 + +*Fixes* ++ Command ~org-ql-refile~ uses the base buffer when refiling to an indirect buffer. ([[https://github.com/alphapapa/org-ql/issues/466][#466]].) ++ Predicate ~link~ could signal an error when searching text that is mistakenly recognized as an Org link (e.g. Bash double-bracket constructs in a source block). (Thanks to [[https://github.com/jwiegley][John Wiegley]] for reporting.) + +** 0.8.9 + +*Fixes* ++ Predicate ~property~ when called with argument form ~(property "PROPERTY-NAME" :inherit t)~. ([[https://github.com/alphapapa/org-ql/issues/460][#460]]. Thanks to [[https://github.com/Stewmath][Stewmath]] for reporting.) ++ Predicate ~level~'s preamble optimizer allows expressions in place of the numeric argument. (See [[https://github.com/alphapapa/org-ql/issues/460][#460]]. Thanks to [[https://github.com/Stewmath][Stewmath]] for reporting.) ++ Reading of view settings from Org links in upcoming Emacs version. ([[https://github.com/alphapapa/org-ql/issues/461][#461]]. Thanks to [[https://github.com/snogge][Ola Nilsson]] for help debugging, and for maintaining [[https://github.com/jorgenschaefer/emacs-buttercup][Buttercup]].) + +*Compatibility* ++ Fix compilation error on Emacs 30. ([[https://github.com/alphapapa/org-ql/issues/433][#433]]. Thanks to [[https://github.com/akirak][Akira Komamura]] and [[https://github.com/monnier][Stefan Monnier]].) + +** 0.8.8 + +*Fixes* ++ Remove text properties from to-do keywords before displaying them in an ~org-ql-view~ buffer. (Such text properties could cause them to, e.g. display with extra leading spaces, depending on which other modes might be enabled in the source Org buffer.) ++ Binding of ~completion-styles-alist~ in ~org-ql-completing-read~. (This fixes compatibility with Helm's ~helm~ completion style, as well as default Emacs completion in recursive minibuffers. [[https://github.com/alphapapa/org-ql/issues/337][#337]]. Thanks to [[https://github.com/progfolio][Nicholas Vollmer]], [[https://github.com/9viz][viz]], and [[https://github.com/karthink][Karthik Chikmagalur]] for reporting and suggesting fixes.) ++ Use of the context snippet function for ~org-ql-completing-read~. ([[https://github.com/alphapapa/org-ql/issues/419][#419]]. Thanks to [[https://github.com/tpeacock19][tpeacock19]] for reporting.) + +** 0.8.7 + +*Fixes* ++ Timestamps with internal time ranges (e.g. ~<2024-06-26 10:00-11:00>~) are matched for simple queries. (This support is not yet comprehensive, e.g. a query that depends on the specific inner time range may not behave as expected. Previously such timestamps were not matched at all. See [[https://github.com/alphapapa/org-ql/pull/237][#237]] and [[https://github.com/alphapapa/org-ql/issues/371][#371]]. Thanks to [[https://github.com/yantar92][Ihor Radchenko]].) ++ Timestamps with day-of-the-week abbreviations are matched more flexibly (allowing, e.g. a period in French locales). (See [[https://github.com/alphapapa/org-ql/discussions/429][#429]], [[https://github.com/alphapapa/org-ql/issues/432][#432]]. Thanks to [[https://github.com/neurolit][Florian D.]] for reporting.) ++ Command ~org-ql-search~ did not narrow properly when called interactively. + +*Compatibility* ++ Dynamic blocks work with Org 9.7. ([[https://github.com/alphapapa/org-ql/issues/431][#431]]. Thanks to [[https://github.com/jezcope][Jez Cope]] for reporting.) + +** 0.8.6 + +*Fixes* ++ Bookmarking ~org-ql-view~ buffers when the ~buffers-files~ argument is a symbol (like ~org-agenda-files~). + +** 0.8.5 + +*Fixes* ++ Predicate ~heading~ incorrectly matched strings as regular expressions, sometimes returning incorrect results. (See [[https://github.com/alphapapa/org-ql/discussions/410][discussion]]. Thanks to [[https://github.com/al3xandru][Alex Popescu]] for reporting.) ++ Predicates ~ancestor~ and ~parent~ did not normalize their sub-queries, sometimes returning incorrect results. ([[https://github.com/alphapapa/org-ql/issues/365][#365]]. Thanks to [[https://github.com/kofm][Gabriele Mongiano]] for reporting.) + +** 0.8.4 + +*Fixes* + ++ Command ~org-ql-find~ goes to the selected entry in the base buffer (rather than potentially an indirect buffer, whose narrowing could leave the selected entry hidden. The nuances around going to entries in buffers that may be indirect and/or narrowed are surprisingly complicated. Hopefully this is the last fix). + +** 0.8.3 + +*Fixes* + ++ Command ~org-ql-find~ incorrectly moved point. (See [[https://github.com/alphapapa/org-ql/issues/380#issuecomment-1881913025][#380]]. Thanks to [[https://github.com/oantolin][Omar Antolín Camarena]] for reporting.) + +** 0.8.2 + +*Fixes* + ++ Command ~org-ql-find~ incorrectly restored the buffer after jumping when not using indirect buffers. (See [[https://github.com/alphapapa/org-ql/issues/380#issuecomment-1881913025][#380]]. Thanks to [[https://github.com/bram85][Bram Schoenmakers]] for reporting.) + +** 0.8.1 + +*Fixes* + ++ Command ~org-ql-find~ widens the buffer before going to the selected entry. ++ In ~org-ql-view~ buffers, links in headings remain clickable links. (Fixes [[https://github.com/alphapapa/org-ql/issues/282][#282]]. Thanks to [[https://github.com/jakebox][Jacob Boxerman]] for reporting.) + +** 0.8 + +*Additions* + ++ Function ~org-ql-completing-read~, used by command ~org-ql-find~, now specifies the completion category as ~org-heading~, providing compatibility with [[https://github.com/oantolin/embark][Embark]]. (This is a powerful feature, as it means any ~org-ql-find~ result can be acted on from inside the search results with Embark, which provides common actions from Org Agenda and Org speed keys bindings.) ([[https://github.com/alphapapa/org-ql/issues/299][#299]]. Thanks to [[https://github.com/oantolin][Omar Antolín Camarena]], [[https://github.com/minad][Daniel Mendler]], and [[https://github.com/akirak][Akira Komamura]].) + - Command ~org-ql-completing-read-export~, bound to ~C-c C-e~ or ~embark-export~ while in an ~org-ql-completing-read~ session, exits and shows an ~org-ql-view~ buffer for the current search. ++ Command ~org-ql-find~ may be called in an ~org-agenda~ or ~org-ql-view~ buffer to search the buffers which contributed to the agenda/view buffer. ++ Command ~org-ql-find-path~, which searches outline paths in the current buffer. ++ Command ~org-ql-open-link~, which finds links in entries matching the given query, and opens the selected one with ~org-open-at-point~. (This is helpful when a collection of links are kept in Org files: rather than having to first visit the entry containing the desired link, then locate it within the entry, and then open it, the user can simply select the link and open it directly.) ++ Items in ~org-ql-view~ buffers now include the ~org-category~ text property, like Org Agenda buffers, which allows grouping with ~org-super-agenda~'s category-related selectors. ([[https://github.com/alphapapa/org-ql/issues/363][#363]]. Thanks to [[https://github.com/kofm][Gabriele Mongiano]] for reporting.) + +*Fixes* + ++ Predicate ~property~ correctly uses the value of ~org-use-property-inheritance~ when not specified. ([[https://github.com/alphapapa/org-ql/pull/346][#346]], [[https://github.com/alphapapa/org-ql/issues/356][#356]]. Thanks to [[https://github.com/bram85][Bram Schoenmakers]].) + +*Compatibility* + ++ Emacs 27.1 or later is now required. ++ Org v9.7's ~org-element~ API changes required some adjustments. ([[https://github.com/alphapapa/org-ql/issues/364][#364]]. Thanks to several users for reporting, and to [[https://github.com/yantar92][Ihor Radchenko]] for his feedback.) + +** 0.7.4 + +*Fixes* ++ Ignore empty quoted strings in plain-string queries ([[https://github.com/alphapapa/org-ql/issues/383][#383]]). + +** 0.7.3 + +*Fixes* ++ Disable ~case-fold-search~ when collecting headings in outline paths. (Headings that started with a word that is also a to-do keyword but with different capitalization would be matched incorrectly.) ++ Saving of ~org-ql-view~ views. ([[https://github.com/alphapapa/org-ql/issues/378][#378]]. Thanks to [[https://github.com/Pentaquark1][Pentaquark1]] for reporting.) ++ Command ~org-ql-find~ didn't move point to the selected entry. ([[https://github.com/alphapapa/org-ql/issues/380][#380]]. Thanks to [[https://github.com/oantolin][Omar Antolín Camarena]] for reporting.) + +** 0.7.2 + +*Fixes* ++ Timestamp predicates are more tolerant of partial input (e.g. preventing errors while the user is typing a query into ~org-ql-find~). ++ Query parser ignores leading whitespace (e.g. preventing errors while the user is typing a query into ~org-ql-find~). ++ Use of ~org-ql-find~ with ~:query-prefix~ argument prevented selection of results. ([[https://github.com/alphapapa/org-ql/issues/351][#351]]. Thanks to [[https://github.com/danielfleischer][Daniel Fleischer]] for reporting.) ++ Handle narrowed buffers correctly in ~org-ql-find~. ++ Warn about empty headings in ~org-ql-completing-read~ (the Org format allows a heading line to have no text, but it's useless for this purpose, and usually indicates unnoticed corruption). + +** 0.7.1 + +*Fixes* ++ Function ~org-ql-completing-read~ is more compatible with default Emacs completion. (See [[https://github.com/alphapapa/org-ql/issues/338][#338]]. Thanks to [[https://github.com/arozbiz][arozbiz]] for reporting.) ++ Function ~org-ql-completing-read~ would sometimes stop updating with changes in input. (See [[https://github.com/alphapapa/org-ql/issues/350][#350]]. Thanks to [[https://github.com/anpandey][Ankit Raj Pandey]] for reporting and fixing, and to [[https://github.com/minad][Daniel Mendler]] for advising.) ++ In ~org-ql-completing-read~, format links for display, and use ~org-entry-get~ internally rather than ~org-get-heading~. + +** 0.7 + +*Added* ++ Command ~org-ql-find~, which jumps to entries selected using Emacs's built-in completion facilities and Org QL queries (like ~helm-org-ql~, but doesn't require Helm.). ++ Command ~org-ql-refile~, which refiles the entry at point to one selected using Org QL completion. ++ Predicate ~rifle~, which matches an entry if each of the given arguments is found in either the entry's contents or its outline path. This provides very intuitive results, mimicing the behavior of [[https://github.com/alphapapa/org-rifle][=org-rifle=]]. In fact, the results are so useful that it's now the default predicate for plain-string query tokens. (It is also aliased to ~smart~, since it's so "smart," and not all users have used =org-rifle=.) ++ Option ~org-ql-default-predicate~, applied to plain-string query tokens (before, the ~regexp~ predicate was always used, but now it may be customized). ++ Alias ~c~ for predicate ~category~. ++ Predicate ~property~ now accepts the argument ~:inherit~ to match entries with property inheritance, and when unspecified, the option ~org-use-property-inheritance~ controls whether inheritance is used. ++ Predicate ~blocked~. (Thanks to [[https://github.com/akirak][Akira Komamura]].) + +*Changed* ++ Give more useful error message for invalid queries. ++ Predicate ~src~ now matches case-insensitively. ++ Command ~org-ql-sparse-tree~ accepts both string and sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]].) + +*Fixed* ++ Predicate ~link~ matches links whose descriptions contain escaped brackets (changed in Org 9.3). (Thanks to [[https://github.com/exot][Daniel Borchmann]] for reporting.) ++ Predicate ~src~'s matching of begin/end block lines, normalization of arguments, and handling in non-sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]] for reporting.) ++ Predicate ~src~'s behavior with various arguments. ++ Various compilation warnings. + +*Internal* ++ Certain query predicates, when called multiple times in an ~and~ sub-expression, are optimized to a single call. ++ Use ~buffer-chars-modified-tick~ instead of ~buffer-modified-tick~. (Thanks to [[https://github.com/yantar92][Ihor Radchenko]].) ++ Implemented tests for ~src~ predicate. + +*Credits* ++ Thanks to [[https://github.com/chasecaleb][Caleb Chase]] for help with [[https://github.com/alphapapa/org-ql/pull/285][#285]], fixed in [[https://github.com/alphapapa/org-ql/commit/91908186fcca4b5fd2e9d26da5bc0375c2b41acf][9190818]]. + +** 0.6.3 + +*Fixed* ++ Non-sexp query parsing with updated version 1.0.1 of the ~peg~ package. (Fixes [[https://github.com/alphapapa/org-ql/issues/314][#314]], [[https://github.com/alphapapa/org-ql/issues/316][#316]]. Thanks to [[https://github.com/akirak][Akira Komamura]] and [[https://github.com/joonro][Joon Ro]] for reporting.) ++ Require library ~org-duration~ (apparently necessary in newer Org versions). + +** 0.6.2 + +*Fixed* ++ ~link~ predicate when used in an ~or~'ed query. ([[https://github.com/alphapapa/org-ql/issues/279][#279]]. Thanks to [[https://github.com/telenieko][Marc Fargas]] for reporting.) + +** 0.6.1 + +*Fixed* ++ In dynamic blocks, links to headings with statistics cookies were broken. (Fixes [[https://github.com/alphapapa/org-ql/issues/248][#248]]. Thanks to [[https://github.com/maikol-solis][Maikol Solis]] and [[https://github.com/yantar92][Ihor Radchenko]].) + +*Updated* ++ Compatibility with new macro names in Transient. ([[https://github.com/alphapapa/org-ql/pull/269][#269]]. Thanks to [[https://github.com/tarsius][Jonas Bernoulli]].) + +** 0.6 + +*Added* ++ Macro =org-ql-defpred=, used to define search predicates. (See [[file:examples/defpred.org][tutorial]].) ++ Predicate ~effort~. ++ Predicate ~heading-regexp~, which matches regular expressions against heading text (alias: ~h*~). ++ Timestamp-related predicates now accept an optional ~:with-time~ argument, which allows matching timestamps with or without times (i.e. HH:MM). ++ Sorting methods: + - ~reverse~ + - ~closed~ (Thanks to [[https://github.com/yejianye][Ryan Ye]].) ++ Dynamic block column ~closed~. (Thanks to [[https://github.com/yejianye][Ryan Ye]].) ++ Abbreviate filenames in bookmarks. (Thanks to [[https://github.com/akirak][Akira Komamura]].) + +*Changed* ++ The order in which sorting functions is applied has been reversed. For example, ~:sort '(todo priority date)~ now does what ~:sort '(date priority todo)~ did in earlier versions. (This change is made to enable the new ~reverse~ sorting method.) Users who have customized =org-ql-views= will need to update the stored views' sorting methods to preserve the desired sort order. ++ Helm support (including the command =helm-org-ql=) has been moved to a separate package, =helm-org-ql=. ++ Predicate ~heading~ now matches plain strings instead of regular expressions. ++ Update =dash= dependency, and remove dependency on obsolete =dash-functional=. (Fixes [[https://github.com/alphapapa/org-ql/issues/179][#179]], [[https://github.com/alphapapa/org-ql/issues/209][#209]]. Thanks to [[https://github.com/landakram][Mark Hudnall]], [[https://github.com/akirak][Akira Komamura]], [[https://github.com/natask][Nathanael kinfe]], [[https://github.com/benthamite][Pablo Stafforini]], [[https://github.com/jmay][Jason May]], and [[https://github.com/basil-conto][Basil L. Contovounesios]].) + +*Removed* ++ Obsolete macro ~org-ql~ (obsolete since 0.5, replaced by functions ~org-ql-select~ and ~org-ql-query~). + +*Fixed* ++ Timestamp-related predicates called with relative-date arguments did not properly invalidate the query cache. (Fixes [[https://github.com/alphapapa/org-ql/issues/223][#223]]. Thanks to [[https://github.com/yantar92][Ihor Radchenko]] for reporting.) + +*Internal* ++ Predicates are now defined more cleanly with a macro (=org-ql-defpred=) that consolidates functionality related to each predicate. This will also allow users to more easily define custom predicates. ++ Version 1.0 of library ~peg~ is now required. ++ Improvements to how arguments to timestamp-related predicates are processed. ++ Predicate normalizers are now applied repeatedly until a query is fully normalized. (Normalizers should be written with this in mind to avoid infinite loops.) + +** 0.5.2 + +*Fixed* ++ Predicate ~link~'s ~:target~ and ~:regexp-p~ arguments. ([[https://github.com/alphapapa/org-ql/pull/220][#220]]. Thanks to [[https://github.com/akirak][Akira Komamura]].) + +** 0.5.1 + +*Fixed* ++ Custom sorting functions could corrupt the cache, causing items to disappear after refreshing an =org-ql-search= buffer. ([[https://github.com/alphapapa/org-ql/issues/186][#186]], [[https://github.com/alphapapa/org-ql/issues/187][#187]]. Thanks to [[https://github.com/natask][Nathanael kinfe]].) + +** 0.5 + +*Added* ++ View dispatcher using =transient.el= (like Magit), bound to =v= in search/view buffers. ++ Predicate =link=, which matches descriptions and targets in Org links. ++ Predicate ~tags-regexp~ (alias: ~tags*~), which matches regexps against entry tags (e.g, helpful when a tag might end in "s"). ++ Emacs bookmark support: Org QL View buffers can be bookmarked with, e.g. =C-x r m= and shown with, e.g. =C-x r b=. (This also enables view restoration with [[https://github.com/alphapapa/burly.el][Burly]].) ++ Dynamic block support. ++ Org link support (storing and opening links to Org QL View searches). ++ Mascot. + +*Changed* ++ Binding to refresh search/view buffers changed to =r=. + +*Internal* ++ When formatting entries for Org QL View buffers, use internal function for retrieving heading tags. This improves speed by using our cache, and it removes the need for a compatibility alias for Org versions before 9.3. + +*Deprecated* ++ Macro =org-ql= is marked obsolete. It will be removed in v0.7. Functions =org-ql-select= and =org-ql-query= should be used instead. (The macro serves only to confuse with regard to quoting arguments.) + +*Acknowledgments* ++ [[https://github.com/tpeacock19][tpeacock19]] for extensive help testing new features in this version. + +** 0.4.9 + +*Fixed* ++ Agenda restriction in =org-ql-block=. (Fixes [[https://github.com/alphapapa/org-ql/issues/84][#84]]. Thanks to [[https://github.com/yantar92][Ihor Radchenko]].) + +** 0.4.8 + +*Fixed* ++ Multiple sorters not preserved when refreshing views. (Fixes [[https://github.com/alphapapa/org-ql/issues/136][#136]], [[https://github.com/alphapapa/org-ql/pull/137][#137]]. Thanks to [[https://github.com/natrys][Imran Khan]].) + +** 0.4.7 + +*Fixed* ++ Give a useful error if =org-ql-search-directories-files= is called without a directories argument and =org-directory= doesn't exist. (Fixes [[https://github.com/alphapapa/org-ql/issues/139][#139]]. Thanks to [[https://github.com/matthuszagh][Matt Huszagh]] for reporting.) + +** 0.4.6 + +*Fixed* ++ Compatibility with newer versions of the =peg= library, which removed a macro used by this package. (Fixes [[https://github.com/alphapapa/org-ql/issues/75][#75]]. Thanks to [[https://github.com/novoid][Karl Voit]] and [[https://github.com/karlicoss][@karlicoss]] for reporting.) + +** 0.4.5 + +*Fixed* ++ Non-case-folding predicates like ~(todo)~ unnecessarily disabled case-folding for other predicates. ([[https://github.com/alphapapa/org-ql/issues/114][Issue #114]]. Thanks to [[https://github.com/bitclick][@bitclick]] for reporting.) + +** 0.4.4 + +*Fixed* ++ Compatibility with Org Agenda remote editing commands (some of which were broken by 0.4.3). (Fixes [[https://github.com/alphapapa/org-ql/issues/102][#102]]. Thanks to [[https://github.com/AloisJanicek][Alois Janíček]] for reporting.) + +** 0.4.3 + +*Fixed* ++ When =org-ql-view-refresh= is called, ensure the buffer is an Org QL View buffer. + +** 0.4.2 + +*Fixed* ++ Items' to-do keywords were not shown in views. + +** 0.4.1 + +*Fixed* ++ =level= predicate used with arguments in plain queries. (Thanks to [[https://github.com/akirak][Akira Komamura]] for reporting.) + +** 0.4 + +/Note:/ The next release, 0.5, may include changes which will require minor updates to written queries (e.g. a few predicates may be renamed). Users who wish to avoid those changes happening unexpectedly in their configs should avoid upgrading =org-ql= beyond 0.4 automatically, as they will be pushed to the =master= branch when ready. + +*Added* ++ *Commands* + - ~helm-org-ql-views~, which shows one of ~org-ql-views~ selected with Helm. + - ~org-ql-search~ can search files in ~org-directory~; customization options are available in the ~org-ql-search~ group. + - ~org-ql-view-refresh~ can be called with a prefix argument to adjust search parameters. ++ *Queries* + - Negation of terms in plain queries using ~!~. For example, ~tags:space !moon~ to exclude entries which contain ~moon~. + - Predicates =outline-path= (alias =olp=) and =outline-path-segment= (alias =olps=). + - Predicate ~src~, which matches Org Babel source blocks. + - Predicates =parent= and =ancestors=. (Thanks to [[https://github.com/mm--][Josh Moller-Mara]].) + - Alias =h= for =heading= predicate. + - Alias =r= for =regexp= predicate. (Thanks to [[https://github.com/tumashu][Feng Shu]].) ++ Info manual. ++ Function ~helm-org-ql-source~, which returns a Helm source that searches given buffers/files with ~helm-org-ql~. It can be used for custom Helm commands that search certain files. ++ Display a message when views are refreshed. (Thanks to [[https://github.com/xeijin][xeijin]].) ++ Respect Org Agenda restriction in =org-ql-block=. (Thanks to [[https://github.com/yantar92][Ihor Radchenko]] for reporting.) ++ Option =org-ql-view-sidebar-sort-views=. ++ Mouseover =help-echo= text for =org-ql-views= default view names. ++ "Dangling tasks" default view in =org-ql-views=. (Users who have modified =org-ql-views= from the default will not see the new view unless they copy it into their config.) + +*Changed* ++ Some default =org-ql-view= views (users who have modified =org-ql-views= from the default will not see the new views unless they copy them into their config): + - Rename some views. + - "Stuck projects" view (now uses =descendants= instead of =children=, which is more useful. + +*Fixed* ++ Inherit file tags when =org-tag-inheritance= is enabled. (Fixes [[https://github.com/alphapapa/org-ql/issues/55][#55]]. Thanks to [[https://github.com/mskorzhinskiy][Mikhail Skorzhinskiy]].) ++ Call =helm-make-source= directly instead of using =helm-build-sync-source= macro. (Fixes [[https://github.com/alphapapa/org-ql/issues/60][#60]]. Thanks to [[https://github.com/matthuszagh][Matt Huszagh]] for reporting.) ++ Search/view buffers now always end with a newline, which prevents side-scrolling of the window when calling =end-of-buffer=. ++ Face for done to-do keywords in =org-ql-view= buffers. (Thanks to [[https://github.com/dsdshcym][Yiming Chen]].) ++ Make view buffers read-only. (Fixes [[https://github.com/alphapapa/org-ql/issues/72][#72]]. Thanks to [[https://github.com/xeijin][xeijin]].) ++ Sorting with single sorter specified as an atom. (Thanks to [[https://github.com/legalnonsense][Jeff Filipovits]].) ++ Autoload for =org-ql-block= agenda block. (Fixes [[https://github.com/alphapapa/org-ql/issues/53][#53]]. Thanks to reports from [[https://github.com/gcantieni][Gus Cantieni]], [[https://github.com/novoid][Karl Voit]], [[https://github.com/rieje][rieje]], and [[https://github.com/jakejx][Jake | Junxuan]].) + +*Internal* ++ Added generic node data cache to speed up recursive, tree-based queries. + +** 0.3.2 + +*Fixed* ++ In =org-ql-search=, accept symbol as ~:super-groups~ argument. ++ In the =This week= and =Next week= default =org-ql-views= views, set timestamps for beginning-of-week to 00:00:00 and end-of-week to 23:59:59. ++ Plain quoted-phrases in non-sexp queries. + +** 0.3.1 + +*Fixed* ++ Compatibility with Org 9.2. Thanks to [[https://github.com/leungbk][Brian Leung]]. + +** 0.3 + +*Added* ++ Alternative, non-sexp query syntax for commands =org-ql-search= and =helm-org-ql=. See [[#non-sexp-query-syntax][documentation]]. ++ Command =helm-org-ql=. ++ Command =org-ql-sparse-tree=, like =org-sparse-tree= for =org-ql= queries. (Thanks to [[https://github.com/akirak][Akira Komamura]].) ++ Command =org-ql-view-sidebar=. ++ Per-buffer, per-heading tag caching, which increases the speed of tags-related queries by 6-7x. ++ More tags-related predicates and aliases: + - For inherited tags: =tags-inherited=, =inherited-tags=, =tags-i=, =itags=. + - For heading-local tags: =tags-local=, =local-tags=, =tags-l=, =ltags=. + - =tags-all=, =tags&=: Matches all given tags using boolean =AND= (rather than boolean =OR=, which the =tags= predicate uses). ++ Variable =org-ql-block-header=, which overrides the default header in =org-ql-block= agenda blocks. ++ Predicate =(path)=. ++ Option =org-ql-views= may now be customized in a guided, structured way with the customization UI (e.g. =M-x customize-option RET org-ql-views RET=, or press =c= in the =org-ql-view-sidebar= buffer). ++ Enable more Org Agenda commands in =org-ql-view= buffers (e.g. setting deadlines and scheduling). (Fixes [[https://github.com/alphapapa/org-ql/issues/35][#35]]. Thanks to [[https://github.com/mz-pdm][Milan Zamazal]] and [[https://github.com/mskorzhinskiy][Mikhail Skorzhinskii]].) ++ Function =org-ql-select='s =buffers-files= argument can be a function which returns a list of buffers and/or files. + +*Changed* ++ Predicate =heading= now accepts multiple regexps, which are matched with boolean =AND=. ++ Predicate =regexp= now matches its regexp arguments with boolean =AND=. ++ Package =org-super-agenda= is now a dependency. This removes the need for awkward code to handle the case where it's not installed, and makes grouping features always available. Of course, the global minor mode =org-super-agenda-mode= is not activated by =org-ql=, so no behavior is changed in Org Agenda or =org-ql=; it only means that commands like =org-ql-search= will always provide grouping when called with the appropriate arguments. + +*Removed* ++ Macro =org-ql-agenda=. Instead, use function =org-ql-search=. See also command =org-ql-view=, etc. + +*Fixed* ++ Predicate =heading= now matches only against heading text, i.e. not including tags at the end of the line, to-do keyword, etc. ++ Predicate =todo= now matches case-sensitively, avoiding non-todo-keyword matches (e.g. a heading which begins =Waiting on= will no longer match for a todo keyword =WAITING=). ++ Interactive completion in =org-ql-search=. + +*Internal* ++ Refactored code from file =org-ql-agenda.el= into files =org-ql-search.el= and =org-ql-view.el=. Function and variable names have been changed accordingly. + +** 0.2.3 + +*Fixed* ++ Priority queries could fail to match headings whose to-do keywords had non-alphabetic characters, like =TO-READ=. + +** 0.2.2 + +*Fixed* ++ =(deadline auto)= selector matched entries whose deadlines had a warning period that had not yet been entered (=org-deadline-warning-days= too soon). + +** 0.2.1 + +*Fixed* ++ =(descendants)= selector matched against parent heading instead of only descendants. + +** 0.2 +:PROPERTIES: +:ID: 67be09f9-e959-4333-9be2-93ad8f458fbe +:END: + +*Added* ++ Function ~org-ql-query~, like ~org-ql-select~ but with arguments named more like a SQL query. ++ Bare strings like ~"string"~ can be used in queries, which are converted to ~(regexp "string")~ automatically. ++ Selector ~(regexp)~ accepts multiple regexps to test. ++ Macro ~org-ql~ and functions ~org-ql-query~ and ~org-ql-select~ now also accept a comparator function in their ~:sort~ argument. ++ Function ~org-ql-block~, which works as an Org Agenda series/composite/block command, usable in custom agenda commands defined in variable ~org-agenda-custom-commands~. (Inspired by [[https://github.com/pestctrl/emacs-config/blob/84c557982a860e86d6f67976a82ea776a7bd2c7a/config-org-new.org#my-own-agenda-renderer][Benson Chu's config]].) ++ Function ~org-ql-agenda--agenda~ optionally takes a list of entries as an argument. ++ Selectors ~ts-a~ and ~ts-i~, aliases for ~ts-active~ and ~ts-inactive~. ++ Selector ~ts~ now accepts a ~:type~ argument. ++ Face =org-ql-agenda-due-date=. ++ Selectors ~(children)~ and ~(descendants)~. ++ Function ~org-ql-search~ and macro ~org-ql-agenda~ accept a ~:title~ argument, which is displayed in the header. ++ Command ~org-ql-search~ offers global ~org-super-agenda-groups~ in completion. ++ Customization group ~org-ql~. ++ Command ~org-ql-view~, which displays views saved to variable ~org-ql-views~, which can be saved from ~org-ql-search~ buffers with command ~org-ql-search-save~, which is bound to =C-x C-s= in view buffers. ++ Variable ~org-ql-view-map~, active in view buffers displayed by ~org-ql-search~, ~org-ql-agenda~, and ~org-ql-view~. ++ =random= sort method. ++ Save position when refreshing search buffers. + +*Changed* ++ Function ~org-ql-query~ renamed to ~org-ql-select~. ~org-ql-query~ now refers to a new function. ++ Macro ~org-ql~ no longer accepts a ~:markers~ argument. Instead, use argument ~:action element-with-markers~. See function ~org-ql-select~, which ~org-ql~ calls. ++ Selector ~(todo)~ no longer matches "done" keywords when used without arguments (i.e. the ones in variable ~org-done-keywords~). ++ Overhauled date/time-based predicates. See documentation for new argument signatures. + +*Removed* ++ Selector ~(date)~, replaced by ~(ts)~. + +*Fixed* ++ Handle date ranges in date-based selectors. (Thanks to [[https://github.com/codygman][Cody Goodman]], [[https://github.com/swflint][Samuel W. Flint]], and [[https://github.com/vikasrawal][Vikas Rawal]].) ++ Don't overwrite bindings in =org-agenda-mode-map=. ++ Don't search buffers without headings, and show a message if the user attempts it. ++ Don't search hidden/special buffers. ++ Properly accept arbitrary sort functions in =org-ql-select=, etc. (Fixes [[https://github.com/alphapapa/org-ql/issues/37][#37]]. Thanks to [[https://github.com/mz-pdm][Milan Zamazal]].) ++ Planning-line-related predicates searched too far into entries. ++ Add autoloads. (Fixes [[https://github.com/alphapapa/org-ql/pull/36/files#][#36]]. Thanks to [[https://github.com/akirak][Akira Komamura]].) + +*Compatibility* ++ Fixes for compatibility with Org 9.2. (Thanks to [[https://github.com/ataias][Ataias Pereira Reis]] and [[https://github.com/dakra][Daniel Kraus]].) + +*Internal* ++ Optimizations for some query selectors, e.g. =regexp= and =todo=. These can provide a significant improvement for some queries. See benchmarks in [[file:notes.org][notes.org]]. ++ Library [[https://github.com/alphapapa/ts.el][ts]] is now used for parsing and comparing timestamps. + +** 0.1 + +First tagged release. + +* Development + +Bug reports, feature requests, and suggestions are welcome. For patches, see below. + +** Copyright assignment + +While Org QL is currently distributed in MELPA, it's [[https://github.com/alphapapa/org-ql/issues/409][intended]] to merge Org QL into Org mode. When that happens, it will become a part of Emacs and Org, and therefore cumulative contributions of more than 15 lines of code will require that the author assign copyright of such contributions to the FSF. Authors who are interested in doing so may contact [[mailto:assign@gnu.org][assign@gnu.org]] to request the appropriate form. + +* Notes +:PROPERTIES: +:TOC: :ignore this +:END: + +** Comparison with Org Agenda searches + +Of course, queries like these can already be written with Org Agenda searches, but the syntax can be complex. For example, this query would be difficult to write in a standard Org Agenda search, because it matches against a to-do keyword /and/ a plain-text search. As described in the [[https://orgmode.org/worg/org-tutorials/advanced-searching.html#combining-metadata-and-full-text-queries][advanced searching tutorial]], it would require using ~org-search-view~ with a query with specific regular expression syntax, like this: + +#+BEGIN_EXAMPLE + +lisp +{^\*+\s-+TO-READ\s-} +#+END_EXAMPLE + +But with =org-ql-search=, you would write a query like =lisp todo:TO-READ=, or in Lisp syntax, ~(and "lisp" (todo "TO-READ"))~. + +** org-sidebar + +This package is used by [[https://github.com/alphapapa/org-sidebar][org-sidebar]], which presents a customizable agenda-like view in a sidebar window. + +* License +:PROPERTIES: +:TOC: :ignore this +:END: + +GPLv3 + +* COMMENT Code :noexport: +:PROPERTIES: +:TOC: :ignore this +:END: + +# The COMMENT keyword prevents GitHub's renderer from showing this entry. + +Code used to update this document. + +** Predicates + +Generates the predicate subtree. + +#+BEGIN_SRC elisp :results silent :exports code + (defun org-ql--readme-update-predicates () + "Update predicate subtree in current document." + (interactive) + (org-ql--readme-replace-node '("Usage" "Queries" "Predicates") (org-ql--readme-predicate-list))) + + (defun org-ql--readme-replace-node (outline-path string) + "Replace contents of node at OUTLINE-PATH with STRING." + (org-with-wide-buffer + (-let* ((subtree-marker (org-find-olp outline-path t)) + ((_headline element) (progn + (goto-char subtree-marker) + (org-element-headline-parser (point-max)))) + ((&plist :contents-begin beg :contents-end end) element)) + (goto-char beg) + (delete-region (point) (1- end)) + (insert string "\n")))) + + (defun org-ql--readme-predicate-list () + "Return an Org list string documenting predicates." + (concat (unpackaged/docstring-to-org + "Arguments are listed next to predicate names, where applicable. + + Note that, for convenience, standard numeric comparator function symbols (`<', `=', etc.) do not need to be quoted when passed as an argument to these predicates. The resemblance to infix notation is coincidental. See examples in documentation.\n\n") + (s-join "\n" (->> org-ql-predicates + (--sort (string< (symbol-name (plist-get it :name)) + (symbol-name (plist-get other :name)))) + (--map (-let* (((&plist :name name :docstring docstring :fn fn :args args) it) + (args (->> args + (--replace-where (listp it) (car it)) + (--replace-where (eq '&rest it) '&optional)))) + (if docstring + (progn + (setq docstring (s-replace "\n" " " docstring)) + (format "+ ~%s%s~ :: %s" name + (if args + (format " %s" args) + "") + (unpackaged/docstring-to-org docstring))) + (when (s-prefix? "org-ql-" (symbol-name name)) + (warn "No docstring for: %s" name)) + nil))) + -non-nil)))) +#+END_SRC + +*** TODO Use async + +If ~org-ql~ is loaded byte-compiled, the argument lists are not named properly (not sure why, as ~help-function-arglist~ is supposed to handle that). We could run the function in another Emacs process with ~async~ to avoid this. + +* COMMENT Export setup :noexport: +:PROPERTIES: +:TOC: :ignore this +:END: + +# Copied from org-super-agenda's readme, in which much was borrowed from Org's =org-manual.org=. + +#+OPTIONS: broken-links:t *:t + +** Info export options + +#+TEXINFO_DIR_CATEGORY: Emacs +#+TEXINFO_DIR_TITLE: Org QL: (org-ql) +#+TEXINFO_DIR_DESC: Query language, search commands, and saved views for Org files + +# NOTE: We could use these, but that causes a pointless error, "org-compile-file: File "..README.info" wasn't produced...", so we just rename the files in the after-save-hook instead. +# #+TEXINFO_FILENAME: org-ql.info +# #+EXPORT_FILE_NAME: org-ql.texi + +** File-local variables + +# NOTE: Setting org-comment-string buffer-locally is a nasty hack to work around GitHub's org-ruby's HTML rendering, which does not respect noexport tags. The only way to hide this tree from its output is to use the COMMENT keyword, but that prevents Org from processing the export options declared in it. So since these file-local variables don't affect org-ruby, wet set org-comment-string to an unused keyword, which prevents Org from deleting this tree from the export buffer, which allows it to find the export options in it. And since org-export does respect the noexport tag, the tree is excluded from the info page. + +# Local Variables: +# before-save-hook: org-make-toc +# after-save-hook: (lambda nil (when (and (require 'ox-texinfo nil t) (org-texinfo-export-to-info)) (delete-file "README.texi") (rename-file "README.info" "org-ql.info" t))) +# org-export-initial-scope: buffer +# org-comment-string: "NOTCOMMENT" +# End: diff --git a/dog-153497_960_720.png b/dog-153497_960_720.png deleted file mode 100644 index 7f1cbef..0000000 Binary files a/dog-153497_960_720.png and /dev/null differ diff --git a/dog.xcf b/dog.xcf deleted file mode 100644 index 7e253aa..0000000 Binary files a/dog.xcf and /dev/null differ diff --git a/examples.org b/examples.org new file mode 100644 index 0000000..1c5ef9d --- /dev/null +++ b/examples.org @@ -0,0 +1,257 @@ +#+TITLE: org-ql examples + +* Contents +:PROPERTIES: +:TOC: :include siblings :ignore this +:END: +:CONTENTS: +- [[#custom-predicates][Custom predicates]] +- [[#agenda-like-view][Agenda-like view]] +- [[#entries-from-the-past-week][Entries from the past week]] +- [[#find-entries-matching-a-certain-custom_id][Find entries matching a certain CUSTOM_ID]] +- [[#listing-bills-coming-due][Listing bills coming due]] +- [[#music-database][Music database]] +- [[#return-org-elements][Return Org elements]] +- [[#set-tags-on-certain-entries][Set tags on certain entries]] +- [[#show-entries-with-recent-timestamps][Show entries with recent timestamps]] +- [[#stuck-projects-block-agenda][Stuck projects block agenda]] +- [[#subproject-and-subtask-queries][Subproject and subtask queries]] +- [[#task-list-for-files-in-subdirectories][Task list for files in subdirectories]] +:END: + +* Custom predicates + ++ [[file:examples/defpred.org][Custom predicate tutorial]] + +* Agenda-like view + +Show an agenda-like view, similar to a "traditional" Org Agenda with Log Mode turned on. + +#+BEGIN_SRC elisp + (org-ql-search (org-agenda-files) + '(or (and (not (done)) + (or (habit) + (deadline auto) + (scheduled :to today) + (ts-active :on today))) + (closed :on today)) + :sort '(todo priority date)) +#+END_SRC + +Another example, showing grouping with [[https://github.com/alphapapa/org-super-agenda][org-super-agenda]]: + +#+BEGIN_SRC elisp + (org-ql-search "~/src/emacs/org-super-agenda/test/test.org" + '(and (or (ts-active :on today) + (deadline auto) + (scheduled :to today)) + (not (done))) + :title "My Agenda View" + ;; The `org-super-agenda-groups' setting is used automatically when set, or it + ;; may be overriden by specifying it here: + :super-groups '((:name "Bills" + :tag "bills") + (:todo ("SOMEDAY" "TO-READ" "CHECK" "TO-WATCH" "WATCHING") + :order 7) + (:name "Personal" + :habit t + :tag "personal" + :order 3) + (:todo "WAITING" + :order 6) + (:priority "A" :order 1) + (:priority "B" :order 2) + (:priority "C" :order 2))) +#+END_SRC + +Which displays this buffer: + +[[images/screenshot.png]] + +* Entries from the past week + +Show entries that have any timestamp within the past week. Group by date using =org-super-agenda= with the =:auto-ts= group. + +#+BEGIN_SRC elisp + (org-ql-search (org-agenda-files) + '(ts :from -7 :to today) + :title "Recent Items" + :sort '(todo priority date) + :super-groups '((:auto-ts t))) +#+END_SRC + +* Find entries matching a certain =CUSTOM_ID= + +Since queries can contain both built-in =org-ql= predicate expressions and arbitrary expressions, they can be combined in useful ways. This example uses the built-in =property= predicate to quickly locate entries that have the =CUSTOM_ID= property set, and then compares the value of that property to the string =issue=. + +#+BEGIN_SRC elisp + (org-ql-query + :select #'org-get-heading + :from "~/org/tickets.org" + :where '(and (property "CUSTOM_ID") + (string-match "issue" (org-entry-get (point) "CUSTOM_ID")))) +#+END_SRC + +Using the =property= predicate as the first clause of the two clauses joined with =and= allows =org-ql= to optimize the query by searching through the buffer directly to entries that set the =CUSTOM_ID= property, which is much faster than testing every entry in a buffer. Also, If the query were only the =string-match= call, it would signal an error on entries that didn't have the property set, because =org-entry-get= would return nil. + +* Listing bills coming due + +This uses the example in the readme file, but maps across the elements returned by ~org-ql~ to present a simple list of titles and deadlines. + +#+BEGIN_SRC elisp + (org-ql-query + :select '(list (substring-no-properties (org-get-heading t t)) + (org-entry-get (point) "DEADLINE")) + :from (org-agenda-files) + :where '(and (not (done)) + (tags "bills") + (deadline auto)) + :order-by 'deadline) + ;;=> (("Electric bill" "<2018-08-23 Thu +1m>") + ;; ("Rent" "<2018-09-01 Sat +1m>")) +#+END_SRC + +This could also be put in a script, which could use desktop notifications to remind of bills coming due: [[examples/org-bills-due.el][org-bills-due.el]]. + +* Music database + + If you kept a database of music in an Org file, you could run a query like this to find tracks composed by Chopin that do not have their key recorded in the database. + +#+BEGIN_SRC elisp + (org-ql-search "~/org/music.org" + '(and (property "genre" "classical") + (property "composer" "Chopin") + (not (property "key")))) +#+END_SRC + +* Return Org elements + +Return a list of Org entry elements in the file =~/org/main.org= which have the =SOMEDAY= to-do keyword, are tagged =Emacs=, and have priority B or higher. =org-ql= is the macro version of =org-ql-select=; it does not require quoting the query sexp. + +#+BEGIN_SRC elisp + (org-ql "~/org/main.org" + (and (todo "SOMEDAY") + (tags "Emacs") + (priority >= "B"))) + ;;=> ((headline (:raw-value "org-board" :begin 1220270 :end 1220403 ...)) ...) +#+END_SRC + +* Set tags on certain entries + +Set the tag =Emacs= on every entry in the inbox file that mentions =Emacs=. The bare-string query ="Emacs"= is equivalent to ~(regexp "Emacs")~. + +#+BEGIN_SRC elisp + (org-ql-select "~/org/inbox.org" + "Emacs" + :action '(org-toggle-tag "Emacs" 'on)) +#+END_SRC + +* Show entries with recent timestamps + +You can also access these views with the command ~org-ql-view~. + +#+BEGIN_SRC elisp + ;; Show entries with any timestamp from last 7 days: + (org-ql-view-recent-items 7) + + ;; Show entries clocked in last 30 days: + (org-ql-view-recent-items 30 'clocked) + + ;; Show entries closed in last 30 days: + (org-ql-view-recent-items 30 'closed) +#+END_SRC + +* Stuck projects block agenda + +Reddit user =emptymatrix= [[https://www.reddit.com/r/emacs/comments/cnrt2d/orgqlblock_integrates_orgql_into_org_agenda/ewtqez8/][shared]] this example of replacing a traditional =org-stuck-projects= view like: + +#+BEGIN_SRC elisp + (setq org-stuck-projects + '("+@project/-DONE" ("NEXT") nil "SCHEDULED:")) +#+END_SRC + +With this =org-ql-block= agenda view, like: + +#+BEGIN_SRC elisp + (setq org-agenda-custom-commands + '(("s" "Stuck Projects" + ((org-ql-block '(and (tags "@project") + (not (done)) + (not (descendants (todo "NEXT"))) + (not (descendants (scheduled)))) + ((org-ql-block-header "Stuck Projects"))))))) +#+END_SRC + +* Subproject and subtask queries + +#+BEGIN_SRC elisp + ;; Search for subprojects. + (org-ql-search (org-agenda-files) + '(and (todo "PROJECT") + (ancestors (todo "PROJECT")))) + + ;; Search for all subtasks of projects, grouped by parent heading. + (org-ql-search (org-agenda-files) + '(and (todo) + (ancestors (todo "PROJECT"))) + :super-groups '((:auto-parent t))) + + ;; Search for direct top-level tasks of projects. + (org-ql-search (org-agenda-files) + '(and (todo) + (parent (todo "PROJECT"))) + :super-groups '((:auto-parent t))) +#+END_SRC + +Of course, all of those presume using a =PROJECT= keyword to define projects. If one defines a project as any task which has an ancestor task, one could use queries like: + +#+BEGIN_SRC elisp + ;; Search for all subtasks of top-level projects, grouped by parent heading. + (org-ql-search (org-agenda-files) + '(and (todo) + (ancestors + (and (todo) + (not (parent))))) + :super-groups '((:auto-parent t))) + + ;; Search for all subtasks of all projects, including subprojects, grouped by project. + (org-ql-search (org-agenda-files) + '(and (todo) + (ancestors (todo))) + :super-groups '((:auto-parent t))) +#+END_SRC + +Other interesting queries: + +#+BEGIN_SRC elisp + ;; Subtasks of upcoming deadline items. + (org-ql-search (org-agenda-files) + '(and (todo) + (ancestors + (and (not (done)) + (deadline auto)))) + :super-groups '((:auto-parent t))) + + ;; TODO items whose ancestor is already DONE, and should therefore be + ;; either marked DONE or CANCELLED. + (org-ql-search (org-agenda-files) + '(and (todo) + (ancestors (done))) + :super-groups '((:auto-parent t))) +#+END_SRC + +* Task list for files in subdirectories + +[[images/org-ql-search-snippet.png]] + +* COMMENT Code :noexport: +:PROPERTIES: +:TOC: :ignore (this descendants) +:END: + +** File-local variables + +# Local Variables: +# eval: (require 'org-make-toc) +# before-save-hook: org-make-toc +# End: diff --git a/examples/defpred.html b/examples/defpred.html new file mode 100644 index 0000000..9c9b57e --- /dev/null +++ b/examples/defpred.html @@ -0,0 +1,766 @@ + + + + + + + +Org QL Custom Predicates Tutorial + + + + + + + + + + + + + +
+

Org QL Custom Predicates Tutorial

+ +

+[2020-11-22 Sun 22:35] Imagine you have weekly meetings with other people, and during the week you take notes about items to discuss at each meeting. When the time for a meeting comes, you want to quickly and easily search for all of the items to discuss at the meeting. +

+ +

+You've been experimenting with different ways to track such data in Org. You've tried using tags, but some of the names in question conflict with other tags in your data (e.g. someone's named Charles, but you also work with a firm named Charles, Inc., and you'd prefer to continue using the tag Charles for entries about that firm), so you've been using tags like :personNAME:, which seems awkward. You've tried using a :person: NAME property on entries, which has the advantage of not cluttering the tags list, but also the disadvantage of not being readily visible in an outline. +

+ +

+So you haven't decided on a long-term solution, but the meetings aren't going to wait–you need to search that data now, and you have a mix of both tags and properties in your entries. What you need is to be able to search for all of the entries about Alice (which you've tagged :personAlice:) when you're meeting with her, and all of the entries about Bob (which have the property :person: Bob) when you're meeting with him. What do you do? +

+ +
+

Using built-in predicates

+
+

+You could start by using built-in Org QL predicates to search your data. For example: +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(or (tags "personAlice")
+                          (property "person" "Bob")))
+
+
+ +
    +
  • [#A] Loud pet parakeet
  • +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
  • [#A] Stinky coffee breath
  • +
+ +

+That was easy enough, but it's not very…semantic. You have to think about the implementation details: Alice uses tags, Bob uses properties, and what if Charlie uses both? It starts to feel complicated, and it's a lot to type out every time. Is there an easier way? +

+
+
+ +
+

A custom (person) predicate

+
+

+Enter org-ql custom search predicates. Let's start simple, by defining a predicate to search for just the :person: property, one person at a time. The predicate will take one argument, a person's name, and search for that property. It would look like this: +

+ +
+
(org-ql-defpred person (name)
+  "Search for entries with the \"person\" property being NAME."
+  :body (property "person" name))
+
+
+ +

+Now, let's see what results we get for searching this file for entries about Bob: +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(person "Bob"))
+
+
+ +
    +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
  • [#A] Stinky coffee breath
  • +
+ +

+Hmm, looks like we need to remind Bob to wash his mug and take some mints after lunch. Now what do we need to discuss with Alice? +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(person "Alice"))
+
+
+ +
+
+ +

+Nothing? Oh, right, Alice's entries use the :personAlice: tag, so we'll also need to search those kind of entries. Let's make the predicate do that, too: +

+ +
+
(org-ql-defpred person (name)
+  "Search for entries with the \"person\" property being NAME or having the tag \"personNAME\"."
+  :body (or (property "person" name)
+            (tags (concat "person" name))))
+
+
+ +

+How about now? +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(person "Alice"))
+
+
+ +
    +
  • [#A] Loud pet parakeet
  • +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
+ +

+Hmm, I thought we already told her to leave Polly at home. +

+
+
+ +
+

Searching for multiple people at once

+
+

+Oh, wait, this week is shortened due to holidays, so we're having a combined meeting. How do we search for entries about either of them? Well, this is the obvious solution: +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(or (person "Alice")
+                          (person "Bob")))
+
+
+ +
    +
  • [#A] Loud pet parakeet
  • +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
  • [#A] Stinky coffee breath
  • +
+ +

+And that works fine. But it seems like a lot to type. Could we make the person predicate accept multiple names instead? +

+ +
+
(org-ql-defpred person (&rest names)
+  "Search for entries about any of NAMES."
+  :body (cl-loop for name in names
+                 thereis (or (property "person" name)
+                             (tags (concat "person" name)))))
+
+
+ +

+Now let's search again: +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(person "Alice" "Bob"))
+
+
+ +
    +
  • [#A] Loud pet parakeet
  • +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
  • [#A] Stinky coffee breath
  • +
+ +

+That was easy! +

+
+
+ +
+

Normalizing queries to rewrite arguments

+
+

+Now, all this is well and good if you don't have hundreds of thousands of Org entries in your files. But what if you do? All that concat'ing happening on every entry could add up, and the query might take a few seconds. What if we could do that stringing-along just once, before running the query? We want to turn our (person "Alice" "Bob") query into this, with the :personNAME: strings already made and the per-person (property ...) predicates also included: +

+ +
+
(or (tags "personAlice" "personBob")
+    (property "person" "Alice")
+    (property "person" "Bob"))
+
+
+ +

+Can we do that? In fact, we can, by using a query normalizer. Normalizers are pcase forms (I know) that normalize query expressions before execution. We can use one to rewrite the query ahead of time, like this: +

+ +
+
(org-ql-defpred person (&rest names)
+  "Search for entries about any of NAMES."
+  :normalizers ((`(person . ,names)
+                 `(or (tags ,@(cl-loop for name in names
+                                       collect (concat "person" name)))
+                      ,@(cl-loop for name in names
+                                 collect `(property "person" ,name)))))
+  :body (cl-loop for name in names
+                 thereis (or (property "person" name)
+                             (tags name))))
+
+
+ +

+Now, don't faint from all the backquoting and unquoting–it's just Lisp, nothing to be afraid of! Let's slow down a moment and see what the normalized query looks like to be sure we're doing it correctly: +

+ +
+
(org-ql--normalize-query '(person "Alice" "Bob"))
+
+
+ +
+
(or (tags "personAlice" "personBob")
+    (property "person" "Alice")
+    (property "person" "Bob"))
+
+
+ +

+And, as they say, Bob's your uncle! Or even if he isn't, let's see if it works: +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(person "Alice" "Bob"))
+
+
+ +
    +
  • [#A] Loud pet parakeet
  • +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
  • [#A] Stinky coffee breath
  • +
+ +

+Yep, same result as the non-normalized query. And look at how much simpler it is to write (person "Alice" "Bob") than to write (or (tags "personAlice" "personBob") (property "person" "Alice") (property "person" "Bob")). +

+
+
+ +
+

Non-sexp query syntax

+
+

+But wait, that's not all! If you order now, we'll throw in non-sexp query syntax for free! That's right, your search could be as simple as typing person:Alice,Bob! +

+ +
+
(org-ql-search (current-buffer) "person:Alice,Bob")
+
+
+ +

+Don't believe me? Well, you see, queries in this syntax are converted to the sexp syntax, like: +

+ +
+
(org-ql--query-string-to-sexp "person:Alice,Bob")
+
+
+ +
+
(person "Alice" "Bob")
+
+
+ +

+And that happens automatically when you use a search command like org-ql-search. If you have org-ql installed already, you could even click this link: Alice or Bob. Which, in Org syntax, looks like: +

+ + + +

+And that would open an Agenda Mode buffer that looks like this: +

+ +
+Query: (person "Alice" "Bob")  In:meetings.org
+  [#A] Loud pet parakeet                                           :personAlice:
+  [#C] Missing sticky notes                                        :personAlice:
+  [#C] Dirty dishes in sink                                        :personAlice:
+  [#A] Stinky coffee breath
+
+
+
+ +
+

Using multiple predicates

+
+

+Oops, you forgot that there's a birthday party in 20 minutes, so you only have time to talk about the highest priority items at this joint meeting today. +

+ +

+No problem, let's just select high-priority items: +

+ +
+
(org-ql-search (current-buffer) "person:Alice,Bob priority:A")
+
+
+ +

+Which shows: +

+ +
+Query: (and (person "Alice" "Bob") (priority "A"))  In:meetings.org
+  [#A] Loud pet parakeet                                           :personAlice:
+  [#A] Stinky coffee breath
+
+
+
+ +
+

Predicate aliases

+
+

+And, you know what, if you're just so busy that you don't even have time to type the word person, you can add an abbreviated alias, p, like this: +

+ +
+
(org-ql-defpred (person p) (&rest names)
+  "Search for entries about any of NAMES."
+  :normalizers ((`(,predicate-names . ,names)
+                 `(or (tags ,@(cl-loop for name in names
+                                       collect (concat "person" name)))
+                      ,@(cl-loop for name in names
+                                 collect `(property "person" ,name)))))
+  :body (cl-loop for name in names
+                 thereis (or (property "person" name)
+                             (tags (concat "person" name)))))
+
+
+ +

+Let's try it: +

+ +
+
(org-ql-search (current-buffer) "p:Alice,Bob priority:A")
+
+
+ +

+And that shows: +

+ +
+Query: (and (person "Alice" "Bob") (priority "A"))  In:meetings.org
+  [#A] Loud pet parakeet                                           :personAlice:
+  [#A] Stinky coffee breath
+
+ +

+(It's up to you to remember whether p means person or priority, but code can't solve everything.) +

+
+
+ +
+

Be formless

+
+

+We can even go a step further: since the normalizer rewrites the query to call the property and tags predicates instead, this person predicate doesn't even need a body form! +

+ +
+
(org-ql-defpred (person p) (&rest names)
+  "Search for entries about any of NAMES."
+  :normalizers ((`(,predicate-names . ,names)
+                 `(or (tags ,@(cl-loop for name in names
+                                       collect (concat "person" name)))
+                      ,@(cl-loop for name in names
+                                 collect `(property "person" ,name))))))
+
+
+ +

+Will it still work? +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(person "Alice" "Bob"))
+
+
+ +
    +
  • [#A] Loud pet parakeet
  • +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
  • [#A] Stinky coffee breath
  • +
+ +

+It does! +

+
+
+ +
+

Conclusion

+
+

+In this tutorial, we've gone from having to write lengthy, complex query expressions for accommodating idiosyncratic requirements, to being able to write simple query expressions that abstract away ugly details, to rewriting those query expressions into a more optimal form before a search is even run. The end result is an Org Query Language that is customized to meet your specific needs. +

+ +

+What new custom predicates will you write next? +

+
+
+ +
+

Appendix: Anaphoric macros

+
+

+Finally, if you're a Lisper who appreciates anaphora, you might prefer a more syntactically concise definition of the predicate using Dash macros: +

+ +
+
(org-ql-defpred (person p) (&rest names)
+  "Search for entries about any of NAMES."
+  :normalizers ((`(,predicate-names . ,names)
+                 `(or (tags ,@(--map `(concat "person" ,it) names))
+                      ,@(--map `(property "person" ,it) names)))))
+
+
+ +

+Let's make sure it works: +

+ +
+
(org-ql-query :select '(org-get-heading :no-tags)
+              :from (current-buffer)
+              :where '(person "Alice" "Bob"))
+
+
+ +
    +
  • [#A] Loud pet parakeet
  • +
  • [#C] Missing sticky notes
  • +
  • [#C] Dirty dishes in sink
  • +
  • [#A] Stinky coffee breath
  • +
+ +

+Lisp is fun! +

+
+
+ +
+

Example data

+
+
+ +
+

Loud pet parakeet   personAlice

+
+ +
+

Missing sticky notes   personAlice

+
+
+
+ +
+

Dirty dishes in sink   personAlice

+
+
+
+ +
+

Stinky coffee breath

+
+
+
+
+
+
+

Created: 2020-11-23 Mon 03:31

+

Validate

+
+ + diff --git a/examples/defpred.org b/examples/defpred.org new file mode 100644 index 0000000..ed26973 --- /dev/null +++ b/examples/defpred.org @@ -0,0 +1,390 @@ +#+TITLE: Org QL Custom Predicates Tutorial +#+OPTIONS: author:nil creator:nil created:nil date:nil num:nil title:t broken-links:t +#+SETUPFILE: export/setup/theme-darksun-local.setup + +[2020-11-22 Sun 22:35] Imagine you have weekly meetings with other people, and during the week you take notes about items to discuss at each meeting. When the time for a meeting comes, you want to quickly and easily search for all of the items to discuss at the meeting. + +You've been experimenting with different ways to track such data in Org. You've tried using tags, but some of the names in question conflict with other tags in your data (e.g. someone's named Charles, but you also work with a firm named Charles, Inc., and you'd prefer to continue using the tag =Charles= for entries about that firm), so you've been using tags like ~:personNAME:~, which seems awkward. You've tried using a ~:person: NAME~ property on entries, which has the advantage of not cluttering the tags list, but also the disadvantage of not being readily visible in an outline. + +So you haven't decided on a long-term solution, but the meetings aren't going to wait--you need to search that data now, and you have a mix of both tags and properties in your entries. What you need is to be able to search for all of the entries about Alice (which you've tagged ~:personAlice:~) when you're meeting with her, and all of the entries about Bob (which have the property ~:person: Bob~) when you're meeting with him. What do you do? + +* Contents :noexport: +:PROPERTIES: +:TOC: :include siblings :ignore this +:END: +:CONTENTS: +- [[#using-built-in-predicates][Using built-in predicates]] +- [[#a-custom-person-predicate][A custom (person) predicate]] +- [[#searching-for-multiple-people-at-once][Searching for multiple people at once]] +- [[#normalizing-queries-to-rewrite-arguments][Normalizing queries to rewrite arguments]] +- [[#non-sexp-query-syntax][Non-sexp query syntax]] +- [[#using-multiple-predicates][Using multiple predicates]] +- [[#predicate-aliases][Predicate aliases]] +- [[#be-formless][Be formless]] +- [[#conclusion][Conclusion]] +- [[#appendix-anaphoric-macros][Appendix: Anaphoric macros]] +:END: + +* Using built-in predicates + +You could start by using built-in Org QL predicates to search your data. For example: + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(or (tags "personAlice") + (property "person" "Bob"))) +#+END_SRC + +#+RESULTS[91a413cda23cb65d6bb99212e111f283e5a5c910]: +- [#A] Loud pet parakeet +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink +- [#A] Stinky coffee breath + +That was easy enough, but it's not very...semantic. You have to think about the implementation details: Alice uses tags, Bob uses properties, and what if Charlie uses both? It starts to feel complicated, and it's a lot to type out every time. Is there an easier way? + +* A custom ~(person)~ predicate + +Enter =org-ql= custom search predicates. Let's start simple, by defining a predicate to search for just the ~:person:~ property, one person at a time. The predicate will take one argument, a person's name, and search for that property. It would look like this: + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-defpred person (name) + "Search for entries with the \"person\" property being NAME." + :body (property "person" name)) +#+END_SRC + +Now, let's see what results we get for searching this file for entries about Bob: + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(person "Bob")) +#+END_SRC + +#+RESULTS[c11a4ce2c4f179d7487c9b46eff9f72766bc2bc4]: +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink +- [#A] Stinky coffee breath + +Hmm, looks like we need to remind Bob to wash his mug and take some mints after lunch. Now what do we need to discuss with Alice? + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(person "Alice")) +#+END_SRC + +#+RESULTS[1f12f437042bbc077a4696d707805c1367f2ca3d]: +#+BEGIN_EXAMPLE + +#+END_EXAMPLE + +Nothing? Oh, right, Alice's entries use the ~:personAlice:~ tag, so we'll also need to search those kind of entries. Let's make the predicate do that, too: + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-defpred person (name) + "Search for entries with the \"person\" property being NAME or having the tag \"personNAME\"." + :body (or (property "person" name) + (tags (concat "person" name)))) +#+END_SRC + +How about now? + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(person "Alice")) +#+END_SRC + +#+RESULTS[1f12f437042bbc077a4696d707805c1367f2ca3d]: +- [#A] Loud pet parakeet +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink + +Hmm, I thought we already told her to leave Polly at home. + +* Searching for multiple people at once + +Oh, wait, this week is shortened due to holidays, so we're having a combined meeting. How do we search for entries about either of them? Well, this is the obvious solution: + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(or (person "Alice") + (person "Bob"))) +#+END_SRC + +#+RESULTS[4e4c75bde4fbceaadb076a53410c1625d1283e06]: +- [#A] Loud pet parakeet +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink +- [#A] Stinky coffee breath + +And that works fine. But it seems like a lot to type. Could we make the =person= predicate accept multiple names instead? + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-defpred person (&rest names) + "Search for entries about any of NAMES." + :body (cl-loop for name in names + thereis (or (property "person" name) + (tags (concat "person" name))))) +#+END_SRC + +Now let's search again: + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(person "Alice" "Bob")) +#+END_SRC + +#+RESULTS[4f5971c56616f01d8d3c28a66ef380495ee3e158]: +- [#A] Loud pet parakeet +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink +- [#A] Stinky coffee breath + +That was easy! + +* Normalizing queries to rewrite arguments + +Now, all this is well and good if you don't have hundreds of thousands of Org entries in your files. But what if you do? All that =concat='ing happening on every entry could add up, and the query might take a few seconds. What if we could do that stringing-along just once, before running the query? We want to turn our ~(person "Alice" "Bob")~ query into this, with the =:personNAME:= strings already made and the per-person ~(property ...)~ predicates also included: + +#+BEGIN_SRC elisp + (or (tags "personAlice" "personBob") + (property "person" "Alice") + (property "person" "Bob")) +#+END_SRC + +Can we do that? In fact, we can, by using a query normalizer. Normalizers are =pcase= forms (I /know/) that normalize query expressions before execution. We can use one to rewrite the query ahead of time, like this: + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-defpred person (&rest names) + "Search for entries about any of NAMES." + :normalizers ((`(person . ,names) + `(or (tags ,@(cl-loop for name in names + collect (concat "person" name))) + ,@(cl-loop for name in names + collect `(property "person" ,name))))) + :body (cl-loop for name in names + thereis (or (property "person" name) + (tags name)))) +#+END_SRC + +/NOTE: Normalizers are applied to a query repeatedly until the query is fully normalized, so normalizers should be carefully written to avoid infinite loops. In this example, there is no risk of an infinite loop, because the normalized query no longer contains the ~person~ predicate, so the normalizer only applies to the query once./ + +Now, don't faint from all the backquoting and unquoting--it's just Lisp, nothing to be afraid of! Let's slow down a moment and see what the normalized query looks like to be sure we're doing it correctly: + +#+BEGIN_SRC elisp :results code :exports both :cache yes + (org-ql--normalize-query '(person "Alice" "Bob")) +#+END_SRC + +#+RESULTS[ebc46fff31b72359353dda539a26c95b7d650df2]: +#+BEGIN_SRC elisp + (or (tags "personAlice" "personBob") + (property "person" "Alice") + (property "person" "Bob")) +#+END_SRC + +And, as they say, Bob's your uncle! Or even if he isn't, let's see if it works: + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(person "Alice" "Bob")) +#+END_SRC + +#+RESULTS[4f5971c56616f01d8d3c28a66ef380495ee3e158]: +- [#A] Loud pet parakeet +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink +- [#A] Stinky coffee breath + +Yep, same result as the non-normalized query. And look at how much simpler it is to write ~(person "Alice" "Bob")~ than to write ~(or (tags "personAlice" "personBob") (property "person" "Alice") (property "person" "Bob"))~. + +* Non-sexp query syntax + +But wait, that's not all! If you order now, we'll throw in non-sexp query syntax for free! That's right, your search could be as simple as typing ~person:Alice,Bob~! + +#+BEGIN_SRC elisp :results none :exports code + (org-ql-search (current-buffer) "person:Alice,Bob") +#+END_SRC + +Don't believe me? Well, you see, queries in this syntax are converted to the sexp syntax, like: + +#+BEGIN_SRC elisp :results code :exports both :cache yes + (org-ql--query-string-to-sexp "person:Alice,Bob") +#+END_SRC + +#+RESULTS[a60655544956644605c23c152570185c329faa87]: +#+BEGIN_SRC elisp + (person "Alice" "Bob") +#+END_SRC + +And that happens automatically when you use a search command like =org-ql-search=. If you have =org-ql= installed already, you could even click this link: [[org-ql-search:person:Alice,Bob][Alice or Bob]]. Which, in Org syntax, looks like: + +#+BEGIN_SRC org + [[org-ql-search:person:Alice,Bob]] +#+END_SRC + +And that would open an Agenda Mode buffer that looks like this: + +#+BEGIN_EXAMPLE + Query: (person "Alice" "Bob") In:meetings.org + [#A] Loud pet parakeet :personAlice: + [#C] Missing sticky notes :personAlice: + [#C] Dirty dishes in sink :personAlice: + [#A] Stinky coffee breath +#+END_EXAMPLE + +* Using multiple predicates + +Oops, you forgot that there's a birthday party in 20 minutes, so you only have time to talk about the highest priority items at this joint meeting today. + +No problem, let's just select high-priority items: + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-search (current-buffer) "person:Alice,Bob priority:A") +#+END_SRC + +Which shows: + +#+BEGIN_EXAMPLE + Query: (and (person "Alice" "Bob") (priority "A")) In:meetings.org + [#A] Loud pet parakeet :personAlice: + [#A] Stinky coffee breath +#+END_EXAMPLE + +* Predicate aliases + +And, you know what, if you're just so busy that you don't even have time to type the word =person=, you can add an abbreviated alias, =p=, like this: + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-defpred (person p) (&rest names) + "Search for entries about any of NAMES." + :normalizers ((`(,predicate-names . ,names) + `(or (tags ,@(cl-loop for name in names + collect (concat "person" name))) + ,@(cl-loop for name in names + collect `(property "person" ,name))))) + :body (cl-loop for name in names + thereis (or (property "person" name) + (tags (concat "person" name))))) +#+END_SRC + +Let's try it: + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-search (current-buffer) "p:Alice,Bob priority:A") +#+END_SRC + +And that shows: + +#+BEGIN_EXAMPLE + Query: (and (person "Alice" "Bob") (priority "A")) In:meetings.org + [#A] Loud pet parakeet :personAlice: + [#A] Stinky coffee breath +#+END_EXAMPLE + +(It's up to you to remember whether =p= means =person= or =priority=, but code can't solve everything.) + +* Be formless + +We can even go a step further: since the normalizer rewrites the query to call the =property= and =tags= predicates instead, this =person= predicate doesn't even need a body form! + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-defpred (person p) (&rest names) + "Search for entries about any of NAMES." + :normalizers ((`(,predicate-names . ,names) + `(or (tags ,@(cl-loop for name in names + collect (concat "person" name))) + ,@(cl-loop for name in names + collect `(property "person" ,name)))))) +#+END_SRC + +Will it still work? + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(person "Alice" "Bob")) +#+END_SRC + +#+RESULTS[4f5971c56616f01d8d3c28a66ef380495ee3e158]: +- [#A] Loud pet parakeet +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink +- [#A] Stinky coffee breath + +It does! + +* Conclusion + +In this tutorial, we've gone from having to write lengthy, complex query expressions for accommodating idiosyncratic requirements, to being able to write simple query expressions that abstract away ugly details, to rewriting those query expressions into a more optimal form before a search is even run. The end result is an Org Query Language that is customized to meet your specific needs. + +What new custom predicates will you write next? + +* Appendix: Anaphoric macros + +Finally, if you're a Lisper who appreciates anaphora, you might prefer a more syntactically concise definition of the predicate using Dash macros: + +#+BEGIN_SRC elisp :results silent :exports code + (org-ql-defpred (person p) (&rest names) + "Search for entries about any of NAMES." + :normalizers ((`(,predicate-names . ,names) + `(or (tags ,@(--map (concat "person" it) names)) + ,@(--map `(property "person" ,it) names))))) +#+END_SRC + +Let's make sure it normalizes correctly: + +#+BEGIN_SRC elisp :results code :exports both :cache yes + (org-ql--normalize-query '(person "Alice" "Bob")) +#+END_SRC + +#+RESULTS[ebc46fff31b72359353dda539a26c95b7d650df2]: +#+BEGIN_SRC elisp + (or (tags "personAlice" "personBob") + (property "person" "Alice") + (property "person" "Bob")) +#+END_SRC + +It does, so the query also produces the correct results: + +#+BEGIN_SRC elisp :results list :exports both :cache yes + (org-ql-query :select '(org-get-heading :no-tags) + :from (current-buffer) + :where '(person "Alice" "Bob")) +#+END_SRC + +#+RESULTS[4f5971c56616f01d8d3c28a66ef380495ee3e158]: +- [#A] Loud pet parakeet +- [#C] Missing sticky notes +- [#C] Dirty dishes in sink +- [#A] Stinky coffee breath + +Lisp is fun! + +* Example data +:PROPERTIES: +:TOC: :ignore (this descendants) +:END: + +** [#A] Loud pet parakeet :personAlice: + +** [#C] Missing sticky notes :personAlice: +:PROPERTIES: +:person: Bob +:END: + +** [#C] Dirty dishes in sink :personAlice: +:PROPERTIES: +:person: Bob +:END: + +** [#A] Stinky coffee breath +:PROPERTIES: +:person: Bob +:END: + diff --git a/examples/export/setup/theme-darksun-local.setup b/examples/export/setup/theme-darksun-local.setup new file mode 100644 index 0000000..1ae015b --- /dev/null +++ b/examples/export/setup/theme-darksun-local.setup @@ -0,0 +1,17 @@ +# -*- mode: org; -*- + +# The files that hide sections and display a navbar and ToC are commented out. + +# #+HTML_HEAD: +#+HTML_HEAD: +# #+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +# #+HTML_HEAD: +#+HTML_HEAD: diff --git a/examples/export/setup/theme-darksun.setup b/examples/export/setup/theme-darksun.setup new file mode 100644 index 0000000..a5abe0e --- /dev/null +++ b/examples/export/setup/theme-darksun.setup @@ -0,0 +1,15 @@ +# -*- mode: org; -*- + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: diff --git a/examples/export/styles/darksun/css/darksun.css b/examples/export/styles/darksun/css/darksun.css new file mode 100644 index 0000000..212fb9a --- /dev/null +++ b/examples/export/styles/darksun/css/darksun.css @@ -0,0 +1,264 @@ +* { + border-color: #657b83; +} +a { + color: #268bd2 !important; +} +a:visited { + color: #6c71c4 !important; +} +body { + background-color: #002b36 !important; + color: #839496 !important; + font-family: Libre Baskerville, serif; +} +html { + background-color: #002b36 !important; +} +input, +textarea { + background-color: #073642 !important; + color: #839496 !important; +} +blockquote, +code, +pre { + background-color: #073642 !important; + border: 1px solid #094352 !important; + border-radius: 2px; + box-shadow: none; + color: #839496 !important; +} +code { + font-size: 1.2em; +} +img { + margin: 0.5em; +} +.buttons { + background-color: #073642 !important; + color: #93a1a1 !important; + font-family: sans-serif; + font-size: 1.5rem; +} +.hsReviewPanel { + display: none; +} +.title { + border: 0; +} +#postamble { + display: none; +} +#banner { + text-align: center; +} +#tabs { + background-color: #073642 !important; + float: left; + margin: 0px 0px 20px 0px; + padding: 0; + width: 100%; + font-family: sans-serif; +} +#tabs ul { + margin: 0; + padding: 0; +} +#tabs li { + float: left; + list-style-type: none; + margin: 0px 2px 0px 0px; + padding: 0px 0px 0px 0px; + white-space: nowrap; +} +#tabs li a { + display: block; + font-size: 120%; + font-weight: bold; + margin: 0; + padding: 4px 10px 4px 10px; + text-decoration: none; +} +#tabs li a:hover { + color: #90c5eb !important; +} +#tabs li.ui-tabs-active a { + background-color: #094352 !important; + color: #59a9e1 !important; +} +#content { + clear: both; + width: 80%; +} +#content > p { + margin: 1em; +} +#content > div > h2 { + margin: 0.25rem; +} +#postamble { + text-align: right; +} +blockquote { + background-color: #073642 !important; + padding-left: 0.75em; + padding-right: 0.75em; + padding-top: 0.01em; + padding-bottom: 0.01em; + overflow: hidden; + margin-left: 0; +} +.outline-text-2, +.outline-text-3, +.outline-text-4, +.outline-text-5, +.outline-text-6 { + padding-left: 4%; +} +.outline-3 { + padding-left: 4%; +} +.outline-4 { + padding-left: 4%; +} +.outline-5 { + padding-left: 4%; +} +.outline-6 { + padding-left: 4%; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: sans-serif; + border-bottom: 2px solid; + border-color: #094352 !important; +} +a:hover { + text-decoration: underline; +} +#search { + display: block; + float: right; +} +.tag { + background-color: #002b36 !important; + color: #93a1a1 !important; + border: 0px; +} +.tag span { + background-color: #094352 !important; + margin: 0.25em; + padding: 0.25em; +} +#table-of-contents { + display: table; + float: right; +} +#table-of-contents h2 { + display: none; +} +#table-of-contents li { + list-style-type: none; +} +#table-of-contents a:hover { + text-decoration: underline; +} +#minitoc { + background-color: #073642 !important; + position: fixed; + top: 0px; + right: -5px; + padding: 0.5em; + z-index: 200; + width: 18%; + word-wrap: normal; + overflow: hidden; +} +#minitoc ul { + margin: 0.5em; + padding-left: 1em; +} +#minitoc h2 { + margin-top: 0; + margin-bottom: 0; + font-size: 110%; +} +#minitoc a { + display: block; + font-family: sans-serif; + text-decoration: none; +} +#minitoc a:hover { + text-decoration: underline; +} +/* #minitoc a { */ +/* display: none; */ +/* } */ +#minitoc:hover a { + display: block; +} +#toTop { + top: -100px; + position: fixed; + text-align: center; + z-index: 999; + display: none; +} +#toTop:hover { + text-decoration: underline; +} +#left-panel-wrapper { + display: none; + position: fixed; + z-index: 200; +} +#left-panel-contents { + display: none; + position: fixed; + text-align: left; + top: 0; + z-index: 200; +} +#left-panel-button { + transform: rotate(90deg); + left: -23px; + position: fixed; + top: 50%; + z-index: 200; +} +#right-panel-wrapper { + position: fixed; + z-index: 200; +} +#right-panel-contents { + display: none; + z-index: 200; + position: fixed; + text-align: left; + top: 0; +} +.snippet-copy-to-clipboard { + display: none; + position: absolute; + left: 50px; + top: 50px; +} +.org-ol > li, +.org-dl > dt { + margin-top: 0.5em; +} +.org-ul { + margin-top: 1em; + margin-bottom: 1em; +} +.org-ul li { + margin-top: 0.5em; +} +.org-ul > li > a { + font-family: sans-serif; +} diff --git a/examples/export/styles/darksun/css/hideshow.css b/examples/export/styles/darksun/css/hideshow.css new file mode 100644 index 0000000..4ded9b5 --- /dev/null +++ b/examples/export/styles/darksun/css/hideshow.css @@ -0,0 +1,110 @@ +/* hideshow.css --- HideShow CSS file */ + +/* Copyright (C) 2014 All Right Reserved, Fabrice Niessen */ + +/* This file 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 file 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. */ + +/* Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")> */ +/* URL: https://github.com/fniessen/hide-show/ */ +/* Version: 20140912.1722 */ + +.hsExpanded.hsAnchor {background: #EE7700;} + +.buttons { + padding: 0px 7px 13px 0px; + background: #0A3F69; +} + +.hsButton { + color: white; + float: right; + font-size: 70%; + margin-left: 10px; +} + + .hsButton:hover { + text-decoration: underline; + cursor: pointer; + } + +.ellipsis { + color: #999999; + /* background-color: #FFF8C0; */ + /* float: right; */ + margin-left: 0.6em; +} + +.hsReview { + border: 1px solid #A4A4A4; + background-color: white; + z-index: 500; /* must be greater then z-index of hsOverlay */ + position: relative; /* required for z-index to work */ +} + +#hsOverlay { + width: 100%; + height: 100%; + position: fixed; + left: 0px; + top: 0px; + background-color: #000; + opacity: .70; + z-index: 250; /* must be greater than any other z-index (except the one for .hsReview */ +} + +.hsReviewPanel { + background-color: #757176; + color: white; + line-height: 1.1em; + margin: 10px 0px; + padding: 10px; + position: fixed; + width: auto; + bottom: 0px; + right: 0px; + z-index: 501; + text-align: center; +} + + .hsReviewPanel.hsReviewing { + display: none; + } + + .hsReviewPanel:hover { + cursor: pointer; + } + +.hsReviewingPanel { + background-color: white; + color: #757176; + line-height: 1.1em; + margin: 10px 0px; + padding: 10px; + position: fixed; + width: auto; + bottom: 0px; + right: 0px; + z-index: 501; + text-align: center; +} + +.hsReviewButton:hover { + cursor: pointer; +} + +.hsUnselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} diff --git a/examples/export/styles/darksun/css/htmlize.css b/examples/export/styles/darksun/css/htmlize.css new file mode 100644 index 0000000..f08e781 --- /dev/null +++ b/examples/export/styles/darksun/css/htmlize.css @@ -0,0 +1,145 @@ +.org-bold { /* bold */ font-weight: bold; } +.org-bold-italic { /* bold-italic */ font-weight: bold; font-style: italic; } +.org-buffer-menu-buffer { /* buffer-menu-buffer */ font-weight: bold; } +.org-builtin { /* font-lock-builtin-face */ color: #7a378b; } +.org-button { /* button */ text-decoration: underline; } +.org-calendar-today { /* calendar-today */ text-decoration: underline; } +.org-change-log-acknowledgement { /* change-log-acknowledgement */ color: #b22222; } +.org-change-log-conditionals { /* change-log-conditionals */ color: #a0522d; } +.org-change-log-date { /* change-log-date */ color: #8b2252; } +.org-change-log-email { /* change-log-email */ color: #a0522d; } +.org-change-log-file { /* change-log-file */ color: #0000ff; } +.org-change-log-function { /* change-log-function */ color: #a0522d; } +.org-change-log-list { /* change-log-list */ color: #a020f0; } +.org-change-log-name { /* change-log-name */ color: #008b8b; } +.org-comint-highlight-input { /* comint-highlight-input */ font-weight: bold; } +.org-comint-highlight-prompt { /* comint-highlight-prompt */ color: #00008b; } +.org-comment { /* font-lock-comment-face */ color: #b22222; } +.org-comment-delimiter { /* font-lock-comment-delimiter-face */ color: #b22222; } +.org-completions-annotations { /* completions-annotations */ font-style: italic; } +.org-completions-common-part { /* completions-common-part */ color: #000000; background-color: #ffffff; } +.org-completions-first-difference { /* completions-first-difference */ font-weight: bold; } +.org-constant { /* font-lock-constant-face */ color: #008b8b; } +.org-diary { /* diary */ color: #ff0000; } +.org-diff-context { /* diff-context */ color: #7f7f7f; } +.org-diff-file-header { /* diff-file-header */ background-color: #b3b3b3; font-weight: bold; } +.org-diff-function { /* diff-function */ background-color: #cccccc; } +.org-diff-header { /* diff-header */ background-color: #cccccc; } +.org-diff-hunk-header { /* diff-hunk-header */ background-color: #cccccc; } +.org-diff-index { /* diff-index */ background-color: #b3b3b3; font-weight: bold; } +.org-diff-nonexistent { /* diff-nonexistent */ background-color: #b3b3b3; font-weight: bold; } +.org-diff-refine-change { /* diff-refine-change */ background-color: #d9d9d9; } +.org-dired-directory { /* dired-directory */ color: #0000ff; } +.org-dired-flagged { /* dired-flagged */ color: #ff0000; font-weight: bold; } +.org-dired-header { /* dired-header */ color: #228b22; } +.org-dired-ignored { /* dired-ignored */ color: #7f7f7f; } +.org-dired-mark { /* dired-mark */ color: #008b8b; } +.org-dired-marked { /* dired-marked */ color: #ff0000; font-weight: bold; } +.org-dired-perm-write { /* dired-perm-write */ color: #b22222; } +.org-dired-symlink { /* dired-symlink */ color: #a020f0; } +.org-dired-warning { /* dired-warning */ color: #ff0000; font-weight: bold; } +.org-doc { /* font-lock-doc-face */ color: #8b2252; } +.org-escape-glyph { /* escape-glyph */ color: #a52a2a; } +.org-file-name-shadow { /* file-name-shadow */ color: #7f7f7f; } +.org-flyspell-duplicate { /* flyspell-duplicate */ color: #cdad00; font-weight: bold; text-decoration: underline; } +.org-flyspell-incorrect { /* flyspell-incorrect */ color: #ff4500; font-weight: bold; text-decoration: underline; } +.org-fringe { /* fringe */ background-color: #f2f2f2; } +.org-function-name { /* font-lock-function-name-face */ color: #0000ff; } +.org-header-line { /* header-line */ color: #333333; background-color: #e5e5e5; } +.org-help-argument-name { /* help-argument-name */ font-style: italic; } +.org-highlight { /* highlight */ background-color: #b4eeb4; } +.org-holiday { /* holiday */ background-color: #ffc0cb; } +.org-isearch { /* isearch */ color: #b0e2ff; background-color: #cd00cd; } +.org-isearch-fail { /* isearch-fail */ background-color: #ffc1c1; } +.org-italic { /* italic */ font-style: italic; } +.org-keyword { /* font-lock-keyword-face */ color: #a020f0; } +.org-lazy-highlight { /* lazy-highlight */ background-color: #afeeee; } +.org-link { /* link */ color: #0000ff; text-decoration: underline; } +.org-link-visited { /* link-visited */ color: #8b008b; text-decoration: underline; } +.org-log-edit-header { /* log-edit-header */ color: #a020f0; } +.org-log-edit-summary { /* log-edit-summary */ color: #0000ff; } +.org-log-edit-unknown-header { /* log-edit-unknown-header */ color: #b22222; } +.org-match { /* match */ background-color: #ffff00; } +.org-next-error { /* next-error */ background-color: #eedc82; } +.org-nobreak-space { /* nobreak-space */ color: #a52a2a; text-decoration: underline; } +.org-org-archived { /* org-archived */ color: #7f7f7f; } +.org-org-block { /* org-block */ color: #7f7f7f; } +.org-org-block-begin-line { /* org-block-begin-line */ color: #b22222; } +.org-org-block-end-line { /* org-block-end-line */ color: #b22222; } +.org-org-checkbox { /* org-checkbox */ font-weight: bold; } +.org-org-checkbox-statistics-done { /* org-checkbox-statistics-done */ color: #228b22; font-weight: bold; } +.org-org-checkbox-statistics-todo { /* org-checkbox-statistics-todo */ color: #ff0000; font-weight: bold; } +.org-org-clock-overlay { /* org-clock-overlay */ background-color: #ffff00; } +.org-org-code { /* org-code */ color: #7f7f7f; } +.org-org-column { /* org-column */ background-color: #e5e5e5; } +.org-org-column-title { /* org-column-title */ background-color: #e5e5e5; font-weight: bold; text-decoration: underline; } +.org-org-date { /* org-date */ color: #a020f0; text-decoration: underline; } +.org-org-document-info { /* org-document-info */ color: #191970; } +.org-org-document-info-keyword { /* org-document-info-keyword */ color: #7f7f7f; } +.org-org-document-title { /* org-document-title */ color: #191970; font-size: 144%; font-weight: bold; } +.org-org-done { /* org-done */ color: #228b22; font-weight: bold; } +.org-org-drawer { /* org-drawer */ color: #0000ff; } +.org-org-ellipsis { /* org-ellipsis */ color: #b8860b; text-decoration: underline; } +.org-org-footnote { /* org-footnote */ color: #a020f0; text-decoration: underline; } +.org-org-formula { /* org-formula */ color: #b22222; } +.org-org-headline-done { /* org-headline-done */ color: #bc8f8f; } +.org-org-hide { /* org-hide */ color: #ffffff; } +.org-org-latex-and-export-specials { /* org-latex-and-export-specials */ color: #8b4513; } +.org-org-level-1 { /* org-level-1 */ color: #0000ff; } +.org-org-level-2 { /* org-level-2 */ color: #a0522d; } +.org-org-level-3 { /* org-level-3 */ color: #a020f0; } +.org-org-level-4 { /* org-level-4 */ color: #b22222; } +.org-org-level-5 { /* org-level-5 */ color: #228b22; } +.org-org-level-6 { /* org-level-6 */ color: #008b8b; } +.org-org-level-7 { /* org-level-7 */ color: #7a378b; } +.org-org-level-8 { /* org-level-8 */ color: #8b2252; } +.org-org-link { /* org-link */ color: #0000ff; text-decoration: underline; } +.org-org-meta-line { /* org-meta-line */ color: #b22222; } +.org-org-mode-line-clock { /* org-mode-line-clock */ color: #000000; background-color: #bfbfbf; } +.org-org-mode-line-clock-overrun { /* org-mode-line-clock-overrun */ color: #000000; background-color: #ff0000; } +.org-org-quote { /* org-quote */ color: #7f7f7f; } +.org-org-scheduled { /* org-scheduled */ color: #006400; } +.org-org-scheduled-previously { /* org-scheduled-previously */ color: #b22222; } +.org-org-scheduled-today { /* org-scheduled-today */ color: #006400; } +.org-org-sexp-date { /* org-sexp-date */ color: #a020f0; } +.org-org-special-keyword { /* org-special-keyword */ color: #a020f0; } +.org-org-table { /* org-table */ color: #0000ff; } +.org-org-tag { /* org-tag */ font-weight: bold; } +.org-org-target { /* org-target */ text-decoration: underline; } +.org-org-time-grid { /* org-time-grid */ color: #b8860b; } +.org-org-todo { /* org-todo */ color: #ff0000; font-weight: bold; } +.org-org-upcoming-deadline { /* org-upcoming-deadline */ color: #b22222; } +.org-org-verbatim { /* org-verbatim */ color: #7f7f7f; } +.org-org-verse { /* org-verse */ color: #7f7f7f; } +.org-org-warning { /* org-warning */ color: #ff0000; font-weight: bold; } +.org-outline-1 { /* outline-1 */ color: #0000ff; } +.org-outline-2 { /* outline-2 */ color: #a0522d; } +.org-outline-3 { /* outline-3 */ color: #a020f0; } +.org-outline-4 { /* outline-4 */ color: #b22222; } +.org-outline-5 { /* outline-5 */ color: #228b22; } +.org-outline-6 { /* outline-6 */ color: #008b8b; } +.org-outline-7 { /* outline-7 */ color: #7a378b; } +.org-outline-8 { /* outline-8 */ color: #8b2252; } +.org-preprocessor { /* font-lock-preprocessor-face */ color: #7a378b; } +.org-query-replace { /* query-replace */ color: #b0e2ff; background-color: #cd00cd; } +.org-regexp-grouping-backslash { /* font-lock-regexp-grouping-backslash */ font-weight: bold; } +.org-regexp-grouping-construct { /* font-lock-regexp-grouping-construct */ font-weight: bold; } +.org-region { /* region */ background-color: #eedc82; } +.org-secondary-selection { /* secondary-selection */ background-color: #ffff00; } +.org-shadow { /* shadow */ color: #7f7f7f; } +.org-show-paren-match { /* show-paren-match */ background-color: #40e0d0; } +.org-show-paren-mismatch { /* show-paren-mismatch */ color: #ffffff; background-color: #a020f0; } +.org-string { /* font-lock-string-face */ color: #8b2252; } +.org-tool-bar { /* tool-bar */ color: #000000; background-color: #bfbfbf; } +.org-tooltip { /* tooltip */ color: #000000; background-color: #ffffe0; } +.org-trailing-whitespace { /* trailing-whitespace */ background-color: #ff0000; } +.org-type { /* font-lock-type-face */ color: #228b22; } +.org-underline { /* underline */ text-decoration: underline; } +.org-variable-name { /* font-lock-variable-name-face */ color: #a0522d; } +.org-warning { /* font-lock-warning-face */ color: #ff0000; font-weight: bold; } +.org-widget-button { /* widget-button */ font-weight: bold; } +.org-widget-button-pressed { /* widget-button-pressed */ color: #ff0000; } +.org-widget-documentation { /* widget-documentation */ color: #006400; } +.org-widget-field { /* widget-field */ background-color: #d9d9d9; } +.org-widget-inactive { /* widget-inactive */ color: #7f7f7f; } +.org-widget-single-line-field { /* widget-single-line-field */ background-color: #d9d9d9; } diff --git a/examples/export/styles/darksun/images/checked.png b/examples/export/styles/darksun/images/checked.png new file mode 100644 index 0000000..ebdc03b Binary files /dev/null and b/examples/export/styles/darksun/images/checked.png differ diff --git a/examples/export/styles/darksun/images/fixme.png b/examples/export/styles/darksun/images/fixme.png new file mode 100644 index 0000000..5b861d8 Binary files /dev/null and b/examples/export/styles/darksun/images/fixme.png differ diff --git a/examples/export/styles/darksun/images/halfchecked.png b/examples/export/styles/darksun/images/halfchecked.png new file mode 100644 index 0000000..afd695e Binary files /dev/null and b/examples/export/styles/darksun/images/halfchecked.png differ diff --git a/examples/export/styles/darksun/images/info.png b/examples/export/styles/darksun/images/info.png new file mode 100644 index 0000000..83de654 Binary files /dev/null and b/examples/export/styles/darksun/images/info.png differ diff --git a/examples/export/styles/darksun/images/note.png b/examples/export/styles/darksun/images/note.png new file mode 100644 index 0000000..1c6b8eb Binary files /dev/null and b/examples/export/styles/darksun/images/note.png differ diff --git a/examples/export/styles/darksun/images/tip.png b/examples/export/styles/darksun/images/tip.png new file mode 100644 index 0000000..743ef89 Binary files /dev/null and b/examples/export/styles/darksun/images/tip.png differ diff --git a/examples/export/styles/darksun/images/unchecked.png b/examples/export/styles/darksun/images/unchecked.png new file mode 100644 index 0000000..b75b7a9 Binary files /dev/null and b/examples/export/styles/darksun/images/unchecked.png differ diff --git a/examples/export/styles/darksun/images/warning.png b/examples/export/styles/darksun/images/warning.png new file mode 100644 index 0000000..296415e Binary files /dev/null and b/examples/export/styles/darksun/images/warning.png differ diff --git a/examples/export/styles/darksun/js/darksun.js b/examples/export/styles/darksun/js/darksun.js new file mode 100644 index 0000000..99ce23f --- /dev/null +++ b/examples/export/styles/darksun/js/darksun.js @@ -0,0 +1,524 @@ +// darksun.js --- darksun JS file +// +// Copyright (C) 2011-2016 All Right Reserved, Fabrice Niessen +// +// This file 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 file 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. +// +// Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")> +// URL: https://github.com/fniessen/org-html-themes/ +// Version: 20140515.1841 + +$(function() { + $('p'). + html(function(index, old) { + return old.replace('FIXME', + 'FIXME'); + }); + $('p'). + html(function(index, old) { + return old.replace('XXX', + 'XXX'); + }); +}); + +// Remove leading section number +$(function() { + $('.section-number-2').text(""); + for (var i = 3; i <= 5; i++) { + $('.section-number-' + i).each(function() { + $(this).text($(this).text().replace(/^[0-9]+\./g, "")); + }); + } +}); + +$(function() { + $('
').prependTo('body'); +}); + +// generate contents of minitoc +function generateMiniToc(divId) { + $('#minitoc-content').empty().append('

In this section

    '); + $('#' + divId).find('h3').each(function(i) { + // [2018-09-03 Mon 03:48] Get text up to non-breaking space, + // to omit the tags. If there are no tags, there will be no + //  , so get all the text. (This fixes a bug in the + // original code.) + let text = null; + let pos = $(this).text().search(/ | ►/); + if (pos > 0) { + text = $(this).text().substring(0, pos); + } + else { + text = $(this).text(); + } + $("#minitoc-content>ul").append("
  • " + + text + "
  • "); + }); + // Ensure that the target is expanded (hideShow) + $('#minitoc-content a[href^="#"]').click(function() { + var href = $(this).attr('href'); + hsExpandAnchor(href); + }); +} + +// display tabs +function tabifySections() { + + // hide TOC (if present) + $('#table-of-contents').hide(); + + // grab the list of `h2' from the page + var allSections = []; + $('h2') + .each(function() { + // Remove TODO keywords and tags (contained in spans) + var tabText = $(this).clone().find('span').remove().end() + .text().trim(); + var tabId = $(this).parent().attr('id'); + if (tabText) { + // - remove heading number (all leading digits) + // - remove progress logging (between square brackets) + // - remove leading and trailing spaces + tabText = tabText.replace(/^\d+\s+/, '').replace(/\[[\d/%]+\]/, '').trim(); + + allSections.push({ + text: tabText, + id: tabId + }); + } + }); + + // create the tab links + var tabs = $('
      '); + for (i = 0; i < allSections.length; i++) { + var item = allSections[i]; + html = $('
    • ' + item.text + '
    • '); + tabs.append(html); + } + + // insert tabs menu after title (`h1'), or at the beginning of the content + if($('.title').length !== 0) { + $('.title').after(tabs); + } + else { + $('#content').prepend(tabs); + } +} + +function selectTabAndScroll(href) { + // At this point we assume that href is local (starts with #) + // alert(href); + + // Find the tab to activate + var targetTab = $(href).closest('.ui-tabs-panel'); + var targetTabId = targetTab.attr('id'); + var targetTabAriaLabel = targetTab.attr('aria-labelledby'); + + var targetTabIndex = $("#content ul li") + .index($('[aria-labelledby="' + targetTabAriaLabel + '"]')); + + // Activate target tab + $('#content').tabs('option', 'active', targetTabIndex); + + // Rebuild minitoc + generateMiniToc(targetTabId); + + // Set the location hash + // document.location.hash = href; + + // Scroll to top if href was a tab + if (href == '#' + targetTabId) { + // alert(targetTabId); + $.scrollTo(0); + } + // Scroll to href if href was not a tab + else { + $.scrollTo(href); + } +} + +$(document).ready(function() { + $('#preamble').remove(); + $('#table-of-contents').remove(); + + // Initialize hideShow + hsInit(); + + // Prepare for tabs + tabifySections(); + + // Build the tabs from the #content div + $('#content').tabs(); + + // Set default animation + $('#content').tabs('option', 'show', true); + + // Rebuild minitoc when a tab is activated + $('#content').tabs({ + activate: function(event, ui) { + var divId = ui.newTab.attr('aria-controls'); + generateMiniToc(divId); + } + }); + + // Required to get the link of the tab in URL + $('#content ul').localScroll({ + target: '#content', + duration: 0, + hash: true + }); + + // Handle hash in URL + if ($('#content') && document.location.hash) { + hsExpandAnchor(document.location.hash); + selectTabAndScroll(document.location.hash); + } + // If no hash, build the minitoc anyway for selected tab + else { + var divId = $('#content div[aria-expanded=true]').attr('id'); + generateMiniToc(divId); + } + + // Handle click on internal links + $('.ui-tabs-panel a[href^="#"]').click(function(e) { + var href = $(this).attr('href'); + hsExpandAnchor(href); + selectTabAndScroll(href); + e.preventDefault(); + }); + + // add sticky headers to tables + $('table').stickyTableHeaders(); +}); + +function copyToClipboard(text) +{ + if (window.clipboardData && window.clipboardData.setData) { // Internet Explorer + window.clipboardData.setData("Text", text); + } + else { // Fallback solution + window.prompt("Copy to clipboard: Ctrl+C, Enter", text); + } +} + +$(document).ready(function() { + // Assuming that the ZeroClipboard swf file is in the same folder than darksun, + // get the path to it (it will be relative to the current page location). + var bbScriptPath = $('script[src$="darksun.js"]').attr('src'); // the js file path + var bbPathToZeroClipboardSwf = bbScriptPath.replace('darksun.js', 'ZeroClipboard.swf'); + + // Add copy to clipboard snippets + $('.org-src-container').prepend('
      [copy]
      '); + + // Display/hide snippets on source block mouseenter/mouseleave + $(document).on('mouseenter', '.org-src-container', function () { + $(this).find('.snippet-copy-to-clipboard').show(); + + // Need to call zclip here, once the button is visible. + // Beacause when the button is not visible, zclip does nothing. + if ((window.location.protocol != 'file:') && ($(this).find('.zclip').length == 0)) { + $(this).find('.copy-to-clipboard-button').zclip({ + //path: 'http://www.steamdev.com/zclip/js/ZeroClipboard.swf', + //path: 'styles/darksun/js/ZeroClipboard.swf', + path: bbPathToZeroClipboardSwf, + copy: function() { + return $(this).parent().parent().find('.src').text(); + } + }); + } + }).on('mouseleave', '.org-src-container', function () { + $(this).find('.snippet-copy-to-clipboard').hide(); + }); + + // Handle copy to clipboard (here, for a local file only 'file://...' + if (window.location.protocol == 'file:') { // if local file use browser-specific code + $('.copy-to-clipboard-button').click(function() { + // Get the text to be copied + var text = $(this).parent().parent().find('.src').text(); + text = text.replace(/\n/g, "\r\n"); + // alert(text); + copyToClipboard(text); + }); + } +}); + +$(function() { + $('li > code :contains("[X]")') + .parent() + .addClass('checked') + .end() + .remove(); + $('li > code :contains("[-]")') + .parent() + .addClass('halfchecked') + .end() + .remove(); + $('li > code :contains("[ ]")') + .parent() + .addClass('unchecked') + .end() + .remove(); +}); + +$(function() { + $('i :contains("[#A]")') + .replaceWith('[#A]'); + $('i :contains("[#B]")') + .replaceWith('[#B]'); + $('i :contains("[#C]")') + .replaceWith('[#C]'); +}); + +function togglePanel(e) { + e.preventDefault(); + + $("#left-panel-contents").toggleClass('active').toggle(200); + $("#right-panel-contents").toggleClass('active').toggle(200); + + var slidePos = + $("#left-panel-button").css("left") == "-23px"? '182px': '-23px'; + + $("#left-panel-button"). + animate({"left": slidePos, "opacity": 0.9}, {duration: "200" }); + + // if ($("#left-panel-contents").hasClass('active')) { + // hsHideTodoKeyword('done'); + // } else { + // hsShowTodoKeyword('done'); + // } + + // return false; +} + +$(function() { + $('') + .appendTo('body'); + + $('
      ') + .appendTo('body'); + + $('#left-panel-button').click(togglePanel); +}); + +$(function() { + var ul = $('
        ').appendTo('#left-panel-contents'); + var countOfTodo = {}, listOfTodo = [], totalOfTodo = 0; + + // assign the counts (avoid double-counting elements from the ToC) + $('span.todo').not($('#table-of-contents span.todo')).each(function() { + var $thisTodo = $(this).text().trim(); + + if ($.inArray($thisTodo, listOfTodo) == -1) { + countOfTodo[$thisTodo] = 1; + listOfTodo.push($thisTodo); + } + else + countOfTodo[$thisTodo] += 1; + totalOfTodo += 1; + }); + + function scoreTodo(t) { + switch (t) { + case 'NEW': return 1; + case 'TODO': return 2; + case 'STRT': return 3; + case 'WAIT': return 4; + case 'DLGT': return 5; + case 'SDAY': return 6; + case 'DFRD': return 7; + case 'DONE': return 8; + case 'CANX': return 9; + default: return 0; + } + } + + function compareTodo(a, b) { + if (scoreTodo(a) < scoreTodo(b)) return -1; + if (scoreTodo(a) > scoreTodo(b)) return 1; + return 0; + } + + listOfTodo.sort(compareTodo); + + // display + for (i = 0; i < listOfTodo.length; i++) { + var $thisTodo = listOfTodo[i]; + $(ul).append('
      • '+ $thisTodo + '' + + ' (' + countOfTodo[$thisTodo] + ')
      • '); + } + + $('#listOfTodo') + .before('Next Actions (' + totalOfTodo + '):
        '); +}); + +$(function() { + var ul = $('
          ').appendTo('#left-panel-contents'); + var countOfDone = {}, listOfDone = [], totalOfDone = 0; + + // assign the counts (avoid double-counting elements from the ToC) + $('span.done').not($('#table-of-contents span.done')).each(function() { + var $thisDone = $(this).text().trim(); + + if ($.inArray($thisDone, listOfDone) == -1) { + countOfDone[$thisDone] = 1; + listOfDone.push($thisDone); + } + else + countOfDone[$thisDone] += 1; + totalOfDone += 1; + }); + + // display + for (i = 0; i < listOfDone.length; i++) { + var $thisDone = listOfDone[i]; + $(ul).append('
        • '+ $thisDone + '' + + ' (' + countOfDone[$thisDone] + ')
        • '); + } + + $('#listOfDone') + .before('Done Actions (' + totalOfDone + '):
          '); +}); + +$(function() { + var ul = $('
            ').appendTo('#right-panel-contents'); + var countOfTags = {}, listOfTags = [], totalOfTags = 0; + + // assign the counts (avoid double-counting elements from the ToC) + $('span.tag').not($('#table-of-contents span.tag')).each(function() { + var $thisTagGroup = $(this).text().trim().split(/\s/); + // \s matches spaces, tabs, new lines, etc. + + for (tag in $thisTagGroup) { + if ($.inArray($thisTagGroup[tag], listOfTags) == -1) { + countOfTags[$thisTagGroup[tag]] = 1; + listOfTags.push($thisTagGroup[tag]); + } + else + countOfTags[$thisTagGroup[tag]] += 1; + totalOfTags += 1; + } + }); + + listOfTags.sort(); + + // display + for (i = 0; i < listOfTags.length; i++) { + var $thisTag = listOfTags[i]; + // $(ul).append('
          • '+ + // $thisTag + ' (' + countOfTags[$thisTag] + ')
          • '); + $(ul).append('
          • ' + $thisTag + + '' + + ' (' + countOfTags[$thisTag] + ')
          • '); + } + + $('#listOfTags') + .before('Contexts (' + totalOfTags + '):
            '); +}); + +$(function() { + $('.done').parent(':header').parent().find(':header').addClass('DONEheader'); + $('.done').parent(':header').parent().css({color: '#999999'}); +}); + +$(function() { + $('span.todo').click(function(e) { + var orgKeyword = $(this).text().trim(); + $('.' + orgKeyword).toggleClass('selected'); + $('#content .' + orgKeyword).parent().parent() + .toggleClass('match' + orgKeyword); + $('#left-panel-wrapper .' + orgKeyword).parent() + .toggleClass('match' + orgKeyword); + e.preventDefault(); + }) +}); + +$(function() { + $('.tag span').click(function(e) { + var orgTag = $(this).text().trim(); + $('.' + orgTag).toggleClass('selected'); + $('#content .' + orgTag).parent().parent().parent() + .toggleClass('matchtag'); + $('#right-panel-wrapper .' + orgTag).parent().parent() + .toggleClass('matchtag'); + e.preventDefault(); + }) +}); + +function clickPreviousTab() { + var active = $('#content').tabs('option', 'active'); + // Avoid going back to last tab + if (active == 0) return; + + $('#content').tabs('option', 'active', active - 1); + + // Set the location href + var href = $('#content div[aria-expanded=true]').attr('id'); + document.location.hash = href; + $.scrollTo(0); +} + +function clickNextTab() { + var active = $('#content').tabs('option', 'active'); + $('#content').tabs('option', 'active', active + 1); + + // Set the location href + var href = $('#content div[aria-expanded=true]').attr('id'); + document.location.hash = href; + $.scrollTo(0); +} + +function orgDefkey(e) { + if (!e) + var e = window.event; + var keycode = (e.keyCode) ? e.keyCode : e.which; + var actualkey = String.fromCharCode(keycode); + switch (actualkey) { + case "?": // help (dashboard) + case "h": + togglePanel(e); + break; + case "n": // next + clickNextTab(); + break; + case "p": // previous + clickPreviousTab(); + break; + // case "b": // scroll down - should be mapped to Shift-SPC + // $(window).scrollTop($(window).scrollTop()-$(window).height()); + // break; + case "<": // scroll to top + $(window).scrollTop(0); + break; + case ">": // scroll to bottom + $(window).scrollTop($(document).height()); + break; + case "-": // collapse all + hsCollapseAll(); + break; + case "+": // expand all + hsExpandAll(); + break; + case "r": // go to next task + hsReviewTaskNext(); + break; + case "R": // go to previous task + hsReviewTaskPrev(); + break; + case "q": // quit reviewing + hsReviewTaskQuit(); + break; + case "g": // refresh the page (from the server, rather than the cache) + location.reload(true); + break; + } +} + +document.onkeypress = orgDefkey; diff --git a/examples/export/styles/darksun/js/hideshow.js b/examples/export/styles/darksun/js/hideshow.js new file mode 100644 index 0000000..e528759 --- /dev/null +++ b/examples/export/styles/darksun/js/hideshow.js @@ -0,0 +1,335 @@ +// hideshow.js --- HideShow JS file +// +// Copyright (C) 2014 All Right Reserved, Fabrice Niessen +// +// This file 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 file 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. +// +// Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")> +// URL: https://github.com/fniessen/hide-show/ +// Version: 20140912.1722 + +// var HS_COLLAPSIBLE_HEADERS = $('h3, h4, h5'); // collapsible headers + +if (typeof HS_STARTUP_FOLDED === 'undefined') { + var HS_STARTUP_FOLDED = false; // Show just the overview, or show all. +} + +if (typeof HS_SHOW_ALL_TEXT === 'undefined') { + var HS_SHOW_ALL_TEXT = 'Expand'; +} +if (typeof HS_HIDE_ALL_TEXT === 'undefined') { + var HS_HIDE_ALL_TEXT = 'Collapse'; +} + +if (typeof HS_ALWAYS_DISPLAY_ICON === 'undefined') { + var HS_ALWAYS_DISPLAY_ICON = false; // Display an icon for all states, or + // just when closed. +} + +if (typeof HS_ICON_CLOSED === 'undefined') { + var HS_ICON_CLOSED = '►'; // black right-pointing pointer +} +if (typeof HS_ICON_OPEN === 'undefined') { + var HS_ICON_OPEN = '▼'; // black down-pointing triangle +} +if (typeof HS_ICON_EMPTY === 'undefined') { + var HS_ICON_EMPTY = '■'; // black square +} + +if (typeof HS_SHOW_ALL_OPEN_DONE_TREES === 'undefined') { + var HS_SHOW_ALL_OPEN_DONE_TREES = false; // Expand all will open DONE trees. +} + +if (typeof HS_CLASS === 'undefined') { + var HS_CLASS = 'hsCollapsible'; +} + +// Expand a header +function hsExpand(header) { + hsExpand2(header, true); +} + +// Expand a header +function hsExpand2(header, expandDoneHeader) { + // Ignore non collapsible entries + if (!header.parent().hasClass(HS_CLASS)) return; + + // Do not expand DONE node if not required + if (hsIsDoneHeader(header) && !expandDoneHeader) return; + + header.children('span[class="ellipsis"]').remove(); + if (HS_ALWAYS_DISPLAY_ICON == true) { + header.append(' ' + HS_ICON_OPEN + ''); + } + header.parent().removeClass('hsCollapsed').addClass('hsExpanded'); + header.nextAll().show(); +} + +// Expand a header and all its parents +function hsExpandParents(header) { + hsExpand(header); + header.parents('.hsCollapsed').each(function() { + hsExpand($(this).children(':header')); + }); +} + +// Collapse a header and all its parents +function hsCollapseParents(header) { + hsCollapse(header); + header.parents('.hsExpanded').each(function() { + hsCollapse($(this).children(':header')); + }); +} + +// Collapse a header +function hsCollapse(header) { + // Ignore non collapsible entries + if (!header.parent().hasClass(HS_CLASS)) return; + + header.children('span[class="ellipsis"]').remove(); + header.append(' ' + HS_ICON_CLOSED + ''); + header.parent().removeClass('hsExpanded').addClass('hsCollapsed'); + // header.nextAll().hide('fast'); + header.nextAll().hide(); +} + +// Toggle a header +function hsToggleCollapsing(header) { + if (header.parent().hasClass('hsCollapsed')) + hsExpand(header); + else if (header.parent().hasClass('hsExpanded')) + hsCollapse(header); +} + +// Expand all headers +function hsExpandAll() { + $('#content .hsCollapsed').each(function() { + hsExpand2($(this).children(':header'), HS_SHOW_ALL_OPEN_DONE_TREES); + }); +} + +// Collapse all headers +function hsCollapseAll() { + $('#content .hsExpanded').each(function() { + hsCollapse($(this).children(':header')); + }); +} + +// Collapse all visible headers +function hsCollapseAllVisible() { + $('#content .hsExpanded:visible').each(function() { + hsCollapse($(this).children(':header')); + }); +} + +// Add click events to H3/H4/H5 headers which have contents. +function hsInit() { + for (var i = 3; i <= 5; i++) { + $('#content .outline-' + i).each(function() { + var header = $(this).children(':header'); + if (header.siblings().length > 0) { + $(this).addClass(HS_CLASS); + header.css({cursor: 'pointer'}); + header.click(function() { + hsToggleCollapsing($(this)); }); + + // Allow to override global Collapse/Expand default on an entry + // basis (see property `:HTML_CONTAINER_CLASS:') + if (header.parent().hasClass('hsCollapsed')) { + hsCollapse(header); + } else if (header.parent().hasClass('hsExpanded')) { + hsExpand(header); + } else { + hsSetDefaultVisibility(header); + } + } + else { + if (HS_ALWAYS_DISPLAY_ICON == true) { + header.append(' ' + HS_ICON_EMPTY + + ''); + } + $(this).addClass('hsEmpty'); + } + }); + } + + // Add div to hold minitoc content (so it can be cleared without deleting the buttons) + $('#minitoc').append($('
            ')); + + // Add buttons + $('#minitoc').append($('
            ')); + $('.buttons').append($('' + HS_SHOW_ALL_TEXT + '') + .addClass('hsButton') + .click(hsExpandAll)); + $('.buttons').append($('' + HS_HIDE_ALL_TEXT + '') + .addClass('hsButton') + .click(hsCollapseAll)); +} + +// Returns true if a header is a DONE header +function hsIsDoneHeader(header) { + return $('span.done', header).length; +} + +// Sets the default visibility state to a header +function hsSetDefaultVisibility(header) { + if (HS_STARTUP_FOLDED) { + hsCollapse(header); + } + else { + if (!hsIsDoneHeader(header) | HS_SHOW_ALL_OPEN_DONE_TREES) { + hsExpand(header); + } + else { + hsCollapse(header); + } + } +} + +// Expands an anchor, i.e. expand all parent headers +function hsExpandAnchor(id) { + // alert(id); + if (id) { + // alert($(id + '.hsNode').length); + $(id).parents('.hsCollapsed').each(function() { + hsExpand2($(this).children(':header'), true); + }); + } +} + +// Search for next task to review, starting from beginning of current tab. +// If BACKWARD is true, search in the reverse direction. +function hsReviewTaskNext(backward) { + // If no tasks to review at all, do nothing. + if ($('.outline-2 span.todo').length == 0) return; + + if ($('.hsReviewing').length == 0) { // reviewing is starting + $('body').addClass('hsReviewing'); + $('.hsReviewPanel').addClass('hsReviewing'); + $('body').prepend('
            '); + hsAddReviewingPanels(); + + hsCollapseAll(); + // Get first task to review on each tab and expand it + $('.outline-2').each(function(){ + var firstTodo = $(this).find('span.todo:first').parent().parent(); + firstTodo.addClass('hsReview'); + hsExpandParents($(firstTodo).children(':header')); + }); + } + else { + // Get all todos + var todosElements = $('.outline-2:visible span.todo').parent().parent(); + // alert(todosElements.length); + var todos = jQuery.makeArray(todosElements); + if (backward) { + todos = todos.reverse(); + } + + // Find current review item and review the next one + var foundReview = false; + var index; + for (index = 0; index < todos.length; ++index) { + var todo = todos[index]; + if (foundReview) { + $(todo).addClass('hsReview'); + hsExpandParents($(todo).children(':header')); + break; + } + if ($(todo).hasClass('hsReview')) { + foundReview = true; + if (index < todos.length - 1) { + $(todo).removeClass('hsReview'); + hsCollapseParents($(todo).children(':header')); + } + } + } + + // Update reviewing panel + if (index < todos.length) { + var reviewItem = index + 1; + if (backward) { + reviewItem = todos.length - index; + } + + $('.outline-2:visible .hsReviewingPanel .hsReviewItem').text(reviewItem); + } + } + + // Scroll to the current review item + $('html, body').animate({ + scrollTop: $(".hsReview:visible").offset().top + }, 200); +} + +// go to previous task to review +function hsReviewTaskPrev() { + hsReviewTaskNext(true); +} + +// stop reviewing tasks +function hsReviewTaskQuit() { + $('body').removeClass('hsReviewing'); + $('.hsReviewPanel').removeClass('hsReviewing'); + $('.hsReview').removeClass('hsReview'); + $('#hsOverlay').remove(); + $('.hsReviewingPanel').remove(); +} + +function hsHideTodoKeyword(kw) { + $('span.' + kw).addClass('hsHidden').parent().parent().hide(); +} + +function hsShowTodoKeyword(kw) { + $('span.' + kw).removeClass('hsHidden').parent().parent().show(); + // XXX Show if parent is not collapsed! +} + +function hsAddReviewPanels() { + $('.outline-2').each(function(e) { + var nbItems = $(this).find('span.todo').length; + if (nbItems > 0) { + $(this).prepend('
            ' + + 'Press r or click here
            ' + + 'to review ' + nbItems + ' tasks
            ' + + '(out of ' + nbReviewTotalTasks + ' tasks)
            '); + } + }); +} + +function hsAddReviewingPanels() { + $('.outline-2').each(function(e) { + var nbItems = $(this).find('span.todo').length; + if (nbItems > 0) { + $(this).prepend('
            Reviewing task 1 / ' + nbItems + '
            ' + + '(out of ' + nbReviewTotalTasks + ' tasks)
            ' + + 'Shortcuts: ' + + 'r (next) - ' + + 'R (previous)' + + '
            '); + } + else { + $(this).prepend('
            No task to review
            ' + + '(out of ' + nbReviewTotalTasks + ' tasks)
            ' + + 'Shortcuts: ' + + 'r (next) - ' + + 'R (previous)' + + '
            '); + } + }); +} + +var nbReviewTotalTasks; + +$(document).ready(function() { + nbReviewTotalTasks = $('.outline-2 span.todo').length; + hsAddReviewPanels(); +}); diff --git a/examples/export/styles/darksun/js/jquery-1.11.0.min.js b/examples/export/styles/darksun/js/jquery-1.11.0.min.js new file mode 100644 index 0000000..73f33fb --- /dev/null +++ b/examples/export/styles/darksun/js/jquery-1.11.0.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
            ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f +}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML="
            a",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/\s*$/g,sb={option:[1,""],legend:[1,"
            ","
            "],area:[1,"",""],param:[1,"",""],thead:[1,"","
            "],tr:[2,"","
            "],col:[2,"","
            "],td:[3,"","
            "],_default:l.htmlSerialize?[0,"",""]:[1,"X
            ","
            "]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?""!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("