pelican-3.7.1/000077500000000000000000000000001303525152100131325ustar00rootroot00000000000000pelican-3.7.1/.coveragerc000066400000000000000000000000411303525152100152460ustar00rootroot00000000000000[report] omit = pelican/tests/* pelican-3.7.1/.gitattributes000066400000000000000000000003661303525152100160320ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto # Improve accuracy of GitHub's Linguist-powered language statistics pelican/tests/content/* linguist-vendored pelican/tests/output/* linguist-vendored samples/* linguist-vendored pelican-3.7.1/.gitignore000066400000000000000000000001751303525152100151250ustar00rootroot00000000000000*.egg-info .*.swp .*.swo *.pyc .DS_Store docs/_build docs/fr/_build build dist tags .tox .coverage htmlcov six-*.egg/ *.orig pelican-3.7.1/.mailmap000066400000000000000000000022701303525152100145540ustar00rootroot00000000000000Alexis Métaireau Alexis Métaireau Alexis Métaireau Axel Haustant Axel Haustant Dave Mankoff Feth Arezki Guillaume Guillaume Guillaume B Guillermo López Guillermo López Jomel Imperio Justin Mayer Justin Mayer Marco Milanesi Massimo Santini Rémy HUBSCHER Simon Conseil Simon Liedtke Skami18 Stuart Colville Stéphane Bunel tBunnyMan pelican-3.7.1/.travis.yml000066400000000000000000000007331303525152100152460ustar00rootroot00000000000000language: python python: - "2.7" env: - TOX_ENV=docs - TOX_ENV=flake8 - TOX_ENV=py27 - TOX_ENV=py33 - TOX_ENV=py34 matrix: include: - python: 3.5 env: - TOX_ENV=py35 addons: apt_packages: - pandoc before_install: - sudo apt-get update -qq - sudo locale-gen fr_FR.UTF-8 tr_TR.UTF-8 install: - pip install tox==2.0.1 script: tox -e $TOX_ENV notifications: irc: channels: - "irc.freenode.org#pelican" on_success: change pelican-3.7.1/CONTRIBUTING.rst000066400000000000000000000165541303525152100156060ustar00rootroot00000000000000Filing issues ============= * Before you file an issue, try `asking for help`_ first. * If determined to file an issue, first check for `existing issues`_, including closed issues. .. _`asking for help`: `How to get help`_ .. _`existing issues`: https://github.com/getpelican/pelican/issues How to get help =============== Before you ask for help, please make sure you do the following: 1. Read the documentation_ thoroughly. If in a hurry, at least use the search field that is provided at top-left on the documentation_ pages. Make sure you read the docs for the Pelican version you are using. 2. Use a search engine (e.g., DuckDuckGo, Google) to search for a solution to your problem. Someone may have already found a solution, perhaps in the form of a plugin_ or a specific combination of settings. 3. Try reproducing the issue in a clean environment, ensuring you are using: * latest Pelican release (or an up-to-date git clone of Pelican master) * latest releases of libraries used by Pelican * no plugins or only those related to the issue **NOTE:** The most common sources of problems are anomalies in (1) themes, (2) settings files, and (3) ``make``/``fab`` automation wrappers. If you can't reproduce your problem when using the following steps to generate your site, then the problem is almost certainly with your chosen theme and/or settings file (and not Pelican itself):: cd ~/projects/your-site git clone https://github.com/getpelican/pelican ~/projects/pelican pelican content -s ~/projects/pelican/samples/pelican.conf.py -t ~/projects/pelican/pelican/themes/notmyidea If despite the above efforts you still cannot resolve your problem, be sure to include in your inquiry the following information, preferably in the form of links to content uploaded to a `paste service`_, GitHub repository, or other publicly-accessible location: * Describe what version of Pelican you are running (output of ``pelican --version`` or the HEAD commit hash if you cloned the repo) and how exactly you installed it (the full command you used, e.g. ``pip install pelican``). * If you are looking for a way to get some end result, prepare a detailed description of what the end result should look like (preferably in the form of an image or a mock-up page) and explain in detail what you have done so far to achieve it. * If you are trying to solve some issue, prepare a detailed description of how to reproduce the problem. If the issue cannot be easily reproduced, it cannot be debugged by developers or volunteers. Describe only the **minimum steps** necessary to reproduce it (no extra plugins, etc.). * Upload your settings file or any other custom code that would enable people to reproduce the problem or to see what you have already tried to achieve the desired end result. * Upload detailed and **complete** output logs and backtraces (remember to add the ``--debug`` flag: ``pelican --debug content [...]``) .. _documentation: http://docs.getpelican.com/ .. _`paste service`: https://dpaste.de/ Once the above preparation is ready, you can contact people willing to help via (preferably) the ``#pelican`` IRC channel or send a message to ``authors at getpelican dot com``. Remember to include all the information you prepared. The #pelican IRC channel ------------------------ * Because of differing time zones, you may not get an immediate response to your question, but please be patient and stay logged into IRC — someone will almost always respond if you wait long enough (it may take a few hours). * If you don't have an IRC client handy, use the webchat_ for quick feedback. * You can direct your IRC client to the channel using this `IRC link`_ or you can manually join the ``#pelican`` IRC channel on the `freenode IRC network`_. .. _webchat: https://kiwiirc.com/client/irc.freenode.net/?#pelican .. _`IRC link`: irc://irc.freenode.org/pelican .. _`freenode IRC network`: http://www.freenode.org/ Contributing code ================= Before you submit a contribution, please ask whether it is desired so that you don't spend a lot of time working on something that would be rejected for a known reason. Consider also whether your new feature might be better suited as a plugin_ — you can `ask for help`_ to make that determination. Using Git and GitHub -------------------- * `Create a new git branch`_ specific to your change (as opposed to making your commits in the master branch). * **Don't put multiple unrelated fixes/features in the same branch / pull request.** For example, if you're hacking on a new feature and find a bugfix that doesn't *require* your new feature, **make a new distinct branch and pull request** for the bugfix. * Check for unnecessary whitespace via ``git diff --check`` before committing. * First line of your commit message should start with present-tense verb, be 50 characters or less, and include the relevant issue number(s) if applicable. *Example:* ``Ensure proper PLUGIN_PATH behavior. Refs #428.`` If the commit *completely fixes* an existing bug report, please use ``Fixes #585`` or ``Fix #585`` syntax (so the relevant issue is automatically closed upon PR merge). * After the first line of the commit message, add a blank line and then a more detailed explanation (when relevant). * `Squash your commits`_ to eliminate merge commits and ensure a clean and readable commit history. * If you have previously filed a GitHub issue and want to contribute code that addresses that issue, **please use** ``hub pull-request`` instead of using GitHub's web UI to submit the pull request. This isn't an absolute requirement, but makes the maintainers' lives much easier! Specifically: `install hub `_ and then run `hub pull-request `_ to turn your GitHub issue into a pull request containing your code. Contribution quality standards ------------------------------ * Adhere to `PEP8 coding standards`_ whenever possible. This can be eased via the `pep8 `_ or `flake8 `_ tools, the latter of which in particular will give you some useful hints about ways in which the code/formatting can be improved. * Make sure your code is compatible with Python 2.7, 3.3, and 3.4 — see our `compatibility cheatsheet`_ for more details. * Add docs and tests for your changes. Undocumented and untested features will not be accepted. * `Run all the tests`_ **on all versions of Python supported by Pelican** to ensure nothing was accidentally broken. Check out our `Git Tips`_ page or `ask for help`_ if you need assistance or have any questions about these guidelines. .. _`plugin`: http://docs.getpelican.com/en/latest/plugins.html .. _`#pelican IRC channel`: http://webchat.freenode.net/?channels=pelican&uio=d4 .. _`Create a new git branch`: https://github.com/getpelican/pelican/wiki/Git-Tips#making-your-changes .. _`Squash your commits`: https://github.com/getpelican/pelican/wiki/Git-Tips#squashing-commits .. _`Run all the tests`: http://docs.getpelican.com/en/latest/contribute.html#running-the-test-suite .. _`Git Tips`: https://github.com/getpelican/pelican/wiki/Git-Tips .. _`PEP8 coding standards`: http://www.python.org/dev/peps/pep-0008/ .. _`ask for help`: `How to get help`_ .. _`compatibility cheatsheet`: http://docs.getpelican.com/en/latest/contribute.html#python-3-development-tips pelican-3.7.1/LICENSE000066400000000000000000001033301303525152100141370ustar00rootroot00000000000000 GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 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 Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are 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. 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. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. 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 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 work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. 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 AGPL, see . pelican-3.7.1/MANIFEST.in000066400000000000000000000002201303525152100146620ustar00rootroot00000000000000include *.rst recursive-include pelican *.html *.css *png *.in *.rst *.markdown *.md *.mkd *.xml *.py include LICENSE THANKS docs/changelog.rst pelican-3.7.1/README.rst000066400000000000000000000042271303525152100146260ustar00rootroot00000000000000Pelican |build-status| |pypi-version| ===================================== Pelican is a static site generator, written in Python_. * Write content in reStructuredText_ or Markdown_ using your editor of choice * Includes a simple command line tool to (re)generate site files * Easy to interface with version control systems and web hooks * Completely static output is simple to host anywhere Features -------- Pelican currently supports: * Chronological content (e.g., articles, blog posts) as well as static pages * Integration with external services (e.g., Google Analytics and Disqus) * Site themes (created using Jinja2_ templates) * Publication of articles in multiple languages * Generation of Atom and RSS feeds * Syntax highlighting via Pygments_ * Importing existing content from WordPress, Dotclear, and other services * Fast rebuild times due to content caching and selective output writing Check out `Pelican's documentation`_ for further information. How to get help, contribute, or provide feedback ------------------------------------------------ See our `contribution submission and feedback guidelines `_. Source code ----------- Pelican's source code is `hosted on GitHub`_. If you feel like hacking, take a look at `Pelican's internals`_. Why the name "Pelican"? ----------------------- "Pelican" is an anagram of *calepin*, which means "notebook" in French. .. Links .. _Python: http://www.python.org/ .. _reStructuredText: http://docutils.sourceforge.net/rst.html .. _Markdown: http://daringfireball.net/projects/markdown/ .. _Jinja2: http://jinja.pocoo.org/ .. _Pygments: http://pygments.org/ .. _`Pelican's documentation`: http://docs.getpelican.com/ .. _`Pelican's internals`: http://docs.getpelican.com/en/latest/internals.html .. _`hosted on GitHub`: https://github.com/getpelican/pelican .. |build-status| image:: https://img.shields.io/travis/getpelican/pelican/master.svg :target: https://travis-ci.org/getpelican/pelican :alt: Travis CI: continuous integration status .. |pypi-version| image:: https://img.shields.io/pypi/v/pelican.svg :target: https://pypi.python.org/pypi/pelican :alt: PyPI: the Python Package Index pelican-3.7.1/THANKS000066400000000000000000000051461303525152100140530ustar00rootroot00000000000000Pelican is a project originally created by Alexis Métaireau , but there are a large number of people that have contributed or implemented key features over time. We do our best to keep this list up-to-date, but you can also have a look at the nice contributor graphs produced by GitHub: https://github.com/getpelican/pelican/graphs/contributors If you want to contribute, check the documentation section about how to do so: Aaron Kavlie Abhishek L Albrecht Mühlenschulte Aldiantoro Nugroho Alen Mujezinovic Alessandro Martin Alexander Artemenko Alexandre RODIERE Alexis Daboville Alexis Métaireau Allan Whatmough Andrea Crotti Andrew Laski Andrew Spiers Arnaud BOS asselinpaul Axel Haustant Ben Rosser (TC01) Benoît HERVIER Bernhard Scheirle Borgar Brandon W Maister Brendan Wholihan Brian C. Lane Brian Hsu Brian St. Pierre Bruno Binet BunnyMan Chenguang Wang Chris Elston Chris McDonald (Wraithan) Chris Streeter Christophe Chauvet Clint Howarth Colin Dunklau Dafydd Crosby Dana Woodman Dave King Dave Mankoff David Beitey David Marble Deniz Turgut (Avaris) derdon Dirkjan Ochtman Dirk Makowski draftcode Edward Delaporte Emily Strickland epatters Eric Case Erik Hetzner FELD Boris Feth Arezki Florian Jacob Florian Preinstorfer Félix Delval Freeculture George V. Reilly Guillaume Guillaume B Guillermo López guillermooo Ian Cordasco Igor Kalnitsky Irfan Ahmad Iuri de Silvio Ivan Dyedov James King James Rowe jawher Jered Boxman Jerome Jiachen Yang Jochen Breuer joe di castro John Kristensen John Mastro Jökull Sólberg Auðunsson Jomel Imperio Joseph Reagle Joshua Adelman Julian Berman Justin Mayer Kevin Deldycke Kyle Fuller Laureline Guerin Leonard Huang Leroy Jiang Marcel Hellkamp Marco Milanesi Marcus Fredriksson Mario Rodas Mark Caudill Martin Brochhaus Massimo Santini Matt Bowcock Matt Layman Meir Kriheli Michael Guntsche Michael Reneer Michael Yanovich Mike Yumatov Mikhail Korobov m-r-r mviera Nico Di Rocco Nicolas Duhamel Nicolas Perriault Nicolas Steinmetz Paul Asselin Pavel Puchkin Perry Roper Peter Desmet Philippe Pepiot Rachid Belaid Randall Degges Ranjhith Kalisamy Remi Rampin Rémy HUBSCHER renhbo Richard Duivenvoorde Rogdham Roman Skvazh Ronny Pfannschmidt Rory McCann Rıdvan Örsvuran saghul sam Samrat Man Singh Simon Conseil Simon Liedtke Skami18 solsTiCe d'Hiver Steve Schwarz Stéphane Bunel Stéphane Raimbault Stuart Colville Talha Mansoor Tarek Ziade Thanos Lefteris Thomas Thurman Tobias Tomi Pieviläinen Trae Blain Tshepang Lekhonkhobe Valentin-Costel Hăloiu Vlad Niculae William Light Wladislaw Merezhko W. Trevor King Zoresvit pelican-3.7.1/bumpr.rc000066400000000000000000000012301303525152100146010ustar00rootroot00000000000000[bumpr] file = pelican/__init__.py vcs = git clean = python setup.py clean rm -rf *egg-info build dist tests = python -m unittest discover publish = python setup.py sdist bdist_wheel register upload files = README.rst setup.py [bump] unsuffix = true message = Bump version {version} [prepare] part = patch suffix = dev message = Prepare version {version} for next development cycle [changelog] file = docs/changelog.rst separator = = bump = {version} ({date:%Y-%m-%d}) prepare = Next release [readthedoc] url = http://docs.getpelican.com/{tag} [commands] bump = sed -i "" "s/last_stable[[:space:]]*=.*/last_stable = '{version}'/" docs/conf.py pelican-3.7.1/docs/000077500000000000000000000000001303525152100140625ustar00rootroot00000000000000pelican-3.7.1/docs/Makefile000066400000000000000000000107661303525152100155340ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Raclette.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Raclette.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Raclette" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Raclette" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." pelican-3.7.1/docs/_static/000077500000000000000000000000001303525152100155105ustar00rootroot00000000000000pelican-3.7.1/docs/_static/overall.png000066400000000000000000000365641303525152100177000ustar00rootroot00000000000000PNG  IHDR"wsBIT|d IDATxy\TUe_%A#%v\p#}%'17J-AM{\0J-)qQ,ED%7PAQaA;u_2s2~{RSS icL!tBJB@!Kggg Y C ]!NZD!" "B B!!BCAB! B!P!B`(B!D0D!" "B B!!BCAB! B!P!B`(B!D0D!" "B B@UU8krW:>|8tuukkkȼ#bcc>ݻwḮGAr~ł B&>}#Fo߾r =zƦϵd 4͏Ki "]|Y:%~QVV*XKKlmmƯ+--E@@!0fmlli&İapm[ݺud>^K磠 ,TUUagg3ft`dee!88h9ذaΞ=+WZ___vvvիWHGGG|WׇGӃX,ի_} +y 7 jkFmkq\xQëM/#^#G;;;$&&Hv؁-[ܹsu~~~Dnn.aaa)SH믿Fqq1 鉧O֭[8z(VZ={D^b޽ys4w/_|7nom;v DFFf̘w17 BII ?]veff"<<NÇqƽ@HWҪ˗9r$&MwUmMbӑ5(r3gcHII).Z`^yhhh`޼y8<c©S}}}!<<'Oh51uT<93gEaԨQ{+WO>*LLL$[Bmm-QQQ߿*pӧOoJҚljlD~ Xd %%% 1tuu&!x upwwH$=RRR|?kzIχ kј:ujikշ :ǎ9n݊}K.9=D;&&&D͞CdÆ C||CdddE9k XTVVa$//Obɓ'cɨBDDPZZ %%*DDD ::8G)|ZXX}}}@xx8D" %1b͘s̑9dff"%%7W^y_l#5H{Brr2`ffKJx' i֭F3gbȑCRRRc͚58vg-8#Fѣannr9I۱1gDDDHJJ˜1c?`͘4i^~eTUUax\\\d:g}`oZXr%6l؀R|ܻwC )"V̚5 /^DRRRO_a4o߆D3s[hXy]P>}6Gϟ?W\ZBaڵ6lBLLLPQQ}! >>>066)l2$''M sahjjprrxZZZرc X~qqq!!!H$„ |%8>>>ʳrXh 8 #"55`ά%<<<؊+׮]c,##ry1 g"2sttd{_fxgϞĉxcҥK8v޽F9;^c5H{.\`ӧs?12btafR_,01RRR؈#紴ٸq㘇/_}%3c666BAkޫW/!44T{ii)߽7''ɨiSfTWW?sk{4vi}ATT|UP^^DGG#((Hvk`С_'?!Cy&=e˖7uVTVVBpyܺu ׵k׾P !ڪE1nݺYBB>9s&355e:::‚͟?1XZZsqqa"2'''رc‚3oz*8p c,<<\M:0&!xd+W07776`֬Yi牏gիٰaXuuuWh"Olĉ8>pfnnܜ}7| !`߾}ܜ26|VUU%tY(<.55Bf""{0ƚ̙3Xz5)K.ػw/6mqrrBDDBgt'i5WWWK6ŰFUUSLAjj*KKK\p^^^ 'O)B(6coo8p`pdggO>26n܈A!33+&"4 "JFCC+VkkkdddU᧰'2D\\\_=)T}oB B]vaÆ +V`֬Y2O/^TlXXX`СBBi"7BBBp!bǎ6m,8q"Q޶(o000w}TWW ]>GJ! B۷AAA w93 H$oˑIuu5N:("(~ "wKtuu1uT0W_ ]LOݺuBH#(CACCXv%uyqk ]T___+!4k BCCo>KB"ƌ׃1\pA蒺K塞 TUU!t9&P! ?OGa̘1(,,.kر077GVVN<)t9MJJJBMM  !4Q[l ;3+,Cb BXcǎaӦMBeCp iT}U oDB155?eee,[ %uI&&&?~,||.-]wcB%XZZbM[_߽B(.cŰիWn:! " QSSÖ-[qÑ-tIQ!]f̘ObΜ9t]BFAt9aaa022BRR#t9ҥQ!] 6lݻwB. "K>}:^uܿBHEAtI!&&FFF8ro.tI( ///pGK#= b1>sϺ޼yS!Q*//}#Fo߾r =zFٱc\]]QRR\BO>;ܹ &ӧBDd8 {ӧ磠 ,TUUagg3fȴf̘]v!..1D"ƌB~?ioC$))) C=XիW7ZBAUU@>}p̙& !-BSSz»ヒ{>7آcL<f7Cee%rssQ\\ L2߯1p:u >Dnn.ƍh}Di! ޽۶m$BH'X \G)@EEpqqAXX`iioV©S}}}!<<'ODaa롦333,]?jkk BA& 8QQQ_~"BHg1k,\xIIICLLݻcƍp>| "00ϟi4yyy8%,--akk Hb޽ cccӧs޽Ht Æ CBBBP!ӧOLJ~?%B:mmmb 0=bccZZZXp!tuu޽;7nKii)lmmxc6&O$୷ނ_c4Q!DUVaʔ)x1Əׯ ]!ի (((@hh(.]O 6m£G"u,1x`̙3ݜZߣFzӇo5'$''066R㑃!Rpxyy^^^qe)xzzbʕ=onnݻwI9p{JqA7uN!XgΜ'|;o9{{{euahjjprreZq888;;cpssĢE`ddH(5FTZe᧟~[o'NW_Ebb"!Hi(//7ڵk@?6ر'N䟋+qɓ=K/{FDͮoL- }vl߾}ӧ%oqrr¹sdZD<WWWcĈve2TUUZZZvǏGjj* ՒFAh|8| K#D\bQVV~͜9k׮dQ!8ʕ+q1t pvvF\\Х"RKhSӦMoٳg7Mmm-$T~ł DzDQ! -- s&NQFgDO>psskrnE __foR]n455%k]ttt rJ0}^ 777D"8::⫯^֙nRYYtuu! `dĉ쭷b>lǪ[mm-bzzz f˗/g%%%>v`` bbbZ_(K-k +SUU=b> KLL"@bb"<==e~Ĉ߿1dݻwgvb1VWWlmm٢EӧOYQQsuueڌ1.]tttիWc|yJ.[DZ2Bދeŋ011AHHoKfGrDPkGc<{/ GGGx{{#)) fff .Op=zpix{{ 15IDATziӦԩS~娮FAA$XZd  bժUu֭[CCC\x&MBsNbcc sssXZZ"**QFFFK-Vmu76{]D~D@@"HII֭[x7!`hhw ,*?\mllj*CZZZ{>899aҤIHOOիW{A[[[2Fu'O?Ʈ] ̜9{.8 xb8y$qek/~G"11zzz޼y#Gĸq'1??? 6 ())ȑ#c=z4PXXJa޼yعs'o޽{011ABB,--q)HHHcǎ_̝;g;C\\֮]t>̜9‡koyyyرcveee8::/2ѫW/@__nϞ=PVV$ŋ1e;&&&,3@~PǏ۽WGSPRR oQEYp"|prrl[kkk\6l@ii)>S~ܻwC :ӭ< < >vXbǎ믟Dgܸq 53gsiiiFhh(+##YYYHNN̰tR/zFF.]D.k۶m q /FBBDN<4gQF!$$1p׶od+Xb?Qp],\ .N""" bٳ'p)B__HBt֭fff"%%{VOZwZJJJ}ikkCMMܗ;޽{8wݻw1k,1^i-> </ ;8GPP aii3g"++ fr cjr[y$ADbcc<ÇئmKKKݽ{oקO"sFII z___ǣԩSQ~HPQ >,Yf>7w?/ijjBCCC}9,_>ӧOj?c|Mn/K*o>hLHRs#I֜H`u7X߮ulX2o+7oބ*<O"!! =6tPhjj{!^{ III8s |MXGG ,@AAc4̙3XhG|C"Æ ԩStRDEE᧟~Bjj*#??o- XeݻCYYqVq{聇u gKG .`4h!uV\~gnUٴi$裏q.]pǔ:nnnøsLMMaee |W2b^ヲ&(4-##qFܼy}ep\r۶mCPPlmmnk>|.pq?x ѷo_FYYY?ȳ{:---[wڵk%.A#cҥ?YzZeggcȐ!ӃRSSK燼<_~=A FV%M<8qۇu@uΝ;f1LMM6;;֎=eEFV0a={6c_~yxx"fllXmm-g1aVZZʞ FܹsDDDx6=@BB={VV:гgO} ???o߾HHHhtvBby&ƎJ(++cҤI2riIEEEM\ؐ,s(5$mN'i=dK h|6YkELL "##1m48::b͚5DiJmm-&NXXX 11&󃟟_jժ3p-L6 pssq 3G7i؈# {5YTF94jɓ'cɨBDDfUBzj>|zzz8tBH)))aX~=6l؀BTWW˘7oΜ9#JKi$g,sI#$''066BsQ]ʈ%B:ѣG#>>'O ccc>HC)$$D,43Hd\ Xh 85Ceee1]]]mذArxkS߹kq j/"BHuuu1co$BiϟGmϞA-E7_|3g ;weuBHQ=Z!իXl8Ν;all,tIf:gPK=BܹscL2BB۷ 011AddBHAAtyXp!g2:x!֣ B/Ӆ.BYti肟}%t ҥEFF>>>>|BH÷?7!Yyy9֬Y#p5(DK .k())'*t9%1&ttrlܸ \ !t]"B-[t!r*++{C-[&p5ҵQ!]Ν;q] 8BHFAt)uuuK,B!DH/իիƍ't9Q!]JvͣQT !DP!]FFF?̜9Sr!B6o B(.}8üy.BwIG^C~.UOӧ ]! j!^uu5!hݻ&M+˗/,ӄ"GEtz_|`B!DPRSS1p@!??:::BD!j!Z}ݠ !"EtZ%%%x饗_$B!@-"ںu+?~#FP!9E-"S%JJJpIxxx]!FPv؁Q!9F-"y)|O5j%Bi @d(G~~> @!B]!J]]֭[ B!)ʷ]짟~BNNz &]!)EtXbg!**44!; "ӈFff&1c !" iZy7R^^+++~I.B Et (**#B! ZDT"r5١ OưaÄ.BE(4c̚5B!(j!RsȮ]0m4௿%Bij! ƍDDDP!DA(jL8>;#iӦ ]!@A(UV!55戌B!/!R="{ԩSǏC! j! ܹs1ccB! Q.]ȑ#c̝;s$B!DfTpi&++ ^^^(**˜1cw^ V!A-"DEEEx7?R!Nk;wīeBi#D\z1*8tՅ.BHRB)%%3f@NNTTT ]!v@-"]\|ރ;rrr`ee !҉)dq80`~g~ v-ӱ^v9Gp )..ƲeЫW/|PRR| sńBA/_j~~~(,,,Y :csɳ?oF}wXn***ܹsXn455;zB!BQ qTTT```ŋɓ' 6ٳ%%% 1tuu#++ D@@@,#99?55:::cCrr2JKKcccD"3F=z@OObWn﷨CԷ_9n݊|L8QbZaհ3>3cĈ8s ~8:: j!tNq={ ++F׏;&&&D/pi,]-:ѣG=== ---,^SLABB233 . vZ_9#%%`nnPBMM 555￑s!99;cpqqBDGGؾ};zvHIIAaa!LLLJ?g>deeԩS(,,> <<"Bmm-!!9sk֬ B/#>>Bnn._ի<==1zh9!.NaȬY@MM Mnwm!?8 8PbHb"&&6mfiM-,, +V7335 777xzz¢#K&"6hkkC,KݮGx!allyTRWW6fѽ{w(++#33S^&Oɓ' Cii)6˗ˋo)..6^{5x{{[nPSS|/!z +Νb@vv6޽ } 5\]]?sc3gR:td@CC @ruu/K.aĉā|r?pttB!D&a basic/UT V)N *Nux PK Jg>basic/templates/UT W)N *Nux PKg>bVbasic/templates/base.htmlUT `W)N *Nux %K0 D9k ݐ U?3U JEwo/3O7B|6*ŘQ出#Y71|GL-}ξ; =ʤ59l-&| Nu}?`!`=ۭoA{YݝPK a> basic/static/UT M)N*Nux PK .i>basic/static/css/UT *N*Nux PKe>d?|:basic/static/css/style.cssUT 5*N<*Nux n0 (cT&mBcUr`:T"}[pAyt<J~$4%ͺ*UH]yMb gSyT$JuJ~rT=T0A6]ͅsmjn wY: D!v$Sҿmti PO k"2o) ,.#ny[FlMyߞ0mV-%&q?3(6.,MPK Wf>Abasic/UTV)Nux PK Jg>A@basic/templates/UTW)Nux PKg>bVbasic/templates/base.htmlUT`W)Nux PK a> Ahbasic/static/UTM)Nux PK .i>Abasic/static/css/UT*Nux PKe>d?|:basic/static/css/style.cssUT5*Nux PK pelican-3.7.1/docs/_static/theme_overrides.css000066400000000000000000000005301303525152100214040ustar00rootroot00000000000000 /* override table width restrictions */ .wy-table-responsive table td, .wy-table-responsive table th { /* !important prevents the common CSS stylesheets from overriding this as on RTD they are loaded after this stylesheet */ white-space: normal !important; } .wy-table-responsive { overflow: visible !important; } pelican-3.7.1/docs/_static/uml.jpg000066400000000000000000002026631303525152100170200ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222C#" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?]gźbov\ʥy+vR@#^*tH5A# C!V&Bz*px<|_SWg]7 ͸1J߿c|+ +ix嶔sms4ۿ} sE?E*?A5P+T"hW/EנQ@_)Q_R^Eyu#u.kqwńvX8QrO~ҫi_F (((+wZx63ŦVF1ЃkrjMrI$u`T.?;]7˦I$1fv1)$ԓkriq:Mq"G@P`(?<x]lu 'Fѡ}OSy Iwʆ8v z]-yċxCrl_ rA*wb5`phSN~kxpYGaMfD <+?P|/-#w-FwaQym#Y񎽯xY|[Gk[U댁]n&YäiW [x x@,U_ u=PC[xtt/$c>#W |[FwVϧyɩn9s c$nKִ]KU->+moS# H(YXee# psXrxGVV E%\rZ6L!`8+Ӛe:Jh%7:|Ki``G#wB t{x4;Icx1cSccs\w"}zxGK"iת,r _S^|@:;خͪ,rle =x P/tEԴtֻݤo*뼕asԾ׵|&uimoM6CNUU1%qڰ<uԵ_Gmeyd4D KIr98<ĞSBwV2QGY\V9^'QR{(j_.i6>%Kk}U(fȘ)p@aGJx!XoeԼ9we$[- 7kX&IVQiMsqm*:Avv*ƣm÷TIn HH(BP ռ2 >̠d6Egie7i|_!]:P^>m p5H)N>Տ ?€=M0[#-SCmm p5H)N>Q^ ?¬XxIQ%:/! ['(5 }COL7Vsp'T2O/zݝ:aXݧ|uv[w@W/M{^/Yhb 8V?&?c' +W5h.Kpu_B@/ N\WQ}y[|6aF[:ٔ y|0(Bϸ#! 2=0۽GJ&}/Q ͬ4Aj1[|Sk }1pXW5h.Kpu_B@/ N\PqEg^j n瑖Ne!_' ./5;Ht-O{ >M0[#-SCm9 J+v<$?~Wn=]?a+7G.߇0@oJ ?%qO7O;JIc'ڶ97 8 /Ar-A,NO57.߇0oJ-OΟF-a7:%ڡFo%A^@Q@Q@Q@akOWxۙ#6*& :ynUMR4ITI#xY$ά #ӽgx2k~Wyti$F,%$zynUM.4I$HHU#'ӵ[dѥԯ(ckUo$!l[Uicyϩqks}ѣm 9mǞzP+ =6ml- _AEQEq$Ư? mf~_% g.;z+0?wQ ?€=L<DOa&2@1px;((?LdG&?c' +0?wQ ?€=L<DOa&2@1px;((?LdG&?c' +0?wQ ?€==[/=.R~<vY?am8ֽvP\ƲmqPQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEy_ۡߥyg'9'4W^;_ ֢>K\7ͻ~W7y_'N\2O- ]QEQEQEs;y_]親Ӿxr8WLV}hGgkO&u}!ah{ĄfTk @8CZVpѵQEpGΑHdU>? %0N.TH8N}ʴY׾1xG! #c6ElxA»m7KTMAd6*zcq@@&=oMִeNSYP]⡟ĺ \kzlS[ %+D=XG_ZКmW:[{m70A AUFezV|iّٚD]ɖ2 xKw}Gqi|ZΫc 4W2\"J-N[IeU1u;+z9jdWA.9'+ӍCП׌'Ѯ淑mw8$2Lqn%;{{W5>EdI)5^S/,,01[vkΙ_N'>.4rj56csK#Z ؚhHӵ- {2>6Qlx pzJ{%ğ; m2u_vn.5[8 eIk-.k%PduSx|fD‚5Ot0˰|GO<?t쳪iYgg~qޡĚZ֜! ؎0sӑ^i|(^.cqHZr7AAmťXxg4:֓+F}2pe2g/YG\tzW5>DdI p3SGCeѕ"=LNx."?}e{e18i"8h1㌏ZX/ߎZY.i)% xRGzh][i;\\l@H&=Q7-4ʞkqǑΉk?Ι$*YmC ;yMslRj=?'_Uy&┐ ȻT)v>%jVoͧ]đyl򬊬ryq] KA|Emt {+sa?*X״ QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|A(~%j+]SZPK#}<%QĶW9'qEw@ipv&}~+sWk&IEr:y+(((Oy4;kQxjOn:~c=1Kyj> 佊U1*I &Hf3y(z]B BIvܫ)1`cpYxER/AZYl$Aky[s2ǹ=s$׼O19f;\ F+} maϿhxoR5M:I+)E7Iq0}$c޶(_ĚF84_6lkoAM2p9 ZƩI>e(.7&x${{^>m p5H)N>SPֵ럆$Դyt B + kx0 + ts6:Fi7ʉ$o$ՁScdrzwO7m-|'6Mzڜpn8$w}xoR5M:I+)E7Iq0}$cޮq:Mq"G@P`(?<r$׼O19f;\ F+} maϿeL׿(W%t՞bJ!bF;xOyYjW˧}kCo`J&}/Q ͬ4Aj1[|Sk }CziOhGFYJ-KɀC^I#Er$׼O19f;\ F+} maϿqԵS㬓ZѮWE%H!/$ozWFwHr[G2.J cQ^Z 6tҘ݉L&1ssÈB3q u?H|=d]zp½/X:爮t6-q3A C'!MtAV[ HF{b=!Mt{@&*+H|=d]> 2.= R?G)o B7O C'Ш=!Mt{@&*+H|=d]> 2.= R?G)o xcEGwU%فw 8|BM :Ƨi ;S6Ӹ=ktDX :4UP ?L<DOPa&2Ŗڙu56@'=+?g!?qzQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kCקS>yw5O'կm& -ݼ6[9999; N4EȻ|۾yxwt9|$"9?뼕EPEPEP?'%Uj+m7Ꮗ.].Km'p9EX*E5s7 nt-+cBrGjՎ!dI4@"8)˫<0 XK}Kn)ePHܼkYɧYXڋƷwdUxwY;#J \xv\_:lAr24Bm꠰`r ynioGre 8Sn d=i&ׇmේ[U' SbWl66e0)ݎN+V\Y4٘$ef \6GjZRt.$[ QtZHvuA >PpȨYvA"qmKSgx3(''^:>HcG5:s$MFH+% ɧJ~Ӧ32O:@\[[I#B# 77$jƟZb_6gE}Udr2=Q\V4A8OZ 6'KU$ppBhQ@y? +k+O1\+@EPEPEPEPEPEPEPEPEPEPEPEPEPEPEP;_ ֢C/nkQ@iiq.E؛+Lvy]'IH] ( ( (9ƥSq9l O6 A  $chw w\GA%\]Usp7?SWPF"kgWZm>wM)#grBVǧLFX rx/ O\*Hw X aۑۊ?SWPF"kSRSZѴ׮a[ng2c`BO˜'Mum`J,GPՀt<@E5Eo)(?ƫFöݼ6 n$ɐ"Ȍy'2F֧/G|<%XjWz\H&?sYETO7G"覯=24_^%5kEiLv ul=A^8R;i"q@F"hO7Z~,յ[}wHtxwI-3|<u"~+LM EY5dRYc1-IQF^L{wOws(K\7ͻ~W7y_'N\2O- ]QEQEQEs;y_]覮¿|cNg&F;WMP|Zaڵkwn&+ dCIŏAZD-4WS(8ҽO/G_ʀZq*!|9ֵ cV72536`l{bOφF;xαnc!_MGz_ʏ-?yΡ[nn--Nۄw:|(>hfj>ڎ5ֵi-2)t^7۳^ة'kܚ4 {Dut9H:?ߏZVcY6q `eOu>q@E/W)cyY\ZGM8S*D8-MVa`F|b# ^zz_-?Zq*ۿ /d`agFǃT~#| L2R2DPDž:zWiP/$lzlztirr{w ;6{X?.#$MQ5~)3Դit5|IŌ+=j~jQ]x+,r@tJQ(|Yxuև|.E7a`B+i* Z(((+wZx63ŦVF1ЃkrjMrI$u`T.?;]7˦I$1fv1)$ԓkriq:Mq"G@P`(?<iuy |WX8\>, ϴXn丵hрW =(B((((((Z_]Kpk7PJۊڣWmUlt-29c%uvv}Z((((((?g!?qzy? +h(((((((((((((((]S 5kmIC;sKwo01 NsNhw%ĿѭE} Ɨbow7nN15vdZ''#w(((((((*z=z-bid=AzsWk񯄣qqgnҬM9@ ZUnM5oKA_1U/ O|nR3s<ް ?VFe{w%wv|b[+ 8; N4EȻ|۾yxwt9|$"9?뼕EPEPEPEPEPEPEPEPfw-.G[]Rhmb~D?"կ@((((((((gq5|Aso+k7q߻hT{MZRm/ Ce(K\7ͻ~W7y_'N\2O- ]QEQEQEQEQEQEWOj_cދvnOE[O0~߿N*&?c' +0?wQ ?€!Z \ź_+-?"ׂO:kLd@Ey&?c' ?0?wPQ^ ?·񇆢3$MQ==(((((((?Mi_\s$rFYDGB9ʩFi7ʉ$o$ՁScdrzw \Mw_JO.m$HřĤORO9ʩƐ6Qĉi*p@Q#<d:vtV}ƣw>%ŭϕ{Fڸl0yZxcP9?𼄤[bGEvQEQEQEQEQEQEͧ^ڐخ`9vT6CS]4B//<[yuxZ((((((?g!?qzy? +h(((((((((((((((PKa[Q(~%j(- N4EȻ|۾yxwt9|$"9?뼕EPEPEPEPEPEPܩuA MoWH6yǦqӵbܩu|X|CGqى%GDC/ius[]A$  cJsO Jt14rӞy}kŴSþ3񆑭_u6z̫ W?+/# е_ͣY7+rf^gKwjO1? c0xQdR sF\х9ҼUׇΔm`V7>2q Q9nY[K Z_\*XX;xN L.%[k ~ou'K5=NL2iH}7u?>m6ﵺ)8T|cfxC4]5nC=s8s4\~_ki>7M6VIo/ }4KMFGVԆ|۱e"0hQ\~_ki>7M6VIo/ }4KMFGVԆ|۱e"0hQ\~_ki>7M6VIo/ }4KMFGVԆ|۱e"0hQ\~_ki>7M6VIo/ }4KMFGVԆ|۱e"0hQ\~_ki>7M6VIo/ }4KMFGVԆ|۱e"0hV&/.mxgM9#b"b#^_ki>7M6VIo/ }շZzב*p9Y݀`C .cx2k~Wyti$F,%$zynW qE`=Я? v o4'|nm^g_׼?OzoI}eqy,R2сz0Nq(?[/4b|C7rrA>t%cojCRMm؁a2ďx|f4(S Lxn,-bPrI$']QEQEQEQEr$ Qi\Tם/-r |\]g&ֆ_˟4ͻv~NҮH.?/!X;Et(%_UM 2;^)Վ\MtYD $9#󮲸/Z}եuH^ NaDϾGwQEQEQEQEQEW3?bVqcQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEye{w%wv|b[+ 8RV:5\4P{ Ɨbow7nN15vdZ''#w((((((_?|;u( kNk+#X +ՏX<@I?:.=R$?G)OO@? 'O S(?)It”$ _Ocۯ”$tcsog3,fF|9<'i chxְ59Pz@(((((gq5|Aso+UVV{xe @OzQ@y? +k+O1\+@EPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7Oi^jM;[ylrsrsE|(~%j(- N4EȻ|۾yxwt9|$"9?뼕EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX~3 -6H䍊0 s[ST&ocHVI 3 9q@ ]6I$3I$s[SK!l8UH0*FyAtV#/Yw<g%":.O'k? v@(%O-B]F_4I1c9>S+ƻ|KC7ZӢn d`{V7?k(+t;k{] RO.yTLPXщQnFDmC bjzZ)v5I/IuvI$r}MV5McY/d{4;״hiv`3orNFxdz}bu'SM.d1<1]9ښ4w.I<9 ?VFe{w%wv|b[+ 8; N4EȻ|۾yxwt9<@I?:.?/>w~ջyYy9q8Ny W”$l(iVg;.^ Sɲ_ڼ}[WgstךEy)OO&jny^Nq}1ӿ^h<@I?:.?/>w~ջyYy9q8Ny W”$l(iVg;.^ Sɲ_ڼ}[WgstךEy)OO&jny^Nq}1ӿ^h<@I?:.?/>w~ջyYy9q8Ny W”$l(iVg;.^ Sɲ_ڼ}[WgstךEy)OO&jny^Nq}1ӿ^h<@I?:.?/>w~ջyYy9q8Ny W”$l(iVg;.^ Sɲ_ڼ}[WgstךEy)OO&jny^Nq}1ӿ^h<@I?:.?/>w~ջyYy9q8Ny W”$l(iVg;.&/.mxgM9#b"b#7 S미д˶Z$Y$|<cqӾ3@<q5߁|?sq+,l}gNm>Hp@ MVjiwymo)."dpyvW^=yKȭwk|Hm˅O8湭+OtHg{HP̗l {rMu -0xϟOfC OJˇF|&!/ c>7`6NrGga+OmCF,m]+Ib $c(kQלzWIOzvk^ [ &v*W;F޿@[▩Ot/~uuLRTPk_o;;A M崉A$g">x+Q~j7%1ڬw(>#74rxjI΋R)> YNώ|i,e7^$k=k~#iwNf5dwhCK8O _𞭡]驩Pm&OFr=^ԺMuMMŽSi8fy1-A7|CIMoh,M`%H<㷸5j/Xv5+nUB98cӚU ^6sL#d9<^m.}zFrѼvA#DIRʠ Jע(?o!zOk+s_AZ ( W נW3?bV=(((((((((((((((5!@ukө}i]wsEj׶ړinw~`b-圜眜@EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY7k>W0jÖyhWB●,滞K[_nm'E xsS'./A$\1z1N{_&7&!ڋݎ0s]V8aEv^%,$Hͮ8r̃xpA@{[xH7wUi2oS E,wqmiβF@M? V6k-*6.a8nm qI&ݨrRpH mJ8NN*ܲ(j/ǯ/vkKyj~ljMCZ}-i{4,}w)԰n8VRv So|egca~ WW(E*N\10#G6zzCY']CJ[ SnYvpC 5Nɬ~m|0۳v:,˸Zh,Y$S`ݖ p A84t߳ 0<~r:gzѮ=\H\XmBb\回x4kAgXo4Im"OneY#vF8éV:9MJLҵfKXQ  w]FSZfFCƻG7A(kvR=!묓-ӆ ,A 8!r{խh RA+e3=\CZ}-i{4,}w)԰n8VRv WC@ɭ\N߬j˒R0q֩ SHAKsUU;pQAʷ|c5kP񍎝}u^H+fp <2[⦼Mj,WirEU~c R6;mC_o^_֖ 3g:սCFzō6A$U7dc:`S#Jĺc.{G̍$w ҏo 7gS|ggcj6Xߴ:kķjD$P_q78Ss@]뷚q/]du )n0UOݹeQ 3սO“jZΨ۲g2vZ]>C6W)M].Hjd Fy9zw]FSZfFCƻG7A(]ϯ7[H[VHݑ0UNzSo'WD{;Q=p??M}t&c/rN aARF{nf.a"Fmu;d =8+<Ei7*gg ZBG+!Tu$=xs_AZ V=(qc '?@(((((((((((((((uO /uk۽A,GC3_0`1j :χg~z9=*(((((((((((((((((((( #5n!O և ŖY7k>W0jÖyhQE xsS'./A$\1z)̕c][> %߈!\PG\y@ǷO0=F:u홴Kf$" A 㜁@j>櫭ê62Ly`.Hqs:Et&KյMz՘\gb.e f®4®4Q ޻yGIPҖTۖ]9=\<%ni`>V|-Pc͝b®4®4Q ޻yGIPҖTۖ]9=o.k>߳[_'gL;6c]'5h]'5hοkyi$R,"ibاfp9f7u Y7[HۙVHݑ0UNzW3 OkA OkAG6zzCY']CJ[ SnYvpC 5ɫ[G#FVfz?Q\o*?~ \}_a<2FycJߐB|.>!3W)ԙXlܨzk^>ͫ%=mk8hkoAb+3t?xt?xPѮc{ A%=dXsgQ|Ay.IfG,gBIt OkA OkAN}SڲZjmF־cn6!TA" Y7[HۙVHݑ0UNzW3 OkA OkAI:~b$3܀@ڏ놈9Դhxӄ-!#敐Ī_~sƿ4Mƿ4Mzyx+G*?~ [u{ۏM5I9gz袊+O1\+^^B~8AZ ( ( ( ( ( ( ( ( ( ( ( ( ( ( (&ů:ig˽WE^ݤR" \hKx?uF?}O+p,[Z.s[zPQ@ݧ?>,ij2I/<KC7ZӢn d`{WO@Q@Q@Q@Q@yz4Z$ !a#yi|x/lGU<EPQEQEQEQEQEQEW3?bVqcQEԼuZ4mC{&o.$uwG?o_ut?xt?x@<t?xt?x@<t?xt?x@<t?xt?xIu]o|R[þfGy),. 6=: OkA OkAkߌzU=^Ydi=*'>ÿ-K0ZjU]^%rryWICh??WICh?[A{kۘYDF  * 38L|_,, h5Xn6'z'*9΀4WICh??WICh?/xUΗcyva?#%@xqRyXwᛍkTOy]$) n ?0t?xt?x7S%vzT4w{)f)1m9nW[mT㸞6GiWyѲrT}08<@ƿ4Mƿ4Mzƿ4Mƿ4Mzƿ4MdxzmZ~1yd5SʖU$zs?4<-4>gGi, wYƤORMkV7?JoֶhuH~Zgo3|]nw=sF_ۡߥyg'9'4PQEQEQEQEQEQX$6 ]c͐&qڶ(((((((((((((((K5F}NK[+ mpan<Ҵ+ơyqKǖs]%y H@ŶZ袊<9IgKPQ Ld.xOlW1]ٺΝ{p[$ܜںz(((())h((((((qc '?@(?o_u@/ 7uc}|!G͙ /ʹr}PЋtO|o΀= ZB/Q ]?E ?:*+k7GgG-t(h1|E}ZLRQL$* I팞pqT:mVٯC4w q6$Ggn kЋtO|o΀29uoHٮt9eXsiil5^KqfchؔȐ|/|tz-t("s?5&_-LmgDg 4fkKy7pTtkū+ n%4[Wv8?*ЋtO|o΀&ǁu ',; ږe_12޸/R":VfN&L/!L:=O|oΏZB/Q^%_h|a{#e O6 1ӽ3U7xڔ+}I (ܥ2s=sŏZB/Q ]?E ?:/> j+_Zj6jZFN0BI=:WD8Q2O|oΏZB/QQ^{ ]?E ?:?k7Gg@Ey-t("zs?k7GgX~3u![쥏ι6ET۸EZZbx5x3ۜk[t·_5PKa[PQEQEQEp~<|U+L9R-ܕ$sPH_^gl<-ch[]æMx֐43l*6pFkCY4xuaepD 8'qRU9o~ YjR-Ws$^kvIN3@}";MGT+IQwT,VU!28) %tPcYW'8 p jGFB7;kF4sq$23l%tP?IS6C28''$uɩNiQ^x.qq~9؅ q<}^%des=U䞌zVc9k RO -$mqXݞŴne\A.ޔEr$cQ|O,$B/'Mclw>V?*?~ @Ep$mύ]p %n5ɴTzWQ}COFs |bAހ4(,ϭ_o[FXHX$cQ|O,$B/'Mclw>PQEy*?~ V,>Ic]xA*Kj;ikϾ݋qg#9 v>F1 QEƖg/-t,r wwu$v +'Zwka"y:m`WICh? +q%mv|m/qM6#Һ,j}ؿr3`lsc |uEgif}nR}b7O. ww\rGoJ'Zwka"y:m`:+WICh?aKF R_&QH;\mN0GwV}o >_ۋ90K91>`:z.4>g}1mcK9#hQ\<"c_K o<m?78Ϡ OkAQ\?+}bN׭5RwM34[@ uSr88 ^p'j /^i羝ravG^zGpz<KC7ZӢn d`{V7|:ƿ4Mƿ4MW/Ö:Fq,x FAbr9**:O3_b<р|͓[p *?~ G*?~ Y:g/xrjZ7*P Ɗ qx/^ [ A}Fu G8ojWICh??WICh?<96=ῇdkmSWյY{:iJW攨M3oP>wq^cP(ȿ] Ȓـcm&}1$u®4®5PEI>+kĨE%y:⺟|UF<4o\ⴎ2˝ ïoW+qGz_U_&U_&fhyOtoI7$a~"Fin6͠x&͸i^$I@]'5h]'5j]O#4 tkq:;OƱ  @]0|OkZMoHm)QÁb5kZ imr )Ӛ OkA&[fi rH H|R.UxHtΙ6z QO>ogcQE '?@?g!?qzQ@y|:zy|:M}QmnZ!<Lf|Ǜ^pnTWAfӯboy90 S q@>_]YBwIe#^O˱@sӳoRKNӮڗ;cpI#<N6/-/E^5ߔ_! \ۑA+9m ɧ D`8;qؐj~ /#Mx%.ddݍض6qS}k-f(%nchhImlt?.&YzISc 6۷wƍu'oaHn+ym˖(7AY kϥ,JY *Hg@i Mmw*8+aԁuZ<%[[$%g˼ɖoޒT@<)2k^swϖֽn6s'+Wu'oaHn+ym˖(7A@TQEQEQEQEQEQEQEEoOM髙$ğ@4w%h?k[5[赭]SZPK#}<%QĶW9'qE?zu3﷙>k7q߻hJ(((%%{/?+%%{/?((5~)xON~C_ye 1׫ןKJ_;P OkA OkAיj׏m[E41G2# By]T#\څmČ!2X;aOG< U_&U_&$<3^ .lj̓9Ċ0 r <[kjV3Ml.^F{PI OkA OkA׉YxY6z՗uJJ-zL|IJL_ _i0V\ vD0sGrd?WICh??WICh?ßc7{&CiM}<\8+/*p7'5GF~,ǧO|R Ѷ}?/Y]'5h]'5k/\sw7 vT2wAp`k ʧ9VO'|+ڑNig٘esʌ:U_&U_&ߊݥƘ-5]*ծ/9c9YSA㌎|T񹳸S钙{VHAQ338φ\vu:VEW S'z%yybUQEQEQEQEQEQEQE__Zl?gύqWW0jÖyhQE xsS'./A$\1z[%{kg$$?ku:/(8I9ruaFlo??0>aEW#8O4'^4gjEo] s(Uy 8Qg|%t__h6kK\34)ʦ''nZB/Q ]?E ?:3Ú<&Yً&،oJxkÚ.YmX?'~Fи-dWk7GgG-t(m/ mY[@Yx$&*oQZ~,gaԊЋtO|o΀9{:.l4ojVJ^+cO2]Dx8=}:WQs-FOK\[ѬѢ6_ݢйaF_Ћt[Ɵ={z`XeUt8uz/hw, - ey#5 ]?E ?:?k7Gg@,>PowKmQ&q`$gR[28<[>_jS+ۥ?9]|Fq"_ ^nxZKu\?V Sk7Gg\ϊHky"I {>_]YBwIe#^O˱@s7]5Ւc"{.ԩQo;Fp(d߈V؍Cbpvۻnf.uKGDKkdw2J\U[OXkf5gҖKvr,q$3q]C{[Rb[r弲J8q9 P+7^1Դy4KHJϺy,߽$1\\Z_ϣ=]Oʲ J4k|Q>k{ Cu Q\n\_iG6! 4=cj&}߻v@ /#&.?/݃bAYhCn|tUi!|۰ dJi߹+Y7{tuv}E&$ko1 Uܜ@m5 ]>Hky"I {sxN[S]Y/2!J69gz((((((+$ğ@5W3I?7h?Joֶk%h?k[4溧j׶ړinw~`b-圜眜_5xJ+uZ~((( I5^+l5h`HrŽ|'k2TӮWOR/$wd8:+%%{/?+Ǣb_kz?i{mҀ/|$~*AwPi'+&J? P[nI4OomX6 ; "_ mxwS/td (IF19 o ]hX?p[8:տZB/Q ]?E ?:~Å]{ppEixᦻj/}^ֺ-53܃zzc:_Ћt7m_QNy^XѬ@msNõe o_U? YŤ.#ӣti\|c&OZB/Q ]?E ?:o>)ҵ/OJM'Axf xFIcsI6Z&^B;zk7GgG-t(=ͼZ_i[HSE1|:wc򭿇tMB[yn`i CFa@=Y_Ћt+>X?/ퟛ} 7yr&c# 8N,kv(2c@NxugR7fbSL_ 9>&Gnm/P[bXqP < L԰.uKGDKkdw2J\V-cV<ُ/da:=]C{[Rb[r弲J8q9 PAO/ўHbNY\AqjYZi1A7缍PCˆ8U zjKc~>+~omq>A5K,u8SN7S[Kj^@$y8> jZ,tǵ X--Z6 +L6]"^@\LOY=m/~n͈6/gnϽ jhQKأ+{ym˗XB8xaӁX kϥ,JY *Hg@~#P.,-t"X$ 3[UM9n|WoMudgȆ˸u*TG$ќ ((((?!?ozy +(+O1\+^^B~8AZ ( ^uq?'Z ^uq?'Z⣤ZܴBx-6r͸6021ܨh~]L~`=r~֡ў-H߉yM17`^thP}^ܹo,Ҏm?9Ctզ$D:|Wq<ͱ[-q .Һ[b>5su3y}nEPEPEPEPEPEPEPEP\_&$tMI`@|!"V`X+AuZ٠%Z򮚲E*VCpA@ΝéB(ٷ2pH{WU]Ͻ;OXl0>fw1-oKHEΩ44ˋVnݢIg*UqӨ=qZ:.X/%*XbsU]3A-Bƣw)[0Z ŷdRxcO-otc1O-?_*<1 (((((((_Y^O26ه\S85V~uߵiXH"X>5%\tVhP\3Ǟ,&kKF1V}zƣ-2y_cbp#Ҁ4(<9IgKPQ Ld.xOr-N]ٺΝ{p[$ܜڱ[%{hk>Wmkr ,e6]éR9&w'=6POEPEPEPEPEPEP^3B~Aj ?V PQEW3?bVbu_Zi)>4̌T6ݠ <בhxM mc G?kg<<AK>~#n|vnshM֮_ 1[}sx⣤ZܴBx-6r͸6021ܨ;7^1Դy4KHJϺy,߽$1\T~ZXk>N,kv(2c@NxF7Pͼyepir /ƭ6%!'⻎1Vmmۈ^v猎u6۷w[b>5su3y}nN6ټ=!7y] >ၸeI(CKN4iR1;~^sn8ޙc0{ ^ݛl_ ݟ{wmۻrjڿ~Զ kϥ,JY *Hg@Q@Q@Q@Q@Q@Q@Q@Q@s?j~"7' ]ZZcxCD-kfR&[:]Ρ](Z^6;qEy*?~ UmZ5֡+ŶXTQIc@|A 0^ heܡ#8<(xGcc^irKʁp@bb ^mn<{!9A>P/Lמŧ|O/~uy!TLE ݎ8G==V?]'5h]'5k(?]'5h]'5k+Io*?~ G*?~ NI?u|=" OkA OkAӿu|="]_a_ x.Px5FkY濔H(kI?u|=";+I?u|=";+I?u|=";+I?u|=";+I?u|=";+I?u|=";+I?u|=";++heew4\jwmҰ˻;m <6HqIЮc$$?ku:/(8I9tV}ƣw>%ŭϕ{Fڸl0yZxcP9?𼄤[bGEvQEsvm;Q-59odtEJ(c yS[4gR>p͸vF S4jmM>q"s ȡ# 0{Neahecߋq8k|ATtk[Of.Y1"F?[a]F:&t YC2e;08oK }ugu %`y?.&Clh `hP}^ܹo,Ҏm?9Ctx-XlB47/& aˌުYhCn|tUi!|۰ dYmjA-ԍA`Xv`sIOi]ok/4RiF Q-4=CXdfyb$.J_gmW17]5Ւc"{.ԩQo;Fp+((((((xC8@ob8ϗl}8?'痂﫪 (]^ k^<@|7rӑ`m˷z]Wh MiO}5nZm-$LAa34?iZ6ļfܒko_u@?o_u ^*:MD'ܳi,ۏc c#-ʊOؾdx+~Q|{snF3YoK }ugu %`y?.&Clh h2^G#ԛSKOJ\ɴɻlml4lZ4qSm0|1Rzܩ篵T.uKGDKkdw2J\T-믷&`r%m$|rkLhP}^ܹo,Ҏm?9CtVzЛ}DO+ Wo[  X)hW}MIrho'7m=Z=YRё!odoqZ 믷&`r%m$|rhk7^1Դy4KHJϺy,߽$1\t4k|Q>k{ Cu Q\n\_iG6! 5R@_sc0(*zЛ}DO+ Wo[  Yĉmgu?١uy0H\go'7m=Z=YRё!odoqSugR7fbSL_ 9а.uKGDKkdw2J\T_ZmBKK COwcܬ۷B+PhP}^ܹo,Ҏm?9CtQ|%(sYmW>W\7n@-Q@Q@Q@Q@Q@s?j~"7' ]ZZcxCD-kf> ?VFxJ+uZ~((( SN5]>H~|ޥL#N=gC9֑}@FP9s?נ((>B~SG~.4ZU=y}n>5ܟ|Fm:K]ExSIڽ$QEW o:EXKv+(BO^^]M/lkW7ݭ 7^2:>|m]z]j3(:r5|?[I3x3K~@`3~Zq*OZs\6%o%k `3+׾,_aYZ0\0H$|$zt=~>x-1),=3Tyi,uO \1-sMlKۏ6H!Շ*>PGzk,mVޢu+R9,9!p>Qω^8 x]"YFU5qxOCx|_Iz/K1q9^O=_ ꭦk:^*+*~7thp^Z)1чb<^/;NIX:R*Sө_kZ_ʲ"7w*ڴXmN9ݍ8y#|_ kBs`ace_NI^S&PW|;#5BUbeqR}O/_8ho4kN'YR y,Gz4ڏ.iMI '!X>`3KuxkK!@?6}u5퍗t+S< R34͹ǹ85 ?ud@᭍ݏ%k5y#muU88#]N^_]YBwIe#^O˱@sӳoRKNӮڗ;cpI#<Nx-XlB47/& aˌީxQ񎥣ɢ]%BV}̙f%N.z+<= C56Іl5ު'C(`a8&Zx[7G43>]+!g07 qdz"nO_Phdb ;{v[hOؾdx+~Q|{snF3S#zM\fı,b8è`g@ӦslygTHRmM->)s&&lű=ٰ~ŬjڇA}1'\gWZ_ϣ=]Oʲ P,Bd7fj3gv4C?.:a7ݷm5B6ټ=!7y] >ၸeI(^qŅ{$V5׃$rTv=j'-ϊwJyܜ3]=QEQEQE?'@?!?ozQ@Q@Q@y|:zy|:M}QmnZ!<Lf|Ǜ^pnTU~!^f4?/ 97yoL13Myia;'ؠBwms9 =KMjP$KmV;/Py ~Kɂ@r88%@>&Gnm/P[bXqP < LugR7fbSL_ 9,4kxfy{# <@:WYҤͼX;e8/d%N=@pjMF"mֆ*O_<x%-5yu{;ŃQP{ApqPA-o]}5d[e˗9,nI#@` ~wDvH;q I\F{}v%ڕe-VHV?EPEPEPEPEPEPEP\_&$tMI`@|!"V`X+AuZ٠5>,կn7\nKe|xQCקS>yw( ( (<_W"3Iڽ_W"3Iڽ ( ()jM隌 5q=b+y f?xrGIu):]D:DǴ~=o ,e8F4r/ nEyO{V3tTǴA P^wj h.KuS<++þx{Ʒt#KXZ&LrrA>z/:Tzfkk8ٙcI=}>`]E47:ywγ.1W1o)(?ƏD#M_A4u>5SAAJ&lx;{t3yHզ\y|q;s\"覯?E5EAx$ԡu}"jYH =i~𵆅w[6S43HpItc8D#M_A4'j DᵞEe>=rH¥>R:26gh3\"覯?E5EG/Ѯ+N7e.38|=2iy͎';nǿzO7G"覯Wš"xxl|q1;zwjorUKK/9rs%zw>D#M_A4'j =/4mR-JC+|ne7Vb)׿ |_]hq=~D(rzg<5o)(?ƏD#M_A4w? _xrZLr閟!i1;Sޛ|?7t";kۻFH$,A''>o)(?ƏD#M_A4}>x5|Y $&3yHզ\y|q;s\"覯?E5E/ȳjC@xI& cQS=Fm\6rۏ< ( :Q#xNfIʙ1 780}P?o_u«ooƏUoCmքW*>;'E#FB|ˁ?| Uη`'֯[6-ycЅgv>bz ~ ?U7cY:7\궶ڒ}ZUf^ x!NK@m5Wqj?7+xk2t/ /;p08qM ~ ?U7cY:7\궶ڒ}ZUf^ x!NK@,lS mx"8Иڬzɠ UoCmi9.$O3i F5F܀pqTٽ﬛9VI eiHl+ZK( -dmJ`'l͸*Á˂<[4«ooƳuZomm% j$*m<CtWwa%^_T­«ooƯ[o/wm0nn4wrkQզQKVR]]ϫJ֢BA89a?iE^k߬mǢ'RuiTRUԗWt6ҫ5EcrrXrS]%Ƴ5ruI]%k)*҈pFC 5U7cQ4I"xf3$gX0nN23,:y5/)n/+}N@埖KO`H5hLu_?:]$aR@|3I&6,yY2226R«ooƷ'D"hnq/oֺjUoCm3u\T5t+9״WLbZ=(((Nuӆ}leLB3bk+[%{h[5QeDѐ_5y8/5sUs /̀plA!Aݏi«ooƣOq%|EOV1e6v6\cxΫkm.mgեVkQ!Pi ǂ {+M/O .. 9)6_.\hUoCmi9.$O3i F5F܀pq^\QZiڔNٛpT/.x4*6hV?xgX:*)sjKYiUHT"y{199,9֡W?-ܣKjf6G%ĖmnB )d.u=I'k.A+׫$ğ@4o\6d?Z۬oȕ:El7Oi^jM;[ylrsrsE|(~%j(( ( (2'$xEգLq! լSN5]>H~|ޥL((('ĞT5O>[%ͤG=GJ^IViVV7W3,o$e!; }3~|3 Ê5GO\:t|:6s+,Ea2#l*ᓡ-n-oMciq4xj}OºFr1=Ք3H13 '5^_PđEFUm' +Q\.0OQ +Q\.0OQ +Q\.0OQ +Q\.0OQ +Q\.0OQ +ߋ,+ż}^(4;FխdP;״1]ٺΝ{p[$ܜںz:}WP\G5 ˏ^|๰Nm#Vv(#;X:*)sjKYiUHT"y{199,9ꔰXl\ȺH%K!O{fu!mj_R^:$V?,s`\krЙ>$XtQl^I>V6-VcneP E#?(rM]etB/62Ykgc?'@(((?o_u@?o_u@y|<:7ZpMi!CJ@1=8ŊGrD]"dhP/p<ko]8E yYOSҀ=VK$&+I`Ygi#56:7\궶ڒ}ZUf^ x!NK@ײ: Y-#R 3n qf:ѧ /Hyu%ƫZ^Agsk ,ʯ/NOV닷j^]6`>6i6^ˍ_>_:?l<~v:'nMv8#@Q%\InF0,\)A'%og<&x&դBd9R48[ iֲ: Y-#R 3n qf:5ah幷[yIaGGnjX-./?DBĒ=56cx$*3*cs7g8Eѳ:h\G Ex6-:_1d2;dW-cxΫkm.mgեVkQ!Pi ǂ #ksTqg%h?k[5[赭PKa[WҺ߅ޠFyKڣl0rO( ( (24~#t8c]iGo5 Ӝ9z ^p'j ((((i7Z΅$A¼VH^}W|`ǤRz7oUZT K&U2e# "O/^g3-5\<}F)ɶnO靾@ QQ@ QQ@ QQ@ W_R"<B4\&I4^۶6 cx94?xGK z֦ɖS(p `r(٭䶻ݣPZ}]:$Ep2Or:(jBOPǗƐ\]xkpMi&Wp1f gEy-XI G-XI ^Ey-XI G-XI ^Ey-XI G-XI ^Ey-XI TYA?ϱaO I4&һ01=8 >5A(? >5A⪳F}F-@ƿj&\iD|A <<פ@mk(u /~pHtIT?ncܚ V?|kWQ@ V?|kV[kž&73M}q Kq׽zQEQEQEWJï:נWJï:q-'@%Wrϗs}u\G|1I p33Ӂ3>|Amz['ˊO 70%} +͎$wpjrC噔eJz c] /&$=Ӱ'C蝻7gw۽EQ#A'QIsZ]%Ƴ5ruI]%k)*҈pFC 榟_fs lmZI$)CM#CU6MK$&+I`Ygi#5-pvV^GTW\\Ak%sjS;fmP>\ EM⢗:VYDB-psÐ=N+om&UkZ;Nv򂸓-ߜT^Ew~(Nb P\InF0,\;+M/O .. 9)6_.\k"QզQKVR]]ϫJ֢BA89aT`Fwsu&$"L g.GE}ck(df2.x*Wy~T5mc76׬ImŞa!;?1G"K=2NRV6DZ((((( *Sov]ܑlI@1CO?/lVs %߈!\PG\y@ǷO0=,o 59.-n|4`-a-JЮ#/Yw<g%":.O'h(((((((((((((((7qu:z>Z}]:$Ep2Or:(jBOP>"'A}?z}c'ƿ(?UQ Zi1\Gr[4b 0'(jBOP?jBOP (jBOP?jBOP (YA?ϱac'ƿ(?Uzc'ƿ(?UWac}^/ϕ`y7D\,pp&"_5ՏTՏUPՏTՏUP?k'b|khƔG߃ʃNM|FPO7$J$LQ8ɯI<$$@<$$@<$|@}s:k夐i$(fRHbqWQ@Kh,v# #PAE·_5PKa[PQEQEQEfXuֹE,60zgYw?:1.# 7iOֽQEQ^wE<;t云͔we|tnz{Q^_)Q_R@Ey"G(?ƏE~"JPzE?E*?A4W+T"hW/E^_D)&GbQ̃ Z߇45];TͬEL{GcW/E^:>$ bh [=> O Qnj5CV_j>1bb`bE*?A4W+T"hW/EQ^_)Q_R@Ey"G(?ƏE~"JPzEYյ ]˭^˻}B{_8DT @;J( ( (<gο55v&/62dmpk}W᝶MC\'tCNXQmw'O>AxE̅~e3{]Y^T}h~ƲLrà9ZP|zY^T} X~Lpǡ9\'ֵX vXp/ʻN3rk<t?x Oj(nF!|_v9WaEgɥ5uOިk. |d,:GOްm.`LT zEq߀Z'Q`%c˜P*82}ɬU_&O>AxE̅~e3{]Y^T}h~ƲLrà9ZP|zY^T} X~Lpǡ9\'ֵX vXp/ʻN3rk<t?x Oj(nF!|_v9WaEgɥ5uOިk. |d,:GOްm.`LT zEq߀Z'Q`%c˜P*82}ɬU_&O>AxE̅~e3{]Y^T}h~ƲLrà9ZP|zY^T} X~Lpǡ9\'ֵX vXp/ʻN3rk<t?x Oj(nF!|_v9WaEgɥ5uOިk. |d,:GOްm.`LT zEq߀Z'Q`%c˜P*82}ɬU_&O>AxE̅~e3{]Y^T}h~ƲLrà9ZP|zY^T} X~Lpǡ9\'ֵX vXp/ʻN3rk<t?x Oj(nF!|_v9WaEgɥ5uOިk. |d,:GOްm.`LT zEq߀Z'Q`%c˜P*82}ɬU_&O>AxE̅~e3{]Y^T}h~ƲLrà9ZP|zY^T} X~Lpǡ9^_k6CZj um|ȗ,nA>KQ,5}g]ʙMqƿ4Mhh}XP>.Ew5 J˴g (>M,ɯC}Dp4?cYq{&9a=,ǯM},?cis`z8cМ (ֱ><].k.…WiqMg®5Px ]b @-d/+.ќg# $̚:TGC5>NwcJТ3zڧXI60&wc= J>OxK˅0~Uqd]ƿ4Mhh}XP>.Ew5 J˴g (>M,ɯC}Dp4?cYq{&9a=,ǯM},?cis`z8cМ (u߀׵Z[R[Zi#Tb7!<*((((%%{/?+%%{/?((?F GK`I`@,(^F)cXx]3yvqCwWqr'Fr;+nM2ai2YtgSo,0H~K\3N/y`VF2Ͽ\歪_.jqYAaK I##Ur9~4յ*[&6:(mcRњw\)*Ƞ\ˮM4WK$S[i*]lqی^^7S-?Syn>j]PK"#K (Ep~񞭭\Sbem1JFiyrh^Xc"{=zO[+xὗMB@| JX7d9([֟ggy6:ObO=0mr'x':mծ^{%m~k|䟘N,r}s@Ep) r =J[E罎o쫫X0̿|*~S=N"R9u#tKs2,w/A64\^6Ԣ[a ĶLٷjAY%$ߙ[j cœf%7yY` UZ2`.Iuh8v6o1ӡ:Y.klS[qo^H-WW+L1(%OF]g#=u\տ7yנWxC/j/꺏No,˪P^=|A7) Z-?o}D|SW,UOxQ]q{@YH;H s@Ey-XI Wtڭ𧊭 ͷϻ|w;:(3MrA1*㢶x+BKW>}c7ao6iFsQՏTWDVm5A=[UUzoqnPgEPErZ@^3[n V?|kPQ\f=[UUzoqnWg@W%4 U>%*~6@mc'ƿ(?U]~"Gjž*36>MN3m 袊(K_h7|K~UU?Ob9mÑ޳?jBOP +~"Gjž*36>MN3m &xgķU[6#9$OHmVxSVf\Irͻ@Q@kH~|ޥL(?F GK`I`@#MdxtHR ٧]Y0U3J  iZeYq B![|'9mQ֠J@O+ú|C!-$wzȑsvHrx]adv$Bͽ̦5b2ʽُ6^t=3Xܦݜ턷OE[P%t]:Q%Zﺕa+1 c(g}iynl ČR mPCtPE42n,⸄bܾJ툶z(I{ QңV+WubJXEPM*^]"|֢YTL䀹g'ޣjb]4m;PH#Ӣ1 omsl=Ż[Eo*ʹ,NIڠuP^E[wzy/5o t ׉Ck֗;f f97C>}\k.Aܠʊ((<KC7ZӢn d`{WO^g_J ((((((((((((((((((((((((((((((((((ӼGgYquyhgP.NrxƵ%%{/?((kľ׋\I9ýtP”$?Jxt]z<@I?:.R$?^Ey)OO? 'OנQ@ S)IuP”$?Jxt]z<@I?:.R$?^Ey)OO? 'OנQ@ S)IuP”$?Jxt]z<@I?:.xoJ[{O0ɰ,IZPEPEPEPohy:窜MrA1*㢶x+B ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (>Y{KMe^>}9ν^$ Hu1K?xݼ+a3P{T5k#Կe@c}9jo.K[:S֊([>;_ώe(>׵I>6Li7o oLGuRX$Rεq'>.ڦGK΅|pzl[Š(n% "^$ Hu1K?xݼ+a3P{T5k#Կe@c}9jo.K[:S֊([>;_ώe(>׵I>6Li7o oLGuRX$Rεq'>.ڦGK΅|pzl[Š(n% "^$ Hu1K?xݼ+a3P{T5k#Կe@c}9jo.K[:S֊([>;_ώe(>׵I>6Li7o oLGuRX$Rεq'>.ڦGK΅|pzl[Š(n% "^$ Hu1K?xݼ+a3P_ዙ|']\d{$VfI?Z((((((((((((((((((((((((((((((((pelican-3.7.1/docs/changelog.rst000066400000000000000000000311301303525152100165410ustar00rootroot00000000000000Release history ############### 3.7.1 (2017-01-10) ================== * Fix locale issues in Quickstart script * Specify encoding for README and CHANGELOG in setup.py 3.7.0 (2016-12-12) ================== * Atom feeds output ```` in addition to ```` * Atom feeds use ```` for the original publication date and ```` for modifications * Simplify Atom feed ID generation and support URL fragments * Produce category feeds with category-specific titles * RSS feeds now default to summary instead of full content; set ``RSS_FEED_SUMMARY_ONLY = False`` to revert to previous behavior * Replace ``MD_EXTENSIONS`` with ``MARKDOWN`` setting * Replace ``JINJA_EXTENSIONS`` with more-robust ``JINJA_ENVIRONMENT`` setting * Improve summary truncation logic to handle special characters and tags that span multiple lines, using HTML parser instead of regular expressions * Include summary when looking for intra-site link substitutions * Link to authors and index via ``{author}name`` and ``{index}`` syntax * Override widget names via ``LINKS_WIDGET_NAME`` and ``SOCIAL_WIDGET_NAME`` * Add ``INDEX_SAVE_AS`` option to override default ``index.html`` value * Remove ``PAGES`` context variable for themes in favor of ``pages`` * ``SLUG_SUBSTITUTIONS`` now accepts 3-tuple elements, allowing URL slugs to contain non-alphanumeric characters * Tag and category slugs can be controlled with greater precision using the ``TAG_SUBSTITUTIONS`` and ``CATEGORY_SUBSTITUTIONS`` settings * Author slugs can be controlled with greater precision using the ``AUTHOR_SUBSTITUTIONS`` setting * ``DEFAULT_DATE`` can be defined as a string * Use ``mtime`` instead of ``ctime`` when ``DEFAULT_DATE = 'fs'`` * Add ``--fatal=errors|warnings`` option for use with continuous integration * When using generator-level caching, ensure previously-cached files are processed instead of just new files. * Add Python and Pelican version information to debug output * Improve compatibility with Python 3.5 * Comply with and enforce PEP8 guidelines * Replace tables in settings documentation with ``data::`` directives 3.6.3 (2015-08-14) ================== * Fix permissions issue in release tarball 3.6.2 (2015-08-01) ================== * Fix installation errors related to Unicode in tests * Don't show pagination in ``notmyidea`` theme if there's only one page * Make hidden pages available in context * Improve URLWrapper comparison 3.6.0 (2015-06-15) ================== * Disable caching by default in order to prevent potential confusion * Improve caching behavior, replacing ``pickle`` with ``cpickle`` * Allow Markdown or reST content in metadata fields other than ``summary`` * Support semicolon-separated author/tag lists * Improve flexibility of article sorting * Add ``--relative-urls`` argument * Support devserver listening on addresses other than localhost * Unify HTTP server handlers to ``pelican.server`` throughout * Handle intra-site links to draft posts * Move ``tag_cloud`` from core to plugin * Load default theme's external resources via HTTPS * Import drafts from WordPress XML * Improve support for Windows users * Enhance logging and test suite * Clean up and refactor codebase * New signals: ``all_generators_finalized`` and ``page_writer_finalized`` 3.5.0 (2014-11-04) ================== * Introduce ``ARTICLE_ORDER_BY`` and ``PAGE_ORDER_BY`` settings to control the order of articles and pages. * Include time zone information in dates rendered in templates. * Expose the reader name in the metadata for articles and pages. * Add the ability to store static files along with content in the same directory as articles and pages using ``{attach}`` in the path. * Prevent Pelican from raising an exception when there are duplicate pieces of metadata in a Markdown file. * Introduce the ``TYPOGRIFY_IGNORE_TAGS`` setting to add HTML tags to be ignored by Typogrify. * Add the ability to use ``-`` in date formats to strip leading zeros. For example, ``%-d/%-m/%y`` will now result in the date ``9/8/12``. * Ensure feed generation is correctly disabled during quickstart configuration. * Fix ``PAGE_EXCLUDES`` and ``ARTICLE_EXCLUDES`` from incorrectly matching sub-directories. * Introduce ``STATIC_EXCLUDE`` setting to add static file excludes. * Fix an issue when using ``PAGINATION_PATTERNS`` while ``RELATIVE_URLS`` is enabled. * Fix feed generation causing links to use the wrong language for month names when using other locales. * Fix an issue where the authors list in the simple template wasn't correctly formatted. * Fix an issue when parsing non-string URLs from settings. * Improve consistency of debug and warning messages. 3.4.0 (2014-07-01) ================== * Speed up content generation via new caching mechanism * Add selective post generation (instead of always building entire site) * Many documentation improvements, including switching to prettier RtD theme * Add support for multiple content and plugin paths * Add ``:modified:`` metadata field to complement ``:date:``. Used to specify the last date and time an article was updated independently from the date and time it was published. * Add support for multiple authors via new ``:authors:`` metadata field * Watch for changes in static directories when in auto-regeneration mode * Add filters to limit log output when desired * Add language support to drafts * Add ``SLUGIFY_SOURCE`` setting to control how post slugs are generated * Fix many issues relating to locale and encoding * Apply Typogrify filter to post summary * Preserve file metadata (e.g. time stamps) when copying static files to output * Move AsciiDoc support from Pelican core into separate plugin * Produce inline links instead of reference-style links when importing content * Improve handling of ``IGNORE_FILES`` setting behavior * Properly escape symbol characters in tag names (e.g., ``C++``) * Minor tweaks for Python 3.4 compatibility * Add several new signals 3.3.0 (2013-09-24) ================== * Drop Python 3.2 support in favor of Python 3.3 * Add ``Fabfile`` so Fabric can be used for workflow automation instead of Make * ``OUTPUT_RETENTION`` setting can be used to preserve metadata (e.g., VCS data such as ``.hg`` and ``.git``) from being removed from output directory * Tumblr import * Improve logic and consistency when cleaning output folder * Improve documentation versioning and release automation * Improve pagination flexibility * Rename signals for better consistency (some plugins may need to be updated) * Move metadata extraction from generators to readers; metadata extraction no longer article-specific * Deprecate ``FILES_TO_COPY`` in favor of ``STATIC_PATHS`` and ``EXTRA_PATH_METADATA`` * Summaries in Markdown posts no longer include footnotes * Remove unnecessary whitespace in output via ``lstrip_blocks`` Jinja parameter * Move PDF generation from core to plugin * Replace ``MARKUP`` setting with ``READERS`` * Add warning if img tag is missing ``alt`` attribute * Add support for ``{}`` in relative links syntax, besides ``||`` * Add support for ``{tag}`` and ``{category}`` relative links * Add a ``content_written`` signal 3.2.1 and 3.2.2 =============== * Facilitate inclusion in FreeBSD Ports Collection 3.2 (2013-04-24) ================ * Support for Python 3! * Override page save-to location from meta-data (enables using a static page as the site's home page, for example) * Time period archives (per-year, per-month, and per-day archives of posts) * Posterous blog import * Improve WordPress blog import * Migrate plugins to separate repository * Improve HTML parser * Provide ability to show or hide categories from menu using ``DISPLAY_CATEGORIES_ON_MENU`` option * Auto-regeneration can be told to ignore files via ``IGNORE_FILES`` setting * Improve post-generation feedback to user * For multilingual posts, use meta-data to designate which is the original and which is the translation * Add ``.mdown`` to list of supported Markdown file extensions * Document-relative URL generation (``RELATIVE_URLS``) is now off by default 3.1 (2012-12-04) ================ * Importer now stores slugs within files by default. This can be disabled with the ``--disable-slugs`` option. * Improve handling of links to intra-site resources * Ensure WordPress import adds paragraphs for all types of line endings in post content * Decode HTML entities within WordPress post titles on import * Improve appearance of LinkedIn icon in default theme * Add GitHub and Google+ social icons support in default theme * Optimize social icons * Add ``FEED_ALL_ATOM`` and ``FEED_ALL_RSS`` to generate feeds containing all posts regardless of their language * Split ``TRANSLATION_FEED`` into ``TRANSLATION_FEED_ATOM`` and ``TRANSLATION_FEED_RSS`` * Different feeds can now be enabled/disabled individually * Allow for blank author: if ``AUTHOR`` setting is not set, author won't default to ``${USER}`` anymore, and a post won't contain any author information if the post author is empty * Move LESS and Webassets support from Pelican core to plugin * The ``DEFAULT_DATE`` setting now defaults to ``None``, which means that articles won't be generated unless date metadata is specified * Add ``FILENAME_METADATA`` setting to support metadata extraction from filename * Add ``gzip_cache`` plugin to compress common text files into a ``.gz`` file within the same directory as the original file, preventing the server (e.g. Nginx) from having to compress files during an HTTP call * Add support for AsciiDoc-formatted content * Add ``USE_FOLDER_AS_CATEGORY`` setting so that feature can be toggled on/off * Support arbitrary Jinja template files * Restore basic functional tests * New signals: ``generator_init``, ``get_generators``, and ``article_generate_preread`` 3.0 (2012-08-08) ================ * Refactored the way URLs are handled * Improved the English documentation * Fixed packaging using ``setuptools`` entrypoints * Added ``typogrify`` support * Added a way to disable feed generation * Added support for ``DIRECT_TEMPLATES`` * Allow multiple extensions for content files * Added LESS support * Improved the import script * Added functional tests * Rsync support in the generated Makefile * Improved feed support (easily pluggable with Feedburner for instance) * Added support for ``abbr`` in reST * Fixed a bunch of bugs :-) 2.8 (2012-02-28) ================== * Dotclear importer * Allow the usage of Markdown extensions * Themes are now easily extensible * Don't output pagination information if there is only one page * Add a page per author, with all their articles * Improved the test suite * Made the themes easier to extend * Removed Skribit support * Added a ``pelican-quickstart`` script * Fixed timezone-related issues * Added some scripts for Windows support * Date can be specified in seconds * Never fail when generating posts (skip and continue) * Allow the use of future dates * Support having different timezones per language * Enhanced the documentation 2.7 (2011-06-11) ================== * Use ``logging`` rather than echoing to stdout * Support custom Jinja filters * Compatibility with Python 2.5 * Added a theme manager * Packaged for Debian * Added draft support 2.6 (2011-03-08) ================== * Changes in the output directory structure * Makes templates easier to work with / create * Added RSS support (was Atom-only) * Added tag support for the feeds * Enhance the documentation * Added another theme (brownstone) * Added translations * Added a way to use cleaner URLs with a rewrite url module (or equivalent) * Added a tag cloud * Added an autoreloading feature: the blog is automatically regenerated each time a modification is detected * Translate the documentation into French * Import a blog from an RSS feed * Pagination support * Added Skribit support 2.5 (2010-11-20) ================== * Import from WordPress * Added some new themes (martyalchin / wide-notmyidea) * First bug report! * Linkedin support * Added a FAQ * Google Analytics support * Twitter support * Use relative URLs, not static ones 2.4 (2010-11-06) ================ * Minor themes changes * Add Disqus support (so we have comments) * Another code refactoring * Added config settings about pages * Blog entries can also be generated in PDF 2.3 (2010-10-31) ================ * Markdown support 2.2 (2010-10-30) ================ * Prettify output * Manages static pages as well 2.1 (2010-10-30) ================ * Make notmyidea the default theme 2.0 (2010-10-30) ================ * Refactoring to be more extensible * Change into the setting variables 1.2 (2010-09-28) ================ * Added a debug option * Added per-category feeds * Use filesystem to get dates if no metadata is provided * Add Pygments support 1.1 (2010-08-19) ================ * First working version pelican-3.7.1/docs/conf.py000066400000000000000000000044161303525152100153660ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import os import sys from pelican import __version__ on_rtd = os.environ.get('READTHEDOCS', None) == 'True' sys.path.append(os.path.abspath(os.pardir)) # -- General configuration ---------------------------------------------------- templates_path = ['_templates'] extensions = ['sphinx.ext.autodoc', 'sphinx.ext.ifconfig', 'sphinx.ext.extlinks'] source_suffix = '.rst' master_doc = 'index' project = 'Pelican' copyright = '2015, Alexis Metaireau and contributors' exclude_patterns = ['_build'] release = __version__ version = '.'.join(release.split('.')[:1]) last_stable = '3.7.1' rst_prolog = ''' .. |last_stable| replace:: :pelican-doc:`{0}` '''.format(last_stable) # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' extlinks = { 'pelican-doc': ('http://docs.getpelican.com/%s/', '') } # -- Options for HTML output -------------------------------------------------- html_theme = 'default' if not on_rtd: try: import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] except ImportError: pass html_static_path = ['_static'] # Output file base name for HTML help builder. htmlhelp_basename = 'Pelicandoc' html_use_smartypants = True # If false, no module index is generated. html_use_modindex = False # If false, no index is generated. html_use_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False def setup(app): # overrides for wide tables in RTD theme app.add_stylesheet('theme_overrides.css') # path relative to _static # -- Options for LaTeX output ------------------------------------------------- latex_documents = [ ('index', 'Pelican.tex', 'Pelican Documentation', 'Alexis Métaireau', 'manual'), ] # -- Options for manual page output ------------------------------------------- man_pages = [ ('index', 'pelican', 'pelican documentation', ['Alexis Métaireau'], 1), ('pelican-themes', 'pelican-themes', 'A theme manager for Pelican', ['Mickaël Raybaud'], 1), ('themes', 'pelican-theming', 'How to create themes for Pelican', ['The Pelican contributors'], 1) ] pelican-3.7.1/docs/content.rst000066400000000000000000000521401303525152100162700ustar00rootroot00000000000000Writing content ############### Articles and pages ================== Pelican considers "articles" to be chronological content, such as posts on a blog, and thus associated with a date. The idea behind "pages" is that they are usually not temporal in nature and are used for content that does not change very often (e.g., "About" or "Contact" pages). You can find sample content in the repository at: ``pelican/samples/content/`` .. _internal_metadata: File metadata ============= Pelican tries to be smart enough to get the information it needs from the file system (for instance, about the category of your articles), but some information you need to provide in the form of metadata inside your files. If you are writing your content in reStructuredText format, you can provide this metadata in text files via the following syntax (give your file the ``.rst`` extension):: My super title ############## :date: 2010-10-03 10:20 :modified: 2010-10-04 18:40 :tags: thats, awesome :category: yeah :slug: my-super-post :authors: Alexis Metaireau, Conan Doyle :summary: Short version for index and feeds Author and tag lists may be semicolon-separated instead, which allows you to write authors and tags containing commas:: :tags: pelican, publishing tool; pelican, bird :authors: Metaireau, Alexis; Doyle, Conan Pelican implements an extension to reStructuredText to enable support for the ``abbr`` HTML tag. To use it, write something like this in your post:: This will be turned into :abbr:`HTML (HyperText Markup Language)`. You can also use Markdown syntax (with a file ending in ``.md``, ``.markdown``, ``.mkd``, or ``.mdown``). Markdown generation requires that you first explicitly install the ``Markdown`` package, which can be done via ``pip install Markdown``. Pelican also supports `Markdown Extensions`_, which might have to be installed separately if they are not included in the default ``Markdown`` package and can be configured and loaded via the ``MARKDOWN`` setting. Metadata syntax for Markdown posts should follow this pattern:: Title: My super title Date: 2010-12-03 10:20 Modified: 2010-12-05 19:30 Category: Python Tags: pelican, publishing Slug: my-super-post Authors: Alexis Metaireau, Conan Doyle Summary: Short version for index and feeds This is the content of my super blog post. Readers for additional formats (such as AsciiDoc_) are available via plugins. Refer to `pelican-plugins`_ repository for those. Pelican can also process HTML files ending in ``.html`` and ``.htm``. Pelican interprets the HTML in a very straightforward manner, reading metadata from ``meta`` tags, the title from the ``title`` tag, and the body out from the ``body`` tag:: My super title This is the content of my super blog post. With HTML, there is one simple exception to the standard metadata: ``tags`` can be specified either via the ``tags`` metadata, as is standard in Pelican, or via the ``keywords`` metadata, as is standard in HTML. The two can be used interchangeably. Note that, aside from the title, none of this article metadata is mandatory: if the date is not specified and ``DEFAULT_DATE`` is set to ``'fs'``, Pelican will rely on the file's "mtime" timestamp, and the category can be determined by the directory in which the file resides. For example, a file located at ``python/foobar/myfoobar.rst`` will have a category of ``foobar``. If you would like to organize your files in other ways where the name of the subfolder would not be a good category name, you can set the setting ``USE_FOLDER_AS_CATEGORY`` to ``False``. When parsing dates given in the page metadata, Pelican supports the W3C's `suggested subset ISO 8601`__. .. note:: When experimenting with different settings (especially the metadata ones) caching may interfere and the changes may not be visible. In such cases disable caching with ``LOAD_CONTENT_CACHE = False`` or use the ``--ignore-cache`` command-line switch. __ `W3C ISO 8601`_ ``modified`` should be last time you updated the article, and defaults to ``date`` if not specified. Besides you can show ``modified`` in the templates, feed entries in feed readers will be updated automatically when you set ``modified`` to the current date after you modified your article. ``authors`` is a comma-separated list of article authors. If there's only one author you can use ``author`` field. If you do not explicitly specify summary metadata for a given post, the ``SUMMARY_MAX_LENGTH`` setting can be used to specify how many words from the beginning of an article are used as the summary. You can also extract any metadata from the filename through a regular expression to be set in the ``FILENAME_METADATA`` setting. All named groups that are matched will be set in the metadata object. The default value for the ``FILENAME_METADATA`` setting will only extract the date from the filename. For example, if you would like to extract both the date and the slug, you could set something like: ``'(?P\d{4}-\d{2}-\d{2})_(?P.*)'`` Please note that the metadata available inside your files takes precedence over the metadata extracted from the filename. Pages ===== If you create a folder named ``pages`` inside the content folder, all the files in it will be used to generate static pages, such as **About** or **Contact** pages. (See example filesystem layout below.) You can use the ``DISPLAY_PAGES_ON_MENU`` setting to control whether all those pages are displayed in the primary navigation menu. (Default is ``True``.) If you want to exclude any pages from being linked to or listed in the menu then add a ``status: hidden`` attribute to its metadata. This is useful for things like making error pages that fit the generated theme of your site. .. _ref-linking-to-internal-content: Linking to internal content =========================== From Pelican 3.1 onwards, it is now possible to specify intra-site links to files in the *source content* hierarchy instead of files in the *generated* hierarchy. This makes it easier to link from the current post to other content that may be sitting alongside that post (instead of having to determine where the other content will be placed after site generation). To link to internal content (files in the ``content`` directory), use the following syntax for the link target: ``{filename}path/to/file`` Note: forward slashes, ``/``, are the required path separator in the ``{filename}`` directive on all operating systems, including Windows. For example, a Pelican project might be structured like this:: website/ ├── content │   ├── category/ │   │   └── article1.rst │   ├── article2.md │ └── pages │      └── about.md └── pelican.conf.py In this example, ``article1.rst`` could look like this:: The first article ################# :date: 2012-12-01 10:02 See below intra-site link examples in reStructuredText format. `a link relative to the current file <{filename}../article2.md>`_ `a link relative to the content root <{filename}/article2.md>`_ and ``article2.md``:: Title: The second article Date: 2012-12-01 10:02 See below intra-site link examples in Markdown format. [a link relative to the current file]({filename}category/article1.rst) [a link relative to the content root]({filename}/category/article1.rst) Linking to static files ----------------------- Linking to non-article or non-page content uses the same ``{filename}`` syntax as described above. It is important to remember that those files will not be copied to the output directory unless the source directories containing them are included in the ``STATIC_PATHS`` setting of the project's ``pelicanconf.py`` file. Pelican's default configuration includes the ``images`` directory for this, but others must be added manually. Forgetting to do so will result in broken links. For example, a project's content directory might be structured like this:: content ├── images │   └── han.jpg ├── pdfs │   └── menu.pdf └── pages    └── test.md ``test.md`` would include:: ![Alt Text]({filename}/images/han.jpg) [Our Menu]({filename}/pdfs/menu.pdf) ``pelicanconf.py`` would include:: STATIC_PATHS = ['images', 'pdfs'] Site generation would then copy ``han.jpg`` to ``output/images/han.jpg``, ``menu.pdf`` to ``output/pdfs/menu.pdf``, and write the appropriate links in ``test.md``. Mixed content in the same directory ----------------------------------- Starting with Pelican 3.5, static files can safely share a source directory with page source files, without exposing the page sources in the generated site. Any such directory must be added to both ``STATIC_PATHS`` and ``PAGE_PATHS`` (or ``STATIC_PATHS`` and ``ARTICLE_PATHS``). Pelican will identify and process the page source files normally, and copy the remaining files as if they lived in a separate directory reserved for static files. Note: Placing static and content source files together in the same source directory does not guarantee that they will end up in the same place in the generated site. The easiest way to do this is by using the ``{attach}`` link syntax (described below). Alternatively, the ``STATIC_SAVE_AS``, ``PAGE_SAVE_AS``, and ``ARTICLE_SAVE_AS`` settings (and the corresponding ``*_URL`` settings) can be configured to place files of different types together, just as they could in earlier versions of Pelican. Attaching static files ---------------------- Starting with Pelican 3.5, static files can be "attached" to a page or article using this syntax for the link target: ``{attach}path/to/file`` This works like the ``{filename}`` syntax, but also relocates the static file into the linking document's output directory. If the static file originates from a subdirectory beneath the linking document's source, that relationship will be preserved on output. Otherwise, it will become a sibling of the linking document. This only works for linking to static files, and only when they originate from a directory included in the ``STATIC_PATHS`` setting. For example, a project's content directory might be structured like this:: content ├── blog │   ├── icons │   │   └── icon.png │   ├── photo.jpg │   └── testpost.md └── downloads └── archive.zip ``pelicanconf.py`` would include:: PATH = 'content' STATIC_PATHS = ['blog', 'downloads'] ARTICLE_PATHS = ['blog'] ARTICLE_SAVE_AS = '{date:%Y}/{slug}.html' ARTICLE_URL = '{date:%Y}/{slug}.html' ``testpost.md`` would include:: Title: Test Post Category: test Date: 2014-10-31 ![Icon]({attach}icons/icon.png) ![Photo]({attach}photo.jpg) [Downloadable File]({attach}/downloads/archive.zip) Site generation would then produce an output directory structured like this:: output └── 2014 ├── archive.zip ├── icons │   └── icon.png ├── photo.jpg └── test-post.html Notice that all the files linked using ``{attach}`` ended up in or beneath the article's output directory. If a static file is linked multiple times, the relocating feature of ``{attach}`` will only work in the first of those links to be processed. After the first link, Pelican will treat ``{attach}`` like ``{filename}``. This avoids breaking the already-processed links. **Be careful when linking to a file from multiple documents:** Since the first link to a file finalizes its location and Pelican does not define the order in which documents are processed, using ``{attach}`` on a file linked by multiple documents can cause its location to change from one site build to the next. (Whether this happens in practice will depend on the operating system, file system, version of Pelican, and documents being added, modified, or removed from the project.) Any external sites linking to the file's old location might then find their links broken. **It is therefore advisable to use {attach} only if you use it in all links to a file, and only if the linking documents share a single directory.** Under these conditions, the file's output location will not change in future builds. In cases where these precautions are not possible, consider using ``{filename}`` links instead of ``{attach}``, and letting the file's location be determined by the project's ``STATIC_SAVE_AS`` and ``STATIC_URL`` settings. (Per-file ``save_as`` and ``url`` overrides can still be set in ``EXTRA_PATH_METADATA``.) Linking to authors, categories, index and tags ---------------------------------------------- You can link to authors, categories, index and tags using the ``{author}name``, ``{category}foobar``, ``{index}`` and ``{tag}tagname`` syntax. Deprecated internal link syntax ------------------------------- To remain compatible with earlier versions, Pelican still supports vertical bars (``||``) in addition to curly braces (``{}``) for internal links. For example: ``|filename|an_article.rst``, ``|tag|tagname``, ``|category|foobar``. The syntax was changed from ``||`` to ``{}`` to avoid collision with Markdown extensions or reST directives. Support for the old syntax may eventually be removed. Importing an existing site ========================== It is possible to import your site from WordPress, Tumblr, Dotclear, and RSS feeds using a simple script. See :ref:`import`. Translations ============ It is possible to translate articles. To do so, you need to add a ``lang`` meta attribute to your articles/pages and set a ``DEFAULT_LANG`` setting (which is English [en] by default). With those settings in place, only articles with the default language will be listed, and each article will be accompanied by a list of available translations for that article. .. note:: This core Pelican functionality does not create sub-sites (e.g. ``example.com/de``) with translated templates for each language. For such advanced functionality the `i18n_subsites plugin`_ can be used. Pelican uses the article's URL "slug" to determine if two or more articles are translations of one another. The slug can be set manually in the file's metadata; if not set explicitly, Pelican will auto-generate the slug from the title of the article. Here is an example of two articles, one in English and the other in French. The English article:: Foobar is not dead ################## :slug: foobar-is-not-dead :lang: en That's true, foobar is still alive! And the French version:: Foobar n'est pas mort ! ####################### :slug: foobar-is-not-dead :lang: fr Oui oui, foobar est toujours vivant ! Post content quality notwithstanding, you can see that only item in common between the two articles is the slug, which is functioning here as an identifier. If you'd rather not explicitly define the slug this way, you must then instead ensure that the translated article titles are identical, since the slug will be auto-generated from the article title. If you do not want the original version of one specific article to be detected by the ``DEFAULT_LANG`` setting, use the ``translation`` metadata to specify which posts are translations:: Foobar is not dead ################## :slug: foobar-is-not-dead :lang: en :translation: true That's true, foobar is still alive! .. _internal_pygments_options: Syntax highlighting =================== Pelican can provide colorized syntax highlighting for your code blocks. To do so, you must use the following conventions inside your content files. For reStructuredText, use the ``code-block`` directive to specify the type of code to be highlighted (in these examples, we'll use ``python``):: .. code-block:: python print("Pelican is a static site generator.") For Markdown, which utilizes the `CodeHilite extension`_ to provide syntax highlighting, include the language identifier just above the code block, indenting both the identifier and the code:: There are two ways to specify the identifier: :::python print("The triple-colon syntax will *not* show line numbers.") To display line numbers, use a path-less shebang instead of colons: #!python print("The path-less shebang syntax *will* show line numbers.") The specified identifier (e.g. ``python``, ``ruby``) should be one that appears on the `list of available lexers `_. When using reStructuredText the following options are available in the code-block directive: ============= ============ ========================================= Option Valid values Description ============= ============ ========================================= anchorlinenos N/A If present wrap line numbers in tags. classprefix string String to prepend to token class names hl_lines numbers List of lines to be highlighted, where line numbers to highlight are separated by a space. This is similar to ``emphasize-lines`` in Sphinx, but it does not support a range of line numbers separated by a hyphen, or comma-separated line numbers. lineanchors string Wrap each line in an anchor using this string and -linenumber. linenos string If present or set to "table" output line numbers in a table, if set to "inline" output them inline. "none" means do not output the line numbers for this table. linenospecial number If set every nth line will be given the 'special' css class. linenostart number Line number for the first line. linenostep number Print every nth line number. lineseparator string String to print between lines of code, '\n' by default. linespans string Wrap each line in a span using this and -linenumber. nobackground N/A If set do not output background color for the wrapping element nowrap N/A If set do not wrap the tokens at all. tagsfile string ctags file to use for name definitions. tagurlformat string format for the ctag links. ============= ============ ========================================= Note that, depending on the version, your Pygments module might not have all of these options available. Refer to the *HtmlFormatter* section of the `Pygments documentation `_ for more details on each of the options. For example, the following code block enables line numbers, starting at 153, and prefixes the Pygments CSS classes with *pgcss* to make the names more unique and avoid possible CSS conflicts:: .. code-block:: identifier :classprefix: pgcss :linenos: table :linenostart: 153 It is also possible to specify the ``PYGMENTS_RST_OPTIONS`` variable in your Pelican settings file to include options that will be automatically applied to every code block. For example, if you want to have line numbers displayed for every code block and a CSS prefix you would set this variable to:: PYGMENTS_RST_OPTIONS = {'classprefix': 'pgcss', 'linenos': 'table'} If specified, settings for individual code blocks will override the defaults in your settings file. Publishing drafts ================= If you want to publish an article as a draft (for friends to review before publishing, for example), you can add a ``Status: draft`` attribute to its metadata. That article will then be output to the ``drafts`` folder and not listed on the index page nor on any category or tag page. If your articles should be automatically published as a draft (to not accidentally publish an article before it is finished) include the status in the ``DEFAULT_METADATA``:: DEFAULT_METADATA = { 'status': 'draft', } To publish a post when the default status is ``draft``, update the post's metadata to include ``Status: published``. .. _W3C ISO 8601: http://www.w3.org/TR/NOTE-datetime .. _AsciiDoc: http://www.methods.co.nz/asciidoc/ .. _pelican-plugins: http://github.com/getpelican/pelican-plugins .. _Markdown Extensions: http://pythonhosted.org/Markdown/extensions/ .. _CodeHilite extension: http://pythonhosted.org/Markdown/extensions/code_hilite.html#syntax .. _i18n_subsites plugin: http://github.com/getpelican/pelican-plugins/tree/master/i18n_subsites pelican-3.7.1/docs/contribute.rst000066400000000000000000000171361303525152100170020ustar00rootroot00000000000000Contributing and feedback guidelines #################################### There are many ways to contribute to Pelican. You can improve the documentation, add missing features, and fix bugs (or just report them). You can also help out by reviewing and commenting on `existing issues `_. Don't hesitate to fork Pelican and submit an issue or pull request on GitHub. When doing so, please adhere to the following guidelines. .. include:: ../CONTRIBUTING.rst Setting up the development environment ====================================== While there are many ways to set up one's development environment, following is a method that uses `virtualenv `_. If you don't have ``virtualenv`` installed, you can install it via:: $ pip install virtualenv Virtual environments allow you to work on Python projects which are isolated from one another so you can use different packages (and package versions) with different projects. To create and activate a virtual environment, use the following syntax:: $ virtualenv ~/virtualenvs/pelican $ cd ~/virtualenvs/pelican $ . bin/activate To clone the Pelican source:: $ git clone https://github.com/getpelican/pelican.git src/pelican To install the development dependencies:: $ cd src/pelican $ pip install -r requirements/developer.pip To install Pelican and its dependencies:: $ python setup.py develop Or using ``pip``:: $ pip install -e . Building the docs ================= If you make changes to the documentation, you should preview your changes before committing them:: $ pip install sphinx $ cd src/pelican/docs $ make html Open ``_build/html/index.html`` in your browser to preview the documentation. Running the test suite ====================== Each time you add a feature, there are two things to do regarding tests: check that the existing tests pass, and add tests for the new feature or bugfix. The tests live in ``pelican/tests`` and you can run them using the "discover" feature of ``unittest``:: $ python -Wd -m unittest discover After making your changes and running the tests, you may see a test failure mentioning that "some generated files differ from the expected functional tests output." If you have made changes that affect the HTML output generated by Pelican, and the changes to that output are expected and deemed correct given the nature of your changes, then you should update the output used by the functional tests. To do so, **make sure you have both ``en_EN.utf8`` and ``fr_FR.utf8`` locales installed**, and then run the following two commands:: $ LC_ALL=en_US.utf8 pelican -o pelican/tests/output/custom/ \ -s samples/pelican.conf.py samples/content/ $ LC_ALL=fr_FR.utf8 pelican -o pelican/tests/output/custom_locale/ \ -s samples/pelican.conf_FR.py samples/content/ $ LC_ALL=en_US.utf8 pelican -o pelican/tests/output/basic/ \ samples/content/ Testing on Python 2 and 3 ------------------------- Testing on Python 3 currently requires some extra steps: installing Python 3-compatible versions of dependent packages and plugins. Tox_ is a useful tool to run tests on both versions. It will install the Python 3-compatible version of dependent packages. .. _Tox: http://testrun.org/tox/latest/ Python 3 development tips ========================= Here are some tips that may be useful when doing some code for both Python 2.7 and Python 3 at the same time: - Assume every string and literal is unicode (import unicode_literals): - Do not use prefix ``u'``. - Do not encode/decode strings in the middle of sth. Follow the code to the source (or target) of a string and encode/decode at the first/last possible point. - In other words, write your functions to expect and to return unicode. - Encode/decode strings if e.g. the source is a Python function that is known to handle this badly, e.g. strftime() in Python 2. - Use new syntax: print function, "except ... *as* e" (not comma) etc. - Refactor method calls like ``dict.iteritems()``, ``xrange()`` etc. in a way that runs without code change in both Python versions. - Do not use magic method ``__unicode()__`` in new classes. Use only ``__str()__`` and decorate the class with ``@python_2_unicode_compatible``. - Do not start int literals with a zero. This is a syntax error in Py3k. - Unfortunately I did not find an octal notation that is valid in both Pythons. Use decimal instead. - use six, e.g.: - ``isinstance(.., basestring) -> isinstance(.., six.string_types)`` - ``isinstance(.., unicode) -> isinstance(.., six.text_type)`` - ``setlocale()`` in Python 2 bails when we give the locale name as unicode, and since we are using ``from __future__ import unicode_literals``, we do that everywhere! As a workaround, I enclosed the localename with ``str()``; in Python 2 this casts the name to a byte string, in Python 3 this should do nothing, because the locale name already had been unicode. - Kept range() almost everywhere as-is (2to3 suggests list(range())), just changed it where I felt necessary. - Changed xrange() back to range(), so it is valid in both Python versions. Logging tips ============ Try to use logging with appropriate levels. For logging messages that are not repeated, use the usual Python way:: # at top of file import logging logger = logging.getLogger(__name__) # when needed logger.warning("A warning with %s formatting", arg_to_be_formatted) Do not format log messages yourself. Use ``%s`` formatting in messages and pass arguments to logger. This is important, because Pelican logger will preprocess some arguments (like Exceptions) for Py2/Py3 compatibility. Limiting extraneous log messages -------------------------------- If the log message can occur several times, you may want to limit the log to prevent flooding. In order to do that, use the ``extra`` keyword argument for the logging message in the following format:: logger.warning("A warning with %s formatting", arg_to_be_formatted, extra={'limit_msg': 'A generic message for too many warnings'}) Optionally, you can also set ``'limit_args'`` as a tuple of arguments in ``extra`` dict if your generic message needs formatting. Limit is set to ``5``, i.e, first four logs with the same ``'limit_msg'`` are outputted normally but the fifth one will be logged using ``'limit_msg'`` (and ``'limit_args'`` if present). After the fifth, corresponding log messages will be ignored. For example, if you want to log missing resources, use the following code:: for resource in resources: if resource.is_missing: logger.warning( 'The resource %s is missing', resource.name, extra={'limit_msg': 'Other resources were missing'}) The log messages will be displayed as follows:: WARNING: The resource prettiest_cat.jpg is missing WARNING: The resource best_cat_ever.jpg is missing WARNING: The resource cutest_cat.jpg is missing WARNING: The resource lolcat.jpg is missing WARNING: Other resources were missing Outputting traceback in the logs -------------------------------- If you're logging inside an ``except`` block, you may want to provide the traceback information as well. You can do that by setting ``exc_info`` keyword argument to ``True`` during logging. However, doing so by default can be undesired because tracebacks are long and can be confusing to regular users. Try to limit them to ``--debug`` mode like the following:: try: some_action() except Exception as e: logger.error('Exception occurred: %s', e, exc_info=settings.get('DEBUG', False)) pelican-3.7.1/docs/faq.rst000066400000000000000000000263221303525152100153700ustar00rootroot00000000000000Frequently Asked Questions (FAQ) ################################ Here are some frequently asked questions about Pelican. What's the best way to communicate a problem, question, or suggestion? ====================================================================== Please read our :doc:`feedback guidelines `. How can I help? =============== There are several ways to help out. First, you can report any Pelican suggestions or problems you might have via IRC (preferred) or the `issue tracker `_. If submitting an issue report, please first check the existing issue list (both open and closed) in order to avoid submitting a duplicate issue. If you want to contribute, please fork `the git repository `_, create a new feature branch, make your changes, and issue a pull request. Someone will review your changes as soon as possible. Please refer to the :doc:`How to Contribute ` section for more details. You can also contribute by creating themes and improving the documentation. Is the Pelican settings file mandatory? ======================================= Configuration files are optional and are just an easy way to configure Pelican. For basic operations, it's possible to specify options while invoking Pelican via the command line. See ``pelican --help`` for more information. Changes to the settings file take no effect =========================================== When experimenting with different settings (especially the metadata ones) caching may interfere and the changes may not be visible. In such cases, ensure that caching is disabled via ``LOAD_CONTENT_CACHE = False`` or use the ``--ignore-cache`` command-line switch. I'm creating my own theme. How do I use Pygments for syntax highlighting? ========================================================================= Pygments adds some classes to the generated content. These classes are used by themes to style code syntax highlighting via CSS. Specifically, you can customize the appearance of your syntax highlighting via the ``.highlight pre`` class in your theme's CSS file. To see how various styles can be used to render Django code, for example, use the style selector drop-down at top-right on the `Pygments project demo site `_. You can use the following example commands to generate a starting CSS file from a Pygments built-in style (in this case, "monokai") and then copy the generated CSS file to your new theme:: pygmentize -S monokai -f html -a .highlight > pygment.css cp pygment.css path/to/theme/static/css/ Don't forget to import your ``pygment.css`` file from your main CSS file. How do I create my own theme? ============================= Please refer to :ref:`theming-pelican`. I want to use Markdown, but I got an error. =========================================== If you try to generate Markdown content without first installing the Markdown library, may see a message that says ``No valid files found in content``. Markdown is not a hard dependency for Pelican, so if you have content in Markdown format, you will need to explicitly install the Markdown library. You can do so by typing the following command, prepending ``sudo`` if permissions require it:: pip install markdown Can I use arbitrary metadata in my templates? ============================================= Yes. For example, to include a modified date in a Markdown post, one could include the following at the top of the article:: Modified: 2012-08-08 For reStructuredText, this metadata should of course be prefixed with a colon:: :Modified: 2012-08-08 This metadata can then be accessed in templates such as ``article.html`` via:: {% if article.modified %} Last modified: {{ article.modified }} {% endif %} If you want to include metadata in templates outside the article context (e.g., ``base.html``), the ``if`` statement should instead be:: {% if article and article.modified %} How do I assign custom templates on a per-page basis? ===================================================== It's as simple as adding an extra line of metadata to any page or article that you want to have its own template. For example, this is how it would be handled for content in reST format:: :template: template_name For content in Markdown format:: Template: template_name Then just make sure your theme contains the relevant template file (e.g. ``template_name.html``). How can I override the generated URL of a specific page or article? =================================================================== Include ``url`` and ``save_as`` metadata in any pages or articles that you want to override the generated URL. Here is an example page in reST format:: Override url/save_as page ######################### :url: override/url/ :save_as: override/url/index.html With this metadata, the page will be written to ``override/url/index.html`` and Pelican will use url ``override/url/`` to link to this page. How can I use a static page as my home page? ============================================ The override feature mentioned above can be used to specify a static page as your home page. The following Markdown example could be stored in ``content/pages/home.md``:: Title: Welcome to My Site URL: save_as: index.html Thank you for visiting. Welcome! If the original blog index is still wanted, it can then be saved in a different location by setting ``INDEX_SAVE_AS = 'blog_index.html'`` for the ``'index'`` direct template. What if I want to disable feed generation? ========================================== To disable feed generation, all feed settings should be set to ``None``. All but three feed settings already default to ``None``, so if you want to disable all feed generation, you only need to specify the following settings:: FEED_ALL_ATOM = None CATEGORY_FEED_ATOM = None TRANSLATION_FEED_ATOM = None AUTHOR_FEED_ATOM = None AUTHOR_FEED_RSS = None The word ``None`` should not be surrounded by quotes. Please note that ``None`` and ``''`` are not the same thing. I'm getting a warning about feeds generated without SITEURL being set properly ============================================================================== `RSS and Atom feeds require all URL links to be absolute `_. In order to properly generate links in Pelican you will need to set ``SITEURL`` to the full path of your site. Feeds are still generated when this warning is displayed, but links within may be malformed and thus the feed may not validate. My feeds are broken since I upgraded to Pelican 3.x =================================================== Starting in 3.0, some of the FEED setting names were changed to more explicitly refer to the Atom feeds they inherently represent (much like the FEED_RSS setting names). Here is an exact list of the renamed settings:: FEED -> FEED_ATOM TAG_FEED -> TAG_FEED_ATOM CATEGORY_FEED -> CATEGORY_FEED_ATOM Starting in 3.1, the new feed ``FEED_ALL_ATOM`` has been introduced: this feed will aggregate all posts regardless of their language. This setting generates ``'feeds/all.atom.xml'`` by default and ``FEED_ATOM`` now defaults to ``None``. The following feed setting has also been renamed:: TRANSLATION_FEED -> TRANSLATION_FEED_ATOM Older themes that referenced the old setting names may not link properly. In order to rectify this, please update your theme for compatibility by changing the relevant values in your template files. For an example of complete feed headers and usage please check out the ``simple`` theme. Is Pelican only suitable for blogs? =================================== No. Pelican can be easily configured to create and maintain any type of static site. This may require a little customization of your theme and Pelican configuration. For example, if you are building a launch site for your product and do not need tags on your site, you could remove the relevant HTML code from your theme. You can also disable generation of tag-related pages via:: TAGS_SAVE_AS = '' TAG_SAVE_AS = '' Why does Pelican always write all HTML files even with content caching enabled? =============================================================================== In order to reliably determine whether the HTML output is different before writing it, a large part of the generation environment including the template contexts, imported plugins, etc. would have to be saved and compared, at least in the form of a hash (which would require special handling of unhashable types), because of all the possible combinations of plugins, pagination, etc. which may change in many different ways. This would require a lot more processing time and memory and storage space. Simply writing the files each time is a lot faster and a lot more reliable. However, this means that the modification time of the files changes every time, so a ``rsync`` based upload will transfer them even if their content hasn't changed. A simple solution is to make ``rsync`` use the ``--checksum`` option, which will make it compare the file checksums in a much faster way than Pelican would. When only several specific output files are of interest (e.g. when working on some specific page or the theme templates), the `WRITE_SELECTED` option may help, see :ref:`writing_only_selected_content`. How to process only a subset of all articles? ============================================= It is often useful to process only e.g. 10 articles for debugging purposes. This can be achieved by explicitly specifying only the filenames of those articles in ``ARTICLE_PATHS``. A list of such filenames could be found using a command similar to ``cd content; find -name '*.md' | head -n 10``. My tag-cloud is missing/broken since I upgraded Pelican ======================================================= In an ongoing effort to steamline Pelican, `tag_cloud` generation has been moved out of the pelican core and into a separate `plugin `_. See the :ref:`plugins` documentation further information about the Pelican plugin system. Since I upgraded Pelican my pages are no longer rendered ======================================================== Pages were available to themes as lowercase ``pages`` and uppercase ``PAGES``. To bring this inline with the :ref:`templates-variables` section, ``PAGES`` has been removed. This is quickly resolved by updating your theme to iterate over ``pages`` instead of ``PAGES``. Just replace:: {% for pg in PAGES %} with something like:: {% for pg in pages %} How can I stop Pelican from trying to parse my static files as content? ======================================================================= Pelican's article and page generators run before it's static generator. That means if you use a setup similar to the default configuration, where a static source directory is defined inside a ``*_PATHS`` setting, all files that have a valid content file ending (``.html``, ``.rst``, ``.md``, ...) will be treated as articles or pages before they get treated as static files. To circumvent this issue either use the appropriate ``*_EXCLUDES`` setting or disable the offending reader via ``READERS`` if you don't need it. pelican-3.7.1/docs/importer.rst000066400000000000000000000100161303525152100164530ustar00rootroot00000000000000.. _import: Importing an existing site ########################## Description =========== ``pelican-import`` is a command-line tool for converting articles from other software to reStructuredText or Markdown. The supported import formats are: - WordPress XML export - Dotclear export - Posterous API - Tumblr API - RSS/Atom feed The conversion from HTML to reStructuredText or Markdown relies on `Pandoc`_. For Dotclear, if the source posts are written with Markdown syntax, they will not be converted (as Pelican also supports Markdown). Dependencies ============ ``pelican-import`` has some dependencies not required by the rest of Pelican: - *BeautifulSoup4* and *lxml*, for WordPress and Dotclear import. Can be installed like any other Python package (``pip install BeautifulSoup4 lxml``). - *Feedparser*, for feed import (``pip install feedparser``). - *Pandoc*, see the `Pandoc site`_ for installation instructions on your operating system. .. _Pandoc: http://johnmacfarlane.net/pandoc/ .. _Pandoc site: http://johnmacfarlane.net/pandoc/installing.html Usage ===== :: pelican-import [-h] [--wpfile] [--dotclear] [--posterous] [--tumblr] [--feed] [-o OUTPUT] [-m MARKUP] [--dir-cat] [--dir-page] [--strip-raw] [--disable-slugs] [-e EMAIL] [-p PASSWORD] [-b BLOGNAME] input|api_token|api_key Positional arguments -------------------- ============= ============================================================================ ``input`` The input file to read ``api_token`` (Posterous only) api_token can be obtained from http://posterous.com/api/ ``api_key`` (Tumblr only) api_key can be obtained from http://www.tumblr.com/oauth/apps ============= ============================================================================ Optional arguments ------------------ -h, --help Show this help message and exit --wpfile WordPress XML export (default: False) --dotclear Dotclear export (default: False) --posterous Posterous API (default: False) --tumblr Tumblr API (default: False) --feed Feed to parse (default: False) -o OUTPUT, --output OUTPUT Output path (default: output) -m MARKUP, --markup MARKUP Output markup format (supports rst & markdown) (default: rst) --dir-cat Put files in directories with categories name (default: False) --dir-page Put files recognised as pages in "pages/" sub- directory (wordpress import only) (default: False) --filter-author Import only post from the specified author. --strip-raw Strip raw HTML code that can't be converted to markup such as flash embeds or iframes (wordpress import only) (default: False) --disable-slugs Disable storing slugs from imported posts within output. With this disabled, your Pelican URLs may not be consistent with your original posts. (default: False) -e EMAIL, --email=EMAIL Email used to authenticate Posterous API -p PASSWORD, --password=PASSWORD Password used to authenticate Posterous API -b BLOGNAME, --blogname=BLOGNAME Blog name used in Tumblr API Examples ======== For WordPress:: $ pelican-import --wpfile -o ~/output ~/posts.xml For Dotclear:: $ pelican-import --dotclear -o ~/output ~/backup.txt for Posterous:: $ pelican-import --posterous -o ~/output --email= --password= For Tumblr:: $ pelican-import --tumblr -o ~/output --blogname= Tests ===== To test the module, one can use sample files: - for WordPress: http://wpcandy.com/made/the-sample-post-collection - for Dotclear: http://media.dotaddict.org/tda/downloads/lorem-backup.txt pelican-3.7.1/docs/index.rst000066400000000000000000000046141303525152100157300ustar00rootroot00000000000000Pelican |release| ================= .. ifconfig:: release.endswith('.dev') .. warning:: This documentation is for the version of Pelican currently under development. Were you looking for version |last_stable| documentation? Pelican is a static site generator, written in Python_. Highlights include: * Write your content directly with your editor of choice in reStructuredText_ or Markdown_ formats * Includes a simple CLI tool to (re)generate your site * Easy to interface with distributed version control systems and web hooks * Completely static output is easy to host anywhere Ready to get started? Check out the :doc:`Quickstart` guide. Features -------- Pelican |version| currently supports: * Articles (e.g., blog posts) and pages (e.g., "About", "Projects", "Contact") * Comments, via an external service (Disqus). If you prefer to have more control over your comment data, self-hosted comments are another option. Check out the `Pelican Plugins`_ repository for more details. * Theming support (themes are created using Jinja2_ templates) * Publication of articles in multiple languages * Atom/RSS feeds * Code syntax highlighting * Import from WordPress, Dotclear, or RSS feeds * Integration with external tools: Twitter, Google Analytics, etc. (optional) * Fast rebuild times thanks to content caching and selective output writing Why the name "Pelican"? ----------------------- "Pelican" is an anagram for *calepin*, which means "notebook" in French. ;) Source code ----------- You can access the source code at: https://github.com/getpelican/pelican How to get help, contribute, or provide feedback ------------------------------------------------ See our :doc:`feedback and contribution submission guidelines `. Documentation ------------- .. toctree:: :maxdepth: 2 quickstart install content publish settings themes plugins pelican-themes importer faq tips contribute internals report changelog .. Links .. _Python: http://www.python.org/ .. _reStructuredText: http://docutils.sourceforge.net/rst.html .. _Markdown: http://daringfireball.net/projects/markdown/ .. _Jinja2: http://jinja.pocoo.org/ .. _`Pelican documentation`: http://docs.getpelican.com/latest/ .. _`Pelican's internals`: http://docs.getpelican.com/en/latest/internals.html .. _`Pelican plugins`: https://github.com/getpelican/pelican-plugins pelican-3.7.1/docs/install.rst000066400000000000000000000101601303525152100162600ustar00rootroot00000000000000Installing Pelican ################## Pelican currently runs best on Python 2.7.x and 3.3+; earlier versions of Python are not supported. You can install Pelican via several different methods. The simplest is via `pip `_:: pip install pelican (Keep in mind that operating systems will often require you to prefix the above command with ``sudo`` in order to install Pelican system-wide.) While the above is the simplest method, the recommended approach is to create a virtual environment for Pelican via virtualenv_ before installing Pelican. Assuming you have virtualenv_ installed, you can then open a new terminal session and create a new virtual environment for Pelican:: virtualenv ~/virtualenvs/pelican cd ~/virtualenvs/pelican source bin/activate Once the virtual environment has been created and activated, Pelican can be installed via ``pip install pelican`` as noted above. Alternatively, if you have the project source, you can install Pelican using the distutils method:: cd path-to-Pelican-source python setup.py install If you have Git installed and prefer to install the latest bleeding-edge version of Pelican rather than a stable release, use the following command:: pip install -e "git+https://github.com/getpelican/pelican.git#egg=pelican" Once Pelican is installed, you can run ``pelican --help`` to see basic usage options. For more detail, refer to the :doc:`Publish` section. Optional packages ----------------- If you plan on using `Markdown `_ as a markup format, you'll need to install the Markdown library:: pip install Markdown Typographical enhancements can be enabled in your settings file, but first the requisite `Typogrify `_ library must be installed:: pip install typogrify Dependencies ------------ When Pelican is installed, the following dependent Python packages should be automatically installed without any action on your part: * `feedgenerator `_, to generate the Atom feeds * `jinja2 `_, for templating support * `pygments `_, for syntax highlighting * `docutils `_, for supporting reStructuredText as an input format * `pytz `_, for timezone definitions * `blinker `_, an object-to-object and broadcast signaling system * `unidecode `_, for ASCII transliterations of Unicode text * `six `_, for Python 2 and 3 compatibility utilities * `MarkupSafe `_, for a markup safe string implementation * `python-dateutil `_, to read the date metadata Upgrading --------- If you installed a stable Pelican release via ``pip`` and wish to upgrade to the latest stable release, you can do so by adding ``--upgrade``:: pip install --upgrade pelican If you installed Pelican via distutils or the bleeding-edge method, simply perform the same step to install the most recent version. Kickstart your site ------------------- Once Pelican has been installed, you can create a skeleton project via the ``pelican-quickstart`` command, which begins by asking some questions about your site:: pelican-quickstart Once you finish answering all the questions, your project will consist of the following hierarchy (except for *pages* — shown in parentheses below — which you can optionally add yourself if you plan to create non-chronological content):: yourproject/ ├── content │   └── (pages) ├── output ├── develop_server.sh ├── fabfile.py ├── Makefile ├── pelicanconf.py # Main settings file └── publishconf.py # Settings to use when ready to publish The next step is to begin to adding content to the *content* folder that has been created for you. .. _virtualenv: http://www.virtualenv.org/ pelican-3.7.1/docs/internals.rst000066400000000000000000000100551303525152100166140ustar00rootroot00000000000000Pelican internals ################# This section describe how Pelican works internally. As you'll see, it's quite simple, but a bit of documentation doesn't hurt. :) You can also find in the :doc:`report` section an excerpt of a report the original author wrote with some software design information. .. _report: :doc:`report` Overall structure ================= What Pelican does is take a list of files and process them into some sort of output. Usually, the input files are reStructuredText and Markdown files, and the output is a blog, but both input and output can be anything you want. The logic is separated into different classes and concepts: * **Writers** are responsible for writing files: .html files, RSS feeds, and so on. Since those operations are commonly used, the object is created once and then passed to the generators. * **Readers** are used to read from various formats (HTML, Markdown and reStructuredText for now, but the system is extensible). Given a file, they return metadata (author, tags, category, etc.) and content (HTML-formatted). * **Generators** generate the different outputs. For instance, Pelican comes with ``ArticlesGenerator`` and ``PageGenerator``. Given a configuration, they can do whatever they want. Most of the time, it's generating files from inputs. * Pelican also uses templates, so it's easy to write your own theme. The syntax is `Jinja2 `_ and is very easy to learn, so don't hesitate to jump in and build your own theme. How to implement a new reader? ============================== Is there an awesome markup language you want to add to Pelican? Well, the only thing you have to do is to create a class with a ``read`` method that returns HTML content and some metadata. Take a look at the Markdown reader:: class MarkdownReader(BaseReader): enabled = bool(Markdown) def read(self, source_path): """Parse content and metadata of markdown files""" text = pelican_open(source_path) md_extensions = {'markdown.extensions.meta': {}, 'markdown.extensions.codehilite': {}} md = Markdown(extensions=md_extensions.keys(), extension_configs=md_extensions) content = md.convert(text) metadata = {} for name, value in md.Meta.items(): name = name.lower() meta = self.process_metadata(name, value[0]) metadata[name] = meta return content, metadata Simple, isn't it? If your new reader requires additional Python dependencies, then you should wrap their ``import`` statements in a ``try...except`` block. Then inside the reader's class, set the ``enabled`` class attribute to mark import success or failure. This makes it possible for users to continue using their favourite markup method without needing to install modules for formats they don't use. How to implement a new generator? ================================= Generators have two important methods. You're not forced to create both; only the existing ones will be called. * ``generate_context``, that is called first, for all the generators. Do whatever you have to do, and update the global context if needed. This context is shared between all generators, and will be passed to the templates. For instance, the ``PageGenerator`` ``generate_context`` method finds all the pages, transforms them into objects, and populates the context with them. Be careful *not* to output anything using this context at this stage, as it is likely to change by the effect of other generators. * ``generate_output`` is then called. And guess what is it made for? Oh, generating the output. :) It's here that you may want to look at the context and call the methods of the ``writer`` object that is passed as the first argument of this function. In the ``PageGenerator`` example, this method will look at all the pages recorded in the global context and output a file on the disk (using the writer method ``write_file``) for each page encountered. pelican-3.7.1/docs/pelican-themes.rst000066400000000000000000000116641303525152100175220ustar00rootroot00000000000000pelican-themes ############## Description =========== ``pelican-themes`` is a command line tool for managing themes for Pelican. Usage """"" | pelican-themes [-h] [-l] [-i theme path [theme path ...]] | [-r theme name [theme name ...]] | [-s theme path [theme path ...]] [-v] [--version] Optional arguments: """"""""""""""""""" -h, --help Show the help an exit -l, --list Show the themes already installed -i theme_path, --install theme_path One or more themes to install -r theme_name, --remove theme_name One or more themes to remove -s theme_path, --symlink theme_path Same as "--install", but create a symbolic link instead of copying the theme. Useful for theme development -v, --verbose Verbose output --version Print the version of this script Examples ======== Listing the installed themes """""""""""""""""""""""""""" With ``pelican-themes``, you can see the available themes by using the ``-l`` or ``--list`` option: .. code-block:: console $ pelican-themes -l notmyidea two-column@ simple $ pelican-themes --list notmyidea two-column@ simple In this example, we can see there are three themes available: ``notmyidea``, ``simple``, and ``two-column``. ``two-column`` is prefixed with an ``@`` because this theme is not copied to the Pelican theme path, but is instead just linked to it (see `Creating symbolic links`_ for details about creating symbolic links). Note that you can combine the ``--list`` option with the ``-v`` or ``--verbose`` option to get more verbose output, like this: .. code-block:: console $ pelican-themes -v -l /usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/notmyidea /usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/two-column (symbolic link to `/home/skami/Dev/Python/pelican-themes/two-column') /usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/simple Installing themes """"""""""""""""" You can install one or more themes using the ``-i`` or ``--install`` option. This option takes as argument the path(s) of the theme(s) you want to install, and can be combined with the verbose option: .. code-block:: console # pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms --verbose .. code-block:: console # pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms\ ~/Dev/Python/pelican-themes/martyalchin \ --verbose .. code-block:: console # pelican-themes -vi ~/Dev/Python/pelican-themes/two-column Removing themes """"""""""""""" The ``pelican-themes`` command can also remove themes from the Pelican themes path. The ``-r`` or ``--remove`` option takes as argument the name(s) of the theme(s) you want to remove, and can be combined with the ``--verbose`` option. .. code-block:: console # pelican-themes --remove two-column .. code-block:: console # pelican-themes -r martyachin notmyidea-cmd -v Creating symbolic links """"""""""""""""""""""" ``pelican-themes`` can also install themes by creating symbolic links instead of copying entire themes into the Pelican themes path. To symbolically link a theme, you can use the ``-s`` or ``--symlink``, which works exactly as the ``--install`` option: .. code-block:: console # pelican-themes --symlink ~/Dev/Python/pelican-themes/two-column In this example, the ``two-column`` theme is now symbolically linked to the Pelican themes path, so we can use it, but we can also modify it without having to reinstall it after each modification. This is useful for theme development: .. code-block:: console $ sudo pelican-themes -s ~/Dev/Python/pelican-themes/two-column $ pelican ~/Blog/content -o /tmp/out -t two-column $ firefox /tmp/out/index.html $ vim ~/Dev/Pelican/pelican-themes/two-column/static/css/main.css $ pelican ~/Blog/content -o /tmp/out -t two-column $ cp /tmp/bg.png ~/Dev/Pelican/pelican-themes/two-column/static/img/bg.png $ pelican ~/Blog/content -o /tmp/out -t two-column $ vim ~/Dev/Pelican/pelican-themes/two-column/templates/index.html $ pelican ~/Blog/content -o /tmp/out -t two-column Doing several things at once """""""""""""""""""""""""""" The ``--install``, ``--remove`` and ``--symlink`` option are not mutually exclusive, so you can combine them in the same command line to do more than one operation at time, like this: .. code-block:: console # pelican-themes --remove notmyidea-cms two-column \ --install ~/Dev/Python/pelican-themes/notmyidea-cms-fr \ --symlink ~/Dev/Python/pelican-themes/two-column \ --verbose In this example, the theme ``notmyidea-cms`` is replaced by the theme ``notmyidea-cms-fr`` pelican-3.7.1/docs/plugins.rst000066400000000000000000000253131303525152100163010ustar00rootroot00000000000000.. _plugins: Plugins ####### Beginning with version 3.0, Pelican supports plugins. Plugins are a way to add features to Pelican without having to directly modify the Pelican core. How to use plugins ================== To load plugins, you have to specify them in your settings file. There are two ways to do so. The first method is to specify strings with the path to the callables:: PLUGINS = ['package.myplugin',] Alternatively, another method is to import them and add them to the list:: from package import myplugin PLUGINS = [myplugin,] .. note:: When experimenting with different plugins (especially the ones that deal with metadata and content) caching may interfere and the changes may not be visible. In such cases disable caching with ``LOAD_CONTENT_CACHE = False`` or use the ``--ignore-cache`` command-line switch. If your plugins are not in an importable path, you can specify a list of paths via the ``PLUGIN_PATHS`` setting. As shown in the following example, paths in the ``PLUGIN_PATHS`` list can be absolute or relative to the settings file:: PLUGIN_PATHS = ["plugins", "/srv/pelican/plugins"] PLUGINS = ["assets", "liquid_tags", "sitemap"] Where to find plugins ===================== We maintain a separate repository of plugins for people to share and use. Please visit the `pelican-plugins`_ repository for a list of available plugins. .. _pelican-plugins: https://github.com/getpelican/pelican-plugins Please note that while we do our best to review and maintain these plugins, they are submitted by the Pelican community and thus may have varying levels of support and interoperability. How to create plugins ===================== Plugins are based on the concept of signals. Pelican sends signals, and plugins subscribe to those signals. The list of signals are defined in a subsequent section. The only rule to follow for plugins is to define a ``register`` callable, in which you map the signals to your plugin logic. Let's take a simple example:: from pelican import signals def test(sender): print "%s initialized !!" % sender def register(): signals.initialized.connect(test) .. note:: Signal receivers are weakly-referenced and thus must not be defined within your ``register`` callable or they will be garbage-collected before the signal is emitted. List of signals =============== Here is the list of currently implemented signals: ================================= ============================ =========================================================================== Signal Arguments Description ================================= ============================ =========================================================================== initialized pelican object finalized pelican object invoked after all the generators are executed and just before pelican exits useful for custom post processing actions, such as: - minifying js/css assets. - notify/ping search engines with an updated sitemap. generator_init generator invoked in the Generator.__init__ all_generators_finalized generators invoked after all the generators are executed and before writing output readers_init readers invoked in the Readers.__init__ article_generator_context article_generator, metadata article_generator_preread article_generator invoked before a article is read in ArticlesGenerator.generate_context; use if code needs to do something before every article is parsed article_generator_init article_generator invoked in the ArticlesGenerator.__init__ article_generator_pretaxonomy article_generator invoked before categories and tags lists are created useful when e.g. modifying the list of articles to be generated so that removed articles are not leaked in categories or tags article_generator_finalized article_generator invoked at the end of ArticlesGenerator.generate_context article_generator_write_article article_generator, content invoked before writing each article, the article is passed as content article_writer_finalized article_generator, writer invoked after all articles and related pages have been written, but before the article generator is closed. get_generators pelican object invoked in Pelican.get_generator_classes, can return a Generator, or several generators in a tuple or in a list. get_writer pelican object invoked in Pelican.get_writer, can return a custom Writer. page_generator_context page_generator, metadata page_generator_preread page_generator invoked before a page is read in PageGenerator.generate_context; use if code needs to do something before every page is parsed. page_generator_init page_generator invoked in the PagesGenerator.__init__ page_generator_finalized page_generator invoked at the end of PagesGenerator.generate_context page_writer_finalized page_generator, writer invoked after all pages have been written, but before the page generator is closed. static_generator_context static_generator, metadata static_generator_preread static_generator invoked before a static file is read in StaticGenerator.generate_context; use if code needs to do something before every static file is added to the staticfiles list. static_generator_init static_generator invoked in the StaticGenerator.__init__ static_generator_finalized static_generator invoked at the end of StaticGenerator.generate_context content_object_init content_object invoked at the end of Content.__init__ content_written path, context invoked each time a content file is written. feed_written path, context, feed invoked each time a feed file is written. ================================= ============================ =========================================================================== .. warning:: Avoid ``content_object_init`` signal if you intend to read ``summary`` or ``content`` properties of the content object. That combination can result in unresolved links when :ref:`ref-linking-to-internal-content` (see `pelican-plugins bug #314`_). Use ``_summary`` and ``_content`` properties instead, or, alternatively, run your plugin at a later stage (e.g. ``all_generators_finalized``). .. note:: After Pelican 3.2, signal names were standardized. Older plugins may need to be updated to use the new names: ========================== =========================== Old name New name ========================== =========================== article_generate_context article_generator_context article_generate_finalized article_generator_finalized article_generate_preread article_generator_preread pages_generate_context page_generator_context pages_generate_preread page_generator_preread pages_generator_finalized page_generator_finalized pages_generator_init page_generator_init static_generate_context static_generator_context static_generate_preread static_generator_preread ========================== =========================== Recipes ======= We eventually realised some of the recipes to create plugins would be best shared in the documentation somewhere, so here they are! How to create a new reader -------------------------- One thing you might want is to add support for your very own input format. While it might make sense to add this feature in Pelican core, we wisely chose to avoid this situation and instead have the different readers defined via plugins. The rationale behind this choice is mainly that plugins are really easy to write and don't slow down Pelican itself when they're not active. No more talking — here is an example:: from pelican import signals from pelican.readers import BaseReader # Create a new reader class, inheriting from the pelican.reader.BaseReader class NewReader(BaseReader): enabled = True # Yeah, you probably want that :-) # The list of file extensions you want this reader to match with. # If multiple readers were to use the same extension, the latest will # win (so the one you're defining here, most probably). file_extensions = ['yeah'] # You need to have a read method, which takes a filename and returns # some content and the associated metadata. def read(self, filename): metadata = {'title': 'Oh yeah', 'category': 'Foo', 'date': '2012-12-01'} parsed = {} for key, value in metadata.items(): parsed[key] = self.process_metadata(key, value) return "Some content", parsed def add_reader(readers): readers.reader_classes['yeah'] = NewReader # This is how pelican works. def register(): signals.readers_init.connect(add_reader) Adding a new generator ---------------------- Adding a new generator is also really easy. You might want to have a look at :doc:`internals` for more information on how to create your own generator. :: def get_generators(pelican_object): # define a new generator here if you need to return MyGenerator signals.get_generators.connect(get_generators) .. _pelican-plugins bug #314: https://github.com/getpelican/pelican-plugins/issues/314 pelican-3.7.1/docs/publish.rst000066400000000000000000000203121303525152100162600ustar00rootroot00000000000000Publish your site ################# .. _site_generation: Site generation =============== Once Pelican is installed and you have some content (e.g., in Markdown or reST format), you can convert your content into HTML via the ``pelican`` command, specifying the path to your content and (optionally) the path to your :doc:`settings` file:: pelican /path/to/your/content/ [-s path/to/your/settings.py] The above command will generate your site and save it in the ``output/`` folder, using the default theme to produce a simple site. The default theme consists of very simple HTML without styling and is provided so folks may use it as a basis for creating their own themes. When working on a single article or page, it is possible to generate only the file that corresponds to that content. To do this, use the ``--write-selected`` argument, like so:: pelican --write-selected output/posts/my-post-title.html Note that you must specify the path to the generated *output* file — not the source content. To determine the output file path, use the ``--debug`` flag to determine the correct file name and location. If desired, ``--write-selected`` can take a comma-separated list of paths or can be configured as a setting. (See: :ref:`writing_only_selected_content`) You can also tell Pelican to watch for your modifications, instead of manually re-running it every time you want to see your changes. To enable this, run the ``pelican`` command with the ``-r`` or ``--autoreload`` option. Pelican has other command-line switches available. Have a look at the help to see all the options you can use:: pelican --help Viewing the generated files --------------------------- The files generated by Pelican are static files, so you don't actually need anything special to view them. You can use your browser to open the generated HTML files directly:: firefox output/index.html Because the above method may have trouble locating your CSS and other linked assets, running a simple web server using Python will often provide a more reliable previewing experience. For Python 2, run:: cd output python -m SimpleHTTPServer For Python 3, run:: cd output python -m http.server Once the basic server has been started, you can preview your site at http://localhost:8000/ Deployment ========== After you have generated your site, previewed it in your local development environment, and are ready to deploy it to production, you might first re-generate your site with any production-specific settings (e.g., analytics feeds, etc.) that you may have defined:: pelican content -s publishconf.py To base your publish configuration on top of your ``pelicanconf.py``, you can import your ``pelicanconf`` settings by including the following line in your ``publishconf.py``:: from pelicanconf import * If you have generated a ``publishconf.py`` using ``pelican-quickstart``, this line is included by default. The steps for deploying your site will depend on where it will be hosted. If you have SSH access to a server running Nginx or Apache, you might use the ``rsync`` tool to transmit your site files:: rsync -avc --delete output/ host.example.com:/var/www/your-site/ There are many other deployment options, some of which can be configured when first setting up your site via the ``pelican-quickstart`` command. See the :doc:`Tips` page for detail on publishing via GitHub Pages. Automation ========== While the ``pelican`` command is the canonical way to generate your site, automation tools can be used to streamline the generation and publication flow. One of the questions asked during the ``pelican-quickstart`` process pertains to whether you want to automate site generation and publication. If you answered "yes" to that question, a ``fabfile.py`` and ``Makefile`` will be generated in the root of your project. These files, pre-populated with certain information gleaned from other answers provided during the ``pelican-quickstart`` process, are meant as a starting point and should be customized to fit your particular needs and usage patterns. If you find one or both of these automation tools to be of limited utility, these files can deleted at any time and will not affect usage of the canonical ``pelican`` command. Following are automation tools that "wrap" the ``pelican`` command and can simplify the process of generating, previewing, and uploading your site. Fabric ------ The advantage of Fabric_ is that it is written in Python and thus can be used in a wide range of environments. The downside is that it must be installed separately. Use the following command to install Fabric, prefixing with ``sudo`` if your environment requires it:: pip install Fabric .. note:: Installing PyCrypto on Windows Fabric depends upon PyCrypto_, which is tricky to install if your system doesn't have a C compiler. For Windows users, before installing Fabric, use ``easy_install http://www.voidspace.org.uk/downloads/pycrypto26/pycrypto-2.6.win32-py2.7.exe`` per this `StackOverflow suggestion `_ You're more likely to have success with the Win32 versions of Python 2.7 and PyCrypto, than with the Win64—\ even if your operating system is a 64-bit version of Windows. Take a moment to open the ``fabfile.py`` file that was generated in your project root. You will see a number of commands, any one of which can be renamed, removed, and/or customized to your liking. Using the out-of-the-box configuration, you can generate your site via:: fab build If you'd prefer to have Pelican automatically regenerate your site every time a change is detected (which is handy when testing locally), use the following command instead:: fab regenerate To serve the generated site so it can be previewed in your browser at http://localhost:8000/:: fab serve If during the ``pelican-quickstart`` process you answered "yes" when asked whether you want to upload your site via SSH, you can use the following command to publish your site via rsync over SSH:: fab publish These are just a few of the commands available by default, so feel free to explore ``fabfile.py`` and see what other commands are available. More importantly, don't hesitate to customize ``fabfile.py`` to suit your specific needs and preferences. Make ---- A ``Makefile`` is also automatically created for you when you say "yes" to the relevant question during the ``pelican-quickstart`` process. The advantage of this method is that the ``make`` command is built into most POSIX systems and thus doesn't require installing anything else in order to use it. The downside is that non-POSIX systems (e.g., Windows) do not include ``make``, and installing it on those systems can be a non-trivial task. If you want to use ``make`` to generate your site using the settings in ``pelicanconf.py``, run:: make html To generate the site for production, using the settings in ``publishconf.py``, run:: make publish If you'd prefer to have Pelican automatically regenerate your site every time a change is detected (which is handy when testing locally), use the following command instead:: make regenerate To serve the generated site so it can be previewed in your browser at http://localhost:8000/:: make serve Normally you would need to run ``make regenerate`` and ``make serve`` in two separate terminal sessions, but you can run both at once via:: make devserver The above command will simultaneously run Pelican in regeneration mode as well as serve the output at http://localhost:8000. Once you are done testing your changes, you should stop the development server via:: ./develop_server.sh stop When you're ready to publish your site, you can upload it via the method(s) you chose during the ``pelican-quickstart`` questionnaire. For this example, we'll use rsync over ssh:: make rsync_upload That's it! Your site should now be live. (The default ``Makefile`` and ``devserver.sh`` scripts use the ``python`` and ``pelican`` executables to complete its tasks. If you want to use different executables, such as ``python3``, you can set the ``PY`` and ``PELICAN`` environment variables, respectively, to override the default executable names.) .. _Fabric: http://fabfile.org/ .. _PyCrypto: http://pycrypto.org pelican-3.7.1/docs/quickstart.rst000066400000000000000000000047511303525152100170150ustar00rootroot00000000000000Quickstart ########## Reading through all the documentation is highly recommended, but for the truly impatient, following are some quick steps to get started. Installation ------------ Install Pelican (and optionally Markdown if you intend to use it) on Python 2.7.x or Python 3.3+ by running the following command in your preferred terminal, prefixing with ``sudo`` if permissions warrant:: pip install pelican markdown Create a project ---------------- First, choose a name for your project, create an appropriately-named directory for your site, and switch to that directory:: mkdir -p ~/projects/yoursite cd ~/projects/yoursite Create a skeleton project via the ``pelican-quickstart`` command, which begins by asking some questions about your site:: pelican-quickstart For questions that have default values denoted in brackets, feel free to use the Return key to accept those default values [#tzlocal_fn]_. When asked for your URL prefix, enter your domain name as indicated (e.g., ``http://example.com``). Create an article ----------------- You cannot run Pelican until you have created some content. Use your preferred text editor to create your first article with the following content:: Title: My First Review Date: 2010-12-03 10:20 Category: Review Following is a review of my favorite mechanical keyboard. Given that this example article is in Markdown format, save it as ``~/projects/yoursite/content/keyboard-review.md``. Generate your site ------------------ From your site directory, run the ``pelican`` command to generate your site:: pelican content Your site has now been generated inside the ``output`` directory. (You may see a warning related to feeds, but that is normal when developing locally and can be ignored for now.) Preview your site ----------------- Open a new terminal session and run the following commands to switch to your ``output`` directory and launch Pelican's web server:: cd ~/projects/yoursite/output python -m pelican.server Preview your site by navigating to http://localhost:8000/ in your browser. Continue reading the other documentation sections for more detail, and check out the Pelican wiki's Tutorials_ page for links to community-published tutorials. .. _Tutorials: https://github.com/getpelican/pelican/wiki/Tutorials Footnotes --------- .. [#tzlocal_fn] You can help localize default fields by installing the optional `tzlocal `_ module. pelican-3.7.1/docs/report.rst000066400000000000000000000122131303525152100161260ustar00rootroot00000000000000Some history about Pelican ########################## .. warning:: This page comes from a report the original author (Alexis Métaireau) wrote right after writing Pelican, in December 2010. The information may not be up-to-date. Pelican is a simple static blog generator. It parses markup files (Markdown or reStructuredText for now) and generates an HTML folder with all the files in it. I've chosen to use Python to implement Pelican because it seemed to be simple and to fit to my needs. I did not wanted to define a class for each thing, but still wanted to keep my things loosely coupled. It turns out that it was exactly what I wanted. From time to time, thanks to the feedback of some users, it took me a very few time to provide fixes on it. So far, I've re-factored the Pelican code by two times; each time took less than 30 minutes. Use case ======== I was previously using WordPress, a solution you can host on a web server to manage your blog. Most of the time, I prefer using markup languages such as Markdown or reStructuredText to type my articles. To do so, I use vim. I think it is important to let the people choose the tool they want to write the articles. In my opinion, a blog manager should just allow you to take any kind of input and transform it to a weblog. That's what Pelican does. You can write your articles using the tool you want, and the markup language you want, and then generate a static HTML weblog. .. image:: _static/overall.png To be flexible enough, Pelican has template support, so you can easily write your own themes if you want to. Design process ============== Pelican came from a need I have. I started by creating a single file application, and I have make it grow to support what it does by now. To start, I wrote a piece of documentation about what I wanted to do. Then, I created the content I wanted to parse (the reStructuredText files) and started experimenting with the code. Pelican was 200 lines long and contained almost ten functions and one class when it was first usable. I have been facing different problems all over the time and wanted to add features to Pelican while using it. The first change I have done was to add the support of a settings file. It is possible to pass the options to the command line, but can be tedious if there is a lot of them. In the same way, I have added the support of different things over time: Atom feeds, multiple themes, multiple markup support, etc. At some point, it appears that the "only one file" mantra was not good enough for Pelican, so I decided to rework a bit all that, and split this in multiple different files. I’ve separated the logic in different classes and concepts: * *writers* are responsible of all the writing process of the files. They are responsible of writing .html files, RSS feeds and so on. Since those operations are commonly used, the object is created once, and then passed to the generators. * *readers* are used to read from various formats (Markdown and reStructuredText for now, but the system is extensible). Given a file, they return metadata (author, tags, category, etc) and content (HTML formatted). * *generators* generate the different outputs. For instance, Pelican comes with an ArticlesGenerator and PagesGenerator, into others. Given a configuration, they can do whatever you want them to do. Most of the time it's generating files from inputs (user inputs and files). I also deal with contents objects. They can be ``Articles``, ``Pages``, ``Quotes``, or whatever you want. They are defined in the ``contents.py`` module and represent some content to be used by the program. In more detail ============== Here is an overview of the classes involved in Pelican. .. image:: _static/uml.jpg The interface does not really exist, and I have added it only to clarify the whole picture. I do use duck typing and not interfaces. Internally, the following process is followed: * First of all, the command line is parsed, and some content from the user is used to initialize the different generator objects. * A ``context`` is created. It contains the settings from the command line and a settings file if provided. * The ``generate_context`` method of each generator is called, updating the context. * The writer is created and given to the ``generate_output`` method of each generator. I make two calls because it is important that when the output is generated by the generators, the context will not change. In other words, the first method ``generate_context`` should modify the context, whereas the second ``generate_output`` method should not. Then, it is up to the generators to do what the want, in the ``generate_context`` and ``generate_content`` method. Taking the ``ArticlesGenerator`` class will help to understand some others concepts. Here is what happens when calling the ``generate_context`` method: * Read the folder “path”, looking for restructured text files, load each of them, and construct a content object (``Article``) with it. To do so, use ``Reader`` objects. * Update the ``context`` with all those articles. Then, the ``generate_content`` method uses the ``context`` and the ``writer`` to generate the wanted output. pelican-3.7.1/docs/settings.rst000066400000000000000000001207121303525152100164570ustar00rootroot00000000000000Settings ######## Pelican is configurable thanks to a settings file you can pass to the command line:: pelican content -s path/to/your/pelicanconf.py If you used the ``pelican-quickstart`` command, your primary settings file will be named ``pelicanconf.py`` by default. .. note:: When experimenting with different settings (especially the metadata ones) caching may interfere and the changes may not be visible. In such cases disable caching with ``LOAD_CONTENT_CACHE = False`` or use the ``--ignore-cache`` command-line switch. Settings are configured in the form of a Python module (a file). There is an `example settings file `_ available for reference. All the setting identifiers must be set in all-caps, otherwise they will not be processed. Setting values that are numbers (5, 20, etc.), booleans (True, False, None, etc.), dictionaries, or tuples should *not* be enclosed in quotation marks. All other values (i.e., strings) *must* be enclosed in quotation marks. Unless otherwise specified, settings that refer to paths can be either absolute or relative to the configuration file. The settings you define in the configuration file will be passed to the templates, which allows you to use your settings to add site-wide content. Here is a list of settings for Pelican: Basic settings ============== .. data:: USE_FOLDER_AS_CATEGORY = True When you don't specify a category in your post metadata, set this setting to ``True``, and organize your articles in subfolders, the subfolder will become the category of your post. If set to ``False``, ``DEFAULT_CATEGORY`` will be used as a fallback. .. data:: DEFAULT_CATEGORY = 'misc' The default category to fall back on. .. data:: DISPLAY_PAGES_ON_MENU = True Whether to display pages on the menu of the template. Templates may or may not honor this setting. .. data:: DISPLAY_CATEGORIES_ON_MENU = True Whether to display categories on the menu of the template. Templates may or not honor this setting. .. data:: DOCUTILS_SETTINGS = {} Extra configuration settings for the docutils publisher (applicable only to reStructuredText). See `Docutils Configuration`_ settings for more details. .. data:: DELETE_OUTPUT_DIRECTORY = False Delete the output directory, and **all** of its contents, before generating new files. This can be useful in preventing older, unnecessary files from persisting in your output. However, **this is a destructive setting and should be handled with extreme care.** .. data:: OUTPUT_RETENTION = [] A list of filenames that should be retained and not deleted from the output directory. One use case would be the preservation of version control data. Example:: OUTPUT_RETENTION = [".hg", ".git", ".bzr"] .. data:: JINJA_ENVIRONMENT = {'trim_blocks': True, 'lstrip_blocks': True} A dictionary of custom Jinja2 environment variables you want to use. This also includes a list of extensions you may want to include. See `Jinja Environment documentation`_. .. data:: JINJA_FILTERS = {} A dictionary of custom Jinja2 filters you want to use. The dictionary should map the filtername to the filter function. Example:: JINJA_FILTERS = {'urlencode': urlencode_filter} See `Jinja custom filters documentation`_. .. data:: LOG_FILTER = [] A list of tuples containing the logging level (up to ``warning``) and the message to be ignored. Example:: LOG_FILTER = [(logging.WARN, 'TAG_SAVE_AS is set to False')] .. data:: READERS = {} A dictionary of file extensions / Reader classes for Pelican to process or ignore. For example, to avoid processing .html files, set:: READERS = {'html': None} To add a custom reader for the ``foo`` extension, set:: READERS = {'foo': FooReader} .. data:: IGNORE_FILES = ['.#*'] A list of glob patterns. Files and directories matching any of these patterns will be ignored by the processor. For example, the default ``['.#*']`` will ignore emacs lock files, and ``['__pycache__']`` would ignore Python 3's bytecode caches. .. data:: MARKDOWN = {...} Extra configuration settings for the Markdown processor. Refer to the Python Markdown documentation's `Options section `_ for a complete list of supported options. The ``extensions`` option will be automatically computed from the ``extension_configs`` option. Defaults to:: MARKDOWN = { 'extension_configs': { 'markdown.extensions.codehilite': {'css_class': 'highlight'}, 'markdown.extensions.extra': {}, 'markdown.extensions.meta': {}, }, 'output_format': 'html5', } .. Note:: The dictionary defined in your settings file will update this default one. .. data:: OUTPUT_PATH = 'output/' Where to output the generated files. .. data:: PATH Path to content directory to be processed by Pelican. If undefined, and content path is not specified via an argument to the ``pelican`` command, Pelican will use the current working directory. .. data:: PAGE_PATHS = ['pages'] A list of directories and files to look at for pages, relative to ``PATH``. .. data:: PAGE_EXCLUDES = [] A list of directories to exclude when looking for pages in addition to ``ARTICLE_PATHS``. .. data:: ARTICLE_PATHS = [''] A list of directories and files to look at for articles, relative to ``PATH``. .. data:: ARTICLE_EXCLUDES = [] A list of directories to exclude when looking for articles in addition to ``PAGE_PATHS``. .. data:: OUTPUT_SOURCES = False Set to True if you want to copy the articles and pages in their original format (e.g. Markdown or reStructuredText) to the specified ``OUTPUT_PATH``. .. data:: OUTPUT_SOURCES_EXTENSION = '.text' Controls the extension that will be used by the SourcesGenerator. Defaults to ``.text``. If not a valid string the default value will be used. .. data:: PLUGINS = [] The list of plugins to load. See :ref:`plugins`. .. data:: PLUGIN_PATHS = [] A list of directories where to look for plugins. See :ref:`plugins`. .. data:: SITENAME = 'A Pelican Blog' Your site name .. data:: SITEURL Base URL of your website. Not defined by default, so it is best to specify your SITEURL; if you do not, feeds will not be generated with properly-formed URLs. You should include ``http://`` and your domain, with no trailing slash at the end. Example: ``SITEURL = 'http://mydomain.com'`` .. data:: STATIC_PATHS = ['images'] A list of directories (relative to ``PATH``) in which to look for static files. Such files will be copied to the output directory without modification. Articles, pages, and other content source files will normally be skipped, so it is safe for a directory to appear both here and in ``PAGE_PATHS`` or ``ARTICLE_PATHS``. Pelican's default settings include the "images" directory here. .. data:: STATIC_EXCLUDES = [] A list of directories to exclude when looking for static files. .. data:: STATIC_EXCLUDE_SOURCES = True If set to False, content source files will not be skipped when copying files found in ``STATIC_PATHS``. This setting is for backward compatibility with Pelican releases before version 3.5. It has no effect unless ``STATIC_PATHS`` contains a directory that is also in ``ARTICLE_PATHS`` or ``PAGE_PATHS``. If you are trying to publish your site's source files, consider using the ``OUTPUT_SOURCES`` setting instead. .. data:: TYPOGRIFY = False If set to True, several typographical improvements will be incorporated into the generated HTML via the `Typogrify `_ library, which can be installed via: ``pip install typogrify`` .. data:: TYPOGRIFY_IGNORE_TAGS = [] A list of tags for Typogrify to ignore. By default Typogrify will ignore ``pre`` and ``code`` tags. This requires that Typogrify version 2.0.4 or later is installed .. data:: SUMMARY_MAX_LENGTH = 50 When creating a short summary of an article, this will be the default length (measured in words) of the text created. This only applies if your content does not otherwise specify a summary. Setting to ``None`` will cause the summary to be a copy of the original content. .. data:: WITH_FUTURE_DATES = True If disabled, content with dates in the future will get a default status of ``draft``. See :ref:`reading_only_modified_content` for caveats. .. data:: INTRASITE_LINK_REGEX = '[{|](?P.*?)[|}]' Regular expression that is used to parse internal links. Default syntax when linking to internal files, tags, etc., is to enclose the identifier, say ``filename``, in ``{}`` or ``||``. Identifier between ``{`` and ``}`` goes into the ``what`` capturing group. For details see :ref:`ref-linking-to-internal-content`. .. data:: PYGMENTS_RST_OPTIONS = [] A list of default Pygments settings for your reStructuredText code blocks. See :ref:`internal_pygments_options` for a list of supported options. .. data:: SLUGIFY_SOURCE = 'title' Specifies where you want the slug to be automatically generated from. Can be set to ``title`` to use the 'Title:' metadata tag or ``basename`` to use the article's file name when creating the slug. .. data:: CACHE_CONTENT = False If ``True``, saves content in caches. See :ref:`reading_only_modified_content` for details about caching. .. data:: CONTENT_CACHING_LAYER = 'reader' If set to ``'reader'``, save only the raw content and metadata returned by readers. If set to ``'generator'``, save processed content objects. .. data:: CACHE_PATH = 'cache' Directory in which to store cache files. .. data:: GZIP_CACHE = True If ``True``, use gzip to (de)compress the cache files. .. data:: CHECK_MODIFIED_METHOD = 'mtime' Controls how files are checked for modifications. .. data:: LOAD_CONTENT_CACHE = False If ``True``, load unmodified content from caches. .. data:: WRITE_SELECTED = [] If this list is not empty, **only** output files with their paths in this list are written. Paths should be either absolute or relative to the current Pelican working directory. For possible use cases see :ref:`writing_only_selected_content`. .. data:: FORMATTED_FIELDS = ['summary'] A list of metadata fields containing reST/Markdown content to be parsed and translated to HTML. URL settings ============ The first thing to understand is that there are currently two supported methods for URL formation: *relative* and *absolute*. Relative URLs are useful when testing locally, and absolute URLs are reliable and most useful when publishing. One method of supporting both is to have one Pelican configuration file for local development and another for publishing. To see an example of this type of setup, use the ``pelican-quickstart`` script as described in the :doc:`Installation ` section, which will produce two separate configuration files for local development and publishing, respectively. You can customize the URLs and locations where files will be saved. The ``*_URL`` and ``*_SAVE_AS`` variables use Python's format strings. These variables allow you to place your articles in a location such as ``{slug}/index.html`` and link to them as ``{slug}`` for clean URLs (see example below). These settings give you the flexibility to place your articles and pages anywhere you want. .. note:: If you specify a ``datetime`` directive, it will be substituted using the input files' date metadata attribute. If the date is not specified for a particular file, Pelican will rely on the file's ``mtime`` timestamp. Check the `Python datetime documentation`_ for more information. .. _Python datetime documentation: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior Also, you can use other file metadata attributes as well: * slug * date * lang * author * category Example usage:: ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/' ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html' PAGE_URL = 'pages/{slug}/' PAGE_SAVE_AS = 'pages/{slug}/index.html' This would save your articles into something like ``/posts/2011/Aug/07/sample-post/index.html``, save your pages into ``/pages/about/index.html``, and render them available at URLs of ``/posts/2011/Aug/07/sample-post/`` and ``/pages/about/``, respectively. .. data:: RELATIVE_URLS = False Defines whether Pelican should use document-relative URLs or not. Only set this to ``True`` when developing/testing and only if you fully understand the effect it can have on links/feeds. .. data:: ARTICLE_URL = '{slug}.html' The URL to refer to an article. .. data:: ARTICLE_SAVE_AS = '{slug}.html' The place where we will save an article. .. data:: ARTICLE_LANG_URL = '{slug}-{lang}.html' The URL to refer to an article which doesn't use the default language. .. data:: ARTICLE_LANG_SAVE_AS = '{slug}-{lang}.html' The place where we will save an article which doesn't use the default language. .. data:: DRAFT_URL = 'drafts/{slug}.html' The URL to refer to an article draft. .. data:: DRAFT_SAVE_AS = 'drafts/{slug}.html' The place where we will save an article draft. .. data:: DRAFT_LANG_URL = 'drafts/{slug}-{lang}.html' The URL to refer to an article draft which doesn't use the default language. .. data:: DRAFT_LANG_SAVE_AS = 'drafts/{slug}-{lang}.html' The place where we will save an article draft which doesn't use the default language. .. data:: PAGE_URL = 'pages/{slug}.html' The URL we will use to link to a page. .. data:: PAGE_SAVE_AS = 'pages/{slug}.html' The location we will save the page. This value has to be the same as PAGE_URL or you need to use a rewrite in your server config. .. data:: PAGE_LANG_URL = 'pages/{slug}-{lang}.html' The URL we will use to link to a page which doesn't use the default language. .. data:: PAGE_LANG_SAVE_AS = 'pages/{slug}-{lang}.html' The location we will save the page which doesn't use the default language. .. data:: CATEGORY_URL = 'category/{slug}.html' The URL to use for a category. .. data:: CATEGORY_SAVE_AS = 'category/{slug}.html' The location to save a category. .. data:: TAG_URL = 'tag/{slug}.html' The URL to use for a tag. .. data:: TAG_SAVE_AS = 'tag/{slug}.html' The location to save the tag page. .. data:: AUTHOR_URL = 'author/{slug}.html' The URL to use for an author. .. data:: AUTHOR_SAVE_AS = 'author/{slug}.html' The location to save an author. .. data:: YEAR_ARCHIVE_SAVE_AS = '' The location to save per-year archives of your posts. .. data:: MONTH_ARCHIVE_SAVE_AS = '' The location to save per-month archives of your posts. .. data:: DAY_ARCHIVE_SAVE_AS = '' The location to save per-day archives of your posts. .. data:: SLUG_SUBSTITUTIONS = () Substitutions to make prior to stripping out non-alphanumerics when generating slugs. Specified as a list of 3-tuples of ``(from, to, skip)`` which are applied in order. ``skip`` is a boolean indicating whether or not to skip replacement of non-alphanumeric characters. Useful for backward compatibility with existing URLs. .. data:: AUTHOR_SUBSTITUTIONS = () Substitutions for authors. ``SLUG_SUBSTITUTIONS`` is not taken into account here! .. data:: CATEGORY_SUBSTITUTIONS = () Added to ``SLUG_SUBSTITUTIONS`` for categories. .. data:: TAG_SUBSTITUTIONS = () Added to ``SLUG_SUBSTITUTIONS`` for tags. .. note:: If you do not want one or more of the default pages to be created (e.g., you are the only author on your site and thus do not need an Authors page), set the corresponding ``*_SAVE_AS`` setting to ``''`` to prevent the relevant page from being generated. .. note:: Substitutions are applied in order with the side effect that keeping non-alphanum characters applies to the whole string when a replacement is made. For example if you have the following setting:: SLUG_SUBSTITUTIONS = (('C++', 'cpp'), ('keep dot', 'keep.dot', True)) the string ``Keep Dot`` will be converted to ``keep.dot``, however ``C++ will keep dot`` will be converted to ``cpp will keep.dot`` instead of ``cpp-will-keep.dot``! If you want to keep non-alphanum characters only for tags or categories but not other slugs then configure ``TAG_SUBSTITUTIONS`` and ``CATEGORY_SUBSTITUTIONS`` respectively! Pelican can optionally create per-year, per-month, and per-day archives of your posts. These secondary archives are disabled by default but are automatically enabled if you supply format strings for their respective ``_SAVE_AS`` settings. Period archives fit intuitively with the hierarchical model of web URLs and can make it easier for readers to navigate through the posts you've written over time. Example usage:: YEAR_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/index.html' MONTH_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/index.html' With these settings, Pelican will create an archive of all your posts for the year at (for instance) ``posts/2011/index.html`` and an archive of all your posts for the month at ``posts/2011/Aug/index.html``. .. note:: Period archives work best when the final path segment is ``index.html``. This way a reader can remove a portion of your URL and automatically arrive at an appropriate archive of posts, without having to specify a page name. ``DIRECT_TEMPLATES`` work a bit differently than noted above. Only the ``_SAVE_AS`` settings are available, but it is available for any direct template. .. data:: ARCHIVES_SAVE_AS = 'archives.html' The location to save the article archives page. .. data:: YEAR_ARCHIVE_SAVE_AS = '' The location to save per-year archives of your posts. .. data:: MONTH_ARCHIVE_SAVE_AS = '' The location to save per-month archives of your posts. .. data:: DAY_ARCHIVE_SAVE_AS = '' The location to save per-day archives of your posts. .. data:: AUTHORS_SAVE_AS = 'authors.html' The location to save the author list. .. data:: CATEGORIES_SAVE_AS = 'categories.html' The location to save the category list. .. data:: TAGS_SAVE_AS = 'tags.html' The location to save the tag list. .. data:: INDEX_SAVE_AS = 'index.html' The location to save the list of all articles. URLs for direct template pages are theme-dependent. Some themes use corresponding ``*_URL`` setting as string, while others hard-code them: ``'archives.html'``, ``'authors.html'``, ``'categories.html'``, ``'tags.html'``. Time and Date ============= .. data:: TIMEZONE The timezone used in the date information, to generate Atom and RSS feeds. If no timezone is defined, UTC is assumed. This means that the generated Atom and RSS feeds will contain incorrect date information if your locale is not UTC. Pelican issues a warning in case this setting is not defined, as it was not mandatory in previous versions. Have a look at `the wikipedia page`_ to get a list of valid timezone values. .. _the wikipedia page: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones .. data:: DEFAULT_DATE = None The default date you want to use. If ``'fs'``, Pelican will use the file system timestamp information (mtime) if it can't get date information from the metadata. If given any other string, it will be parsed by the same method as article metadata. If set to a tuple object, the default datetime object will instead be generated by passing the tuple to the ``datetime.datetime`` constructor. .. data:: DEFAULT_DATE_FORMAT = '%a %d %B %Y' The default date format you want to use. .. data:: DATE_FORMATS = {} If you manage multiple languages, you can set the date formatting here. If no ``DATE_FORMATS`` are set, Pelican will fall back to ``DEFAULT_DATE_FORMAT``. If you need to maintain multiple languages with different date formats, you can set the ``DATE_FORMATS`` dictionary using the language name (``lang`` metadata in your post content) as the key. In addition to the standard C89 strftime format codes that are listed in `Python strftime documentation`_, you can use the ``-`` character between ``%`` and the format character to remove any leading zeros. For example, ``%d/%m/%Y`` will output ``01/01/2014`` whereas ``%-d/%-m/%Y`` will result in ``1/1/2014``. .. parsed-literal:: DATE_FORMATS = { 'en': '%a, %d %b %Y', 'jp': '%Y-%m-%d(%a)', } It is also possible to set different locale settings for each language by using a ``(locale, format)`` tuple as a dictionary value which will override the ``LOCALE`` setting: .. parsed-literal:: # On Unix/Linux DATE_FORMATS = { 'en': ('en_US','%a, %d %b %Y'), 'jp': ('ja_JP','%Y-%m-%d(%a)'), } # On Windows DATE_FORMATS = { 'en': ('usa','%a, %d %b %Y'), 'jp': ('jpn','%Y-%m-%d(%a)'), } .. data:: LOCALE Change the locale [#]_. A list of locales can be provided here or a single string representing one locale. When providing a list, all the locales will be tried until one works. You can set locale to further control date format: .. parsed-literal:: LOCALE = ('usa', 'jpn', # On Windows 'en_US', 'ja_JP' # On Unix/Linux ) For a list of available locales refer to `locales on Windows`_ or on Unix/Linux, use the ``locale -a`` command; see manpage `locale(1)`_ for more information. .. [#] Default is the system locale. .. _Python strftime documentation: http://docs.python.org/library/datetime.html#strftime-strptime-behavior .. _locales on Windows: http://msdn.microsoft.com/en-us/library/cdax410z%28VS.71%29.aspx .. _locale(1): http://linux.die.net/man/1/locale .. _template_pages: Template pages ============== .. data:: TEMPLATE_PAGES = None A mapping containing template pages that will be rendered with the blog entries. See :ref:`template_pages`. If you want to generate custom pages besides your blog entries, you can point any Jinja2 template file with a path pointing to the file and the destination path for the generated file. For instance, if you have a blog with three static pages — a list of books, your resume, and a contact page — you could have:: TEMPLATE_PAGES = {'src/books.html': 'dest/books.html', 'src/resume.html': 'dest/resume.html', 'src/contact.html': 'dest/contact.html'} .. data:: DIRECT_TEMPLATES = ['index', 'categories', 'authors', 'archives'] List of templates that are used directly to render content. Typically direct templates are used to generate index pages for collections of content (e.g., tags and category index pages). If the tag and category collections are not needed, set ``DIRECT_TEMPLATES = ['index', 'archives']`` .. data:: PAGINATED_DIRECT_TEMPLATES = ['index'] Provides the direct templates that should be paginated. .. data:: EXTRA_TEMPLATES_PATHS = [] A list of paths you want Jinja2 to search for templates. Can be used to separate templates from the theme. Example: projects, resume, profile ... These templates need to use ``DIRECT_TEMPLATES`` setting. Metadata ======== .. data:: AUTHOR Default author (usually your name). .. data:: DEFAULT_METADATA = {} The default metadata you want to use for all articles and pages. .. data:: FILENAME_METADATA = '(?P\d{4}-\d{2}-\d{2}).*' The regexp that will be used to extract any metadata from the filename. All named groups that are matched will be set in the metadata object. The default value will only extract the date from the filename. For example, to extract both the date and the slug:: FILENAME_METADATA = '(?P\d{4}-\d{2}-\d{2})_(?P.*)' See also ``SLUGIFY_SOURCE``. .. data:: PATH_METADATA = '' Like ``FILENAME_METADATA``, but parsed from a page's full path relative to the content source directory. .. data:: EXTRA_PATH_METADATA = {} Extra metadata dictionaries keyed by relative path. Relative paths require correct OS-specific directory separators (i.e. / in UNIX and \\ in Windows) unlike some other Pelican file settings. Not all metadata needs to be :ref:`embedded in source file itself `. For example, blog posts are often named following a ``YYYY-MM-DD-SLUG.rst`` pattern, or nested into ``YYYY/MM/DD-SLUG`` directories. To extract metadata from the filename or path, set ``FILENAME_METADATA`` or ``PATH_METADATA`` to regular expressions that use Python's `group name notation`_ ``(?P…)``. If you want to attach additional metadata but don't want to encode it in the path, you can set ``EXTRA_PATH_METADATA``: .. parsed-literal:: EXTRA_PATH_METADATA = { 'relative/path/to/file-1': { 'key-1a': 'value-1a', 'key-1b': 'value-1b', }, 'relative/path/to/file-2': { 'key-2': 'value-2', }, } This can be a convenient way to shift the installed location of a particular file: .. parsed-literal:: # Take advantage of the following defaults # STATIC_SAVE_AS = '{path}' # STATIC_URL = '{path}' STATIC_PATHS = [ 'static/robots.txt', ] EXTRA_PATH_METADATA = { 'static/robots.txt': {'path': 'robots.txt'}, } .. _group name notation: http://docs.python.org/3/library/re.html#regular-expression-syntax Feed settings ============= By default, Pelican uses Atom feeds. However, it is also possible to use RSS feeds if you prefer. Pelican generates category feeds as well as feeds for all your articles. It does not generate feeds for tags by default, but it is possible to do so using the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings: .. data:: FEED_DOMAIN = None, i.e. base URL is "/" The domain prepended to feed URLs. Since feed URLs should always be absolute, it is highly recommended to define this (e.g., "http://feeds.example.com"). If you have already explicitly defined SITEURL (see above) and want to use the same domain for your feeds, you can just set: ``FEED_DOMAIN = SITEURL``. .. data:: FEED_ATOM = None, i.e. no Atom feed Relative URL to output the Atom feed. .. data:: FEED_RSS = None, i.e. no RSS Relative URL to output the RSS feed. .. data:: FEED_ALL_ATOM = 'feeds/all.atom.xml' Relative URL to output the all-posts Atom feed: this feed will contain all posts regardless of their language. .. data:: FEED_ALL_RSS = None, i.e. no all-posts RSS Relative URL to output the all-posts RSS feed: this feed will contain all posts regardless of their language. .. data:: CATEGORY_FEED_ATOM = 'feeds/%s.atom.xml' Where to put the category Atom feeds. [2]_ .. data:: CATEGORY_FEED_RSS = None, i.e. no RSS Where to put the category RSS feeds. .. data:: AUTHOR_FEED_ATOM = 'feeds/%s.atom.xml' Where to put the author Atom feeds. [2]_ .. data:: AUTHOR_FEED_RSS = 'feeds/%s.rss.xml' Where to put the author RSS feeds. [2]_ .. data:: TAG_FEED_ATOM = None, i.e. no tag feed Relative URL to output the tag Atom feed. It should be defined using a "%s" match in the tag name. .. data:: TAG_FEED_RSS = None, i.e. no RSS tag feed Relative URL to output the tag RSS feed .. data:: FEED_MAX_ITEMS Maximum number of items allowed in a feed. Feed item quantity is unrestricted by default. .. data:: RSS_FEED_SUMMARY_ONLY = True Only include item summaries in the ``description`` tag of RSS feeds. If set to ``False``, the full content will be included instead. This setting doesn't affect Atom feeds, only RSS ones. If you don't want to generate some or any of these feeds, set the above variables to ``None``. .. [2] %s is the name of the category. FeedBurner ---------- If you want to use FeedBurner for your feed, you will likely need to decide upon a unique identifier. For example, if your site were called "Thyme" and hosted on the www.example.com domain, you might use "thymefeeds" as your unique identifier, which we'll use throughout this section for illustrative purposes. In your Pelican settings, set the ``FEED_ATOM`` attribute to ``thymefeeds/main.xml`` to create an Atom feed with an original address of ``http://www.example.com/thymefeeds/main.xml``. Set the ``FEED_DOMAIN`` attribute to ``http://feeds.feedburner.com``, or ``http://feeds.example.com`` if you are using a CNAME on your own domain (i.e., FeedBurner's "MyBrand" feature). There are two fields to configure in the `FeedBurner `_ interface: "Original Feed" and "Feed Address". In this example, the "Original Feed" would be ``http://www.example.com/thymefeeds/main.xml`` and the "Feed Address" suffix would be ``thymefeeds/main.xml``. Pagination ========== The default behaviour of Pelican is to list all the article titles along with a short description on the index page. While this works well for small-to-medium sites, sites with a large quantity of articles will probably benefit from paginating this list. You can use the following settings to configure the pagination. .. data:: DEFAULT_ORPHANS = 0 The minimum number of articles allowed on the last page. Use this when you don't want the last page to only contain a handful of articles. .. data:: DEFAULT_PAGINATION = False The maximum number of articles to include on a page, not including orphans. False to disable pagination. .. data:: PAGINATION_PATTERNS A set of patterns that are used to determine advanced pagination output. Using Pagination Patterns ------------------------- The ``PAGINATION_PATTERNS`` setting can be used to configure where subsequent pages are created. The setting is a sequence of three element tuples, where each tuple consists of:: (minimum page, URL setting, SAVE_AS setting,) For example, if you wanted the first page to just be ``/``, and the second (and subsequent) pages to be ``/page/2/``, you would set ``PAGINATION_PATTERNS`` as follows:: PAGINATION_PATTERNS = ( (1, '{base_name}/', '{base_name}/index.html'), (2, '{base_name}/page/{number}/', '{base_name}/page/{number}/index.html'), ) This would cause the first page to be written to ``{base_name}/index.html``, and subsequent ones would be written into ``page/{number}`` directories. Translations ============ Pelican offers a way to translate articles. See the :doc:`Content ` section for more information. .. data:: DEFAULT_LANG = 'en' The default language to use. .. data:: TRANSLATION_FEED_ATOM = 'feeds/all-%s.atom.xml' Where to put the Atom feed for translations. [3]_ .. data:: TRANSLATION_FEED_RSS = None, i.e. no RSS Where to put the RSS feed for translations. .. [3] %s is the language Ordering content ================ .. data:: NEWEST_FIRST_ARCHIVES = True Order archives by newest first by date. (False: orders by date with older articles first.) .. data:: REVERSE_CATEGORY_ORDER = False Reverse the category order. (True: lists by reverse alphabetical order; default lists alphabetically.) .. data:: ARTICLE_ORDER_BY = 'reversed-date' Defines how the articles (``articles_page.object_list`` in the template) are sorted. Valid options are: metadata as a string (use ``reversed-`` prefix the reverse the sort order), special option ``'basename'`` which will use the basename of the file (without path) or a custom function to extract the sorting key from articles. The default value, ``'reversed-date'``, will sort articles by date in reverse order (i.e. newest article comes first). .. data:: PAGE_ORDER_BY = 'basename' Defines how the pages (``PAGES`` variable in the template) are sorted. Options are same as ``ARTICLE_ORDER_BY``. The default value, ``'basename'`` will sort pages by their basename. Themes ====== Creating Pelican themes is addressed in a dedicated section (see :ref:`theming-pelican`). However, here are the settings that are related to themes. .. data:: THEME Theme to use to produce the output. Can be a relative or absolute path to a theme folder, or the name of a default theme or a theme installed via ``pelican-themes`` (see below). .. data:: THEME_STATIC_DIR = 'theme' Destination directory in the output path where Pelican will place the files collected from `THEME_STATIC_PATHS`. Default is `theme`. .. data:: THEME_STATIC_PATHS = ['static'] Static theme paths you want to copy. Default value is `static`, but if your theme has other static paths, you can put them here. If files or directories with the same names are included in the paths defined in this settings, they will be progressively overwritten. .. data:: CSS_FILE = 'main.css' Specify the CSS file you want to load. By default, two themes are available. You can specify them using the ``THEME`` setting or by passing the ``-t`` option to the ``pelican`` command: * notmyidea * simple (a synonym for "plain text" :) There are a number of other themes available at https://github.com/getpelican/pelican-themes. Pelican comes with :doc:`pelican-themes`, a small script for managing themes. You can define your own theme, either by starting from scratch or by duplicating and modifying a pre-existing theme. Here is :doc:`a guide on how to create your theme `. Following are example ways to specify your preferred theme:: # Specify name of a built-in theme THEME = "notmyidea" # Specify name of a theme installed via the pelican-themes tool THEME = "chunk" # Specify a customized theme, via path relative to the settings file THEME = "themes/mycustomtheme" # Specify a customized theme, via absolute path THEME = "/home/myuser/projects/mysite/themes/mycustomtheme" The built-in ``notmyidea`` theme can make good use of the following settings. Feel free to use them in your themes as well. .. data:: SITESUBTITLE A subtitle to appear in the header. .. data:: DISQUS_SITENAME Pelican can handle Disqus comments. Specify the Disqus sitename identifier here. .. data:: GITHUB_URL Your GitHub URL (if you have one). It will then use this information to create a GitHub ribbon. .. data:: GOOGLE_ANALYTICS Set to ``UA-XXXXX-Y`` Property's tracking ID to activate Google Analytics. .. data:: GA_COOKIE_DOMAIN Set cookie domain field of Google Analytics tracking code. Defaults to ``auto``. .. data:: GOSQUARED_SITENAME Set to 'XXX-YYYYYY-X' to activate GoSquared. .. data:: MENUITEMS A list of tuples (Title, URL) for additional menu items to appear at the beginning of the main menu. .. data:: PIWIK_URL URL to your Piwik server - without 'http://' at the beginning. .. data:: PIWIK_SSL_URL If the SSL-URL differs from the normal Piwik-URL you have to include this setting too. (optional) .. data:: PIWIK_SITE_ID ID for the monitored website. You can find the ID in the Piwik admin interface > Settings > Websites. .. data:: LINKS A list of tuples (Title, URL) for links to appear on the header. .. data:: SOCIAL A list of tuples (Title, URL) to appear in the "social" section. .. data:: TWITTER_USERNAME Allows for adding a button to articles to encourage others to tweet about them. Add your Twitter username if you want this button to appear. .. data:: LINKS_WIDGET_NAME Allows override of the name of the links widget. If not specified, defaults to "links". .. data:: SOCIAL_WIDGET_NAME Allows override of the name of the "social" widget. If not specified, defaults to "social". In addition, you can use the "wide" version of the ``notmyidea`` theme by adding the following to your configuration:: CSS_FILE = "wide.css" Logging ======= Sometimes, a long list of warnings may appear during site generation. Finding the **meaningful** error message in the middle of tons of annoying log output can be quite tricky. In order to filter out redundant log messages, Pelican comes with the ``LOG_FILTER`` setting. ``LOG_FILTER`` should be a list of tuples ``(level, msg)``, each of them being composed of the logging level (up to ``warning``) and the message to be ignored. Simply populate the list with the log messages you want to hide, and they will be filtered out. For example:: [(logging.WARN, 'TAG_SAVE_AS is set to False')] It is possible to filter out messages by a template. Check out source code to obtain a template. For example:: [(logging.WARN, 'Empty alt attribute for image %s in %s')] .. Warning:: Silencing messages by templates is a dangerous feature. It is possible to unintentionally filter out multiple message types with the same template (including messages from future Pelican versions). Proceed with caution. .. note:: This option does nothing if ``--debug`` is passed. .. _reading_only_modified_content: Reading only modified content ============================= To speed up the build process, Pelican can optionally read only articles and pages with modified content. When Pelican is about to read some content source file: 1. The hash or modification time information for the file from a previous build are loaded from a cache file if ``LOAD_CONTENT_CACHE`` is ``True``. These files are stored in the ``CACHE_PATH`` directory. If the file has no record in the cache file, it is read as usual. 2. The file is checked according to ``CHECK_MODIFIED_METHOD``: - If set to ``'mtime'``, the modification time of the file is checked. - If set to a name of a function provided by the ``hashlib`` module, e.g. ``'md5'``, the file hash is checked. - If set to anything else or the necessary information about the file cannot be found in the cache file, the content is read as usual. 3. If the file is considered unchanged, the content data saved in a previous build corresponding to the file is loaded from the cache, and the file is not read. 4. If the file is considered changed, the file is read and the new modification information and the content data are saved to the cache if ``CACHE_CONTENT`` is ``True``. If ``CONTENT_CACHING_LAYER`` is set to ``'reader'`` (the default), the raw content and metadata returned by a reader are cached. If this setting is instead set to ``'generator'``, the processed content object is cached. Caching the processed content object may conflict with plugins (as some reading related signals may be skipped) and the ``WITH_FUTURE_DATES`` functionality (as the ``draft`` status of the cached content objects would not change automatically over time). Checking modification times is faster than comparing file hashes, but it is not as reliable because ``mtime`` information can be lost, e.g., when copying content source files using the ``cp`` or ``rsync`` commands without the ``mtime`` preservation mode (which for ``rsync`` can be invoked by passing the ``--archive`` flag). The cache files are Python pickles, so they may not be readable by different versions of Python as the pickle format often changes. If such an error is encountered, it is caught and the cache file is rebuilt automatically in the new format. The cache files will also be rebuilt after the ``GZIP_CACHE`` setting has been changed. The ``--ignore-cache`` command-line option is useful when the whole cache needs to be regenerated, such as when making modifications to the settings file that will affect the cached content, or just for debugging purposes. When Pelican runs in autoreload mode, modification of the settings file will make it ignore the cache automatically if ``AUTORELOAD_IGNORE_CACHE`` is ``True``. Note that even when using cached content, all output is always written, so the modification times of the generated ``*.html`` files will always change. Therefore, ``rsync``-based uploading may benefit from the ``--checksum`` option. .. _writing_only_selected_content: Writing only selected content ============================= When only working on a single article or page, or making tweaks to your theme, it is often desirable to generate and review your work as quickly as possible. In such cases, generating and writing the entire site output is often unnecessary. By specifying only the desired files as output paths in the ``WRITE_SELECTED`` list, **only** those files will be written. This list can be also specified on the command line using the ``--write-selected`` option, which accepts a comma-separated list of output file paths. By default this list is empty, so all output is written. See :ref:`site_generation` for more details. Example settings ================ .. literalinclude:: ../samples/pelican.conf.py :language: python .. _Jinja custom filters documentation: http://jinja.pocoo.org/docs/api/#custom-filters .. _Jinja Environment documentation: http://jinja.pocoo.org/docs/dev/api/#jinja2.Environment .. _Docutils Configuration: http://docutils.sourceforge.net/docs/user/config.html pelican-3.7.1/docs/themes.rst000066400000000000000000000544561303525152100161170ustar00rootroot00000000000000.. _theming-pelican: Creating themes ############### To generate its HTML output, Pelican uses the `Jinja `_ templating engine due to its flexibility and straightforward syntax. If you want to create your own theme, feel free to take inspiration from the `"simple" theme `_. To generate your site using a theme you have created (or downloaded manually and then modified), you can specify that theme via the ``-t`` flag:: pelican content -s pelicanconf.py -t /projects/your-site/themes/your-theme If you'd rather not specify the theme on every invocation, you can define ``THEME`` in your settings to point to the location of your preferred theme. Structure ========= To make your own theme, you must follow the following structure:: ├── static │   ├── css │   └── images └── templates ├── archives.html // to display archives ├── period_archives.html // to display time-period archives ├── article.html // processed for each article ├── author.html // processed for each author ├── authors.html // must list all the authors ├── categories.html // must list all the categories ├── category.html // processed for each category ├── index.html // the index (list all the articles) ├── page.html // processed for each page ├── tag.html // processed for each tag └── tags.html // must list all the tags. Can be a tag cloud. * `static` contains all the static assets, which will be copied to the output `theme` folder. The above filesystem layout includes CSS and image folders, but those are just examples. Put what you need here. * `templates` contains all the templates that will be used to generate the content. The template files listed above are mandatory; you can add your own templates if it helps you keep things organized while creating your theme. .. _templates-variables: Templates and variables ======================= The idea is to use a simple syntax that you can embed into your HTML pages. This document describes which templates should exist in a theme, and which variables will be passed to each template at generation time. All templates will receive the variables defined in your settings file, as long as they are in all-caps. You can access them directly. Common variables ---------------- All of these settings will be available to all templates. ============= =================================================== Variable Description ============= =================================================== output_file The name of the file currently being generated. For instance, when Pelican is rendering the home page, output_file will be "index.html". articles The list of articles, ordered descending by date. All the elements are `Article` objects, so you can access their attributes (e.g. title, summary, author etc.). Sometimes this is shadowed (for instance in the tags page). You will then find info about it in the `all_articles` variable. dates The same list of articles, but ordered by date, ascending. drafts The list of draft articles tags A list of (tag, articles) tuples, containing all the tags. categories A list of (category, articles) tuples, containing all the categories and corresponding articles (values) pages The list of pages hidden_pages The list of hidden pages ============= =================================================== Sorting ------- URL wrappers (currently categories, tags, and authors), have comparison methods that allow them to be easily sorted by name:: {% for tag, articles in tags|sort %} If you want to sort based on different criteria, `Jinja's sort command`__ has a number of options. __ http://jinja.pocoo.org/docs/templates/#sort Date Formatting --------------- Pelican formats the date according to your settings and locale (``DATE_FORMATS``/``DEFAULT_DATE_FORMAT``) and provides a ``locale_date`` attribute. On the other hand, the ``date`` attribute will be a `datetime`_ object. If you need custom formatting for a date different than your settings, use the Jinja filter ``strftime`` that comes with Pelican. Usage is same as Python `strftime`_ format, but the filter will do the right thing and format your date according to the locale given in your settings:: {{ article.date|strftime('%d %B %Y') }} .. _datetime: http://docs.python.org/2/library/datetime.html#datetime-objects .. _strftime: http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior index.html ---------- This is the home page or index of your blog, generated at ``index.html``. If pagination is active, subsequent pages will reside in ``index{number}.html``. ====================== =================================================== Variable Description ====================== =================================================== articles_paginator A paginator object for the list of articles articles_page The current page of articles articles_previous_page The previous page of articles (``None`` if page does not exist) articles_next_page The next page of articles (``None`` if page does not exist) dates_paginator A paginator object for the article list, ordered by date, ascending. dates_page The current page of articles, ordered by date, ascending. dates_previous_page The previous page of articles, ordered by date, ascending (``None`` if page does not exist) dates_next_page The next page of articles, ordered by date, ascending (``None`` if page does not exist) page_name 'index' -- useful for pagination links ====================== =================================================== author.html ------------- This template will be processed for each of the existing authors, with output generated according to the ``AUTHOR_SAVE_AS`` setting (`Default:` ``author/{author_name}.html``). If pagination is active, subsequent pages will by default reside at ``author/{author_name}{number}.html``. ====================== =================================================== Variable Description ====================== =================================================== author The name of the author being processed articles Articles by this author dates Articles by this author, but ordered by date, ascending articles_paginator A paginator object for the list of articles articles_page The current page of articles articles_previous_page The previous page of articles (``None`` if page does not exist) articles_next_page The next page of articles (``None`` if page does not exist) dates_paginator A paginator object for the article list, ordered by date, ascending. dates_page The current page of articles, ordered by date, ascending. dates_previous_page The previous page of articles, ordered by date, ascending (``None`` if page does not exist) dates_next_page The next page of articles, ordered by date, ascending (``None`` if page does not exist) page_name AUTHOR_URL where everything after `{slug}` is removed -- useful for pagination links ====================== =================================================== category.html ------------- This template will be processed for each of the existing categories, with output generated according to the ``CATEGORY_SAVE_AS`` setting (`Default:` ``category/{category_name}.html``). If pagination is active, subsequent pages will by default reside at ``category/{category_name}{number}.html``. ====================== =================================================== Variable Description ====================== =================================================== category The name of the category being processed articles Articles for this category dates Articles for this category, but ordered by date, ascending articles_paginator A paginator object for the list of articles articles_page The current page of articles articles_previous_page The previous page of articles (``None`` if page does not exist) articles_next_page The next page of articles (``None`` if page does not exist) dates_paginator A paginator object for the list of articles, ordered by date, ascending dates_page The current page of articles, ordered by date, ascending dates_previous_page The previous page of articles, ordered by date, ascending (``None`` if page does not exist) dates_next_page The next page of articles, ordered by date, ascending (``None`` if page does not exist) page_name CATEGORY_URL where everything after `{slug}` is removed -- useful for pagination links ====================== =================================================== article.html ------------- This template will be processed for each article, with output generated according to the ``ARTICLE_SAVE_AS`` setting (`Default:` ``{article_name}.html``). The following variables are available when rendering. ============= =================================================== Variable Description ============= =================================================== article The article object to be displayed category The name of the category for the current article ============= =================================================== Any metadata that you put in the header of the article source file will be available as fields on the ``article`` object. The field name will be the same as the name of the metadata field, except in all-lowercase characters. For example, you could add a field called `FacebookImage` to your article metadata, as shown below: .. code-block:: markdown Title: I love Python more than music Date: 2013-11-06 10:06 Tags: personal, python Category: Tech Slug: python-je-l-aime-a-mourir Author: Francis Cabrel FacebookImage: http://franciscabrel.com/images/pythonlove.png This new metadata will be made available as `article.facebookimage` in your `article.html` template. This would allow you, for example, to specify an image for the Facebook open graph tags that will change for each article: .. code-block:: html+jinja page.html --------- This template will be processed for each page, with output generated according to the ``PAGE_SAVE_AS`` setting (`Default:` ``pages/{page_name}.html``). The following variables are available when rendering. ============= =================================================== Variable Description ============= =================================================== page The page object to be displayed. You can access its title, slug, and content. ============= =================================================== tag.html -------- This template will be processed for each tag, with output generated according to the ``TAG_SAVE_AS`` setting (`Default:` ``tag/{tag_name}.html``). If pagination is active, subsequent pages will by default reside at ``tag/{tag_name}{number}.html``. ====================== =================================================== Variable Description ====================== =================================================== tag The name of the tag being processed articles Articles related to this tag dates Articles related to this tag, but ordered by date, ascending articles_paginator A paginator object for the list of articles articles_page The current page of articles articles_previous_page The previous page of articles (``None`` if page does not exist) articles_next_page The next page of articles (``None`` if page does not exist) dates_paginator A paginator object for the list of articles, ordered by date, ascending dates_page The current page of articles, ordered by date, ascending dates_previous_page The previous page of articles, ordered by date, ascending (``None`` if page does not exist) dates_next_page The next page of articles, ordered by date, ascending (``None`` if page does not exist) page_name TAG_URL where everything after `{slug}` is removed -- useful for pagination links ====================== =================================================== period_archives.html -------------------- This template will be processed for each year of your posts if a path for ``YEAR_ARCHIVE_SAVE_AS`` is defined, each month if ``MONTH_ARCHIVE_SAVE_AS`` is defined, and each day if ``DAY_ARCHIVE_SAVE_AS`` is defined. =================== =================================================== Variable Description =================== =================================================== period A tuple of the form (`year`, `month`, `day`) that indicates the current time period. `year` and `day` are numbers while `month` is a string. This tuple only contains `year` if the time period is a given year. It contains both `year` and `month` if the time period is over years and months and so on. =================== =================================================== You can see an example of how to use `period` in the `"simple" theme period_archives.html template `_. Objects ======= Detail objects attributes that are available and useful in templates. Not all attributes are listed here, this is a selection of attributes considered useful in a template. .. _object-article: Article ------- The string representation of an Article is the `source_path` attribute. =================== =================================================== Attribute Description =================== =================================================== author The :ref:`Author ` of this article. authors A list of :ref:`Authors ` of this article. category The :ref:`Category ` of this article. content The rendered content of the article. date Datetime object representing the article date. date_format Either default date format or locale date format. default_template Default template name. in_default_lang Boolean representing if the article is written in the default language. lang Language of the article. locale_date Date formatted by the `date_format`. metadata Article header metadata `dict`. save_as Location to save the article page. slug Page slug. source_path Full system path of the article source file. status The article status, can be any of 'published' or 'draft'. summary Rendered summary content. tags List of :ref:`Tag ` objects. template Template name to use for rendering. title Title of the article. translations List of translations :ref:`Article ` objects. url URL to the article page. =================== =================================================== .. _object-author_cat_tag: Author / Category / Tag ----------------------- The string representation of those objects is the `name` attribute. =================== =================================================== Attribute Description =================== =================================================== name Name of this object [1]_. page_name Author page name. save_as Location to save the author page. slug Page slug. url URL to the author page. =================== =================================================== .. [1] for Author object, coming from `:authors:` or `AUTHOR`. .. _object-page: Page ---- The string representation of a Page is the `source_path` attribute. =================== =================================================== Attribute Description =================== =================================================== author The :ref:`Author ` of this page. content The rendered content of the page. date Datetime object representing the page date. date_format Either default date format or locale date format. default_template Default template name. in_default_lang Boolean representing if the article is written in the default language. lang Language of the article. locale_date Date formatted by the `date_format`. metadata Page header metadata `dict`. save_as Location to save the page. slug Page slug. source_path Full system path of the page source file. status The page status, can be any of 'published' or 'draft'. summary Rendered summary content. tags List of :ref:`Tag ` objects. template Template name to use for rendering. title Title of the page. translations List of translations :ref:`Article ` objects. url URL to the page. =================== =================================================== Feeds ===== The feed variables changed in 3.0. Each variable now explicitly lists ATOM or RSS in the name. ATOM is still the default. Old themes will need to be updated. Here is a complete list of the feed variables:: FEED_ATOM FEED_RSS FEED_ALL_ATOM FEED_ALL_RSS CATEGORY_FEED_ATOM CATEGORY_FEED_RSS AUTHOR_FEED_ATOM AUTHOR_FEED_RSS TAG_FEED_ATOM TAG_FEED_RSS TRANSLATION_FEED_ATOM TRANSLATION_FEED_RSS Inheritance =========== Since version 3.0, Pelican supports inheritance from the ``simple`` theme, so you can re-use the ``simple`` theme templates in your own themes. If one of the mandatory files in the ``templates/`` directory of your theme is missing, it will be replaced by the matching template from the ``simple`` theme. So if the HTML structure of a template in the ``simple`` theme is right for you, you don't have to write a new template from scratch. You can also extend templates from the ``simple`` theme in your own themes by using the ``{% extends %}`` directive as in the following example: .. code-block:: html+jinja {% extends "!simple/index.html" %} {% extends "index.html" %} Example ------- With this system, it is possible to create a theme with just two files. base.html """"""""" The first file is the ``templates/base.html`` template: .. code-block:: html+jinja {% extends "!simple/base.html" %} {% block head %} {{ super() }} {% endblock %} 1. On the first line, we extend the ``base.html`` template from the ``simple`` theme, so we don't have to rewrite the entire file. 2. On the third line, we open the ``head`` block which has already been defined in the ``simple`` theme. 3. On the fourth line, the function ``super()`` keeps the content previously inserted in the ``head`` block. 4. On the fifth line, we append a stylesheet to the page. 5. On the last line, we close the ``head`` block. This file will be extended by all the other templates, so the stylesheet will be linked from all pages. style.css """"""""" The second file is the ``static/css/style.css`` CSS stylesheet: .. code-block:: css body { font-family : monospace ; font-size : 100% ; background-color : white ; color : #111 ; width : 80% ; min-width : 400px ; min-height : 200px ; padding : 1em ; margin : 5% 10% ; border : thin solid gray ; border-radius : 5px ; display : block ; } a:link { color : blue ; text-decoration : none ; } a:hover { color : blue ; text-decoration : underline ; } a:visited { color : blue ; } h1 a { color : inherit !important } h2 a { color : inherit !important } h3 a { color : inherit !important } h4 a { color : inherit !important } h5 a { color : inherit !important } h6 a { color : inherit !important } pre { margin : 2em 1em 2em 4em ; } #menu li { display : inline ; } #post-list { margin-bottom : 1em ; margin-top : 1em ; } Download """""""" You can download this example theme :download:`here <_static/theme-basic.zip>`. pelican-3.7.1/docs/tips.rst000066400000000000000000000125311303525152100155750ustar00rootroot00000000000000Tips #### Here are some tips about Pelican that you might find useful. Custom 404 Pages ================ When a browser requests a resource that the web server cannot find, the web server usually displays a generic "File not found" (404) error page that can be stark and unsightly. One way to provide an error page that matches the theme of your site is to create a custom 404 page (*not* an article), such as this Markdown-formatted example stored in ``content/pages/404.md``:: Title: Not Found Status: hidden Save_as: 404.html The requested item could not be located. Perhaps you might want to check the [Archives](/archives.html)? The next step is to configure your web server to display this custom page instead of its default 404 page. For Nginx, add the following to your configuration file's ``location`` block:: error_page 404 /404.html; For Apache:: ErrorDocument 404 /404.html For Amazon S3, first navigate to the ``Static Site Hosting`` menu in the bucket settings on your AWS cosole. From there:: Error Document: 404.html Publishing to GitHub ==================== `GitHub Pages `_ offer an easy and convenient way to publish Pelican sites. There are `two types of GitHub Pages `_: *Project Pages* and *User Pages*. Pelican sites can be published as both Project Pages and User Pages. Project Pages ------------- To publish a Pelican site as a Project Page you need to *push* the content of the ``output`` dir generated by Pelican to a repository's ``gh-pages`` branch on GitHub. The excellent `ghp-import `_, which can be installed with ``pip``, makes this process really easy. For example, if the source of your Pelican site is contained in a GitHub repository, and if you want to publish that Pelican site in the form of Project Pages to this repository, you can then use the following:: $ pelican content -o output -s pelicanconf.py $ ghp-import output $ git push origin gh-pages The ``ghp-import output`` command updates the local ``gh-pages`` branch with the content of the ``output`` directory (creating the branch if it doesn't already exist). The ``git push origin gh-pages`` command updates the remote ``gh-pages`` branch, effectively publishing the Pelican site. .. note:: The ``github`` target of the Makefile (and the ``gh_pages`` task of the Fabfile) created by the ``pelican-quickstart`` command publishes the Pelican site as Project Pages, as described above. .. note:: ghp-import on Windows Until `ghp-import Pull Request #25 `_ is accepted, you will need to install a custom build of ghp-import: ``pip install https://github.com/chevah/ghp-import/archive/win-support.zip`` User Pages ---------- To publish a Pelican site in the form of User Pages, you need to *push* the content of the ``output`` dir generated by Pelican to the ``master`` branch of your ``.github.io`` repository on GitHub. Again, you can take advantage of ``ghp-import``:: $ pelican content -o output -s pelicanconf.py $ ghp-import output $ git push git@github.com:elemoine/elemoine.github.io.git gh-pages:master The ``git push`` command pushes the local ``gh-pages`` branch (freshly updated by the ``ghp-import`` command) to the ``elemoine.github.io`` repository's ``master`` branch on GitHub. .. note:: To publish your Pelican site as User Pages, feel free to adjust the ``github`` target of the Makefile. Custom 404 Pages ---------------- GitHub Pages will display the custom 404 page described above, as noted in the relevant `GitHub docs `_. Extra Tips ---------- Tip #1: To automatically update your Pelican site on each commit, you can create a post-commit hook. For example, you can add the following to ``.git/hooks/post-commit``:: pelican content -o output -s pelicanconf.py && ghp-import output && git push origin gh-pages Tip #2: To use a `custom domain `_ with GitHub Pages, you need to put the domain of your site (e.g., ``blog.example.com``) inside a ``CNAME`` file at the root of your site. To do this, create the ``content/extra/`` directory and add a ``CNAME`` file to it. Then use the ``STATIC_PATHS`` setting to tell Pelican to copy this file to your output directory. For example:: STATIC_PATHS = ['images', 'extra/CNAME'] EXTRA_PATH_METADATA = {'extra/CNAME': {'path': 'CNAME'},} Note: use forward slashes, ``/``, even on Windows. .. hint:: You can also use the ``EXTRA_PATH_METADATA`` mechanism to place a ``favicon.ico`` or ``robots.txt`` at the root of any site. How to add YouTube or Vimeo Videos ================================== The easiest way is to paste the embed code of the video from these sites directly into your source content. Alternatively, you can also use Pelican plugins like ``liquid_tags``, ``pelican_youtube``, or ``pelican_vimeo`` to embed videos in your content. Moreover, markup languages like reST and Markdown have plugins that let you embed videos in the markup. You can use `reST video directive `_ for reST or `mdx_video plugin `_ for Markdown. pelican-3.7.1/pelican/000077500000000000000000000000001303525152100145455ustar00rootroot00000000000000pelican-3.7.1/pelican/__init__.py000066400000000000000000000466231303525152100166710ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import argparse import collections import locale import logging import os import re import sys import time import six # pelican.log has to be the first pelican module to be loaded # because logging.setLoggerClass has to be called before logging.getLogger from pelican.log import init # noqa from pelican import signals from pelican.generators import (ArticlesGenerator, PagesGenerator, SourceFileGenerator, StaticGenerator, TemplatePagesGenerator) from pelican.readers import Readers from pelican.settings import read_settings from pelican.utils import (clean_output_dir, file_watcher, folder_watcher, maybe_pluralize) from pelican.writers import Writer __version__ = "3.7.1" DEFAULT_CONFIG_NAME = 'pelicanconf.py' logger = logging.getLogger(__name__) class Pelican(object): def __init__(self, settings): """Pelican initialisation Performs some checks on the environment before doing anything else. """ # define the default settings self.settings = settings self._handle_deprecation() self.path = settings['PATH'] self.theme = settings['THEME'] self.output_path = settings['OUTPUT_PATH'] self.ignore_files = settings['IGNORE_FILES'] self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY'] self.output_retention = settings['OUTPUT_RETENTION'] self.init_path() self.init_plugins() signals.initialized.send(self) def init_path(self): if not any(p in sys.path for p in ['', os.curdir]): logger.debug("Adding current directory to system path") sys.path.insert(0, '') def init_plugins(self): self.plugins = [] logger.debug('Temporarily adding PLUGIN_PATHS to system path') _sys_path = sys.path[:] for pluginpath in self.settings['PLUGIN_PATHS']: sys.path.insert(0, pluginpath) for plugin in self.settings['PLUGINS']: # if it's a string, then import it if isinstance(plugin, six.string_types): logger.debug("Loading plugin `%s`", plugin) try: plugin = __import__(plugin, globals(), locals(), str('module')) except ImportError as e: logger.error( "Cannot load plugin `%s`\n%s", plugin, e) continue logger.debug("Registering plugin `%s`", plugin.__name__) plugin.register() self.plugins.append(plugin) logger.debug('Restoring system path') sys.path = _sys_path def _handle_deprecation(self): if self.settings.get('CLEAN_URLS', False): logger.warning('Found deprecated `CLEAN_URLS` in settings.' ' Modifying the following settings for the' ' same behaviour.') self.settings['ARTICLE_URL'] = '{slug}/' self.settings['ARTICLE_LANG_URL'] = '{slug}-{lang}/' self.settings['PAGE_URL'] = 'pages/{slug}/' self.settings['PAGE_LANG_URL'] = 'pages/{slug}-{lang}/' for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL', 'PAGE_LANG_URL'): logger.warning("%s = '%s'", setting, self.settings[setting]) if self.settings.get('AUTORELOAD_IGNORE_CACHE'): logger.warning('Found deprecated `AUTORELOAD_IGNORE_CACHE` in ' 'settings. Use --ignore-cache instead.') self.settings.pop('AUTORELOAD_IGNORE_CACHE') if self.settings.get('ARTICLE_PERMALINK_STRUCTURE', False): logger.warning('Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in' ' settings. Modifying the following settings for' ' the same behaviour.') structure = self.settings['ARTICLE_PERMALINK_STRUCTURE'] # Convert %(variable) into {variable}. structure = re.sub('%\((\w+)\)s', '{\g<1>}', structure) # Convert %x into {date:%x} for strftime structure = re.sub('(%[A-z])', '{date:\g<1>}', structure) # Strip a / prefix structure = re.sub('^/', '', structure) for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL', 'PAGE_LANG_URL', 'DRAFT_URL', 'DRAFT_LANG_URL', 'ARTICLE_SAVE_AS', 'ARTICLE_LANG_SAVE_AS', 'DRAFT_SAVE_AS', 'DRAFT_LANG_SAVE_AS', 'PAGE_SAVE_AS', 'PAGE_LANG_SAVE_AS'): self.settings[setting] = os.path.join(structure, self.settings[setting]) logger.warning("%s = '%s'", setting, self.settings[setting]) for new, old in [('FEED', 'FEED_ATOM'), ('TAG_FEED', 'TAG_FEED_ATOM'), ('CATEGORY_FEED', 'CATEGORY_FEED_ATOM'), ('TRANSLATION_FEED', 'TRANSLATION_FEED_ATOM')]: if self.settings.get(new, False): logger.warning( 'Found deprecated `%(new)s` in settings. Modify %(new)s ' 'to %(old)s in your settings and theme for the same ' 'behavior. Temporarily setting %(old)s for backwards ' 'compatibility.', {'new': new, 'old': old} ) self.settings[old] = self.settings[new] def run(self): """Run the generators and return""" start_time = time.time() context = self.settings.copy() # Share these among all the generators and content objects: context['filenames'] = {} # maps source path to Content object or None context['localsiteurl'] = self.settings['SITEURL'] generators = [ cls( context=context, settings=self.settings, path=self.path, theme=self.theme, output_path=self.output_path, ) for cls in self.get_generator_classes() ] # erase the directory if it is not the source and if that's # explicitly asked if (self.delete_outputdir and not os.path.realpath(self.path).startswith(self.output_path)): clean_output_dir(self.output_path, self.output_retention) for p in generators: if hasattr(p, 'generate_context'): p.generate_context() signals.all_generators_finalized.send(generators) writer = self.get_writer() for p in generators: if hasattr(p, 'generate_output'): p.generate_output(writer) signals.finalized.send(self) articles_generator = next(g for g in generators if isinstance(g, ArticlesGenerator)) pages_generator = next(g for g in generators if isinstance(g, PagesGenerator)) pluralized_articles = maybe_pluralize( (len(articles_generator.articles) + len(articles_generator.translations)), 'article', 'articles') pluralized_drafts = maybe_pluralize( (len(articles_generator.drafts) + len(articles_generator.drafts_translations)), 'draft', 'drafts') pluralized_pages = maybe_pluralize( (len(pages_generator.pages) + len(pages_generator.translations)), 'page', 'pages') pluralized_hidden_pages = maybe_pluralize( (len(pages_generator.hidden_pages) + len(pages_generator.hidden_translations)), 'hidden page', 'hidden pages') print('Done: Processed {}, {}, {} and {} in {:.2f} seconds.'.format( pluralized_articles, pluralized_drafts, pluralized_pages, pluralized_hidden_pages, time.time() - start_time)) def get_generator_classes(self): generators = [ArticlesGenerator, PagesGenerator] if self.settings['TEMPLATE_PAGES']: generators.append(TemplatePagesGenerator) if self.settings['OUTPUT_SOURCES']: generators.append(SourceFileGenerator) for pair in signals.get_generators.send(self): (funct, value) = pair if not isinstance(value, collections.Iterable): value = (value, ) for v in value: if isinstance(v, type): logger.debug('Found generator: %s', v) generators.append(v) # StaticGenerator must run last, so it can identify files that # were skipped by the other generators, and so static files can # have their output paths overridden by the {attach} link syntax. generators.append(StaticGenerator) return generators def get_writer(self): writers = [w for (_, w) in signals.get_writer.send(self) if isinstance(w, type)] writers_found = len(writers) if writers_found == 0: return Writer(self.output_path, settings=self.settings) else: writer = writers[0] if writers_found == 1: logger.debug('Found writer: %s', writer) else: logger.warning( '%s writers found, using only first one: %s', writers_found, writer) return writer(self.output_path, settings=self.settings) def parse_arguments(): parser = argparse.ArgumentParser( description='A tool to generate a static blog, ' ' with restructured text input files.', formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument(dest='path', nargs='?', help='Path where to find the content files.', default=None) parser.add_argument('-t', '--theme-path', dest='theme', help='Path where to find the theme templates. If not ' 'specified, it will use the default one included with ' 'pelican.') parser.add_argument('-o', '--output', dest='output', help='Where to output the generated files. If not ' 'specified, a directory will be created, named ' '"output" in the current path.') parser.add_argument('-s', '--settings', dest='settings', help='The settings of the application, this is ' 'automatically set to {0} if a file exists with this ' 'name.'.format(DEFAULT_CONFIG_NAME)) parser.add_argument('-d', '--delete-output-directory', dest='delete_outputdir', action='store_true', default=None, help='Delete the output directory.') parser.add_argument('-v', '--verbose', action='store_const', const=logging.INFO, dest='verbosity', help='Show all messages.') parser.add_argument('-q', '--quiet', action='store_const', const=logging.CRITICAL, dest='verbosity', help='Show only critical errors.') parser.add_argument('-D', '--debug', action='store_const', const=logging.DEBUG, dest='verbosity', help='Show all messages, including debug messages.') parser.add_argument('--version', action='version', version=__version__, help='Print the pelican version and exit.') parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true', help='Relaunch pelican each time a modification occurs' ' on the content files.') parser.add_argument('--relative-urls', dest='relative_paths', action='store_true', help='Use relative urls in output, ' 'useful for site development') parser.add_argument('--cache-path', dest='cache_path', help=('Directory in which to store cache files. ' 'If not specified, defaults to "cache".')) parser.add_argument('--ignore-cache', action='store_true', dest='ignore_cache', help='Ignore content cache ' 'from previous runs by not loading cache files.') parser.add_argument('-w', '--write-selected', type=str, dest='selected_paths', default=None, help='Comma separated list of selected paths to write') parser.add_argument('--fatal', metavar='errors|warnings', choices=('errors', 'warnings'), default='', help=('Exit the program with non-zero status if any ' 'errors/warnings encountered.')) return parser.parse_args() def get_config(args): config = {} if args.path: config['PATH'] = os.path.abspath(os.path.expanduser(args.path)) if args.output: config['OUTPUT_PATH'] = \ os.path.abspath(os.path.expanduser(args.output)) if args.theme: abstheme = os.path.abspath(os.path.expanduser(args.theme)) config['THEME'] = abstheme if os.path.exists(abstheme) else args.theme if args.delete_outputdir is not None: config['DELETE_OUTPUT_DIRECTORY'] = args.delete_outputdir if args.ignore_cache: config['LOAD_CONTENT_CACHE'] = False if args.cache_path: config['CACHE_PATH'] = args.cache_path if args.selected_paths: config['WRITE_SELECTED'] = args.selected_paths.split(',') if args.relative_paths: config['RELATIVE_URLS'] = args.relative_paths config['DEBUG'] = args.verbosity == logging.DEBUG # argparse returns bytes in Py2. There is no definite answer as to which # encoding argparse (or sys.argv) uses. # "Best" option seems to be locale.getpreferredencoding() # http://mail.python.org/pipermail/python-list/2006-October/405766.html if not six.PY3: enc = locale.getpreferredencoding() for key in config: if key in ('PATH', 'OUTPUT_PATH', 'THEME'): config[key] = config[key].decode(enc) return config def get_instance(args): config_file = args.settings if config_file is None and os.path.isfile(DEFAULT_CONFIG_NAME): config_file = DEFAULT_CONFIG_NAME args.settings = DEFAULT_CONFIG_NAME settings = read_settings(config_file, override=get_config(args)) cls = settings['PELICAN_CLASS'] if isinstance(cls, six.string_types): module, cls_name = cls.rsplit('.', 1) module = __import__(module) cls = getattr(module, cls_name) return cls(settings), settings def main(): args = parse_arguments() init(args.verbosity, args.fatal) logger.debug('Pelican version: %s', __version__) logger.debug('Python version: %s', sys.version.split()[0]) try: pelican, settings = get_instance(args) readers = Readers(settings) watchers = {'content': folder_watcher(pelican.path, readers.extensions, pelican.ignore_files), 'theme': folder_watcher(pelican.theme, [''], pelican.ignore_files), 'settings': file_watcher(args.settings)} old_static = settings.get("STATIC_PATHS", []) for static_path in old_static: # use a prefix to avoid possible overriding of standard watchers # above watchers['[static]%s' % static_path] = folder_watcher( os.path.join(pelican.path, static_path), [''], pelican.ignore_files) if args.autoreload: print(' --- AutoReload Mode: Monitoring `content`, `theme` and' ' `settings` for changes. ---') while True: try: # Check source dir for changed files ending with the given # extension in the settings. In the theme dir is no such # restriction; all files are recursively checked if they # have changed, no matter what extension the filenames # have. modified = {k: next(v) for k, v in watchers.items()} if modified['settings']: pelican, settings = get_instance(args) # Adjust static watchers if there are any changes new_static = settings.get("STATIC_PATHS", []) # Added static paths # Add new watchers and set them as modified new_watchers = set(new_static).difference(old_static) for static_path in new_watchers: static_key = '[static]%s' % static_path watchers[static_key] = folder_watcher( os.path.join(pelican.path, static_path), [''], pelican.ignore_files) modified[static_key] = next(watchers[static_key]) # Removed static paths # Remove watchers and modified values old_watchers = set(old_static).difference(new_static) for static_path in old_watchers: static_key = '[static]%s' % static_path watchers.pop(static_key) modified.pop(static_key) # Replace old_static with the new one old_static = new_static if any(modified.values()): print('\n-> Modified: {}. re-generating...'.format( ', '.join(k for k, v in modified.items() if v))) if modified['content'] is None: logger.warning('No valid files found in content.') if modified['theme'] is None: logger.warning('Empty theme folder. Using `basic` ' 'theme.') pelican.run() except KeyboardInterrupt: logger.warning("Keyboard interrupt, quitting.") break except Exception as e: if (args.verbosity == logging.DEBUG): raise logger.warning( 'Caught exception "%s". Reloading.', e) finally: time.sleep(.5) # sleep to avoid cpu load else: if next(watchers['content']) is None: logger.warning('No valid files found in content.') if next(watchers['theme']) is None: logger.warning('Empty theme folder. Using `basic` theme.') pelican.run() except Exception as e: logger.critical('%s', e) if args.verbosity == logging.DEBUG: raise else: sys.exit(getattr(e, 'exitcode', 1)) pelican-3.7.1/pelican/cache.py000066400000000000000000000121771303525152100161720ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import hashlib import logging import os from six.moves import cPickle as pickle from pelican.utils import mkdir_p logger = logging.getLogger(__name__) class FileDataCacher(object): """Class that can cache data contained in files""" def __init__(self, settings, cache_name, caching_policy, load_policy): """Load the specified cache within CACHE_PATH in settings only if *load_policy* is True, May use gzip if GZIP_CACHE ins settings is True. Sets caching policy according to *caching_policy*. """ self.settings = settings self._cache_path = os.path.join(self.settings['CACHE_PATH'], cache_name) self._cache_data_policy = caching_policy if self.settings['GZIP_CACHE']: import gzip self._cache_open = gzip.open else: self._cache_open = open if load_policy: try: with self._cache_open(self._cache_path, 'rb') as fhandle: self._cache = pickle.load(fhandle) except (IOError, OSError) as err: logger.debug('Cannot load cache %s (this is normal on first ' 'run). Proceeding with empty cache.\n%s', self._cache_path, err) self._cache = {} except pickle.PickleError as err: logger.warning('Cannot unpickle cache %s, cache may be using ' 'an incompatible protocol (see pelican ' 'caching docs). ' 'Proceeding with empty cache.\n%s', self._cache_path, err) self._cache = {} else: self._cache = {} def cache_data(self, filename, data): """Cache data for given file""" if self._cache_data_policy: self._cache[filename] = data def get_cached_data(self, filename, default=None): """Get cached data for the given file if no data is cached, return the default object """ return self._cache.get(filename, default) def save_cache(self): """Save the updated cache""" if self._cache_data_policy: try: mkdir_p(self.settings['CACHE_PATH']) with self._cache_open(self._cache_path, 'wb') as fhandle: pickle.dump(self._cache, fhandle) except (IOError, OSError, pickle.PicklingError) as err: logger.warning('Could not save cache %s\n ... %s', self._cache_path, err) class FileStampDataCacher(FileDataCacher): """Subclass that also caches the stamp of the file""" def __init__(self, settings, cache_name, caching_policy, load_policy): """This sublcass additionally sets filestamp function and base path for filestamping operations """ super(FileStampDataCacher, self).__init__(settings, cache_name, caching_policy, load_policy) method = self.settings['CHECK_MODIFIED_METHOD'] if method == 'mtime': self._filestamp_func = os.path.getmtime else: try: hash_func = getattr(hashlib, method) def filestamp_func(filename): """return hash of file contents""" with open(filename, 'rb') as fhandle: return hash_func(fhandle.read()).digest() self._filestamp_func = filestamp_func except AttributeError as err: logger.warning('Could not get hashing function\n\t%s', err) self._filestamp_func = None def cache_data(self, filename, data): """Cache stamp and data for the given file""" stamp = self._get_file_stamp(filename) super(FileStampDataCacher, self).cache_data(filename, (stamp, data)) def _get_file_stamp(self, filename): """Check if the given file has been modified since the previous build. depending on CHECK_MODIFIED_METHOD a float may be returned for 'mtime', a hash for a function name in the hashlib module or an empty bytes string otherwise """ try: return self._filestamp_func(filename) except (IOError, OSError, TypeError) as err: logger.warning('Cannot get modification stamp for %s\n\t%s', filename, err) return '' def get_cached_data(self, filename, default=None): """Get the cached data for the given filename if the file has not been modified. If no record exists or file has been modified, return default. Modification is checked by comparing the cached and current file stamp. """ stamp, data = super(FileStampDataCacher, self).get_cached_data( filename, (None, default)) if stamp != self._get_file_stamp(filename): return default return data pelican-3.7.1/pelican/contents.py000066400000000000000000000422751303525152100167660ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import copy import locale import logging import os import re import sys import pytz import six from six.moves.urllib.parse import urlparse, urlunparse from pelican import signals from pelican.settings import DEFAULT_CONFIG from pelican.utils import (SafeDatetime, deprecated_attribute, memoized, path_to_url, posixize_path, python_2_unicode_compatible, set_date_tzinfo, slugify, strftime, truncate_html_words) # Import these so that they're avalaible when you import from pelican.contents. from pelican.urlwrappers import (Author, Category, Tag, URLWrapper) # NOQA logger = logging.getLogger(__name__) @python_2_unicode_compatible class Content(object): """Represents a content. :param content: the string to parse, containing the original content. :param metadata: the metadata associated to this page (optional). :param settings: the settings dictionary (optional). :param source_path: The location of the source of this content (if any). :param context: The shared context between generators. """ @deprecated_attribute(old='filename', new='source_path', since=(3, 2, 0)) def filename(): return None def __init__(self, content, metadata=None, settings=None, source_path=None, context=None): if metadata is None: metadata = {} if settings is None: settings = copy.deepcopy(DEFAULT_CONFIG) self.settings = settings self._content = content if context is None: context = {} self._context = context self.translations = [] local_metadata = dict() local_metadata.update(metadata) # set metadata as attributes for key, value in local_metadata.items(): if key in ('save_as', 'url'): key = 'override_' + key setattr(self, key.lower(), value) # also keep track of the metadata attributes available self.metadata = local_metadata # default template if it's not defined in page self.template = self._get_template() # First, read the authors from "authors", if not, fallback to "author" # and if not use the settings defined one, if any. if not hasattr(self, 'author'): if hasattr(self, 'authors'): self.author = self.authors[0] elif 'AUTHOR' in settings: self.author = Author(settings['AUTHOR'], settings) if not hasattr(self, 'authors') and hasattr(self, 'author'): self.authors = [self.author] # XXX Split all the following code into pieces, there is too much here. # manage languages self.in_default_lang = True if 'DEFAULT_LANG' in settings: default_lang = settings['DEFAULT_LANG'].lower() if not hasattr(self, 'lang'): self.lang = default_lang self.in_default_lang = (self.lang == default_lang) # create the slug if not existing, generate slug according to # setting of SLUG_ATTRIBUTE if not hasattr(self, 'slug'): if (settings['SLUGIFY_SOURCE'] == 'title' and hasattr(self, 'title')): self.slug = slugify(self.title, settings.get('SLUG_SUBSTITUTIONS', ())) elif (settings['SLUGIFY_SOURCE'] == 'basename' and source_path is not None): basename = os.path.basename( os.path.splitext(source_path)[0]) self.slug = slugify( basename, settings.get('SLUG_SUBSTITUTIONS', ())) self.source_path = source_path # manage the date format if not hasattr(self, 'date_format'): if hasattr(self, 'lang') and self.lang in settings['DATE_FORMATS']: self.date_format = settings['DATE_FORMATS'][self.lang] else: self.date_format = settings['DEFAULT_DATE_FORMAT'] if isinstance(self.date_format, tuple): locale_string = self.date_format[0] if sys.version_info < (3, ) and isinstance(locale_string, six.text_type): locale_string = locale_string.encode('ascii') locale.setlocale(locale.LC_ALL, locale_string) self.date_format = self.date_format[1] # manage timezone default_timezone = settings.get('TIMEZONE', 'UTC') timezone = getattr(self, 'timezone', default_timezone) if hasattr(self, 'date'): self.date = set_date_tzinfo(self.date, timezone) self.locale_date = strftime(self.date, self.date_format) if hasattr(self, 'modified'): self.modified = set_date_tzinfo(self.modified, timezone) self.locale_modified = strftime(self.modified, self.date_format) # manage status if not hasattr(self, 'status'): self.status = settings['DEFAULT_STATUS'] if not settings['WITH_FUTURE_DATES'] and hasattr(self, 'date'): if self.date.tzinfo is None: now = SafeDatetime.now() else: now = SafeDatetime.utcnow().replace(tzinfo=pytz.utc) if self.date > now: self.status = 'draft' # store the summary metadata if it is set if 'summary' in metadata: self._summary = metadata['summary'] signals.content_object_init.send(self) def __str__(self): return self.source_path or repr(self) def check_properties(self): """Test mandatory properties are set.""" for prop in self.mandatory_properties: if not hasattr(self, prop): raise NameError(prop) @property def url_format(self): """Returns the URL, formatted with the proper values""" metadata = copy.copy(self.metadata) path = self.metadata.get('path', self.get_relative_source_path()) metadata.update({ 'path': path_to_url(path), 'slug': getattr(self, 'slug', ''), 'lang': getattr(self, 'lang', 'en'), 'date': getattr(self, 'date', SafeDatetime.now()), 'author': self.author.slug if hasattr(self, 'author') else '', 'tag': self.tag.slug if hasattr(self, 'tag') else '', 'category': self.category.slug if hasattr(self, 'category') else '' }) return metadata def _expand_settings(self, key): fq_key = ('%s_%s' % (self.__class__.__name__, key)).upper() return self.settings[fq_key].format(**self.url_format) def get_url_setting(self, key): if hasattr(self, 'override_' + key): return getattr(self, 'override_' + key) key = key if self.in_default_lang else 'lang_%s' % key return self._expand_settings(key) def _update_content(self, content, siteurl): """Update the content attribute. Change all the relative paths of the content to relative paths suitable for the output content. :param content: content resource that will be passed to the templates. :param siteurl: siteurl which is locally generated by the writer in case of RELATIVE_URLS. """ if not content: return content instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX'] regex = r""" (?P<\s*[^\>]* # match tag with all url-value attributes (?:href|src|poster|data|cite|formaction|action)\s*=) (?P["\']) # require value to be quoted (?P{0}(?P.*?)) # the url value \2""".format(instrasite_link_regex) hrefs = re.compile(regex, re.X) def replacer(m): what = m.group('what') value = urlparse(m.group('value')) path = value.path origin = m.group('path') # XXX Put this in a different location. if what in {'filename', 'attach'}: if path.startswith('/'): path = path[1:] else: # relative to the source path of this content path = self.get_relative_source_path( os.path.join(self.relative_dir, path) ) if path not in self._context['filenames']: unquoted_path = path.replace('%20', ' ') if unquoted_path in self._context['filenames']: path = unquoted_path linked_content = self._context['filenames'].get(path) if linked_content: if what == 'attach': if isinstance(linked_content, Static): linked_content.attach_to(self) else: logger.warning( "%s used {attach} link syntax on a " "non-static file. Use {filename} instead.", self.get_relative_source_path()) origin = '/'.join((siteurl, linked_content.url)) origin = origin.replace('\\', '/') # for Windows paths. else: logger.warning( "Unable to find `%s`, skipping url replacement.", value.geturl(), extra={ 'limit_msg': ("Other resources were not found " "and their urls not replaced")}) elif what == 'category': origin = '/'.join((siteurl, Category(path, self.settings).url)) elif what == 'tag': origin = '/'.join((siteurl, Tag(path, self.settings).url)) elif what == 'index': origin = '/'.join((siteurl, self.settings['INDEX_SAVE_AS'])) elif what == 'author': origin = '/'.join((siteurl, Author(path, self.settings).url)) else: logger.warning( "Replacement Indicator '%s' not recognized, " "skipping replacement", what) # keep all other parts, such as query, fragment, etc. parts = list(value) parts[2] = origin origin = urlunparse(parts) return ''.join((m.group('markup'), m.group('quote'), origin, m.group('quote'))) return hrefs.sub(replacer, content) def get_siteurl(self): return self._context.get('localsiteurl', '') @memoized def get_content(self, siteurl): if hasattr(self, '_get_content'): content = self._get_content() else: content = self._content return self._update_content(content, siteurl) @property def content(self): return self.get_content(self.get_siteurl()) @memoized def get_summary(self, siteurl): """Returns the summary of an article. This is based on the summary metadata if set, otherwise truncate the content. """ if hasattr(self, '_summary'): return self._update_content(self._summary, siteurl) if self.settings['SUMMARY_MAX_LENGTH'] is None: return self.content return truncate_html_words(self.content, self.settings['SUMMARY_MAX_LENGTH']) @property def summary(self): return self.get_summary(self.get_siteurl()) def _get_summary(self): """deprecated function to access summary""" logger.warning('_get_summary() has been deprecated since 3.6.4. ' 'Use the summary decorator instead') return self.summary @summary.setter def summary(self, value): """Dummy function""" pass @property def url(self): return self.get_url_setting('url') @property def save_as(self): return self.get_url_setting('save_as') def _get_template(self): if hasattr(self, 'template') and self.template is not None: return self.template else: return self.default_template def get_relative_source_path(self, source_path=None): """Return the relative path (from the content path) to the given source_path. If no source path is specified, use the source path of this content object. """ if not source_path: source_path = self.source_path if source_path is None: return None return posixize_path( os.path.relpath( os.path.abspath(os.path.join( self.settings['PATH'], source_path)), os.path.abspath(self.settings['PATH']) )) @property def relative_dir(self): return posixize_path( os.path.dirname( os.path.relpath( os.path.abspath(self.source_path), os.path.abspath(self.settings['PATH'])))) class Page(Content): mandatory_properties = ('title',) default_template = 'page' class Article(Page): mandatory_properties = ('title', 'date', 'category') default_template = 'article' class Draft(Page): mandatory_properties = ('title', 'category') default_template = 'article' class Quote(Page): base_properties = ('author', 'date') @python_2_unicode_compatible class Static(Page): def __init__(self, *args, **kwargs): super(Static, self).__init__(*args, **kwargs) self._output_location_referenced = False @deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0)) def filepath(): return None @deprecated_attribute(old='src', new='source_path', since=(3, 2, 0)) def src(): return None @deprecated_attribute(old='dst', new='save_as', since=(3, 2, 0)) def dst(): return None @property def url(self): # Note when url has been referenced, so we can avoid overriding it. self._output_location_referenced = True return super(Static, self).url @property def save_as(self): # Note when save_as has been referenced, so we can avoid overriding it. self._output_location_referenced = True return super(Static, self).save_as def attach_to(self, content): """Override our output directory with that of the given content object. """ # Determine our file's new output path relative to the linking # document. If it currently lives beneath the linking # document's source directory, preserve that relationship on output. # Otherwise, make it a sibling. linking_source_dir = os.path.dirname(content.source_path) tail_path = os.path.relpath(self.source_path, linking_source_dir) if tail_path.startswith(os.pardir + os.sep): tail_path = os.path.basename(tail_path) new_save_as = os.path.join( os.path.dirname(content.save_as), tail_path) # We do not build our new url by joining tail_path with the linking # document's url, because we cannot know just by looking at the latter # whether it points to the document itself or to its parent directory. # (An url like 'some/content' might mean a directory named 'some' # with a file named 'content', or it might mean a directory named # 'some/content' with a file named 'index.html'.) Rather than trying # to figure it out by comparing the linking document's url and save_as # path, we simply build our new url from our new save_as path. new_url = path_to_url(new_save_as) def _log_reason(reason): logger.warning( "The {attach} link in %s cannot relocate " "%s because %s. Falling back to " "{filename} link behavior instead.", content.get_relative_source_path(), self.get_relative_source_path(), reason, extra={'limit_msg': "More {attach} warnings silenced."}) # We never override an override, because we don't want to interfere # with user-defined overrides that might be in EXTRA_PATH_METADATA. if hasattr(self, 'override_save_as') or hasattr(self, 'override_url'): if new_save_as != self.save_as or new_url != self.url: _log_reason("its output location was already overridden") return # We never change an output path that has already been referenced, # because we don't want to break links that depend on that path. if self._output_location_referenced: if new_save_as != self.save_as or new_url != self.url: _log_reason("another link already referenced its location") return self.override_save_as = new_save_as self.override_url = new_url def is_valid_content(content, f): try: content.check_properties() return True except NameError as e: logger.error( "Skipping %s: could not find information about '%s'", f, six.text_type(e)) return False pelican-3.7.1/pelican/generators.py000066400000000000000000000750171303525152100173020ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import calendar import fnmatch import logging import os from codecs import open from collections import defaultdict from functools import partial from itertools import chain, groupby from operator import attrgetter from jinja2 import (BaseLoader, ChoiceLoader, Environment, FileSystemLoader, PrefixLoader, TemplateNotFound) import six from pelican import signals from pelican.cache import FileStampDataCacher from pelican.contents import Article, Draft, Page, Static, is_valid_content from pelican.readers import Readers from pelican.utils import (DateFormatter, copy, copy_file_metadata, mkdir_p, posixize_path, process_translations, python_2_unicode_compatible) logger = logging.getLogger(__name__) class PelicanTemplateNotFound(Exception): pass @python_2_unicode_compatible class Generator(object): """Baseclass generator""" def __init__(self, context, settings, path, theme, output_path, readers_cache_name='', **kwargs): self.context = context self.settings = settings self.path = path self.theme = theme self.output_path = output_path for arg, value in kwargs.items(): setattr(self, arg, value) self.readers = Readers(self.settings, readers_cache_name) # templates cache self._templates = {} self._templates_path = [] self._templates_path.append(os.path.expanduser( os.path.join(self.theme, 'templates'))) self._templates_path += self.settings['EXTRA_TEMPLATES_PATHS'] theme_path = os.path.dirname(os.path.abspath(__file__)) simple_loader = FileSystemLoader(os.path.join(theme_path, "themes", "simple", "templates")) self.env = Environment( loader=ChoiceLoader([ FileSystemLoader(self._templates_path), simple_loader, # implicit inheritance PrefixLoader({'!simple': simple_loader}) # explicit one ]), **self.settings['JINJA_ENVIRONMENT'] ) logger.debug('Template list: %s', self.env.list_templates()) # provide utils.strftime as a jinja filter self.env.filters.update({'strftime': DateFormatter()}) # get custom Jinja filters from user settings custom_filters = self.settings['JINJA_FILTERS'] self.env.filters.update(custom_filters) signals.generator_init.send(self) def get_template(self, name): """Return the template by name. Use self.theme to get the templates to use, and return a list of templates ready to use with Jinja2. """ if name not in self._templates: try: self._templates[name] = self.env.get_template(name + '.html') except TemplateNotFound: raise PelicanTemplateNotFound( '[templates] unable to load {}.html from {}'.format( name, self._templates_path)) return self._templates[name] def _include_path(self, path, extensions=None): """Inclusion logic for .get_files(), returns True/False :param path: the path which might be including :param extensions: the list of allowed extensions, or False if all extensions are allowed """ if extensions is None: extensions = tuple(self.readers.extensions) basename = os.path.basename(path) # check IGNORE_FILES ignores = self.settings['IGNORE_FILES'] if any(fnmatch.fnmatch(basename, ignore) for ignore in ignores): return False ext = os.path.splitext(basename)[1][1:] if extensions is False or ext in extensions: return True return False def get_files(self, paths, exclude=[], extensions=None): """Return a list of files to use, based on rules :param paths: the list pf paths to search (relative to self.path) :param exclude: the list of path to exclude :param extensions: the list of allowed extensions (if False, all extensions are allowed) """ # backward compatibility for older generators if isinstance(paths, six.string_types): paths = [paths] # group the exclude dir names by parent path, for use with os.walk() exclusions_by_dirpath = {} for e in exclude: parent_path, subdir = os.path.split(os.path.join(self.path, e)) exclusions_by_dirpath.setdefault(parent_path, set()).add(subdir) files = [] ignores = self.settings['IGNORE_FILES'] for path in paths: # careful: os.path.join() will add a slash when path == ''. root = os.path.join(self.path, path) if path else self.path if os.path.isdir(root): for dirpath, dirs, temp_files in os.walk( root, followlinks=True): drop = [] excl = exclusions_by_dirpath.get(dirpath, ()) for d in dirs: if (d in excl or any(fnmatch.fnmatch(d, ignore) for ignore in ignores)): drop.append(d) for d in drop: dirs.remove(d) reldir = os.path.relpath(dirpath, self.path) for f in temp_files: fp = os.path.join(reldir, f) if self._include_path(fp, extensions): files.append(fp) elif os.path.exists(root) and self._include_path(path, extensions): files.append(path) # can't walk non-directories return files def add_source_path(self, content): """Record a source file path that a Generator found and processed. Store a reference to its Content object, for url lookups later. """ location = content.get_relative_source_path() self.context['filenames'][location] = content def _add_failed_source_path(self, path): """Record a source file path that a Generator failed to process. (For example, one that was missing mandatory metadata.) The path argument is expected to be relative to self.path. """ self.context['filenames'][posixize_path(os.path.normpath(path))] = None def _is_potential_source_path(self, path): """Return True if path was supposed to be used as a source file. (This includes all source files that have been found by generators before this method is called, even if they failed to process.) The path argument is expected to be relative to self.path. """ return (posixize_path(os.path.normpath(path)) in self.context['filenames']) def _update_context(self, items): """Update the context with the given items from the currrent processor. """ for item in items: value = getattr(self, item) if hasattr(value, 'items'): value = list(value.items()) # py3k safeguard for iterators self.context[item] = value def __str__(self): # return the name of the class for logging purposes return self.__class__.__name__ class CachingGenerator(Generator, FileStampDataCacher): '''Subclass of Generator and FileStampDataCacher classes enables content caching, either at the generator or reader level ''' def __init__(self, *args, **kwargs): '''Initialize the generator, then set up caching note the multiple inheritance structure ''' cls_name = self.__class__.__name__ Generator.__init__(self, *args, readers_cache_name=(cls_name + '-Readers'), **kwargs) cache_this_level = \ self.settings['CONTENT_CACHING_LAYER'] == 'generator' caching_policy = cache_this_level and self.settings['CACHE_CONTENT'] load_policy = cache_this_level and self.settings['LOAD_CONTENT_CACHE'] FileStampDataCacher.__init__(self, self.settings, cls_name, caching_policy, load_policy ) def _get_file_stamp(self, filename): '''Get filestamp for path relative to generator.path''' filename = os.path.join(self.path, filename) return super(CachingGenerator, self)._get_file_stamp(filename) class _FileLoader(BaseLoader): def __init__(self, path, basedir): self.path = path self.fullpath = os.path.join(basedir, path) def get_source(self, environment, template): if template != self.path or not os.path.exists(self.fullpath): raise TemplateNotFound(template) mtime = os.path.getmtime(self.fullpath) with open(self.fullpath, 'r', encoding='utf-8') as f: source = f.read() return (source, self.fullpath, lambda: mtime == os.path.getmtime(self.fullpath)) class TemplatePagesGenerator(Generator): def generate_output(self, writer): for source, dest in self.settings['TEMPLATE_PAGES'].items(): self.env.loader.loaders.insert(0, _FileLoader(source, self.path)) try: template = self.env.get_template(source) rurls = self.settings['RELATIVE_URLS'] writer.write_file(dest, template, self.context, rurls, override_output=True) finally: del self.env.loader.loaders[0] class ArticlesGenerator(CachingGenerator): """Generate blog articles""" def __init__(self, *args, **kwargs): """initialize properties""" self.articles = [] # only articles in default language self.translations = [] self.dates = {} self.tags = defaultdict(list) self.categories = defaultdict(list) self.related_posts = [] self.authors = defaultdict(list) self.drafts = [] # only drafts in default language self.drafts_translations = [] super(ArticlesGenerator, self).__init__(*args, **kwargs) signals.article_generator_init.send(self) def generate_feeds(self, writer): """Generate the feeds from the current context, and output files.""" if self.settings.get('FEED_ATOM'): writer.write_feed(self.articles, self.context, self.settings['FEED_ATOM']) if self.settings.get('FEED_RSS'): writer.write_feed(self.articles, self.context, self.settings['FEED_RSS'], feed_type='rss') if (self.settings.get('FEED_ALL_ATOM') or self.settings.get('FEED_ALL_RSS')): all_articles = list(self.articles) for article in self.articles: all_articles.extend(article.translations) all_articles.sort(key=attrgetter('date'), reverse=True) if self.settings.get('FEED_ALL_ATOM'): writer.write_feed(all_articles, self.context, self.settings['FEED_ALL_ATOM']) if self.settings.get('FEED_ALL_RSS'): writer.write_feed(all_articles, self.context, self.settings['FEED_ALL_RSS'], feed_type='rss') for cat, arts in self.categories: arts.sort(key=attrgetter('date'), reverse=True) if self.settings.get('CATEGORY_FEED_ATOM'): writer.write_feed(arts, self.context, self.settings['CATEGORY_FEED_ATOM'] % cat.slug, feed_title=cat.name) if self.settings.get('CATEGORY_FEED_RSS'): writer.write_feed(arts, self.context, self.settings['CATEGORY_FEED_RSS'] % cat.slug, feed_title=cat.name, feed_type='rss') for auth, arts in self.authors: arts.sort(key=attrgetter('date'), reverse=True) if self.settings.get('AUTHOR_FEED_ATOM'): writer.write_feed(arts, self.context, self.settings['AUTHOR_FEED_ATOM'] % auth.slug, feed_title=auth.name) if self.settings.get('AUTHOR_FEED_RSS'): writer.write_feed(arts, self.context, self.settings['AUTHOR_FEED_RSS'] % auth.slug, feed_title=auth.name, feed_type='rss') if (self.settings.get('TAG_FEED_ATOM') or self.settings.get('TAG_FEED_RSS')): for tag, arts in self.tags.items(): arts.sort(key=attrgetter('date'), reverse=True) if self.settings.get('TAG_FEED_ATOM'): writer.write_feed(arts, self.context, self.settings['TAG_FEED_ATOM'] % tag.slug, feed_title=tag.name) if self.settings.get('TAG_FEED_RSS'): writer.write_feed(arts, self.context, self.settings['TAG_FEED_RSS'] % tag.slug, feed_title=tag.name, feed_type='rss') if (self.settings.get('TRANSLATION_FEED_ATOM') or self.settings.get('TRANSLATION_FEED_RSS')): translations_feeds = defaultdict(list) for article in chain(self.articles, self.translations): translations_feeds[article.lang].append(article) for lang, items in translations_feeds.items(): items.sort(key=attrgetter('date'), reverse=True) if self.settings.get('TRANSLATION_FEED_ATOM'): writer.write_feed( items, self.context, self.settings['TRANSLATION_FEED_ATOM'] % lang) if self.settings.get('TRANSLATION_FEED_RSS'): writer.write_feed( items, self.context, self.settings['TRANSLATION_FEED_RSS'] % lang, feed_type='rss') def generate_articles(self, write): """Generate the articles.""" for article in chain(self.translations, self.articles): signals.article_generator_write_article.send(self, content=article) write(article.save_as, self.get_template(article.template), self.context, article=article, category=article.category, override_output=hasattr(article, 'override_save_as'), blog=True) def generate_period_archives(self, write): """Generate per-year, per-month, and per-day archives.""" try: template = self.get_template('period_archives') except PelicanTemplateNotFound: template = self.get_template('archives') period_save_as = { 'year': self.settings['YEAR_ARCHIVE_SAVE_AS'], 'month': self.settings['MONTH_ARCHIVE_SAVE_AS'], 'day': self.settings['DAY_ARCHIVE_SAVE_AS'], } period_date_key = { 'year': attrgetter('date.year'), 'month': attrgetter('date.year', 'date.month'), 'day': attrgetter('date.year', 'date.month', 'date.day') } def _generate_period_archives(dates, key, save_as_fmt): """Generate period archives from `dates`, grouped by `key` and written to `save_as`. """ # `dates` is already sorted by date for _period, group in groupby(dates, key=key): archive = list(group) # arbitrarily grab the first date so that the usual # format string syntax can be used for specifying the # period archive dates date = archive[0].date save_as = save_as_fmt.format(date=date) context = self.context.copy() if key == period_date_key['year']: context["period"] = (_period,) else: month_name = calendar.month_name[_period[1]] if not six.PY3: month_name = month_name.decode('utf-8') if key == period_date_key['month']: context["period"] = (_period[0], month_name) else: context["period"] = (_period[0], month_name, _period[2]) write(save_as, template, context, dates=archive, blog=True) for period in 'year', 'month', 'day': save_as = period_save_as[period] if save_as: key = period_date_key[period] _generate_period_archives(self.dates, key, save_as) def generate_direct_templates(self, write): """Generate direct templates pages""" PAGINATED_TEMPLATES = self.settings['PAGINATED_DIRECT_TEMPLATES'] for template in self.settings['DIRECT_TEMPLATES']: paginated = {} if template in PAGINATED_TEMPLATES: paginated = {'articles': self.articles, 'dates': self.dates} save_as = self.settings.get("%s_SAVE_AS" % template.upper(), '%s.html' % template) if not save_as: continue write(save_as, self.get_template(template), self.context, blog=True, paginated=paginated, page_name=os.path.splitext(save_as)[0]) def generate_tags(self, write): """Generate Tags pages.""" tag_template = self.get_template('tag') for tag, articles in self.tags.items(): articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] write(tag.save_as, tag_template, self.context, tag=tag, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, blog=True, page_name=tag.page_name, all_articles=self.articles) def generate_categories(self, write): """Generate category pages.""" category_template = self.get_template('category') for cat, articles in self.categories: articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] write(cat.save_as, category_template, self.context, category=cat, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, blog=True, page_name=cat.page_name, all_articles=self.articles) def generate_authors(self, write): """Generate Author pages.""" author_template = self.get_template('author') for aut, articles in self.authors: articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] write(aut.save_as, author_template, self.context, author=aut, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, blog=True, page_name=aut.page_name, all_articles=self.articles) def generate_drafts(self, write): """Generate drafts pages.""" for draft in chain(self.drafts_translations, self.drafts): write(draft.save_as, self.get_template(draft.template), self.context, article=draft, category=draft.category, override_output=hasattr(draft, 'override_save_as'), blog=True, all_articles=self.articles) def generate_pages(self, writer): """Generate the pages on the disk""" write = partial(writer.write_file, relative_urls=self.settings['RELATIVE_URLS']) # to minimize the number of relative path stuff modification # in writer, articles pass first self.generate_articles(write) self.generate_period_archives(write) self.generate_direct_templates(write) # and subfolders after that self.generate_tags(write) self.generate_categories(write) self.generate_authors(write) self.generate_drafts(write) def generate_context(self): """Add the articles into the shared context""" all_articles = [] all_drafts = [] for f in self.get_files( self.settings['ARTICLE_PATHS'], exclude=self.settings['ARTICLE_EXCLUDES']): article_or_draft = self.get_cached_data(f, None) if article_or_draft is None: # TODO needs overhaul, maybe nomad for read_file # solution, unified behaviour try: article_or_draft = self.readers.read_file( base_path=self.path, path=f, content_class=Article, context=self.context, preread_signal=signals.article_generator_preread, preread_sender=self, context_signal=signals.article_generator_context, context_sender=self) except Exception as e: logger.error( 'Could not process %s\n%s', f, e, exc_info=self.settings.get('DEBUG', False)) self._add_failed_source_path(f) continue if not is_valid_content(article_or_draft, f): self._add_failed_source_path(f) continue if article_or_draft.status.lower() == "published": pass elif article_or_draft.status.lower() == "draft": article_or_draft = self.readers.read_file( base_path=self.path, path=f, content_class=Draft, context=self.context, preread_signal=signals.article_generator_preread, preread_sender=self, context_signal=signals.article_generator_context, context_sender=self) else: logger.error( "Unknown status '%s' for file %s, skipping it.", article_or_draft.status, f) self._add_failed_source_path(f) continue self.cache_data(f, article_or_draft) if article_or_draft.status.lower() == "published": all_articles.append(article_or_draft) else: all_drafts.append(article_or_draft) self.add_source_path(article_or_draft) self.articles, self.translations = process_translations( all_articles, order_by=self.settings['ARTICLE_ORDER_BY']) self.drafts, self.drafts_translations = \ process_translations(all_drafts) signals.article_generator_pretaxonomy.send(self) for article in self.articles: # only main articles are listed in categories and tags # not translations self.categories[article.category].append(article) if hasattr(article, 'tags'): for tag in article.tags: self.tags[tag].append(article) for author in getattr(article, 'authors', []): self.authors[author].append(article) self.dates = list(self.articles) self.dates.sort(key=attrgetter('date'), reverse=self.context['NEWEST_FIRST_ARCHIVES']) # and generate the output :) # order the categories per name self.categories = list(self.categories.items()) self.categories.sort( reverse=self.settings['REVERSE_CATEGORY_ORDER']) self.authors = list(self.authors.items()) self.authors.sort() self._update_context(('articles', 'dates', 'tags', 'categories', 'authors', 'related_posts', 'drafts')) self.save_cache() self.readers.save_cache() signals.article_generator_finalized.send(self) def generate_output(self, writer): self.generate_feeds(writer) self.generate_pages(writer) signals.article_writer_finalized.send(self, writer=writer) class PagesGenerator(CachingGenerator): """Generate pages""" def __init__(self, *args, **kwargs): self.pages = [] self.hidden_pages = [] self.hidden_translations = [] super(PagesGenerator, self).__init__(*args, **kwargs) signals.page_generator_init.send(self) def generate_context(self): all_pages = [] hidden_pages = [] for f in self.get_files( self.settings['PAGE_PATHS'], exclude=self.settings['PAGE_EXCLUDES']): page = self.get_cached_data(f, None) if page is None: try: page = self.readers.read_file( base_path=self.path, path=f, content_class=Page, context=self.context, preread_signal=signals.page_generator_preread, preread_sender=self, context_signal=signals.page_generator_context, context_sender=self) except Exception as e: logger.error( 'Could not process %s\n%s', f, e, exc_info=self.settings.get('DEBUG', False)) self._add_failed_source_path(f) continue if not is_valid_content(page, f): self._add_failed_source_path(f) continue if page.status.lower() not in ("published", "hidden"): logger.error( "Unknown status '%s' for file %s, skipping it.", page.status, f) self._add_failed_source_path(f) continue self.cache_data(f, page) if page.status.lower() == "published": all_pages.append(page) elif page.status.lower() == "hidden": hidden_pages.append(page) self.add_source_path(page) self.pages, self.translations = process_translations( all_pages, order_by=self.settings['PAGE_ORDER_BY']) self.hidden_pages, self.hidden_translations = \ process_translations(hidden_pages) self._update_context(('pages', 'hidden_pages')) self.save_cache() self.readers.save_cache() signals.page_generator_finalized.send(self) def generate_output(self, writer): for page in chain(self.translations, self.pages, self.hidden_translations, self.hidden_pages): writer.write_file( page.save_as, self.get_template(page.template), self.context, page=page, relative_urls=self.settings['RELATIVE_URLS'], override_output=hasattr(page, 'override_save_as')) signals.page_writer_finalized.send(self, writer=writer) class StaticGenerator(Generator): """copy static paths (what you want to copy, like images, medias etc. to output""" def __init__(self, *args, **kwargs): super(StaticGenerator, self).__init__(*args, **kwargs) signals.static_generator_init.send(self) def _copy_paths(self, paths, source, destination, output_path, final_path=None): """Copy all the paths from source to destination""" for path in paths: if final_path: copy(os.path.join(source, path), os.path.join(output_path, destination, final_path), self.settings['IGNORE_FILES']) else: copy(os.path.join(source, path), os.path.join(output_path, destination, path), self.settings['IGNORE_FILES']) def generate_context(self): self.staticfiles = [] for f in self.get_files(self.settings['STATIC_PATHS'], exclude=self.settings['STATIC_EXCLUDES'], extensions=False): # skip content source files unless the user explicitly wants them if self.settings['STATIC_EXCLUDE_SOURCES']: if self._is_potential_source_path(f): continue static = self.readers.read_file( base_path=self.path, path=f, content_class=Static, fmt='static', context=self.context, preread_signal=signals.static_generator_preread, preread_sender=self, context_signal=signals.static_generator_context, context_sender=self) self.staticfiles.append(static) self.add_source_path(static) self._update_context(('staticfiles',)) signals.static_generator_finalized.send(self) def generate_output(self, writer): self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.theme, self.settings['THEME_STATIC_DIR'], self.output_path, os.curdir) # copy all Static files for sc in self.context['staticfiles']: source_path = os.path.join(self.path, sc.source_path) save_as = os.path.join(self.output_path, sc.save_as) mkdir_p(os.path.dirname(save_as)) logger.info('Copying %s to %s', sc.source_path, sc.save_as) copy_file_metadata(source_path, save_as) class SourceFileGenerator(Generator): def generate_context(self): self.output_extension = self.settings['OUTPUT_SOURCES_EXTENSION'] def _create_source(self, obj): output_path, _ = os.path.splitext(obj.save_as) dest = os.path.join(self.output_path, output_path + self.output_extension) copy(obj.source_path, dest) def generate_output(self, writer=None): logger.info('Generating source files...') for obj in chain(self.context['articles'], self.context['pages']): self._create_source(obj) for obj_trans in obj.translations: self._create_source(obj_trans) pelican-3.7.1/pelican/log.py000066400000000000000000000166311303525152100157070ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import locale import logging import os import sys from collections import Mapping, defaultdict import six __all__ = [ 'init' ] class BaseFormatter(logging.Formatter): def __init__(self, fmt=None, datefmt=None): FORMAT = '%(customlevelname)s %(message)s' super(BaseFormatter, self).__init__(fmt=FORMAT, datefmt=datefmt) def format(self, record): customlevel = self._get_levelname(record.levelname) record.__dict__['customlevelname'] = customlevel # format multiline messages 'nicely' to make it clear they are together record.msg = record.msg.replace('\n', '\n | ') return super(BaseFormatter, self).format(record) def formatException(self, ei): ''' prefix traceback info for better representation ''' # .formatException returns a bytestring in py2 and unicode in py3 # since .format will handle unicode conversion, # str() calls are used to normalize formatting string s = super(BaseFormatter, self).formatException(ei) # fancy format traceback s = str('\n').join(str(' | ') + line for line in s.splitlines()) # separate the traceback from the preceding lines s = str(' |___\n{}').format(s) return s def _get_levelname(self, name): ''' NOOP: overridden by subclasses ''' return name class ANSIFormatter(BaseFormatter): ANSI_CODES = { 'red': '\033[1;31m', 'yellow': '\033[1;33m', 'cyan': '\033[1;36m', 'white': '\033[1;37m', 'bgred': '\033[1;41m', 'bggrey': '\033[1;100m', 'reset': '\033[0;m'} LEVEL_COLORS = { 'INFO': 'cyan', 'WARNING': 'yellow', 'ERROR': 'red', 'CRITICAL': 'bgred', 'DEBUG': 'bggrey'} def _get_levelname(self, name): color = self.ANSI_CODES[self.LEVEL_COLORS.get(name, 'white')] if name == 'INFO': fmt = '{0}->{2}' else: fmt = '{0}{1}{2}:' return fmt.format(color, name, self.ANSI_CODES['reset']) class TextFormatter(BaseFormatter): """ Convert a `logging.LogRecord' object into text. """ def _get_levelname(self, name): if name == 'INFO': return '->' else: return name + ':' class LimitFilter(logging.Filter): """ Remove duplicates records, and limit the number of records in the same group. Groups are specified by the message to use when the number of records in the same group hit the limit. E.g.: log.warning(('43 is not the answer', 'More erroneous answers')) """ _ignore = set() _raised_messages = set() _threshold = 5 _group_count = defaultdict(int) def filter(self, record): # don't limit log messages for anything above "warning" if record.levelno > logging.WARN: return True # extract group group = record.__dict__.get('limit_msg', None) group_args = record.__dict__.get('limit_args', ()) # ignore record if it was already raised message_key = (record.levelno, record.getMessage()) if message_key in self._raised_messages: return False else: self._raised_messages.add(message_key) # ignore LOG_FILTER records by templates when "debug" isn't enabled logger_level = logging.getLogger().getEffectiveLevel() if logger_level > logging.DEBUG: ignore_key = (record.levelno, record.msg) if ignore_key in self._ignore: return False # check if we went over threshold if group: key = (record.levelno, group) self._group_count[key] += 1 if self._group_count[key] == self._threshold: record.msg = group record.args = group_args elif self._group_count[key] > self._threshold: return False return True class SafeLogger(logging.Logger): """ Base Logger which properly encodes Exceptions in Py2 """ _exc_encoding = locale.getpreferredencoding() def _log(self, level, msg, args, exc_info=None, extra=None): # if the only argument is a Mapping, Logger uses that for formatting # format values for that case if args and len(args) == 1 and isinstance(args[0], Mapping): args = ({k: self._decode_arg(v) for k, v in args[0].items()},) # otherwise, format each arg else: args = tuple(self._decode_arg(arg) for arg in args) super(SafeLogger, self)._log( level, msg, args, exc_info=exc_info, extra=extra) def _decode_arg(self, arg): ''' properly decode an arg for Py2 if it's Exception localized systems have errors in native language if locale is set so convert the message to unicode with the correct encoding ''' if isinstance(arg, Exception): text = str('%s: %s') % (arg.__class__.__name__, arg) if six.PY2: text = text.decode(self._exc_encoding) return text else: return arg class LimitLogger(SafeLogger): """ A logger which adds LimitFilter automatically """ limit_filter = LimitFilter() def __init__(self, *args, **kwargs): super(LimitLogger, self).__init__(*args, **kwargs) self.enable_filter() def disable_filter(self): self.removeFilter(LimitLogger.limit_filter) def enable_filter(self): self.addFilter(LimitLogger.limit_filter) class FatalLogger(LimitLogger): warnings_fatal = False errors_fatal = False def warning(self, *args, **kwargs): super(FatalLogger, self).warning(*args, **kwargs) if FatalLogger.warnings_fatal: raise RuntimeError('Warning encountered') def error(self, *args, **kwargs): super(FatalLogger, self).error(*args, **kwargs) if FatalLogger.errors_fatal: raise RuntimeError('Error encountered') logging.setLoggerClass(FatalLogger) def supports_color(): """ Returns True if the running system's terminal supports color, and False otherwise. from django.core.management.color """ plat = sys.platform supported_platform = plat != 'Pocket PC' and \ (plat != 'win32' or 'ANSICON' in os.environ) # isatty is not always implemented, #6223. is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() if not supported_platform or not is_a_tty: return False return True def get_formatter(): if supports_color(): return ANSIFormatter() else: return TextFormatter() def init(level=None, fatal='', handler=logging.StreamHandler(), name=None): FatalLogger.warnings_fatal = fatal.startswith('warning') FatalLogger.errors_fatal = bool(fatal) logger = logging.getLogger(name) handler.setFormatter(get_formatter()) logger.addHandler(handler) if level: logger.setLevel(level) def log_warnings(): import warnings logging.captureWarnings(True) warnings.simplefilter("default", DeprecationWarning) init(logging.DEBUG, name='py.warnings') if __name__ == '__main__': init(level=logging.DEBUG) root_logger = logging.getLogger() root_logger.debug('debug') root_logger.info('info') root_logger.warning('warning') root_logger.error('error') root_logger.critical('critical') pelican-3.7.1/pelican/paginator.py000066400000000000000000000114401303525152100171030ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import functools import logging import os from collections import namedtuple from math import ceil import six logger = logging.getLogger(__name__) PaginationRule = namedtuple( 'PaginationRule', 'min_page URL SAVE_AS', ) class Paginator(object): def __init__(self, name, object_list, settings): self.name = name self.object_list = object_list self.settings = settings if settings.get('DEFAULT_PAGINATION'): self.per_page = settings.get('DEFAULT_PAGINATION') self.orphans = settings.get('DEFAULT_ORPHANS') else: self.per_page = len(object_list) self.orphans = 0 self._num_pages = self._count = None def page(self, number): "Returns a Page object for the given 1-based page number." bottom = (number - 1) * self.per_page top = bottom + self.per_page if top + self.orphans >= self.count: top = self.count return Page(self.name, self.object_list[bottom:top], number, self, self.settings) def _get_count(self): "Returns the total number of objects, across all pages." if self._count is None: self._count = len(self.object_list) return self._count count = property(_get_count) def _get_num_pages(self): "Returns the total number of pages." if self._num_pages is None: hits = max(1, self.count - self.orphans) self._num_pages = int(ceil(hits / (float(self.per_page) or 1))) return self._num_pages num_pages = property(_get_num_pages) def _get_page_range(self): """ Returns a 1-based range of pages for iterating through within a template for loop. """ return list(range(1, self.num_pages + 1)) page_range = property(_get_page_range) class Page(object): def __init__(self, name, object_list, number, paginator, settings): self.name, self.extension = os.path.splitext(name) self.object_list = object_list self.number = number self.paginator = paginator self.settings = settings def __repr__(self): return '' % (self.number, self.paginator.num_pages) def has_next(self): return self.number < self.paginator.num_pages def has_previous(self): return self.number > 1 def has_other_pages(self): return self.has_previous() or self.has_next() def next_page_number(self): return self.number + 1 def previous_page_number(self): return self.number - 1 def start_index(self): """ Returns the 1-based index of the first object on this page, relative to total objects in the paginator. """ # Special case, return zero if no items. if self.paginator.count == 0: return 0 return (self.paginator.per_page * (self.number - 1)) + 1 def end_index(self): """ Returns the 1-based index of the last object on this page, relative to total objects found (hits). """ # Special case for the last page because there can be orphans. if self.number == self.paginator.num_pages: return self.paginator.count return self.number * self.paginator.per_page def _from_settings(self, key): """Returns URL information as defined in settings. Similar to URLWrapper._from_settings, but specialized to deal with pagination logic.""" rule = None # find the last matching pagination rule for p in self.settings['PAGINATION_PATTERNS']: if p.min_page <= self.number: rule = p if not rule: return '' prop_value = getattr(rule, key) if not isinstance(prop_value, six.string_types): logger.warning('%s is set to %s', key, prop_value) return prop_value # URL or SAVE_AS is a string, format it with a controlled context context = { 'name': self.name.replace(os.sep, '/'), 'object_list': self.object_list, 'number': self.number, 'paginator': self.paginator, 'settings': self.settings, 'base_name': os.path.dirname(self.name), 'number_sep': '/', 'extension': self.extension, } if self.number == 1: # no page numbers on the first page context['number'] = '' context['number_sep'] = '' ret = prop_value.format(**context) if ret[0] == '/': ret = ret[1:] return ret url = property(functools.partial(_from_settings, key='URL')) save_as = property(functools.partial(_from_settings, key='SAVE_AS')) pelican-3.7.1/pelican/readers.py000066400000000000000000000601241303525152100165470ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import logging import os import re from collections import OrderedDict import docutils import docutils.core import docutils.io from docutils.writers.html4css1 import HTMLTranslator import six from six.moves.html_parser import HTMLParser from pelican import rstdirectives # NOQA from pelican import signals from pelican.cache import FileStampDataCacher from pelican.contents import Author, Category, Page, Tag from pelican.utils import SafeDatetime, escape_html, get_date, pelican_open, \ posixize_path try: from markdown import Markdown except ImportError: Markdown = False # NOQA # Metadata processors have no way to discard an unwanted value, so we have # them return this value instead to signal that it should be discarded later. # This means that _filter_discardable_metadata() must be called on processed # metadata dicts before use, to remove the items with the special value. _DISCARD = object() METADATA_PROCESSORS = { 'tags': lambda x, y: ([ Tag(tag, y) for tag in ensure_metadata_list(x) ] or _DISCARD), 'date': lambda x, y: get_date(x.replace('_', ' ')), 'modified': lambda x, y: get_date(x), 'status': lambda x, y: x.strip() or _DISCARD, 'category': lambda x, y: _process_if_nonempty(Category, x, y), 'author': lambda x, y: _process_if_nonempty(Author, x, y), 'authors': lambda x, y: ([ Author(author, y) for author in ensure_metadata_list(x) ] or _DISCARD), 'slug': lambda x, y: x.strip() or _DISCARD, } logger = logging.getLogger(__name__) def ensure_metadata_list(text): """Canonicalize the format of a list of authors or tags. This works the same way as Docutils' "authors" field: if it's already a list, those boundaries are preserved; otherwise, it must be a string; if the string contains semicolons, it is split on semicolons; otherwise, it is split on commas. This allows you to write author lists in either "Jane Doe, John Doe" or "Doe, Jane; Doe, John" format. Regardless, all list items undergo .strip() before returning, and empty items are discarded. """ if isinstance(text, six.text_type): if ';' in text: text = text.split(';') else: text = text.split(',') return list(OrderedDict.fromkeys( [v for v in (w.strip() for w in text) if v] )) def _process_if_nonempty(processor, name, settings): """Removes extra whitespace from name and applies a metadata processor. If name is empty or all whitespace, returns _DISCARD instead. """ name = name.strip() return processor(name, settings) if name else _DISCARD def _filter_discardable_metadata(metadata): """Return a copy of a dict, minus any items marked as discardable.""" return {name: val for name, val in metadata.items() if val is not _DISCARD} class BaseReader(object): """Base class to read files. This class is used to process static files, and it can be inherited for other types of file. A Reader class must have the following attributes: - enabled: (boolean) tell if the Reader class is enabled. It generally depends on the import of some dependency. - file_extensions: a list of file extensions that the Reader will process. - extensions: a list of extensions to use in the reader (typical use is Markdown). """ enabled = True file_extensions = ['static'] extensions = None def __init__(self, settings): self.settings = settings def process_metadata(self, name, value): if name in METADATA_PROCESSORS: return METADATA_PROCESSORS[name](value, self.settings) return value def read(self, source_path): "No-op parser" content = None metadata = {} return content, metadata class _FieldBodyTranslator(HTMLTranslator): def __init__(self, document): HTMLTranslator.__init__(self, document) self.compact_p = None def astext(self): return ''.join(self.body) def visit_field_body(self, node): pass def depart_field_body(self, node): pass def render_node_to_html(document, node): visitor = _FieldBodyTranslator(document) node.walkabout(visitor) return visitor.astext() class PelicanHTMLTranslator(HTMLTranslator): def visit_abbreviation(self, node): attrs = {} if node.hasattr('explanation'): attrs['title'] = node['explanation'] self.body.append(self.starttag(node, 'abbr', '', **attrs)) def depart_abbreviation(self, node): self.body.append('') def visit_image(self, node): # set an empty alt if alt is not specified # avoids that alt is taken from src node['alt'] = node.get('alt', '') return HTMLTranslator.visit_image(self, node) class RstReader(BaseReader): """Reader for reStructuredText files""" enabled = bool(docutils) file_extensions = ['rst'] class FileInput(docutils.io.FileInput): """Patch docutils.io.FileInput to remove "U" mode in py3. Universal newlines is enabled by default and "U" mode is deprecated in py3. """ def __init__(self, *args, **kwargs): if six.PY3: kwargs['mode'] = kwargs.get('mode', 'r').replace('U', '') docutils.io.FileInput.__init__(self, *args, **kwargs) def __init__(self, *args, **kwargs): super(RstReader, self).__init__(*args, **kwargs) def _parse_metadata(self, document): """Return the dict containing document metadata""" formatted_fields = self.settings['FORMATTED_FIELDS'] output = {} for docinfo in document.traverse(docutils.nodes.docinfo): for element in docinfo.children: if element.tagname == 'field': # custom fields (e.g. summary) name_elem, body_elem = element.children name = name_elem.astext() if name in formatted_fields: value = render_node_to_html(document, body_elem) else: value = body_elem.astext() elif element.tagname == 'authors': # author list name = element.tagname value = [element.astext() for element in element.children] else: # standard fields (e.g. address) name = element.tagname value = element.astext() name = name.lower() output[name] = self.process_metadata(name, value) return output def _get_publisher(self, source_path): extra_params = {'initial_header_level': '2', 'syntax_highlight': 'short', 'input_encoding': 'utf-8', 'exit_status_level': 2, 'embed_stylesheet': False} user_params = self.settings.get('DOCUTILS_SETTINGS') if user_params: extra_params.update(user_params) pub = docutils.core.Publisher( source_class=self.FileInput, destination_class=docutils.io.StringOutput) pub.set_components('standalone', 'restructuredtext', 'html') pub.writer.translator_class = PelicanHTMLTranslator pub.process_programmatic_settings(None, extra_params, None) pub.set_source(source_path=source_path) pub.publish(enable_exit_status=True) return pub def read(self, source_path): """Parses restructured text""" pub = self._get_publisher(source_path) parts = pub.writer.parts content = parts.get('body') metadata = self._parse_metadata(pub.document) metadata.setdefault('title', parts.get('title')) return content, metadata class MarkdownReader(BaseReader): """Reader for Markdown files""" enabled = bool(Markdown) file_extensions = ['md', 'markdown', 'mkd', 'mdown'] def __init__(self, *args, **kwargs): super(MarkdownReader, self).__init__(*args, **kwargs) settings = self.settings['MARKDOWN'] settings.setdefault('extension_configs', {}) settings.setdefault('extensions', []) for extension in settings['extension_configs'].keys(): if extension not in settings['extensions']: settings['extensions'].append(extension) if 'markdown.extensions.meta' not in settings['extensions']: settings['extensions'].append('markdown.extensions.meta') self._source_path = None def _parse_metadata(self, meta): """Return the dict containing document metadata""" formatted_fields = self.settings['FORMATTED_FIELDS'] output = {} for name, value in meta.items(): name = name.lower() if name in formatted_fields: # formatted metadata is special case and join all list values formatted_values = "\n".join(value) # reset the markdown instance to clear any state self._md.reset() formatted = self._md.convert(formatted_values) output[name] = self.process_metadata(name, formatted) elif name in METADATA_PROCESSORS: if len(value) > 1: logger.warning( 'Duplicate definition of `%s` ' 'for %s. Using first one.', name, self._source_path) output[name] = self.process_metadata(name, value[0]) elif len(value) > 1: # handle list metadata as list of string output[name] = self.process_metadata(name, value) else: # otherwise, handle metadata as single string output[name] = self.process_metadata(name, value[0]) return output def read(self, source_path): """Parse content and metadata of markdown files""" self._source_path = source_path self._md = Markdown(**self.settings['MARKDOWN']) with pelican_open(source_path) as text: content = self._md.convert(text) if hasattr(self._md, 'Meta'): metadata = self._parse_metadata(self._md.Meta) else: metadata = {} return content, metadata class HTMLReader(BaseReader): """Parses HTML files as input, looking for meta, title, and body tags""" file_extensions = ['htm', 'html'] enabled = True class _HTMLParser(HTMLParser): def __init__(self, settings, filename): try: # Python 3.4+ HTMLParser.__init__(self, convert_charrefs=False) except TypeError: HTMLParser.__init__(self) self.body = '' self.metadata = {} self.settings = settings self._data_buffer = '' self._filename = filename self._in_top_level = True self._in_head = False self._in_title = False self._in_body = False self._in_tags = False def handle_starttag(self, tag, attrs): if tag == 'head' and self._in_top_level: self._in_top_level = False self._in_head = True elif tag == 'title' and self._in_head: self._in_title = True self._data_buffer = '' elif tag == 'body' and self._in_top_level: self._in_top_level = False self._in_body = True self._data_buffer = '' elif tag == 'meta' and self._in_head: self._handle_meta_tag(attrs) elif self._in_body: self._data_buffer += self.build_tag(tag, attrs, False) def handle_endtag(self, tag): if tag == 'head': if self._in_head: self._in_head = False self._in_top_level = True elif tag == 'title': self._in_title = False self.metadata['title'] = self._data_buffer elif tag == 'body': self.body = self._data_buffer self._in_body = False self._in_top_level = True elif self._in_body: self._data_buffer += ''.format(escape_html(tag)) def handle_startendtag(self, tag, attrs): if tag == 'meta' and self._in_head: self._handle_meta_tag(attrs) if self._in_body: self._data_buffer += self.build_tag(tag, attrs, True) def handle_comment(self, data): self._data_buffer += ''.format(data) def handle_data(self, data): self._data_buffer += data def handle_entityref(self, data): self._data_buffer += '&{};'.format(data) def handle_charref(self, data): self._data_buffer += '&#{};'.format(data) def build_tag(self, tag, attrs, close_tag): result = '<{}'.format(escape_html(tag)) for k, v in attrs: result += ' ' + escape_html(k) if v is not None: # If the attribute value contains a double quote, surround # with single quotes, otherwise use double quotes. if '"' in v: result += "='{}'".format(escape_html(v, quote=False)) else: result += '="{}"'.format(escape_html(v, quote=False)) if close_tag: return result + ' />' return result + '>' def _handle_meta_tag(self, attrs): name = self._attr_value(attrs, 'name') if name is None: attr_list = ['{}="{}"'.format(k, v) for k, v in attrs] attr_serialized = ', '.join(attr_list) logger.warning("Meta tag in file %s does not have a 'name' " "attribute, skipping. Attributes: %s", self._filename, attr_serialized) return name = name.lower() contents = self._attr_value(attrs, 'content', '') if not contents: contents = self._attr_value(attrs, 'contents', '') if contents: logger.warning( "Meta tag attribute 'contents' used in file %s, should" " be changed to 'content'", self._filename, extra={'limit_msg': "Other files have meta tag " "attribute 'contents' that should " "be changed to 'content'"}) if name == 'keywords': name = 'tags' self.metadata[name] = contents @classmethod def _attr_value(cls, attrs, name, default=None): return next((x[1] for x in attrs if x[0] == name), default) def read(self, filename): """Parse content and metadata of HTML files""" with pelican_open(filename) as content: parser = self._HTMLParser(self.settings, filename) parser.feed(content) parser.close() metadata = {} for k in parser.metadata: metadata[k] = self.process_metadata(k, parser.metadata[k]) return parser.body, metadata class Readers(FileStampDataCacher): """Interface for all readers. This class contains a mapping of file extensions / Reader classes, to know which Reader class must be used to read a file (based on its extension). This is customizable both with the 'READERS' setting, and with the 'readers_init' signall for plugins. """ def __init__(self, settings=None, cache_name=''): self.settings = settings or {} self.readers = {} self.reader_classes = {} for cls in [BaseReader] + BaseReader.__subclasses__(): if not cls.enabled: logger.debug('Missing dependencies for %s', ', '.join(cls.file_extensions)) continue for ext in cls.file_extensions: self.reader_classes[ext] = cls if self.settings['READERS']: self.reader_classes.update(self.settings['READERS']) signals.readers_init.send(self) for fmt, reader_class in self.reader_classes.items(): if not reader_class: continue self.readers[fmt] = reader_class(self.settings) # set up caching cache_this_level = (cache_name != '' and self.settings['CONTENT_CACHING_LAYER'] == 'reader') caching_policy = cache_this_level and self.settings['CACHE_CONTENT'] load_policy = cache_this_level and self.settings['LOAD_CONTENT_CACHE'] super(Readers, self).__init__(settings, cache_name, caching_policy, load_policy, ) @property def extensions(self): return self.readers.keys() def read_file(self, base_path, path, content_class=Page, fmt=None, context=None, preread_signal=None, preread_sender=None, context_signal=None, context_sender=None): """Return a content object parsed with the given format.""" path = os.path.abspath(os.path.join(base_path, path)) source_path = posixize_path(os.path.relpath(path, base_path)) logger.debug( 'Read file %s -> %s', source_path, content_class.__name__) if not fmt: _, ext = os.path.splitext(os.path.basename(path)) fmt = ext[1:] if fmt not in self.readers: raise TypeError( 'Pelican does not know how to parse %s', path) if preread_signal: logger.debug( 'Signal %s.send(%s)', preread_signal.name, preread_sender) preread_signal.send(preread_sender) reader = self.readers[fmt] metadata = _filter_discardable_metadata(default_metadata( settings=self.settings, process=reader.process_metadata)) metadata.update(path_metadata( full_path=path, source_path=source_path, settings=self.settings)) metadata.update(_filter_discardable_metadata(parse_path_metadata( source_path=source_path, settings=self.settings, process=reader.process_metadata))) reader_name = reader.__class__.__name__ metadata['reader'] = reader_name.replace('Reader', '').lower() content, reader_metadata = self.get_cached_data(path, (None, None)) if content is None: content, reader_metadata = reader.read(path) self.cache_data(path, (content, reader_metadata)) metadata.update(_filter_discardable_metadata(reader_metadata)) if content: # find images with empty alt find_empty_alt(content, path) # eventually filter the content with typogrify if asked so if self.settings['TYPOGRIFY']: from typogrify.filters import typogrify import smartypants # Tell `smartypants` to also replace " HTML entities with # smart quotes. This is necessary because Docutils has already # replaced double quotes with said entities by the time we run # this filter. smartypants.Attr.default |= smartypants.Attr.w def typogrify_wrapper(text): """Ensures ignore_tags feature is backward compatible""" try: return typogrify( text, self.settings['TYPOGRIFY_IGNORE_TAGS']) except TypeError: return typogrify(text) if content: content = typogrify_wrapper(content) if 'title' in metadata: metadata['title'] = typogrify_wrapper(metadata['title']) if 'summary' in metadata: metadata['summary'] = typogrify_wrapper(metadata['summary']) if context_signal: logger.debug( 'Signal %s.send(%s, )', context_signal.name, context_sender) context_signal.send(context_sender, metadata=metadata) return content_class(content=content, metadata=metadata, settings=self.settings, source_path=path, context=context) def find_empty_alt(content, path): """Find images with empty alt Create warnings for all images with empty alt (up to a certain number), as they are really likely to be accessibility flaws. """ imgs = re.compile(r""" (?: # src before alt ]* src=(['"])(.*?)\1 [^\>]* alt=(['"])\3 )|(?: # alt before src ]* alt=(['"])\4 [^\>]* src=(['"])(.*?)\5 ) """, re.X) for match in re.findall(imgs, content): logger.warning( 'Empty alt attribute for image %s in %s', os.path.basename(match[1] + match[5]), path, extra={'limit_msg': 'Other images have empty alt attributes'}) def default_metadata(settings=None, process=None): metadata = {} if settings: for name, value in dict(settings.get('DEFAULT_METADATA', {})).items(): if process: value = process(name, value) metadata[name] = value if 'DEFAULT_CATEGORY' in settings: value = settings['DEFAULT_CATEGORY'] if process: value = process('category', value) metadata['category'] = value if settings.get('DEFAULT_DATE', None) and \ settings['DEFAULT_DATE'] != 'fs': if isinstance(settings['DEFAULT_DATE'], six.string_types): metadata['date'] = get_date(settings['DEFAULT_DATE']) else: metadata['date'] = SafeDatetime(*settings['DEFAULT_DATE']) return metadata def path_metadata(full_path, source_path, settings=None): metadata = {} if settings: if settings.get('DEFAULT_DATE', None) == 'fs': metadata['date'] = SafeDatetime.fromtimestamp( os.stat(full_path).st_mtime) metadata.update(settings.get('EXTRA_PATH_METADATA', {}).get( source_path, {})) return metadata def parse_path_metadata(source_path, settings=None, process=None): """Extract a metadata dictionary from a file's path >>> import pprint >>> settings = { ... 'FILENAME_METADATA': '(?P[^.]*).*', ... 'PATH_METADATA': ... '(?P[^/]*)/(?P\d{4}-\d{2}-\d{2})/.*', ... } >>> reader = BaseReader(settings=settings) >>> metadata = parse_path_metadata( ... source_path='my-cat/2013-01-01/my-slug.html', ... settings=settings, ... process=reader.process_metadata) >>> pprint.pprint(metadata) # doctest: +ELLIPSIS {'category': , 'date': SafeDatetime(2013, 1, 1, 0, 0), 'slug': 'my-slug'} """ metadata = {} dirname, basename = os.path.split(source_path) base, ext = os.path.splitext(basename) subdir = os.path.basename(dirname) if settings: checks = [] for key, data in [('FILENAME_METADATA', base), ('PATH_METADATA', source_path)]: checks.append((settings.get(key, None), data)) if settings.get('USE_FOLDER_AS_CATEGORY', None): checks.append(('(?P.*)', subdir)) for regexp, data in checks: if regexp and data: match = re.match(regexp, data) if match: # .items() for py3k compat. for k, v in match.groupdict().items(): k = k.lower() # metadata must be lowercase if k not in metadata: if process: v = process(k, v) metadata[k] = v return metadata pelican-3.7.1/pelican/rstdirectives.py000066400000000000000000000057171303525152100200230ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import re from docutils import nodes, utils from docutils.parsers.rst import Directive, directives, roles from pygments import highlight from pygments.formatters import HtmlFormatter from pygments.lexers import TextLexer, get_lexer_by_name import six import pelican.settings as pys class Pygments(Directive): """ Source code syntax highlighting. """ required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True option_spec = { 'anchorlinenos': directives.flag, 'classprefix': directives.unchanged, 'hl_lines': directives.unchanged, 'lineanchors': directives.unchanged, 'linenos': directives.unchanged, 'linenospecial': directives.nonnegative_int, 'linenostart': directives.nonnegative_int, 'linenostep': directives.nonnegative_int, 'lineseparator': directives.unchanged, 'linespans': directives.unchanged, 'nobackground': directives.flag, 'nowrap': directives.flag, 'tagsfile': directives.unchanged, 'tagurlformat': directives.unchanged, } has_content = True def run(self): self.assert_has_content() try: lexer = get_lexer_by_name(self.arguments[0]) except ValueError: # no lexer found - use the text one instead of an exception lexer = TextLexer() # Fetch the defaults if pys.PYGMENTS_RST_OPTIONS is not None: for k, v in six.iteritems(pys.PYGMENTS_RST_OPTIONS): # Locally set options overrides the defaults if k not in self.options: self.options[k] = v if ('linenos' in self.options and self.options['linenos'] not in ('table', 'inline')): if self.options['linenos'] == 'none': self.options.pop('linenos') else: self.options['linenos'] = 'table' for flag in ('nowrap', 'nobackground', 'anchorlinenos'): if flag in self.options: self.options[flag] = True # noclasses should already default to False, but just in case... formatter = HtmlFormatter(noclasses=False, **self.options) parsed = highlight('\n'.join(self.content), lexer, formatter) return [nodes.raw('', parsed, format='html')] directives.register_directive('code-block', Pygments) directives.register_directive('sourcecode', Pygments) _abbr_re = re.compile('\((.*)\)$', re.DOTALL) class abbreviation(nodes.Inline, nodes.TextElement): pass def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) m = _abbr_re.search(text) if m is None: return [abbreviation(text, text)], [] abbr = text[:m.start()].strip() expl = m.group(1) return [abbreviation(abbr, abbr, explanation=expl)], [] roles.register_local_role('abbr', abbr_role) pelican-3.7.1/pelican/server.py000066400000000000000000000045221303525152100164300ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import logging import os import sys try: from magic import from_file as magic_from_file except ImportError: magic_from_file = None from six.moves import SimpleHTTPServer as srvmod from six.moves import socketserver class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler): SUFFIXES = ['', '.html', '/index.html'] def do_GET(self): # cut off a query string if '?' in self.path: self.path, _ = self.path.split('?', 1) # Try to detect file by applying various suffixes for suffix in self.SUFFIXES: if not hasattr(self, 'original_path'): self.original_path = self.path self.path = self.original_path + suffix path = self.translate_path(self.path) if os.path.exists(path): srvmod.SimpleHTTPRequestHandler.do_GET(self) logging.info("Found `%s`." % self.path) break logging.info("Tried to find `%s`, but it doesn't exist.", self.path) else: # Fallback if there were no matches logging.warning("Unable to find `%s` or variations.", self.original_path) def guess_type(self, path): """Guess at the mime type for the specified file. """ mimetype = srvmod.SimpleHTTPRequestHandler.guess_type(self, path) # If the default guess is too generic, try the python-magic library if mimetype == 'application/octet-stream' and magic_from_file: mimetype = magic_from_file(path, mime=True) return mimetype if __name__ == '__main__': PORT = len(sys.argv) in (2, 3) and int(sys.argv[1]) or 8000 SERVER = len(sys.argv) == 3 and sys.argv[2] or "" socketserver.TCPServer.allow_reuse_address = True try: httpd = socketserver.TCPServer( (SERVER, PORT), ComplexHTTPRequestHandler) except OSError as e: logging.error("Could not listen on port %s, server %s.", PORT, SERVER) sys.exit(getattr(e, 'exitcode', 1)) logging.info("Serving at port %s, server %s.", PORT, SERVER) try: httpd.serve_forever() except KeyboardInterrupt as e: logging.info("Shutting down server.") httpd.socket.close() pelican-3.7.1/pelican/settings.py000066400000000000000000000376361303525152100167760ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import copy import inspect import locale import logging import os from os.path import isabs from posixpath import join as posix_join import six from pelican.log import LimitFilter try: # SourceFileLoader is the recommended way in 3.3+ from importlib.machinery import SourceFileLoader def load_source(name, path): return SourceFileLoader(name, path).load_module() except ImportError: # but it does not exist in 3.2-, so fall back to imp import imp load_source = imp.load_source logger = logging.getLogger(__name__) DEFAULT_THEME = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'themes', 'notmyidea') DEFAULT_CONFIG = { 'PATH': os.curdir, 'ARTICLE_PATHS': [''], 'ARTICLE_EXCLUDES': [], 'PAGE_PATHS': ['pages'], 'PAGE_EXCLUDES': [], 'THEME': DEFAULT_THEME, 'OUTPUT_PATH': 'output', 'READERS': {}, 'STATIC_PATHS': ['images'], 'STATIC_EXCLUDES': [], 'STATIC_EXCLUDE_SOURCES': True, 'THEME_STATIC_DIR': 'theme', 'THEME_STATIC_PATHS': ['static', ], 'FEED_ALL_ATOM': posix_join('feeds', 'all.atom.xml'), 'CATEGORY_FEED_ATOM': posix_join('feeds', '%s.atom.xml'), 'AUTHOR_FEED_ATOM': posix_join('feeds', '%s.atom.xml'), 'AUTHOR_FEED_RSS': posix_join('feeds', '%s.rss.xml'), 'TRANSLATION_FEED_ATOM': posix_join('feeds', 'all-%s.atom.xml'), 'FEED_MAX_ITEMS': '', 'RSS_FEED_SUMMARY_ONLY': True, 'SITEURL': '', 'SITENAME': 'A Pelican Blog', 'DISPLAY_PAGES_ON_MENU': True, 'DISPLAY_CATEGORIES_ON_MENU': True, 'DOCUTILS_SETTINGS': {}, 'OUTPUT_SOURCES': False, 'OUTPUT_SOURCES_EXTENSION': '.text', 'USE_FOLDER_AS_CATEGORY': True, 'DEFAULT_CATEGORY': 'misc', 'WITH_FUTURE_DATES': True, 'CSS_FILE': 'main.css', 'NEWEST_FIRST_ARCHIVES': True, 'REVERSE_CATEGORY_ORDER': False, 'DELETE_OUTPUT_DIRECTORY': False, 'OUTPUT_RETENTION': [], 'INDEX_SAVE_AS': 'index.html', 'ARTICLE_URL': '{slug}.html', 'ARTICLE_SAVE_AS': '{slug}.html', 'ARTICLE_ORDER_BY': 'reversed-date', 'ARTICLE_LANG_URL': '{slug}-{lang}.html', 'ARTICLE_LANG_SAVE_AS': '{slug}-{lang}.html', 'DRAFT_URL': 'drafts/{slug}.html', 'DRAFT_SAVE_AS': posix_join('drafts', '{slug}.html'), 'DRAFT_LANG_URL': 'drafts/{slug}-{lang}.html', 'DRAFT_LANG_SAVE_AS': posix_join('drafts', '{slug}-{lang}.html'), 'PAGE_URL': 'pages/{slug}.html', 'PAGE_SAVE_AS': posix_join('pages', '{slug}.html'), 'PAGE_ORDER_BY': 'basename', 'PAGE_LANG_URL': 'pages/{slug}-{lang}.html', 'PAGE_LANG_SAVE_AS': posix_join('pages', '{slug}-{lang}.html'), 'STATIC_URL': '{path}', 'STATIC_SAVE_AS': '{path}', 'CATEGORY_URL': 'category/{slug}.html', 'CATEGORY_SAVE_AS': posix_join('category', '{slug}.html'), 'TAG_URL': 'tag/{slug}.html', 'TAG_SAVE_AS': posix_join('tag', '{slug}.html'), 'AUTHOR_URL': 'author/{slug}.html', 'AUTHOR_SAVE_AS': posix_join('author', '{slug}.html'), 'PAGINATION_PATTERNS': [ (0, '{name}{number}{extension}', '{name}{number}{extension}'), ], 'YEAR_ARCHIVE_SAVE_AS': '', 'MONTH_ARCHIVE_SAVE_AS': '', 'DAY_ARCHIVE_SAVE_AS': '', 'RELATIVE_URLS': False, 'DEFAULT_LANG': 'en', 'DIRECT_TEMPLATES': ['index', 'tags', 'categories', 'authors', 'archives'], 'EXTRA_TEMPLATES_PATHS': [], 'PAGINATED_DIRECT_TEMPLATES': ['index'], 'PELICAN_CLASS': 'pelican.Pelican', 'DEFAULT_DATE_FORMAT': '%a %d %B %Y', 'DATE_FORMATS': {}, 'MARKDOWN': { 'extension_configs': { 'markdown.extensions.codehilite': {'css_class': 'highlight'}, 'markdown.extensions.extra': {}, 'markdown.extensions.meta': {}, }, 'output_format': 'html5', }, 'JINJA_FILTERS': {}, 'JINJA_ENVIRONMENT': { 'trim_blocks': True, 'lstrip_blocks': True, 'extensions': [], }, 'LOG_FILTER': [], 'LOCALE': [''], # defaults to user locale 'DEFAULT_PAGINATION': False, 'DEFAULT_ORPHANS': 0, 'DEFAULT_METADATA': {}, 'FILENAME_METADATA': '(?P\d{4}-\d{2}-\d{2}).*', 'PATH_METADATA': '', 'EXTRA_PATH_METADATA': {}, 'DEFAULT_STATUS': 'published', 'ARTICLE_PERMALINK_STRUCTURE': '', 'TYPOGRIFY': False, 'TYPOGRIFY_IGNORE_TAGS': [], 'SUMMARY_MAX_LENGTH': 50, 'PLUGIN_PATHS': [], 'PLUGINS': [], 'PYGMENTS_RST_OPTIONS': {}, 'TEMPLATE_PAGES': {}, 'IGNORE_FILES': ['.#*'], 'SLUG_SUBSTITUTIONS': (), 'INTRASITE_LINK_REGEX': '[{|](?P.*?)[|}]', 'SLUGIFY_SOURCE': 'title', 'CACHE_CONTENT': False, 'CONTENT_CACHING_LAYER': 'reader', 'CACHE_PATH': 'cache', 'GZIP_CACHE': True, 'CHECK_MODIFIED_METHOD': 'mtime', 'LOAD_CONTENT_CACHE': False, 'WRITE_SELECTED': [], 'FORMATTED_FIELDS': ['summary'], } PYGMENTS_RST_OPTIONS = None def read_settings(path=None, override=None): if path: local_settings = get_settings_from_file(path) # Make the paths relative to the settings file for p in ['PATH', 'OUTPUT_PATH', 'THEME', 'CACHE_PATH']: if p in local_settings and local_settings[p] is not None \ and not isabs(local_settings[p]): absp = os.path.abspath(os.path.normpath(os.path.join( os.path.dirname(path), local_settings[p]))) if p != 'THEME' or os.path.exists(absp): local_settings[p] = absp if 'PLUGIN_PATH' in local_settings: logger.warning('PLUGIN_PATH setting has been replaced by ' 'PLUGIN_PATHS, moving it to the new setting name.') local_settings['PLUGIN_PATHS'] = local_settings['PLUGIN_PATH'] del local_settings['PLUGIN_PATH'] if 'JINJA_EXTENSIONS' in local_settings: logger.warning('JINJA_EXTENSIONS setting has been deprecated, ' 'moving it to JINJA_ENVIRONMENT setting.') local_settings['JINJA_ENVIRONMENT']['extensions'] = \ local_settings['JINJA_EXTENSIONS'] del local_settings['JINJA_EXTENSIONS'] if isinstance(local_settings['PLUGIN_PATHS'], six.string_types): logger.warning("Defining PLUGIN_PATHS setting as string " "has been deprecated (should be a list)") local_settings['PLUGIN_PATHS'] = [local_settings['PLUGIN_PATHS']] elif local_settings['PLUGIN_PATHS'] is not None: def getabs(path, pluginpath): if isabs(pluginpath): return pluginpath else: path_dirname = os.path.dirname(path) path_joined = os.path.join(path_dirname, pluginpath) path_normed = os.path.normpath(path_joined) path_absolute = os.path.abspath(path_normed) return path_absolute pluginpath_list = [getabs(path, pluginpath) for pluginpath in local_settings['PLUGIN_PATHS']] local_settings['PLUGIN_PATHS'] = pluginpath_list else: local_settings = copy.deepcopy(DEFAULT_CONFIG) if override: local_settings.update(override) parsed_settings = configure_settings(local_settings) # This is because there doesn't seem to be a way to pass extra # parameters to docutils directive handlers, so we have to have a # variable here that we'll import from within Pygments.run (see # rstdirectives.py) to see what the user defaults were. global PYGMENTS_RST_OPTIONS PYGMENTS_RST_OPTIONS = parsed_settings.get('PYGMENTS_RST_OPTIONS', None) return parsed_settings def get_settings_from_module(module=None, default_settings=DEFAULT_CONFIG): """Loads settings from a module, returns a dictionary.""" context = copy.deepcopy(default_settings) if module is not None: context.update( (k, v) for k, v in inspect.getmembers(module) if k.isupper()) return context def get_settings_from_file(path, default_settings=DEFAULT_CONFIG): """Loads settings from a file path, returning a dict.""" name, ext = os.path.splitext(os.path.basename(path)) module = load_source(name, path) return get_settings_from_module(module, default_settings=default_settings) def get_jinja_environment(settings): """Sets the environment for Jinja""" jinja_env = settings.setdefault('JINJA_ENVIRONMENT', DEFAULT_CONFIG['JINJA_ENVIRONMENT']) # Make sure we include the defaults if the user has set env variables for key, value in DEFAULT_CONFIG['JINJA_ENVIRONMENT'].items(): if key not in jinja_env: jinja_env[key] = value return settings def configure_settings(settings): """Provide optimizations, error checking, and warnings for the given settings. Also, specify the log messages to be ignored. """ if 'PATH' not in settings or not os.path.isdir(settings['PATH']): raise Exception('You need to specify a path containing the content' ' (see pelican --help for more information)') # specify the log messages to be ignored log_filter = settings.get('LOG_FILTER', DEFAULT_CONFIG['LOG_FILTER']) LimitFilter._ignore.update(set(log_filter)) # lookup the theme in "pelican/themes" if the given one doesn't exist if not os.path.isdir(settings['THEME']): theme_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'themes', settings['THEME']) if os.path.exists(theme_path): settings['THEME'] = theme_path else: raise Exception("Could not find the theme %s" % settings['THEME']) # make paths selected for writing absolute if necessary settings['WRITE_SELECTED'] = [ os.path.abspath(path) for path in settings.get('WRITE_SELECTED', DEFAULT_CONFIG['WRITE_SELECTED']) ] # standardize strings to lowercase strings for key in ['DEFAULT_LANG']: if key in settings: settings[key] = settings[key].lower() # set defaults for Jinja environment settings = get_jinja_environment(settings) # standardize strings to lists for key in ['LOCALE']: if key in settings and isinstance(settings[key], six.string_types): settings[key] = [settings[key]] # check settings that must be a particular type for key, types in [ ('OUTPUT_SOURCES_EXTENSION', six.string_types), ('FILENAME_METADATA', six.string_types), ]: if key in settings and not isinstance(settings[key], types): value = settings.pop(key) logger.warn( 'Detected misconfigured %s (%s), ' 'falling back to the default (%s)', key, value, DEFAULT_CONFIG[key]) # try to set the different locales, fallback on the default. locales = settings.get('LOCALE', DEFAULT_CONFIG['LOCALE']) for locale_ in locales: try: locale.setlocale(locale.LC_ALL, str(locale_)) break # break if it is successful except locale.Error: pass else: logger.warning( "Locale could not be set. Check the LOCALE setting, ensuring it " "is valid and available on your system.") if ('SITEURL' in settings): # If SITEURL has a trailing slash, remove it and provide a warning siteurl = settings['SITEURL'] if (siteurl.endswith('/')): settings['SITEURL'] = siteurl[:-1] logger.warning("Removed extraneous trailing slash from SITEURL.") # If SITEURL is defined but FEED_DOMAIN isn't, # set FEED_DOMAIN to SITEURL if 'FEED_DOMAIN' not in settings: settings['FEED_DOMAIN'] = settings['SITEURL'] # check content caching layer and warn of incompatibilities if settings.get('CACHE_CONTENT', False) and \ settings.get('CONTENT_CACHING_LAYER', '') == 'generator' and \ settings.get('WITH_FUTURE_DATES', False): logger.warning( "WITH_FUTURE_DATES conflicts with CONTENT_CACHING_LAYER " "set to 'generator', use 'reader' layer instead") # Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined feed_keys = [ 'FEED_ATOM', 'FEED_RSS', 'FEED_ALL_ATOM', 'FEED_ALL_RSS', 'CATEGORY_FEED_ATOM', 'CATEGORY_FEED_RSS', 'AUTHOR_FEED_ATOM', 'AUTHOR_FEED_RSS', 'TAG_FEED_ATOM', 'TAG_FEED_RSS', 'TRANSLATION_FEED_ATOM', 'TRANSLATION_FEED_RSS', ] if any(settings.get(k) for k in feed_keys): if not settings.get('SITEURL'): logger.warning('Feeds generated without SITEURL set properly may' ' not be valid') if 'TIMEZONE' not in settings: logger.warning( 'No timezone information specified in the settings. Assuming' ' your timezone is UTC for feed generation. Check ' 'http://docs.getpelican.com/en/latest/settings.html#timezone ' 'for more information') # fix up pagination rules from pelican.paginator import PaginationRule pagination_rules = [ PaginationRule(*r) for r in settings.get( 'PAGINATION_PATTERNS', DEFAULT_CONFIG['PAGINATION_PATTERNS'], ) ] settings['PAGINATION_PATTERNS'] = sorted( pagination_rules, key=lambda r: r[0], ) # move {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS for key in ['ARTICLE', 'PAGE']: old_key = key + '_DIR' new_key = key + '_PATHS' if old_key in settings: logger.warning( 'Deprecated setting %s, moving it to %s list', old_key, new_key) settings[new_key] = [settings[old_key]] # also make a list del settings[old_key] # Save people from accidentally setting a string rather than a list path_keys = ( 'ARTICLE_EXCLUDES', 'DEFAULT_METADATA', 'DIRECT_TEMPLATES', 'EXTRA_TEMPLATES_PATHS', 'FILES_TO_COPY', 'IGNORE_FILES', 'PAGINATED_DIRECT_TEMPLATES', 'PLUGINS', 'STATIC_EXCLUDES', 'STATIC_PATHS', 'THEME_STATIC_PATHS', 'ARTICLE_PATHS', 'PAGE_PATHS', ) for PATH_KEY in filter(lambda k: k in settings, path_keys): if isinstance(settings[PATH_KEY], six.string_types): logger.warning("Detected misconfiguration with %s setting " "(must be a list), falling back to the default", PATH_KEY) settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY] # Deprecated warning of MD_EXTENSIONS if 'MD_EXTENSIONS' in settings: logger.warning('MD_EXTENSIONS is deprecated use MARKDOWN ' 'instead. Falling back to the default.') settings['MARKDOWN'] = DEFAULT_CONFIG['MARKDOWN'] # Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES mutually_exclusive = ('ARTICLE', 'PAGE') for type_1, type_2 in [mutually_exclusive, mutually_exclusive[::-1]]: try: includes = settings[type_1 + '_PATHS'] excludes = settings[type_2 + '_EXCLUDES'] for path in includes: if path not in excludes: excludes.append(path) except KeyError: continue # setting not specified, nothing to do for old, new, doc in [ ('LESS_GENERATOR', 'the Webassets plugin', None), ('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA', 'https://github.com/getpelican/pelican/' 'blob/master/docs/settings.rst#path-metadata'), ]: if old in settings: message = 'The {} setting has been removed in favor of {}'.format( old, new) if doc: message += ', see {} for details'.format(doc) logger.warning(message) return settings pelican-3.7.1/pelican/signals.py000066400000000000000000000032001303525152100165520ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals from blinker import signal # Run-level signals: initialized = signal('pelican_initialized') get_generators = signal('get_generators') all_generators_finalized = signal('all_generators_finalized') get_writer = signal('get_writer') finalized = signal('pelican_finalized') # Reader-level signals readers_init = signal('readers_init') # Generator-level signals generator_init = signal('generator_init') article_generator_init = signal('article_generator_init') article_generator_pretaxonomy = signal('article_generator_pretaxonomy') article_generator_finalized = signal('article_generator_finalized') article_generator_write_article = signal('article_generator_write_article') article_writer_finalized = signal('article_writer_finalized') page_generator_init = signal('page_generator_init') page_generator_finalized = signal('page_generator_finalized') page_writer_finalized = signal('page_writer_finalized') static_generator_init = signal('static_generator_init') static_generator_finalized = signal('static_generator_finalized') # Page-level signals article_generator_preread = signal('article_generator_preread') article_generator_context = signal('article_generator_context') page_generator_preread = signal('page_generator_preread') page_generator_context = signal('page_generator_context') static_generator_preread = signal('static_generator_preread') static_generator_context = signal('static_generator_context') content_object_init = signal('content_object_init') # Writers signals content_written = signal('content_written') feed_written = signal('feed_written') pelican-3.7.1/pelican/tests/000077500000000000000000000000001303525152100157075ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/TestPages/000077500000000000000000000000001303525152100176065ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/TestPages/bad_page.rst000066400000000000000000000002611303525152100220610ustar00rootroot00000000000000This is a test bad page ####################### :status: invalid The quick brown fox jumped over the lazy dog's back. The status here is invalid, the page should not render. pelican-3.7.1/pelican/tests/TestPages/hidden_page.rst000066400000000000000000000002221303525152100225630ustar00rootroot00000000000000This is a test hidden page ########################## :status: hidden The quick brown fox jumped over the lazy dog's back. This page is hidden pelican-3.7.1/pelican/tests/TestPages/hidden_page_markdown.md000066400000000000000000000003471303525152100242650ustar00rootroot00000000000000title: This is a markdown test hidden page status: hidden Test Markdown File Header ========================= Used for pelican test --------------------- The quick brown fox jumped over the lazy dog's back. This page is hidden pelican-3.7.1/pelican/tests/TestPages/hidden_page_with_template.rst000066400000000000000000000004161303525152100255160ustar00rootroot00000000000000This is a test hidden page with a custom template ################################################# :status: hidden :template: custom The quick brown fox jumped over the lazy dog's back. This page is hidden This page has a custom template to be called when rendered pelican-3.7.1/pelican/tests/TestPages/page.rst000066400000000000000000000001361303525152100212540ustar00rootroot00000000000000This is a test page ################### The quick brown fox jumped over the lazy dog's back. pelican-3.7.1/pelican/tests/TestPages/page_markdown.md000066400000000000000000000002741303525152100227510ustar00rootroot00000000000000title: This is a markdown test page Test Markdown File Header ========================= Used for pelican test --------------------- The quick brown fox jumped over the lazy dog's back. pelican-3.7.1/pelican/tests/TestPages/page_used_for_sorting_test.rst000066400000000000000000000002061303525152100257440ustar00rootroot00000000000000A Page (Test) for sorting ######################### :slug: zzzz When using title, should be first. When using slug, should be last. pelican-3.7.1/pelican/tests/TestPages/page_with_category_and_tag_links.md000066400000000000000000000001411303525152100266450ustar00rootroot00000000000000Title: Page with a bunch of links My links: [Link 1]({tag}マック) [Link 2]({category}Yeah) pelican-3.7.1/pelican/tests/TestPages/page_with_template.rst000066400000000000000000000003361303525152100242040ustar00rootroot00000000000000This is a test page with a preset template ########################################## :template: custom The quick brown fox jumped over the lazy dog's back. This article has a custom template to be called when rendered pelican-3.7.1/pelican/tests/__init__.py000066400000000000000000000007171303525152100200250ustar00rootroot00000000000000import logging import warnings from pelican.log import log_warnings # redirect warnings modulole to use logging instead log_warnings() # setup warnings to log DeprecationWarning's and error on # warnings in pelican's codebase warnings.simplefilter("default", DeprecationWarning) warnings.filterwarnings("error", ".*", Warning, "pelican") # Add a NullHandler to silence warning about no available handlers logging.getLogger().addHandler(logging.NullHandler()) pelican-3.7.1/pelican/tests/content/000077500000000000000000000000001303525152100173615ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/content/2012-11-29_rst_w_filename_meta#foo-bar.rst000066400000000000000000000001431303525152100265410ustar00rootroot00000000000000 Rst with filename metadata ########################## :category: yeah :author: Alexis Métaireau pelican-3.7.1/pelican/tests/content/2012-11-30_md_w_filename_meta#foo-bar.md000066400000000000000000000001531303525152100261120ustar00rootroot00000000000000category: yeah author: Alexis Métaireau Markdown with filename metadata =============================== pelican-3.7.1/pelican/tests/content/TestCategory/000077500000000000000000000000001303525152100217765ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/content/TestCategory/article_with_category.rst000066400000000000000000000002251303525152100271020ustar00rootroot00000000000000This is an article with category ! ################################## :category: yeah :date: 1970-01-01 This article should be in 'yeah' category. pelican-3.7.1/pelican/tests/content/TestCategory/article_without_category.rst000066400000000000000000000002001303525152100276230ustar00rootroot00000000000000This is an article without category ! ##################################### This article should be in 'TestCategory' category. pelican-3.7.1/pelican/tests/content/article.rst000066400000000000000000000002251303525152100215350ustar00rootroot00000000000000Article title ############# THIS is some content. With some stuff to "typogrify"... Now with added support for :abbr:`TLA (three letter acronym)`. pelican-3.7.1/pelican/tests/content/article_with_attributes_containing_double_quotes.html000066400000000000000000000006311303525152100323360ustar00rootroot00000000000000 Ensure that if an attribute value contains a double quote, it is surrounded with single quotes, otherwise with double quotes. Span content Span content Span content pelican-3.7.1/pelican/tests/content/article_with_code_block.rst000066400000000000000000000003161303525152100247350ustar00rootroot00000000000000An Article With Code Block To Test Typogrify Ignore ################################################### An article with some code .. code-block:: python x & y A block quote: x & y Normal: x & y pelican-3.7.1/pelican/tests/content/article_with_comments.html000066400000000000000000000002341303525152100246310ustar00rootroot00000000000000 Body content pelican-3.7.1/pelican/tests/content/article_with_duplicate_tags_authors.md000066400000000000000000000005561303525152100272040ustar00rootroot00000000000000Title: Test metadata duplicates Category: test Tags: foo, bar, foobar, foo, bar Authors: Author, First; Author, Second; Author, First Date: 2010-12-02 10:14 Modified: 2010-12-02 10:20 Summary: I have a lot to test Test Markdown File Header ========================= Used for pelican test --------------------- The quick brown fox jumped over the lazy dog's back. pelican-3.7.1/pelican/tests/content/article_with_keywords.html000066400000000000000000000002231303525152100246510ustar00rootroot00000000000000 This is a super article ! pelican-3.7.1/pelican/tests/content/article_with_markdown_and_footnote.md000066400000000000000000000010701303525152100270200ustar00rootroot00000000000000Title: Article with markdown containing footnotes Date: 2012-10-31 Modified: 2012-11-01 Summary: Summary with **inline** markup *should* be supported. Multiline: Line Metadata should be handle properly. See syntax of Meta-Data extension of Python Markdown package: If a line is indented by 4 or more spaces, that line is assumed to be an additional line of the value for the previous keyword. A keyword may have as many lines as desired. This is some content[^1] with some footnotes[^footnote] [^1]: Numbered footnote [^footnote]: Named footnote pelican-3.7.1/pelican/tests/content/article_with_markdown_and_nonascii_summary.md000066400000000000000000000011111303525152100305370ustar00rootroot00000000000000Title: マックOS X 10.8でパイソンとVirtualenvをインストールと設定 Slug: python-virtualenv-on-mac-osx-mountain-lion-10.8 Date: 2012-12-20 Modified: 2012-12-22 Tags: パイソン, マック Category: 指導書 Summary: パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。 Writing unicode is certainly fun. パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。 And let's mix languages. первый пост Now another. İlk yazı çok özel değil. pelican-3.7.1/pelican/tests/content/article_with_markdown_and_summary_metadata_multi.md000066400000000000000000000004741303525152100317410ustar00rootroot00000000000000Title: Article with markdown and summary metadata multi Date: 2012-10-31 Summary: A multi-line summary should be supported as well as **inline markup**. custom_formatted_field: Multi-line metadata should also be supported as well as *inline markup* and stuff to "typogrify"... This is some content. pelican-3.7.1/pelican/tests/content/article_with_markdown_and_summary_metadata_single.md000066400000000000000000000002621303525152100320630ustar00rootroot00000000000000Title: Article with markdown and summary metadata single Date: 2012-10-30 Summary: A single-line summary should be supported as well as **inline markup**. This is some content. pelican-3.7.1/pelican/tests/content/article_with_markdown_extension.markdown000066400000000000000000000003161303525152100276010ustar00rootroot00000000000000title: Test markdown File category: test Test Markdown File Header ========================= Used for pelican test --------------------- This is another markdown test file. Uses the markdown extension. pelican-3.7.1/pelican/tests/content/article_with_markdown_markup_extensions.md000066400000000000000000000000771303525152100301250ustar00rootroot00000000000000Title: Test Markdown extensions [TOC] ## Level1 ### Level2 pelican-3.7.1/pelican/tests/content/article_with_md_extension.md000066400000000000000000000004421303525152100251350ustar00rootroot00000000000000Title: Test md File Category: test Tags: foo, bar, foobar Date: 2010-12-02 10:14 Modified: 2010-12-02 10:20 Summary: I have a lot to test Test Markdown File Header ========================= Used for pelican test --------------------- The quick brown fox jumped over the lazy dog's back. pelican-3.7.1/pelican/tests/content/article_with_mdown_extension.mdown000066400000000000000000000003101303525152100263770ustar00rootroot00000000000000title: Test mdown File category: test Test Markdown File Header ========================= Used for pelican test --------------------- This is another markdown test file. Uses the mdown extension. pelican-3.7.1/pelican/tests/content/article_with_metadata.html000066400000000000000000000010541303525152100245650ustar00rootroot00000000000000 This is a super article ! Multi-line metadata should be supported as well as inline markup. pelican-3.7.1/pelican/tests/content/article_with_metadata.rst000066400000000000000000000007111303525152100244300ustar00rootroot00000000000000 This is a super article ! ######################### :tags: foo, bar, foobar :date: 2010-12-02 10:14 :modified: 2010-12-02 10:20 :category: yeah :author: Alexis Métaireau :summary: Multi-line metadata should be supported as well as **inline markup** and stuff to "typogrify"... :custom_field: http://notmyidea.org :custom_formatted_field: Multi-line metadata should also be supported as well as *inline markup* and stuff to "typogrify"... pelican-3.7.1/pelican/tests/content/article_with_metadata.unknownextension000066400000000000000000000004151303525152100272550ustar00rootroot00000000000000 This is a super article ! ######################### :tags: foo, bar, foobar :date: 2010-12-02 10:14 :category: yeah :author: Alexis Métaireau :summary: Multi-line metadata should be supported as well as **inline markup**. :custom_field: http://notmyidea.org pelican-3.7.1/pelican/tests/content/article_with_metadata_and_contents.html000066400000000000000000000010621303525152100273230ustar00rootroot00000000000000 This is a super article ! Multi-line metadata should be supported as well as inline markup. pelican-3.7.1/pelican/tests/content/article_with_mkd_extension.mkd000066400000000000000000000003041303525152100254600ustar00rootroot00000000000000title: Test mkd File category: test Test Markdown File Header ========================= Used for pelican test --------------------- This is another markdown test file. Uses the mkd extension. pelican-3.7.1/pelican/tests/content/article_with_multiple_authors.html000066400000000000000000000002551303525152100264070ustar00rootroot00000000000000 This is an article with multiple authors! pelican-3.7.1/pelican/tests/content/article_with_multiple_authors.rst000066400000000000000000000002571303525152100262550ustar00rootroot00000000000000This is an article with multiple authors! ######################################### :date: 2014-02-09 02:20 :modified: 2014-02-09 02:20 :authors: First Author, Second Author pelican-3.7.1/pelican/tests/content/article_with_multiple_authors_list.rst000066400000000000000000000004771303525152100273140ustar00rootroot00000000000000This is an article with multiple authors in list format! ######################################################## :date: 2014-02-09 02:20 :modified: 2014-02-09 02:20 :authors: - Author, First - Author, Second The author names are in last,first form to verify that they are not just getting split on commas. pelican-3.7.1/pelican/tests/content/article_with_multiple_authors_semicolon.rst000066400000000000000000000003551303525152100303240ustar00rootroot00000000000000This is an article with multiple authors in lastname, firstname format! ####################################################################### :date: 2014-02-09 02:20 :modified: 2014-02-09 02:20 :authors: Author, First; Author, Second pelican-3.7.1/pelican/tests/content/article_with_nonconformant_meta_tags.html000066400000000000000000000005761303525152100277220ustar00rootroot00000000000000 Article with Nonconformant HTML meta tags Multi-line metadata should be supported as well as inline markup. pelican-3.7.1/pelican/tests/content/article_with_null_attributes.html000066400000000000000000000002471303525152100262300ustar00rootroot00000000000000 Ensure that empty attributes are copied properly. pelican-3.7.1/pelican/tests/content/article_with_template.rst000066400000000000000000000002651303525152100244670ustar00rootroot00000000000000Article with template ##################### :template: custom This article has a custom template to be called when rendered This is some content. With some stuff to "typogrify". pelican-3.7.1/pelican/tests/content/article_with_uppercase_metadata.html000066400000000000000000000002071303525152100266330ustar00rootroot00000000000000 This is a super article ! pelican-3.7.1/pelican/tests/content/article_with_uppercase_metadata.rst000066400000000000000000000001071303525152100264760ustar00rootroot00000000000000 This is a super article ! ######################### :Category: Yeah pelican-3.7.1/pelican/tests/content/article_without_category.rst000066400000000000000000000001771303525152100252230ustar00rootroot00000000000000 This is an article without category ! ##################################### This article should be in the DEFAULT_CATEGORY. pelican-3.7.1/pelican/tests/content/bad_extension.mmd000066400000000000000000000001341303525152100227000ustar00rootroot00000000000000Title: Bad Extension This file shouldn't be included because its file extension is `.mmd`. pelican-3.7.1/pelican/tests/content/empty.md000066400000000000000000000000001303525152100210270ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/content/empty_with_bom.md000066400000000000000000000000031303525152100227220ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/content/wordpress_content_decoded000066400000000000000000000061421303525152100245400ustar00rootroot00000000000000

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

  a = [1, 2, 3]
  b = [4, 5, 6]
  for i in zip(a, b):
    print i

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

pelican-3.7.1/pelican/tests/content/wordpress_content_encoded000066400000000000000000000061061303525152100245520ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

  a = [1, 2, 3]
  b = [4, 5, 6]
  for i in zip(a, b):
    print i

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. pelican-3.7.1/pelican/tests/content/wordpressexport.xml000066400000000000000000001677131303525152100234140ustar00rootroot00000000000000 Pelican test channel http://thisisa.test Not a real feed, just for test Sun, 13 May 2012 01:13:52 +0000 en 1.1 http://thisisa.test http://thisisa.test 2Bobbob@thisisa.test 3Jonhjonh@thisisa.test 7categ-1 11categ-2 1uncategorized 15categ-3 25tag-1 122tag2 68tag-3 http://wordpress.org/?v=3.3.1 Empty post http://thisisa.test/?attachment_id=24 Sat, 04 Feb 2012 03:17:33 +0000 bob https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Pelican_lakes_entrance02.jpg/240px-Pelican_lakes_entrance02.jpg 24 2012-02-04 03:17:33 2012-02-04 03:17:33 open open empty-post inherit 0 0 attachment 0 https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Pelican_lakes_entrance02.jpg/240px-Pelican_lakes_entrance02.jpg _wp_attachment_metadata _wp_attached_file _wp_attachment_image_alt http://thisisa.test/?p=168 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=168 168 2012-02-15 21:23:57 0000-00-00 00:00:00 open open draft 0 0 post 0 _edit_last A normal post http://thisisa.test/?p=174 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=174
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    174 2012-02-16 15:52:55 0000-00-00 00:00:00 open open draft 0 0 post 0 _edit_last
    Complete draft http://thisisa.test/?p=176 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=176 176 2012-02-17 15:11:55 0000-00-00 00:00:00 open open draft 0 0 post 0 _edit_last Page http://thisisa.test/contact/ Wed, 11 Apr 2012 11:38:08 +0000 bob http://thisisa.test/?page_id=334 334 2012-04-11 06:38:08 2012-04-11 11:38:08 open open contact publish 0 0 page 0 sharing_disabled _wp_page_template _edit_last Empty Page http://thisisa.test/empty/ Wed, 11 Apr 2012 11:38:08 +0000 bob http://thisisa.test/?page_id=334 334 2012-04-11 06:38:08 2012-04-11 11:38:08 open open empty publish 0 0 page 0 sharing_disabled _wp_page_template _edit_last Special chars: l'é http://thisisa.test/?p=471 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=471 471 2012-04-29 09:44:27 0000-00-00 00:00:00 open open draft 0 0 post 0 _edit_last With excerpt http://thisisa.test/with-excerpt/ Sat, 04 Feb 2012 02:03:06 +0000 bob http://thisisa.test/?p=8 8 2012-02-04 02:03:06 2012-02-04 02:03:06 open open with-excerpt publish 0 0 post 0 _edit_last et_bigpost _thumbnail_id With tags http://thisisa.test/tags/ Sat, 04 Feb 2012 21:05:25 +0000 bob http://thisisa.test/?p=25 25 2012-02-04 21:05:25 2012-02-04 21:05:25 open open with-tags publish 0 0 post 0 _edit_last et_bigpost _thumbnail_id With comments http://thisisa.test/with-comments/ Wed, 18 Apr 2012 08:36:26 +0000 john http://thisisa.test/?p=422 422 2012-04-18 03:36:26 2012-04-18 08:36:26 open open with-comments publish 0 0 post 0 _edit_last _thumbnail_id 116 User2@mail.test 127.0.0.1 2012-05-06 15:46:06 2012-05-06 20:46:06 1 0 0 akismet_result akismet_history akismet_as_submitted 117 bob@thisisa.test 127.0.0.1 2012-05-06 17:44:06 2012-05-06 22:44:06 1 116 3 akismet_result akismet_history akismet_as_submitted 156 http://thisisa.test/to-article-you-ping-back/ 127.0.0.1 2012-05-09 19:30:19 2012-05-10 00:30:19 trash pingback 0 0 akismet_history _wp_trash_meta_status _wp_trash_meta_time 122 bob@thisisa.test 127.0.0.1 2012-05-07 14:11:34 2012-05-07 19:11:34 1 121 3 akismet_result akismet_history akismet_as_submitted Post with raw data http://thisisa.test/?p=173 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=173 Pelicans are scary Pelicans are supposed to eat fish, damn it! Bottom line: don't mess up with birds]]> 173 2012-02-16 15:52:55 0000-00-00 00:00:00 open open post-with-raw-data publish 0 0 post 0 _edit_last A normal post with some <html> entities in the title. You can't miss them. http://thisisa.test/?p=175 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=175
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    175 2012-02-16 15:52:55 0000-00-00 00:00:00 open open html-entity-test publish 0 0 post 0 _edit_last
    Code in List http://thisisa.test/?p=175 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=175
  • List Item One!
  • List Item Two!
  • This is a code sample
    
      a = [1, 2, 3]
      b = [4, 5, 6]
      for i in zip(a, b):
        print i
    
    
  • List Item Four!
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    175 2012-02-16 15:52:55 0000-00-00 00:00:00 open open code-in-list-test publish 0 0 post 0 _edit_last
    A custom post in category 4 http://thisisa.test/?p=175 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=175
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    175 2012-02-16 15:52:55 0000-00-00 00:00:00 open open custpost1cat4 publish 0 0 custom1 0 _edit_last
    A custom post in category 5 http://thisisa.test/?p=176 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=176
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    176 2012-02-16 15:52:55 0000-00-00 00:00:00 open open custpost1cat5 publish 0 0 custom1 0 _edit_last
    A 2nd custom post type also in category 5 http://thisisa.test/?p=177 Thu, 01 Jan 1970 00:00:00 +0000 bob http://thisisa.test/?p=177
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    177 2012-02-16 15:52:55 0000-00-00 00:00:00 open open custpost2cat5 publish 0 0 custom2 0 _edit_last
    Attachment with a parent http://thisisa.test/?attachment_id=24 Sat, 04 Feb 2012 03:17:33 +0000 bob http://thisurlisinvalid.notarealdomain/not_an_image.jpg 25 2012-02-04 03:17:33 2012-02-04 03:17:33 open open attachment-with-a-parent inherit 8 0 attachment 0 http://thisurlisinvalid.notarealdomain/not_an_image.jpg _wp_attachment_metadata _wp_attached_file _wp_attachment_image_alt 2nd Attachment to same parent http://thisisa.test/?attachment_id=25 Sat, 04 Feb 2012 03:17:33 +0000 bob http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg 25 2012-02-04 03:17:33 2012-02-04 03:17:33 open open 2nd[attachment-to-same-parent inherit 8 0 attachment 0 http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg _wp_attachment_metadata _wp_attached_file _wp_attachment_image_alt Attachment with a different parent http://thisisa.test/?attachment_id=26 Sat, 04 Feb 2012 03:17:33 +0000 bob http://thisurlisinvalid.notarealdomain 25 2012-02-04 03:17:33 2012-02-04 03:17:33 open open attachment-with-a-different-parent inherit 25 0 attachment 0 http://thisurlisinvalid.notarealdomain _wp_attachment_metadata _wp_attached_file _wp_attachment_image_alt
    pelican-3.7.1/pelican/tests/default_conf.py000066400000000000000000000025241303525152100207150ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals AUTHOR = 'Alexis Métaireau' SITENAME = "Alexis' log" SITEURL = 'http://blog.notmyidea.org' TIMEZONE = 'UTC' GITHUB_URL = 'http://github.com/ametaireau/' DISQUS_SITENAME = "blog-notmyidea" PDF_GENERATOR = False REVERSE_CATEGORY_ORDER = True DEFAULT_PAGINATION = 2 FEED_RSS = 'feeds/all.rss.xml' CATEGORY_FEED_RSS = 'feeds/%s.rss.xml' LINKS = (('Biologeek', 'http://biologeek.org'), ('Filyb', "http://filyb.info/"), ('Libert-fr', "http://www.libert-fr.com"), ('N1k0', "http://prendreuncafe.com/blog/"), ('Tarek Ziadé', "http://ziade.org/blog"), ('Zubin Mithra', "http://zubin71.wordpress.com/"),) SOCIAL = (('twitter', 'http://twitter.com/ametaireau'), ('lastfm', 'http://lastfm.com/user/akounet'), ('github', 'http://github.com/ametaireau'),) # global metadata to all the contents DEFAULT_METADATA = {'yeah': 'it is'} # path-specific metadata EXTRA_PATH_METADATA = { 'extra/robots.txt': {'path': 'robots.txt'}, } # static paths will be copied without parsing their contents STATIC_PATHS = [ 'pictures', 'extra/robots.txt', ] FORMATTED_FIELDS = ['summary', 'custom_formatted_field'] # foobar will not be used, because it's not in caps. All configuration keys # have to be in caps foobar = "barbaz" pelican-3.7.1/pelican/tests/mixed_content/000077500000000000000000000000001303525152100205475ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/mixed_content/fake_image.jpg000066400000000000000000000000001303525152100233070ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/mixed_content/short_page.md000066400000000000000000000000641303525152100232240ustar00rootroot00000000000000Title: Short Page This is a page with little text. pelican-3.7.1/pelican/tests/mixed_content/subdir/000077500000000000000000000000001303525152100220375ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/mixed_content/subdir/subdir_fake_image.jpg000066400000000000000000000000001303525152100261470ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/nested_content/000077500000000000000000000000001303525152100207235ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/nested_content/maindir/000077500000000000000000000000001303525152100223465ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/nested_content/maindir/maindir.md000066400000000000000000000000621303525152100243110ustar00rootroot00000000000000Title: Main Dir Page This page lives in maindir. pelican-3.7.1/pelican/tests/nested_content/maindir/subdir/000077500000000000000000000000001303525152100236365ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/nested_content/maindir/subdir/subdir.md000066400000000000000000000000671303525152100254530ustar00rootroot00000000000000Title: Subdir Page This page lives in maindir/subdir. pelican-3.7.1/pelican/tests/output/000077500000000000000000000000001303525152100172475ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/000077500000000000000000000000001303525152100203305ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/a-markdown-powered-article.html000066400000000000000000000054661303525152100263550ustar00rootroot00000000000000 A markdown powered article
    pelican-3.7.1/pelican/tests/output/basic/archives.html000066400000000000000000000060721303525152100230270ustar00rootroot00000000000000 A Pelican Blog

    Archives for A Pelican Blog

    Fri 30 November 2012
    FILENAME_METADATA example
    Wed 29 February 2012
    Second article
    Wed 20 April 2011
    A markdown powered article
    Thu 17 February 2011
    Article 1
    Thu 17 February 2011
    Article 2
    Thu 17 February 2011
    Article 3
    Thu 02 December 2010
    This is a super article !
    Wed 20 October 2010
    Oh yeah !
    Fri 15 October 2010
    Unbelievable !
    Sun 14 March 2010
    The baz tag
    pelican-3.7.1/pelican/tests/output/basic/article-1.html000066400000000000000000000051221303525152100227770ustar00rootroot00000000000000 Article 1
    pelican-3.7.1/pelican/tests/output/basic/article-2.html000066400000000000000000000051221303525152100230000ustar00rootroot00000000000000 Article 2
    pelican-3.7.1/pelican/tests/output/basic/article-3.html000066400000000000000000000051221303525152100230010ustar00rootroot00000000000000 Article 3
    pelican-3.7.1/pelican/tests/output/basic/author/000077500000000000000000000000001303525152100216325ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/author/alexis-metaireau.html000066400000000000000000000120101303525152100257510ustar00rootroot00000000000000 A Pelican Blog - Alexis Métaireau

    Other articles


    pelican-3.7.1/pelican/tests/output/basic/authors.html000066400000000000000000000043241303525152100227060ustar00rootroot00000000000000 A Pelican Blog - Authors

    Authors on A Pelican Blog

    pelican-3.7.1/pelican/tests/output/basic/categories.html000066400000000000000000000043451303525152100233510ustar00rootroot00000000000000 A Pelican Blog
    pelican-3.7.1/pelican/tests/output/basic/category/000077500000000000000000000000001303525152100221455ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/category/bar.html000066400000000000000000000060471303525152100236060ustar00rootroot00000000000000 A Pelican Blog - bar
    pelican-3.7.1/pelican/tests/output/basic/category/cat1.html000066400000000000000000000120131303525152100236600ustar00rootroot00000000000000 A Pelican Blog - cat1

    Other articles


    pelican-3.7.1/pelican/tests/output/basic/category/misc.html000066400000000000000000000144661303525152100240010ustar00rootroot00000000000000 A Pelican Blog - misc

    Other articles


    1. The baz tag

      Published: Sun 14 March 2010

      In misc.

      This article overrides the listening of the articles under the baz tag.

      read more
    pelican-3.7.1/pelican/tests/output/basic/category/yeah.html000066400000000000000000000070451303525152100237670ustar00rootroot00000000000000 A Pelican Blog - yeah
    pelican-3.7.1/pelican/tests/output/basic/feeds/000077500000000000000000000000001303525152100214165ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/feeds/alexis-metaireau.atom.xml000066400000000000000000000052211303525152100263360ustar00rootroot00000000000000 A Pelican Blog - Alexis Métaireau/2013-11-17T23:29:00+00:00This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> pelican-3.7.1/pelican/tests/output/basic/feeds/alexis-metaireau.rss.xml000066400000000000000000000026741303525152100262160ustar00rootroot00000000000000 A Pelican Blog - Alexis Métaireau/Sun, 17 Nov 2013 23:29:00 +0000This is a super article !/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0000tag:None,2010-12-02:/this-is-a-super-article.htmlfoobarfoobarOh yeah !/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0000tag:None,2010-10-20:/oh-yeah.htmlohbaryeahpelican-3.7.1/pelican/tests/output/basic/feeds/all-en.atom.xml000066400000000000000000000516071303525152100242600ustar00rootroot00000000000000 A Pelican Blog/2013-11-17T23:29:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:002012-11-30T00:00:00+00:00tag:None,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article.html<p>This is some article, in english</p> <p>This is some article, in english</p> A markdown powered article2011-04-20T00:00:00+00:002011-04-20T00:00:00+00:00tag:None,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="/unbelievable.html">a root-relative link to unbelievable</a> <a href="/unbelievable.html">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="/unbelievable.html">a root-relative link to unbelievable</a> <a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-1.html<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-2.html<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-3.html<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+00:002010-10-15T20:30:00+00:00tag:None,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+00:002010-03-14T00:00:00+00:00tag:None,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/basic/feeds/all-fr.atom.xml000066400000000000000000000014521303525152100242560ustar00rootroot00000000000000 A Pelican Blog/2012-02-29T00:00:00+00:00Deuxième article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> <p>Ceci est un article, en français.</p> pelican-3.7.1/pelican/tests/output/basic/feeds/all.atom.xml000066400000000000000000000526471303525152100236650ustar00rootroot00000000000000 A Pelican Blog/2013-11-17T23:29:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:002012-11-30T00:00:00+00:00tag:None,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article.html<p>This is some article, in english</p> <p>This is some article, in english</p> Deuxième article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> <p>Ceci est un article, en français.</p> A markdown powered article2011-04-20T00:00:00+00:002011-04-20T00:00:00+00:00tag:None,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="/unbelievable.html">a root-relative link to unbelievable</a> <a href="/unbelievable.html">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="/unbelievable.html">a root-relative link to unbelievable</a> <a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-1.html<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-2.html<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-3.html<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+00:002010-10-15T20:30:00+00:00tag:None,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+00:002010-03-14T00:00:00+00:00tag:None,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/basic/feeds/bar.atom.xml000066400000000000000000000024701303525152100236460ustar00rootroot00000000000000 A Pelican Blog - bar/2010-10-20T10:14:00+00:00Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> pelican-3.7.1/pelican/tests/output/basic/feeds/cat1.atom.xml000066400000000000000000000042611303525152100237320ustar00rootroot00000000000000 A Pelican Blog - cat1/2011-04-20T00:00:00+00:00A markdown powered article2011-04-20T00:00:00+00:002011-04-20T00:00:00+00:00tag:None,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="/unbelievable.html">a root-relative link to unbelievable</a> <a href="/unbelievable.html">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="/unbelievable.html">a root-relative link to unbelievable</a> <a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-1.html<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-2.html<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-3.html<p>Article 3</p> <p>Article 3</p> pelican-3.7.1/pelican/tests/output/basic/feeds/misc.atom.xml000066400000000000000000000411731303525152100240400ustar00rootroot00000000000000 A Pelican Blog - misc/2012-11-30T00:00:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:002012-11-30T00:00:00+00:00tag:None,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article.html<p>This is some article, in english</p> <p>This is some article, in english</p> Unbelievable !2010-10-15T20:30:00+00:002010-10-15T20:30:00+00:00tag:None,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+00:002010-03-14T00:00:00+00:00tag:None,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/basic/feeds/yeah.atom.xml000066400000000000000000000031121303525152100240220ustar00rootroot00000000000000 A Pelican Blog - yeah/2013-11-17T23:29:00+00:00This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> pelican-3.7.1/pelican/tests/output/basic/filename_metadata-example.html000066400000000000000000000052311303525152100262700ustar00rootroot00000000000000 FILENAME_METADATA example
    pelican-3.7.1/pelican/tests/output/basic/index.html000066400000000000000000000273261303525152100223370ustar00rootroot00000000000000 A Pelican Blog

    Other articles


    1. The baz tag

      Published: Sun 14 March 2010

      In misc.

      This article overrides the listening of the articles under the baz tag.

      read more
    pelican-3.7.1/pelican/tests/output/basic/oh-yeah.html000066400000000000000000000061621303525152100225550ustar00rootroot00000000000000 Oh yeah !

    Oh yeah !

    Why not ?

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !

    alternate text
    pelican-3.7.1/pelican/tests/output/basic/override/000077500000000000000000000000001303525152100221475ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/override/index.html000066400000000000000000000043731303525152100241530ustar00rootroot00000000000000 Override url/save_as

    Override url/save_as

    Test page which overrides save_as and url so that this page will be generated at a custom location.

    pelican-3.7.1/pelican/tests/output/basic/pages/000077500000000000000000000000001303525152100214275ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/pages/this-is-a-test-hidden-page.html000066400000000000000000000043751303525152100272440ustar00rootroot00000000000000 This is a test hidden page

    This is a test hidden page

    This is great for things like error(404) pages Anyone can see this page but it's not linked to anywhere!

    pelican-3.7.1/pelican/tests/output/basic/pages/this-is-a-test-page.html000066400000000000000000000044141303525152100260050ustar00rootroot00000000000000 This is a test page

    This is a test page

    Just an image.

    alternate text
    pelican-3.7.1/pelican/tests/output/basic/second-article-fr.html000066400000000000000000000054641303525152100245300ustar00rootroot00000000000000 Deuxième article
    pelican-3.7.1/pelican/tests/output/basic/second-article.html000066400000000000000000000054511303525152100241170ustar00rootroot00000000000000 Second article
    pelican-3.7.1/pelican/tests/output/basic/tag/000077500000000000000000000000001303525152100211035ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/tag/bar.html000066400000000000000000000126551303525152100225460ustar00rootroot00000000000000 A Pelican Blog - bar

    Other articles


    pelican-3.7.1/pelican/tests/output/basic/tag/baz.html000066400000000000000000000052321303525152100225470ustar00rootroot00000000000000 The baz tag

    The baz tag

    Published: Sun 14 March 2010

    In misc.

    This article overrides the listening of the articles under the baz tag.

    pelican-3.7.1/pelican/tests/output/basic/tag/foo.html000066400000000000000000000103221303525152100225520ustar00rootroot00000000000000 A Pelican Blog - foo

    Other articles


    pelican-3.7.1/pelican/tests/output/basic/tag/foobar.html000066400000000000000000000070301303525152100232410ustar00rootroot00000000000000 A Pelican Blog - foobar
    pelican-3.7.1/pelican/tests/output/basic/tag/oh.html000066400000000000000000000043141303525152100224010ustar00rootroot00000000000000 Oh Oh Oh

    Oh Oh Oh

    This page overrides the listening of the articles under the oh tag.

    pelican-3.7.1/pelican/tests/output/basic/tag/yeah.html000066400000000000000000000060311303525152100227170ustar00rootroot00000000000000 A Pelican Blog - yeah
    pelican-3.7.1/pelican/tests/output/basic/tags.html000066400000000000000000000047001303525152100221550ustar00rootroot00000000000000 A Pelican Blog - Tags

    Tags for A Pelican Blog

    pelican-3.7.1/pelican/tests/output/basic/theme/000077500000000000000000000000001303525152100214325ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/theme/css/000077500000000000000000000000001303525152100222225ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/theme/css/main.css000066400000000000000000000254161303525152100236700ustar00rootroot00000000000000/* Name: Smashing HTML5 Date: July 2009 Description: Sample layout for HTML5 and CSS3 goodness. Version: 1.0 License: MIT Licensed by: Smashing Media GmbH Original author: Enrique Ramírez */ /* Imports */ @import url("reset.css"); @import url("pygment.css"); @import url("typogrify.css"); @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); /***** Global *****/ /* Body */ body { background: #F5F4EF; color: #000305; font-size: 87.5%; /* Base font size: 14px */ font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; line-height: 1.429; margin: 0; padding: 0; text-align: left; } /* Headings */ h1 {font-size: 2em } h2 {font-size: 1.571em} /* 22px */ h3 {font-size: 1.429em} /* 20px */ h4 {font-size: 1.286em} /* 18px */ h5 {font-size: 1.143em} /* 16px */ h6 {font-size: 1em} /* 14px */ h1, h2, h3, h4, h5, h6 { font-weight: 400; line-height: 1.1; margin-bottom: .8em; font-family: 'Yanone Kaffeesatz', arial, serif; } h3, h4, h5, h6 { margin-top: .8em; } hr { border: 2px solid #EEEEEE; } /* Anchors */ a {outline: 0;} a img {border: 0px; text-decoration: none;} a:link, a:visited { color: #C74350; padding: 0 1px; text-decoration: underline; } a:hover, a:active { background-color: #C74350; color: #fff; text-decoration: none; text-shadow: 1px 1px 1px #333; } h1 a:hover { background-color: inherit } /* Paragraphs */ div.line-block, p { margin-top: 1em; margin-bottom: 1em;} strong, b {font-weight: bold;} em, i {font-style: italic;} /* Lists */ ul { list-style: outside disc; margin: 0em 0 0 1.5em; } ol { list-style: outside decimal; margin: 0em 0 0 1.5em; } li { margin-top: 0.5em; margin-bottom: 1em; } .post-info { float:right; margin:10px; padding:5px; } .post-info p{ margin-top: 1px; margin-bottom: 1px; } .readmore { float: right } dl {margin: 0 0 1.5em 0;} dt {font-weight: bold;} dd {margin-left: 1.5em;} pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} /* Quotes */ blockquote { margin: 20px; font-style: italic; } cite {} q {} div.note { float: right; margin: 5px; font-size: 85%; max-width: 300px; } /* Tables */ table {margin: .5em auto 1.5em auto; width: 98%;} /* Thead */ thead th {padding: .5em .4em; text-align: left;} thead td {} /* Tbody */ tbody td {padding: .5em .4em;} tbody th {} tbody .alt td {} tbody .alt th {} /* Tfoot */ tfoot th {} tfoot td {} /* HTML5 tags */ header, section, footer, aside, nav, article, figure { display: block; } /***** Layout *****/ .body {clear: both; margin: 0 auto; width: 800px;} img.right, figure.right {float: right; margin: 0 0 2em 2em;} img.left, figure.left {float: left; margin: 0 2em 2em 0;} /* Header *****************/ #banner { margin: 0 auto; padding: 2.5em 0 0 0; } /* Banner */ #banner h1 {font-size: 3.571em; line-height: 0;} #banner h1 a:link, #banner h1 a:visited { color: #000305; display: block; font-weight: bold; margin: 0 0 .6em .2em; text-decoration: none; } #banner h1 a:hover, #banner h1 a:active { background: none; color: #C74350; text-shadow: none; } #banner h1 strong {font-size: 0.36em; font-weight: normal;} /* Main Nav */ #banner nav { background: #000305; font-size: 1.143em; height: 40px; line-height: 30px; margin: 0 auto 2em auto; padding: 0; text-align: center; width: 800px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #banner nav ul {list-style: none; margin: 0 auto; width: 800px;} #banner nav li {float: left; display: inline; margin: 0;} #banner nav a:link, #banner nav a:visited { color: #fff; display: inline-block; height: 30px; padding: 5px 1.5em; text-decoration: none; } #banner nav a:hover, #banner nav a:active, #banner nav .active a:link, #banner nav .active a:visited { background: #C74451; color: #fff; text-shadow: none !important; } #banner nav li:first-child a { border-top-left-radius: 5px; -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; } /* Featured *****************/ #featured { background: #fff; margin-bottom: 2em; overflow: hidden; padding: 20px; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } #featured figure { border: 2px solid #eee; float: right; margin: 0.786em 2em 0 5em; width: 248px; } #featured figure img {display: block; float: right;} #featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} #featured h3 {font-size: 1.429em; margin-bottom: .5em;} #featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} #featured h3 a:hover, #featured h3 a:active {color: #fff;} /* Body *****************/ #content { background: #fff; margin-bottom: 2em; overflow: hidden; padding: 20px 20px; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } /* Extras *****************/ #extras {margin: 0 auto 3em auto; overflow: hidden;} #extras ul {list-style: none; margin: 0;} #extras li {border-bottom: 1px solid #fff;} #extras h2 { color: #C74350; font-size: 1.429em; margin-bottom: .25em; padding: 0 3px; } #extras a:link, #extras a:visited { color: #444; display: block; border-bottom: 1px solid #F4E3E3; text-decoration: none; padding: .3em .25em; } #extras a:hover, #extras a:active {color: #fff;} /* Blogroll */ #extras .blogroll { float: left; width: 615px; } #extras .blogroll li {float: left; margin: 0 20px 0 0; width: 185px;} /* Social */ #extras .social { float: right; width: 175px; } #extras div[class='social'] a { background-repeat: no-repeat; background-position: 3px 6px; padding-left: 25px; } /* Icons */ .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} .social a[href*='github.com'], .social a[href*='git.io'] { background-image: url('../images/icons/github.png'); background-size: 16px 16px; } .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} .social a[href*='news.ycombinator.com'], .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} .social a[href*='stackoverflow.com'] {background-image: url('../images/icons/stackoverflow.png');} .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} /* About *****************/ #about { background: #fff; font-style: normal; margin-bottom: 2em; overflow: hidden; padding: 20px; text-align: left; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } #about .primary {float: left; width: 165px;} #about .primary strong {color: #C64350; display: block; font-size: 1.286em;} #about .photo {float: left; margin: 5px 20px;} #about .url:link, #about .url:visited {text-decoration: none;} #about .bio {float: right; width: 500px;} /* Footer *****************/ #contentinfo {padding-bottom: 2em; text-align: right;} /***** Sections *****/ /* Blog */ .hentry { display: block; clear: both; border-bottom: 1px solid #eee; padding: 1.5em 0; } li:last-child .hentry, #content > .hentry {border: 0; margin: 0;} #content > .hentry {padding: 1em 0;} .hentry img{display : none ;} .entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} .entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} .entry-title a:visited {background-color: #fff;} .hentry .post-info * {font-style: normal;} /* Content */ .hentry footer {margin-bottom: 2em;} .hentry footer address {display: inline;} #posts-list footer address {display: block;} /* Blog Index */ #posts-list {list-style: none; margin: 0;} #posts-list .hentry {padding-left: 10px; position: relative;} #posts-list footer { left: 10px; position: relative; float: left; top: 0.5em; width: 190px; } /* About the Author */ #about-author { background: #f9f9f9; clear: both; font-style: normal; margin: 2em 0; padding: 10px 20px 15px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #about-author strong { color: #C64350; clear: both; display: block; font-size: 1.429em; } #about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} /* Comments */ #comments-list {list-style: none; margin: 0 1em;} #comments-list blockquote { background: #f8f8f8; clear: both; font-style: normal; margin: 0; padding: 15px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} #comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} /* Add a Comment */ #add-comment label {clear: left; float: left; text-align: left; width: 150px;} #add-comment input[type='text'], #add-comment input[type='email'], #add-comment input[type='url'] {float: left; width: 200px;} #add-comment textarea {float: left; height: 150px; width: 495px;} #add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} #add-comment input[type='submit'] {float: right; margin: 0 .5em;} #add-comment * {margin-bottom: .5em;} pelican-3.7.1/pelican/tests/output/basic/theme/css/pygment.css000066400000000000000000000034521303525152100244230ustar00rootroot00000000000000.hll { background-color:#eee; } .c { color:#408090; font-style:italic; } .err { border:1px solid #FF0000; } .k { color:#007020; font-weight:bold; } .o { color:#666666; } .cm { color:#408090; font-style:italic; } .cp { color:#007020; } .c1 { color:#408090; font-style:italic; } .cs { background-color:#FFF0F0; color:#408090; } .gd { color:#A00000; } .ge { font-style:italic; } .gr { color:#FF0000; } .gh { color:#000080; font-weight:bold; } .gi { color:#00A000; } .go { color:#303030; } .gp { color:#C65D09; font-weight:bold; } .gs { font-weight:bold; } .gu { color:#800080; font-weight:bold; } .gt { color:#0040D0; } .kc { color:#007020; font-weight:bold; } .kd { color:#007020; font-weight:bold; } .kn { color:#007020; font-weight:bold; } .kp { color:#007020; } .kr { color:#007020; font-weight:bold; } .kt { color:#902000; } .m { color:#208050; } .s { color:#4070A0; } .na { color:#4070A0; } .nb { color:#007020; } .nc { color:#0E84B5; font-weight:bold; } .no { color:#60ADD5; } .nd { color:#555555; font-weight:bold; } .ni { color:#D55537; font-weight:bold; } .ne { color:#007020; } .nf { color:#06287E; } .nl { color:#002070; font-weight:bold; } .nn { color:#0E84B5; font-weight:bold; } .nt { color:#062873; font-weight:bold; } .nv { color:#BB60D5; } .ow { color:#007020; font-weight:bold; } .w { color:#BBBBBB; } .mf { color:#208050; } .mh { color:#208050; } .mi { color:#208050; } .mo { color:#208050; } .sb { color:#4070A0; } .sc { color:#4070A0; } .sd { color:#4070A0; font-style:italic; } .s2 { color:#4070A0; } .se { color:#4070A0; font-weight:bold; } .sh { color:#4070A0; } .si { color:#70A0D0; font-style:italic; } .sx { color:#C65D09; } .sr { color:#235388; } .s1 { color:#4070A0; } .ss { color:#517918; } .bp { color:#007020; } .vc { color:#BB60D5; } .vg { color:#BB60D5; } .vi { color:#BB60D5; } .il { color:#208050; } pelican-3.7.1/pelican/tests/output/basic/theme/css/reset.css000066400000000000000000000021171303525152100240570ustar00rootroot00000000000000/* Name: Reset Stylesheet Description: Resets browser's default CSS Author: Eric Meyer Author URI: http://meyerweb.com/eric/tools/css/reset/ */ /* v1.0 | 20080212 */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { background: transparent; border: 0; font-size: 100%; margin: 0; outline: 0; padding: 0; vertical-align: baseline; } body {line-height: 1;} ol, ul {list-style: none;} blockquote, q {quotes: none;} blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } /* remember to define focus styles! */ :focus { outline: 0; } /* remember to highlight inserts somehow! */ ins {text-decoration: none;} del {text-decoration: line-through;} /* tables still need 'cellspacing="0"' in the markup */ table { border-collapse: collapse; border-spacing: 0; }pelican-3.7.1/pelican/tests/output/basic/theme/css/typogrify.css000066400000000000000000000002761303525152100247750ustar00rootroot00000000000000.caps {font-size:.92em;} .amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} .dquo {margin-left:-.38em;} pelican-3.7.1/pelican/tests/output/basic/theme/css/wide.css000066400000000000000000000011501303525152100236610ustar00rootroot00000000000000@import url("main.css"); body { font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; } .post-info{ display: none; } #banner nav { display: none; -moz-border-radius: 0px; margin-bottom: 20px; overflow: hidden; font-size: 1em; background: #F5F4EF; } #banner nav ul{ padding-right: 50px; } #banner nav li{ float: right; color: #000; } #banner nav li a { color: #000; } #banner h1 { margin-bottom: -18px; } #featured, #extras { padding: 50px; } #featured { padding-top: 20px; } #extras { padding-top: 0px; padding-bottom: 0px; } pelican-3.7.1/pelican/tests/output/basic/theme/images/000077500000000000000000000000001303525152100226775ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/000077500000000000000000000000001303525152100240125ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/aboutme.png000066400000000000000000000013571303525152100261620ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ< PLTE >b :\a``__^][XNz 8Y]\\ZZXVS Js Ch 6UXXWVUTRQ~N{ Lw El @d4S P} O| Nz Mx Lw Ku Js Hq Fn Ek @e >a2O Mw3 Ip Dj Bg >a <]0L Hp Ho Gn Bg Cg;]9Y ;[.I Dk :ZAf 7U=_0K,F@e(>=_%:6U"4*D2O'@/K &=-G#:*D!7(@4%=1k/tRNS@f pHYsHHFk>IDATURPEcJP t(P)RcB]7p $YpܪHWUU?9'g^DXz&[|y6:dd#'r7_4L˚7L?`ZW|;h%tEXtdate:create2013-03-15T18:16:20-07:00#6%tEXtdate:modify2013-03-15T18:16:16-07:00SIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/bitbucket.png000066400000000000000000000072021303525152100264750ustar00rootroot00000000000000PNG  IHDRh6 AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  niTXtXML:com.adobe.xmp ? AmIDAT(ERkAtIݐۤ?jִPЖRD {$xP"1FlҺ>t GTЂ}FD%BdD,>[ēPR@+*ȌFՍJpL +x~,*p*K$ћBJ{iqne6;Ĉv}vpn`k KӲW7ͅ'tՅ |ZWotL,(w,}+WҩP8d״ˍJsP\ C$IAk筕sGt*JB\׆\08Sֿ#/9bSs\&_t@z8vIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/delicious.png000066400000000000000000000016761303525152100265120ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS4ӠtEXtCreation Time20/7/09zcIDAT8ou}Kn6IKb*K D(B1/ 1Ll,t@JtCDڦIIS׉o{}yX,Vq#jKZxwv~}z;mgӃ`ڮfOk̙{~5޻~~n4i3/}{׃g½cW=>֚./}p B:m&tkJFLi_ ?ԓIrR "&bi?3$bZ)Hէڲ @8L !:(NDm2yqrK)I%dCesG J) ?ϧJ>2pF> 6`CAsJﳽG7qG52/}Cca@\Ş.M[9rʲ W*YR=*;{"""H$""_}47u6wD*x~8Q3̱P!L4֖j$FH|q  ƾJg0.q!`x@0^5"1"`E^'81ZB`0Kׯh'a.W Ox^8G,b89.~/T+^`c`j )efЩ2},W${{b1}x'mmnko}w㰻u`}?=}yf;wZ?W.72 䭘fIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/facebook.png000066400000000000000000000003121303525152100262650ustar00rootroot00000000000000PNG  IHDRRPLTE;Y;Y`xEbmgtRNSACbKGDH pHYsHHFk>=IDATc`F%0``0 e C%P RBeBT\Cp0K 0ef>IENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/github.png000066400000000000000000000032621303525152100260050ustar00rootroot00000000000000PNG  IHDR szztEXtSoftwareAdobe ImageReadyqe<$iTXtXML:com.adobe.xmp $IDATxėmhayL30A+R#f>IHکy(M)_o5 0+0Ėl&o{i^]u<{Yws}=uC>$L, }<w}8^ AO?p! xaяPKI3`'B>0QT1<+`}^nvkp^ƅF|1"Gp.*oO׀Vp ]߅jc8K$q 8jV`#`vmpGѢu!#}#:U_?_yhE $=;c*xNOo+&w)%K-R%6n'o">j/t³qoGW7j%2q GX?woibCÐAzbǰt \14|S.DZ]# b|H$(ʕohmqͱRP셣$,0Z20 tNvRW3K8Xk2 IO6LbIDAT}1 % h#"#M 홴z)} .?_"{B4!>}HVU8T% )mu CbD, F IIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/gittip.png000066400000000000000000000007471303525152100260300ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME  mgIDAT8c`o0cm=H_P| *0CF`1d=6_LԄj.d*LsHg#MM@v7S!0lÕs' m`=-oqEv 4plٰl$.4g4ܴb)f ā@,`.&@yjB P q7!UA?~p11?FhhDd"EDm j4'$MOH(I%^V8ǟ)LfgoǑXIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/google-groups.png000066400000000000000000000014431303525152100273130ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<5PLTE,r#bFEB@>=:875}3{1zDB@<7~4|CA>=986~?>6~4|2{1x>2z0x=98;9/w1y0w2{.v3|.uʡ-ṭ,s+qtRNS}abKGD-IDAT5y[QW-q̄13p}(B/繞j;.{`(E( )-O$9dAL#B /$Jryu]Bpp2OiR.;7EBpNb>cã}%bP}fC}(,ggxE)_Oz70Yn`-:9@ 3$%ts%tEXtdate:create2013-01-13T02:11:01-08:00̕%tEXtdate:modify2013-01-13T02:10:36-08:00&zIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/google-plus.png000066400000000000000000000010171303525152100267540ustar00rootroot00000000000000PNG  IHDRh6IDAT(cmIbeq&nt9@ A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  niTXtXML:com.adobe.xmp ? AIDAT8cD^V4?PAuLU?7g0arp m3Fpu06L.d s`]8bw3lfd ьP#<= Is aLd6\<(A_&#Ft6ab/$eqoIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/lastfm.png000066400000000000000000000017171303525152100260140ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS4ӠtEXtCreation Time20/7/09zc(IDAT8OlU{v6*U(D Qc@#'ăO=sp1 ϩD--4Pv{??=~.KxNyfƤTH'*"1֮Br:i$k.>7HXy?؁s(I HrwL.Ig~ Ig9R  (%c5y@F6CH,D ? N6(!cQ6{dPȡpsJ0j0e$pNU.x " 8zZ^5˫3uh`{#at0:Nh`/F1%쑔}#l̮qo2^'#rxqS'ɽshb@c;2I~7;{U,J,yoɾq[ bYBE2'y:fIMw.);#,8vmJK"",7%KRd'""6Q,yJ泓'w>׍j﯒ܹ.P.3_XDz]e?n g_)G_{!bGժԡhvdKAg^䋅kwЕ!dOCPY.cЉ#[{AbXM~bѻD\k-3rUe<$7V%-e?O=k;ʆQFxD0UmTgjzϯ|psO?ϕsݪCIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/linkedin.png000066400000000000000000000016001303525152100263120ustar00rootroot00000000000000PNG  IHDR(-S7PLTEhiklklmmoommnnoonopqoqprrpqstsutv vw w v w y yx y yy { {zzzz{|{|~ !"#$%&',-21223E9:9::<=~^|^X۳~#rӯ#"{:(#u;p )*R)j NA^AT kk1HgO\(vo84QImÏY`e)S IENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/reddit.png000066400000000000000000000012651303525152100257770ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTER[eeq}bjsdeg|_ju_lz`][JNSiup|VZ^ߍy)/6w]dknyo~djm{[aflpv><:w{qpoGGG20nprS\eɨFJNˁ~~~U^gjklգxgscmx6 pHYsHHFk>IDATePﵻ;X("6蠎s!/^`4-V-r{>]44"O$S > b\8!Vo4[xj65Bڝ.z6!0'c`4ԢS|j|,sMō6spy /R1$ DBTr\ߤ0^|xfNܸ !bT S<~C# %g;$/)QEuM"I`^~.:%n課~| wV :&15R§w 3OPvmd)$ỵ_%YBڶȦ3_JndW|Ui#5Lf:JS8d$7ԈPwɸ^?3u}ȜmEfS쮉 A*bk;K/T1UcDjVz_3:T80}wNpJɠAke,}:{m;?[/4E5[񮺱馕ny'}^8+` x<IENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/slideshare.png000066400000000000000000000010271303525152100266430ustar00rootroot00000000000000PNG  IHDR(-SPLTEâz既d{o˦K>dHk;}unw;97o&wE4fpA,]_z|r]+,$zqfmaHtRNS-)IDATNP^oea01Hc\iGL89qM,n$$LzROQ ]vgchKl#u_וb?oQܔ! . k;GW/ JD44!9ԛIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/speakerdeck.png000066400000000000000000000020311303525152100267750ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTE9,2tU7]6~\6\7]3uU.qSF~G/qS.vW(qS(pS#kO"jNeKdK_I`I[GXFXETDQCOAMAM@K@I?H?I@A;`VaVB;$!F@F@E??|>{>{@|?{?|;x7u6u6u6t7v;y6u4s3r3q3r4s2r/o0p0q1q,m,l*i*h*g)g)g)f+j,m)j'f\FP>O<VCYGUCN<\F(g%g#bM<K3A7Dd]@d\Ed^A8 =2G:|bv_r\^MXHXHUEUFVGVF_Ns]o\n[p\o\o[n[hXgXgWgXfWfWhYbVaU`T `TcV^U ]U ]T ]S \SǶ(tRNS{{m pHYsHHFk> IDATc``dbfaef&6v M-m]-mN.n=}}C}C#c}nS333s KKKs+3+S^>k[ "[{~G'gWW77wgOA!/o_? /aаȨظ$Դ̬d1¢⒒ҲJqںƦ*Iֶ֎ֶήVi }d&MIDATHT;H+A3;dU (AĀ [(#l"Z GVjaF% PPD$dd;!Oŧ»a̜{a|exc)]^ Cnw4LrtW ݛ&ơ_(r:_6ndkcTRgR@@ W>Ez8>8;0Gi!D)c oԌ󳢌vu qÍeGi|ee.'F_ `l!XE|v TՍ BfgE㹻BHr9!R}Aq==E"T[kO` cR)t] Tt]Υ[JK eYL@J)憳WW$oo׽ssD6{yrUUe##V+!>5c`LmߗM`?ZZLbRJ(eLI4fRBU֦iU.! d2vN3qGg;;!!Ðee]7 !qE'`0dw$ jQ盛 hכl ''PO5(6V\Q(u>~ [e(~@~;IɅT%tEXtdate:create2013-07-03T22:30:09-07:001D%tEXtdate:modify2013-07-01T14:56:54-07:00IENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/twitter.png000066400000000000000000000027451303525152100262320ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp ]ivIDATxb?%BrC~$q#P#C&Ffq@7(w࿨>7 }|?O]} @ (ceM1K10p301W6gP*`V1TĤ/deCy }h|@JHɀmF, U1odpMD0ڧ!`^10zt,,Dde`AU`aQ~3AL0Sce Ɠцe`be`,@p988|*}\_n\ϟ?<4+r3h2; )1-9%Zu@@1(u$eX>p2bռɂ3^{HiH[xP:#}浽: ,CgFokL旿*ϿWfgf"RN2Ka@O5 yix/cd;{@IENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/vimeo.png000066400000000000000000000010401303525152100256320ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTE ; +ۆwٕJwIۃi {5{ ϲE ΡrdD|b uCw[stRNS@fbKGD ٥IDATU D.*]k< b[!'3"HHnI ::.zaxlIX X`7[`xpS@vֱ7xݛ Szʺz ۿxϛ%tEXtdate:create2013-01-13T02:07:08-08:00&%tEXtdate:modify2013-01-13T02:06:39-08:00.hIENDB`pelican-3.7.1/pelican/tests/output/basic/theme/images/icons/youtube.png000066400000000000000000000007121303525152100262140ustar00rootroot00000000000000PNG  IHDR_*?tEXtSoftwareAdobe ImageReadyqe<lPLTE#UO#"DfGJ pկnfȹGծnf֯ng9$tRNSX, IDATxbPf``d ~ @ lLL @1&q8X  ,  UƀYA200*@4h0#@2jab7XIAIAd B@[!0hV fdf`p000H0aIe;}1cIENDB`pelican-3.7.1/pelican/tests/output/basic/this-is-a-super-article.html000066400000000000000000000072171303525152100256000ustar00rootroot00000000000000 This is a super article !
    pelican-3.7.1/pelican/tests/output/basic/unbelievable.html000066400000000000000000000277141303525152100236660ustar00rootroot00000000000000 Unbelievable !

    Unbelievable !

    Published: Fri 15 October 2010

    In misc.

    Or completely awesome. Depends the needs.

    a root-relative link to markdown-article a file-relative link to markdown-article

    Testing sourcecode directive

    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Testing another case

    This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.

    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Lovely.

    Testing more sourcecode directives

     8 def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]

    Lovely.

    Testing even more sourcecode directives

    formatter = self.options and VARIANTS[self.options.keys()[0]]

    Lovely.

    Testing overriding config defaults

    Even if the default is line numbers, we can override it here

    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Lovely.

    pelican-3.7.1/pelican/tests/output/custom/000077500000000000000000000000001303525152100205615ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/a-markdown-powered-article.html000066400000000000000000000130501303525152100265720ustar00rootroot00000000000000 A markdown powered article Fork me on GitHub

    A markdown powered article

    You're mutually oblivious.

    a root-relative link to unbelievable a file-relative link to unbelievable

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/archives.html000066400000000000000000000116571303525152100232650ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    Archives for Alexis' log

    Fri 30 November 2012
    FILENAME_METADATA example
    Wed 29 February 2012
    Second article
    Wed 20 April 2011
    A markdown powered article
    Thu 17 February 2011
    Article 1
    Thu 17 February 2011
    Article 2
    Thu 17 February 2011
    Article 3
    Thu 02 December 2010
    This is a super article !
    Wed 20 October 2010
    Oh yeah !
    Fri 15 October 2010
    Unbelievable !
    Sun 14 March 2010
    The baz tag
    pelican-3.7.1/pelican/tests/output/custom/article-1.html000066400000000000000000000124401303525152100232310ustar00rootroot00000000000000 Article 1 Fork me on GitHub

    Article 1

    Article 1

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/article-2.html000066400000000000000000000124401303525152100232320ustar00rootroot00000000000000 Article 2 Fork me on GitHub

    Article 2

    Article 2

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/article-3.html000066400000000000000000000124401303525152100232330ustar00rootroot00000000000000 Article 3 Fork me on GitHub

    Article 3

    Article 3

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/author/000077500000000000000000000000001303525152100220635ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/author/alexis-metaireau.html000066400000000000000000000205011303525152100262060ustar00rootroot00000000000000 Alexis' log - Alexis Métaireau Fork me on GitHub

    Other articles


    Page 1 / 3 »

    pelican-3.7.1/pelican/tests/output/custom/author/alexis-metaireau2.html000066400000000000000000000215211303525152100262730ustar00rootroot00000000000000 Alexis' log - Alexis Métaireau Fork me on GitHub

    « Page 2 / 3 »

    pelican-3.7.1/pelican/tests/output/custom/author/alexis-metaireau3.html000066400000000000000000000164771303525152100263120ustar00rootroot00000000000000 Alexis' log - Alexis Métaireau Fork me on GitHub

    « Page 3 / 3

    pelican-3.7.1/pelican/tests/output/custom/authors.html000066400000000000000000000101011303525152100231250ustar00rootroot00000000000000 Alexis' log - Authors Fork me on GitHub

    Authors on Alexis' log

    pelican-3.7.1/pelican/tests/output/custom/categories.html000066400000000000000000000101271303525152100235750ustar00rootroot00000000000000 Alexis' log Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom/category/000077500000000000000000000000001303525152100223765ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/category/bar.html000066400000000000000000000120421303525152100240270ustar00rootroot00000000000000 Alexis' log - bar Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom/category/cat1.html000066400000000000000000000176351303525152100241300ustar00rootroot00000000000000 Alexis' log - cat1 Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom/category/misc.html000066400000000000000000000223251303525152100242230ustar00rootroot00000000000000 Alexis' log - misc Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom/category/yeah.html000066400000000000000000000127561303525152100242250ustar00rootroot00000000000000 Alexis' log - yeah Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom/drafts/000077500000000000000000000000001303525152100220445ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/drafts/a-draft-article.html000066400000000000000000000113711303525152100256740ustar00rootroot00000000000000 A draft article Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom/feeds/000077500000000000000000000000001303525152100216475ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/feeds/alexis-metaireau.atom.xml000066400000000000000000000537161303525152100266030ustar00rootroot00000000000000 Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> <p>This is some article, in english</p> A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom/feeds/alexis-metaireau.rss.xml000066400000000000000000000150261303525152100264420ustar00rootroot00000000000000 Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.htmlSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article.htmlfoobarbazA markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.htmlArticle 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-1.htmlArticle 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-2.htmlArticle 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-3.htmlThis is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.htmlfoobarfoobarOh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah.htmlohbaryeahUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/unbelievable.htmlThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlpelican-3.7.1/pelican/tests/output/custom/feeds/all-en.atom.xml000066400000000000000000000536601303525152100245120ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> <p>This is some article, in english</p> A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom/feeds/all-fr.atom.xml000066400000000000000000000026151303525152100245110ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/2012-03-02T14:01:01+01:00Trop bien !2012-03-02T14:01:01+01:002012-03-02T14:01:01+01:00Alexis Métaireautag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html<p>Et voila du contenu en français</p> <p>Et voila du contenu en français</p> Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> <p>Ceci est un article, en français.</p> pelican-3.7.1/pelican/tests/output/custom/feeds/all.atom.xml000066400000000000000000000557531303525152100241170ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> <p>Some cool stuff!</p> Trop bien !2012-03-02T14:01:01+01:002012-03-02T14:01:01+01:00Alexis Métaireautag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html<p>Et voila du contenu en français</p> <p>Et voila du contenu en français</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> <p>This is some article, in english</p> Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> <p>Ceci est un article, en français.</p> A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom/feeds/all.rss.xml000066400000000000000000000165561303525152100237640ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.htmlTrop bien !http://blog.notmyidea.org/oh-yeah-fr.html<p>Et voila du contenu en français</p> Alexis MétaireauFri, 02 Mar 2012 14:01:01 +0100tag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.htmlSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article.htmlfoobarbazDeuxième articlehttp://blog.notmyidea.org/second-article-fr.html<p>Ceci est un article, en français.</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article-fr.htmlfoobarbazA markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.htmlArticle 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-1.htmlArticle 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-2.htmlArticle 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-3.htmlThis is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.htmlfoobarfoobarOh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah.htmlohbaryeahUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/unbelievable.htmlThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlpelican-3.7.1/pelican/tests/output/custom/feeds/bar.atom.xml000066400000000000000000000027051303525152100241000ustar00rootroot00000000000000 Alexis' log - barhttp://blog.notmyidea.org/2010-10-20T10:14:00+02:00Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> pelican-3.7.1/pelican/tests/output/custom/feeds/bar.rss.xml000066400000000000000000000017261303525152100237510ustar00rootroot00000000000000 Alexis' log - barhttp://blog.notmyidea.org/Wed, 20 Oct 2010 10:14:00 +0200Oh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah.htmlohbaryeahpelican-3.7.1/pelican/tests/output/custom/feeds/cat1.atom.xml000066400000000000000000000050751303525152100241670ustar00rootroot00000000000000 Alexis' log - cat1http://blog.notmyidea.org/2011-04-20T00:00:00+02:00A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> <p>Article 3</p> pelican-3.7.1/pelican/tests/output/custom/feeds/cat1.rss.xml000066400000000000000000000037201303525152100240310ustar00rootroot00000000000000 Alexis' log - cat1http://blog.notmyidea.org/Wed, 20 Apr 2011 00:00:00 +0200A markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.htmlArticle 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-1.htmlArticle 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-2.htmlArticle 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-3.htmlpelican-3.7.1/pelican/tests/output/custom/feeds/misc.atom.xml000066400000000000000000000423261303525152100242720ustar00rootroot00000000000000 Alexis' log - mischttp://blog.notmyidea.org/2012-11-30T00:00:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> <p>This is some article, in english</p> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom/feeds/misc.rss.xml000066400000000000000000000067771303525152100241530ustar00rootroot00000000000000 Alexis' log - mischttp://blog.notmyidea.org/Fri, 30 Nov 2012 00:00:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.htmlSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article.htmlfoobarbazUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/unbelievable.htmlThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlpelican-3.7.1/pelican/tests/output/custom/feeds/yeah.atom.xml000066400000000000000000000033271303525152100242630ustar00rootroot00000000000000 Alexis' log - yeahhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> pelican-3.7.1/pelican/tests/output/custom/feeds/yeah.rss.xml000066400000000000000000000014771303525152100241360ustar00rootroot00000000000000 Alexis' log - yeahhttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100This is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.htmlfoobarfoobarpelican-3.7.1/pelican/tests/output/custom/filename_metadata-example.html000066400000000000000000000126071303525152100265260ustar00rootroot00000000000000 FILENAME_METADATA example Fork me on GitHub

    FILENAME_METADATA example

    Some cool stuff!

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/index.html000066400000000000000000000203701303525152100225600ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    Other articles


    Page 1 / 3 »

    pelican-3.7.1/pelican/tests/output/custom/index2.html000066400000000000000000000213621303525152100226440ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    « Page 2 / 3 »

    pelican-3.7.1/pelican/tests/output/custom/index3.html000066400000000000000000000164031303525152100226450ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    « Page 3 / 3

    pelican-3.7.1/pelican/tests/output/custom/jinja2_template.html000066400000000000000000000076061303525152100245300ustar00rootroot00000000000000 Alexis' log Fork me on GitHub Some text
    pelican-3.7.1/pelican/tests/output/custom/oh-yeah-fr.html000066400000000000000000000125631303525152100234150ustar00rootroot00000000000000 Trop bien ! Fork me on GitHub

    Trop bien !

    Et voila du contenu en français

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/oh-yeah.html000066400000000000000000000132751303525152100230110ustar00rootroot00000000000000 Oh yeah ! Fork me on GitHub

    Oh yeah !

    Why not ?

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !

    alternate text

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/override/000077500000000000000000000000001303525152100224005ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/override/index.html000066400000000000000000000101651303525152100244000ustar00rootroot00000000000000 Override url/save_as Fork me on GitHub

    Override url/save_as

    Test page which overrides save_as and url so that this page will be generated at a custom location.

    pelican-3.7.1/pelican/tests/output/custom/pages/000077500000000000000000000000001303525152100216605ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/pages/this-is-a-test-hidden-page.html000066400000000000000000000101671303525152100274710ustar00rootroot00000000000000 This is a test hidden page Fork me on GitHub

    This is a test hidden page

    This is great for things like error(404) pages Anyone can see this page but it's not linked to anywhere!

    pelican-3.7.1/pelican/tests/output/custom/pages/this-is-a-test-page.html000066400000000000000000000101761303525152100262400ustar00rootroot00000000000000 This is a test page Fork me on GitHub

    This is a test page

    Just an image.

    alternate text
    pelican-3.7.1/pelican/tests/output/custom/pictures/000077500000000000000000000000001303525152100224175ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/pictures/Fat_Cat.jpg000066400000000000000000001723231303525152100244320ustar00rootroot00000000000000JFIFHHOExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:31:29 PrintIM0250$"'@0220    I &|z.0100,   Dd2010:01:09 14:55:402010:01:09 14:55:40 Ndd%ddFddFUJIFILM 0130Jj r !"#012S100 S100 A592D34383231100603D7050TR73277NORMAL d^^R980100<D(LHHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?6LOn7SoCW,6tĠ>*IwrJp@]~&hFx应FNsSX$4:02~lnOp~\Қ2pR%HQL`tiͅ?r j\n+.AvLpG 9PXtMKL x9 *%T0h$H9??E(A81.cʰ;pDnXRC+F;֠Vx _zIo?́8ֆ\IN!"%T=2"$֎O 攜 B.8Jb"\ɹ`RGZ[;F!Kq}(M~l֔_ 9}ji2sv)Kހ OHԕA1ɖҁꭆݑh2l=r3(X_hRR)Ҡ0{Rc>EP‡"1b[硦/ݷ$*nAp{@;if I':Rݸ=N=i8A=+a*pcTЕ;PWV} ?漺ھOxc;Efn5jr= ;+!jnt\L~\\!_Ą=/ҵ 26v?+ώdz4r=mܾ67 ҷS37VRU]nCNa!D>Rz{.#s֑{p知fh%u-̠d{VAP8 9CE 'U$d*G]オO&BLň ?VFi XOC؋7N}N#Gpbp׵DmAnwcSYXg$6MyQWǽG#Q+)`@dž2 :əFǓȥ9Է;<*2T4Qj@g $f`hD+⢝_3MXx|5)+e= 1]0Xٽw?%W#v\Nj5!on.zw4 ;O$ pNYg͹;*;}X"$`҂۹Jl"}pF=iF3Xɤi oq9曚z.rzUv23WWn{g4ˉ|zk+اyWaEF#aG^^Tu" ($yhU >F9.;K;Tt#0)rLOovJ1+Y-3fWi;0ҹGC9Y"ǣ}* ''TzV`cmޒEl8( N}м_C2ntURXkIr\OJMXW ~vIG˟Zs:,@&F$Rfd5GҐ HLEW4TOcןE^ivaZH%wkIHćS~nZxRI>ILj.bϩEuI'JQ}>f˜Cʫiq\0OLSzdyiIT6uJC>f\}}BA{p@H:uSXc+&h@c f'= qJ7(,FUv$ = P`F =)J8jr>.TyՔ~}҈nW|@1cmrp+"$4=qZb71/`8ϭ7y-m^G]*yK.T]yqܲ)8k#A]J𝸻 Uqj.$rƊ<4?oƾdp'[-"gԛmR#qֹh%u=M р7׊z.t qm, xkt Y\[rḲ-8{=.V%e돧^6,1oZJQ'K0{bgGԮ8OSj*XqWEd8 u>Rܵu7FӌHQֲ|x]z+48ۓҢxAhW* ~EDLR1UN@doW/hjM'BN[HW>S;oO;YanUsB |߅hM#S, &UHdI^'iچ7ZJN8F *C""P5Ic{-d$4ȱtV@46C>m"[u] FᎢdb{qszy3ՑMUWfB#@Nl1Ou. q)d8ʝՖՆbr 7C`=hzX@mM,s %Ipǰ- bܢҲQ7mF7E<)NcE#ieA؂B g-WRTRRAC&xm@ 9u(ձW, Qs7D䠐2FبFG~ Vz,DaA4QJ.@}*t~@[GTTuSȩ  h,lH8W.S;MQ<ҿʄBGQlnq.4B# ($l#p)‰O]5*ƱL`p7g`ŚjU5BFgx+)*~mq2.0rN؝ * s42T>vji6P_g׷!}=54Mh]^%K.4> x}9ռt֮4gCCrdNݻ`mk3-\h'֥d֪ 8f=xQ|K,QPڥʨBG>n?a }-Lk׫G ױ RA;G߫ޫx$gd:(.*w's gbQԜk*BV)%He )99䡧K:UT7Yj$AvM"i:F~`m'8MM=55E0EIvtg'-QyU' FdG;/PpoV`}5-ʞ8xv=Mbu01dVx9lza\Ji>uI#Tr/T$M,ȑHd(2k}1sۆ9,R\&q]::A4T=N891 kJ15U"Fj&]1kgbr[ n<9çHl7rKԎ* ]bDBA՝)r"ϢJzVfX%hDzRz/HKY'`̬ʺ|20; cpmKJr5]ٚdC2 {\c$@?).w&枔 C+yYrs6A;-jZR‘I#i$ֲarA/YmցN1ަثH\f7+H,u,2MIrIH;1Y&%P|P|( FGN c1 M(^6ZbHKrq~~]k4RJ`*?Bvlt-fJ:e"j9]{$ؚ|+ ix~;8O lM?+s];KE*@+3,c꽻 mǵvVGPM&T6R6%-9?I#з b&Gu"jJ@" *p9=Ǿ1{=u-4"zr<ͤX6|!̐Ʊ=-5XQ)rL#" 8ReB0#`0Fޜ`JɋS^zd|+$7Ս2dIRH [r(Q{Q`2٠\vQ vB٭b)fՐN|Һ7m=$9`q/1J`ؖܖ۹>$M4G3T*aX i=<әT M׸6qFzy)by)TOdHUvR@ )y`J5h Ab1r5mi"{!jI6$%B0[l ce.,T+MtY`) }8*Պ2Fj]C '}d_^2S,sK$ÍXa#Lyv4DRB$h,]2X;'z9!f3(+$O aF>^T3T뒑r:UePIl Rt؝;x)l)V\^x%dxԹsf!q A8qWIWC ku {y|lGہkDCױ-E,늳[L>5܁'t&Q(%q؁뇈5 ssWA, #Ï./ԢkXh\dc'|lr\x{`s=Rَ߰|r_ARֶvP^{wӌ.+&SCӌe.DZZCcGgP ԈbH N |qB >U v:9%ȵª\eAOӍG`qW r+,=^@ C m.iSҕe뢡U %YJ7/Y-]B *q_^ &KdQ%5%ae!DB)6w]#gH#Hs* Z@ƮqmE=tBzP ~e j,NV)SC,фM.cM Q;cmMk#y(jMR9ܕFOm7&-7V*$"yΘt @ eOSOSVy%OD!oΕ=p: g#,**n1[β@WT(p~/Y FezyJk|¿~trrX(g)C4}1'PC&vmƱ\h)gHG U@%4w%N7#2t0[TLi#U-*W`c$v` ʙEGU5yDŃĽ5g T:5w:*{|F ST6 9$d03 QEUT¢%.R<*pO~[V5:_2TKA2G<3YũD.1'.FANN M+;ȏ*N>XvSܗLs*\ qjw6Z^QS+*, %\n.(SFfjEcG`No =QU ȵz]##$7ǣf:I::S WsvF%Y ZV1t0V\ [60}dbGJDQLjeEIfl #s8 TRܨ0)=m?I cըRrb}8o }M%LeGs i ۊi$TYm!E0/!XcnI:$[O[Jid! َ?1<#x-6[^u!Y$\'a07'\9o \=tQ ?1UV_RF}#I~EJAJ>;5 ,6#9`^ُr Sa4cELIիP*.G2)s3STuqYj) CN@2{nK-'ڷZz9F[*\MƬnN8J(*nvB2^̯I\vI=25%XS"q#)Qΐ8i.G^ ١Zp*dy v{i؟~R[hy%X~qׅ$wEuHӍazRK@6 'ԦL~=[SOU:Tav#HܑOrqvvhtXds(.ñ@A#|qlUQOye,z!tҬO0vCTubZDe>m {Qz'VUH Yf %W;0r r~nFs[I3dv6")n6yDi[RƯ0PՋAVX*DŖXŽ3AӰ%z<5Қ\VպTNCI5a70T ةxޮ:Ί5,Jls&sX g_GQQFRW0),aFvsK|[h!H<8wr#f\nRdOY6k,Z&g8 UjuLf*24{'ok>c xH &bJm ~f6C~ڸoAfz\cj1P$(Q$?V@ gOrX)Nu.#"AW@%}lA μg\N̕idZa JuzNOlm=Kд_Ω ;3dۀ ^ԼH,0bޞHNHՐ*%˵:T+Z1uw}oX\+TF$sG0p:`3ܩaevK|P"RuF3$;?n%ؠP^Y9zl428]W *$U"%Umi}Mv%hj֥UZws3Gm̖ieq3ըzV;ar3hlek'DJш8X@Q;6#.28:{\'jx#fAL3+!й8n/ZBdft@~Y.Z,KH"ȳ6@9Q&lgxt.K:S3"H͆ʔ;`bu<>^==)AP0PX_A_&DyʳǔT}Ďn. zQJ{@RF #IZӴSMbWdv#)錏0[ Xg.&A}yǶcwe`&z^fFpq$R)yb\*uEYP9vZ_N S]]e#e$Nv'H5AO _UD꘦(Nlq`mxoq4x6=҂iޟLDW1Vh6;sj =VRCJUlNA jR@N@0LUl -Tȸe8탿O흸 5ӣ4H@9m#auی=,UBP!ETn`1a-zkE%hf3n!Iv"j =]U5S/Q l0 lL2S*Q$# 6c=eƑFHbΈ9}3I\LM!=6m0pj~"۫bDuelH;9 (5y Z@Ә2v9+k<Lx 7pOiZfzxLSc?H l\VV{Q]^SW!zWf `201-W[.J q":`'q*Lky办:LH4UQ ƜwZ"H$Z cpPM QB6֧LdigtfVu6̧|8|vCrL 庤noBp_o^$mt$ #:UP`sRב,< Qr$3DyFFs;q$Z-UtR,TnO@ m-HSz;^)9L+"B9: v~b.ecKUy:"B%+Ldum +^JP2emI6>wG=١ʺIVEG%S;@)8'pp3iuri$g%9]AI8cNl3y o*BP4 ye 27wlr14 ey%edhT is%)7zlPƢJ D]3t ^X/ 2l1W߭j/Xѻ?1)rF M;:u1@(3"iܗj)sTub2T9aP3،PwI'b5UAF3 e(G.=PZijzY0Ơ}x9УQ9oz٩y f&),l9bNJGJiB0F78p6BTOO-2s]JZzr"NČyHT-m_LdQM# 9=~GH)nQ6MZ]{$t0H騍STQuH¡I!۸'h{ ع_5=M- 7S$:@Ab+KId(˩!Sl8z`p/DyoEA$#x 4 ye$6DwDLӤq:UK a$;nRÎ0ꑰ'Nވ8WGgL 5} \axVUtIK Y5T% ۩##9jϔZQ#\~^ emz@P6$>#)y{NU[KBSNᖼ 6 3"y/Co-Ti32N'FY;.u.·I<5yiPU C- YИNi*b&*zC8;,mƎH.L@F}Hx3gᐒKn팏sCeic_|Q7`MNĔf25 H3gڝ0㨆E'NF5~gm*Aԑâ~C)tC&,]2ZP@'.!K_M%n% bɝ nu @5B 0XGc$ "G!iT::\ǿ*(^Ǿxlf(1lOۏ>]$'Vqۂ-nC.1∧%|Jf\F@3L~ ǯIM4).YC0 (|zʆQ4 O֕VD}'x-r#w83GY\W G:~N+udS_j'/..8GSA շ5YHm敜ySO,-N,1 ' 4E* ah@4A VʺyHJA:N7+qɏ?;xGP.T~sM/XZ^\@y::1 6VϦ|KC :wvuhs@0RAzytq7"%rJAKmJ@8ܮ}fC]h.si.mSd`9j85dQGOMFx؉F|n{^r4qQOѢыTS87]v[QHt@,2GBR"ՊZp@ TGZ.96Ⱦwʋ4BfO(|OxrO*%3:$EePXt./9S\',tR8$1{7$xy t:z̪A ylμ5V# Jp3wرU7-:: P6݆GDde* NHLi#iRN;j=gfv#`ldy;Kd -ec?NMA#vn#H ]]ۦHSwp6˗I硯e0"A؍8pr924jZT\c, `ocm|US :2H''#ntn(h"$\eJNIՌ3@F$ SU B%H|O|*zW+43u`$KA PcBH*䧐nv`pW m9p\i*rgQJ/۝?ڊ+)ɅT$ I&Wv^ۓn۫Rq2Je {NH(N] B`}aq6 0?5?W%]%UIBP ˰`(%}>%~(y[ồ~HjDIj'C!ϓ$|g:]m9¹X Dq䞜`)tgϖ۫GH-6ey ߑx/Q"FM*wl{q6[xCyq>8YE! ;9Y51\(hL$8C* $d}Ś )Tly2OxѴX1\[ r! V8e `|r㐖b e0= ~ ,"}9} Bi]И d߷C,Ta ?]ĉ!8s۾?t$1ó1 7w~#6ZE_HJw9g{I1 K"H䃝ĝ7!B&~.];ln܍Dڷʟ{~\TYܴѶCn7Rvu5bfVӑ^,Er{B] q2L:]Cf?}c1eSE$lP9Fc  8tc/#X֙d9Ks8~Wpab!,I ߊ.0*eݖWW $' i獁P|9aˌ%+/iPw{uODs?p2?~/r3uޖJJ)h&de %u/̮: 9< _W:##mnӍ14ugGX gG--%+ZwWIQ`dn5HeCK4I-<$eBKV8DA_.Uu-$ R9S"W_n5KY@"<S%FVRr g0pYLUutUVS"w(!2Cd|cՂ+6/ hz-%QIx{Q# 5ltW\Kf[*UDc;)bXce< .hIuS)3ȚdfLww ̶bGG⩋C5$u1rt`l+.bh+MeBC;SL :6Lef >~aIbog7Cx\lA̎w:C}G1-]3,1T -^I a$ 1gH>*ս嬚{ETϟ#3CSiZ=O@ROW;a2G?)/wTRi3Xb)Ol~A[+m5WCXqRg%rHw?0U\uKTTC<ñUʜ,h"u`Pb csr 2m vRY+@KDFWJI=VÃIvAⒺ 0aoAHg$3~ZhV4RpP3 $wj4ZTb S1Gu[]u5-&  2urU:O}~%XtꠍTC/P4 )b ʐtoyUG]piɊD^[*mGAҚ9%סKd6 'mEBnȟeA3)qNc N !`J"bpb~翧-a@i@Q)0N9 ;ߑij&jQEsB1Iv9< L쮞5*2̡BVg͆0>y .pK*ERqty\m"+XXq14ŋo9y`(m29y9#H>9YIKъv'}+MIN7u1Y%J"|rN/gOjُ5rH[M.*++ce9cfy0sn+0R{joۿ@Rj:u$y2\ @{L_8Fc ;r{zkj`θ$~\,5* 1b L۶ |.zK{qi '?޼\QIneUf]*V}0wu'*L:tăwG37m1* JFΘm}غtsD?n < ƧVŽ}dJO1߶='5IGeu*Hg66ʜU*T A'ޥJy|>ۊLi:#T79oPYI2TJL>*`v6TfΜ x67dq(N `Ԝpknnk=4ST,sB$pA~6/|aEEtUdx$m=ԕmGcR2IR=8 w:c@#Qrq/|o{ɗZ;3,u[!S02YwpbTrqcѥ"'_:r墮ZkaOC4*#tǕt)H'r*9;j$5`VpNIo̓;xH$P f8 UNˬi;|A)*" \"V:@*8.Y7φǶkg /(X€6OSs&rYm,0u2lѨ]MN3xW21t&# r;~@wKB*lx!)t`E! qfOOy#k5nr(iD朂AHBz빅REM * pGprzp{U]%m2EԮV6Rce +(㊦*B H-*ap}TT1U4 $vg9O~#G6ARO|嶶zeMAd:Jc`4$%rw F~ dTF& 4_Sj685,<%&һ32Nܓoi9Xjе`FtzvSrNGscL| 8=2Jݠ-mjR,Jw[Y? "ڕP߶UIv=P?∩E=IE;OvtbUtz~lۿsRۂ|Η{tjڊBŋ= ~`e`ѱ`Tv=͑(*67Om&%5\:M B2lQTg*(\1l?kR/b\4%!i]Yp;nus$dƥ̘`Cq [=|W Yt:ib[љlkpj`ÒI9nZZ]IkYհs(=;pJu{E}}BH6 ϯo^5ۑ|,V*r; QLz~d_u8꫕8u8MNs΄%zaRuI@W#2T7mAk-=ʉ&zE%1|En5o&t'`!߯|uNc0<];3lv;QETV%3 k$h .Cߴ.Gr$ctfQOqj 4P e`;n%b(s7S教ʪ)Lgn+)U hJ7X {xsH%P"7A R*+v66 c!=ꡩ- 3RHS@U1Bb| Jj{Ⲇ#%NNi  4^BM z~Y$әחʐCM )A,q;{Ċ[5cY8Z3"VDAm9 <^-MR믎K,Lnb=P1QdH]!#7hWPncb0xMF4βڨ)eԘ`BĐDzU,E@Cber2FGs`q?5U=(ڐyֱ֌ru*ccgǷL+g.nUϜtC<7*IY|ؽCtNnk ¡G؞݉ny8ҖCPe)?n:5mʈ唸ƈ|Vf18xM}b3.+SH CFH*3Y;`KU1n#bO[p*`l*p}9GV2C 7Ʀ@9߿2 @ebTs>p"! C guH@ ԍ!׀9#nG8rN#==E&BdbsrxO^b${`p|&,] U'$=lTVFrHɬ#Y9=yРe* -~]xYq4tx؏HQ97.1/I[/s)ߋy1N!Q{NnN&2}%ʹr;ct9qEbbT|{ot7 {qXF5cǴUUu>e*37f7.f{]Y32T$>`{jS)"*`gV0duIgc'>| oG}ĿҴeE|8#o\ovl6rQQ 213〴Va:Q%\䗔,I!lؗe򒛗o-H(=!!;psէ)kj:y$ɼ)Rw*T6Oߊe7"ND~J$,KPtΕ~rebF ؜yG vxf&xS!+ap>ns{o|)ynJEt.u>-a/?>*Aɒ:xmˉK{H$|&`[`0=ۇ{#[y^1z+dMt+ض5wH*b )tЦ?8ggL7t?~&IZ$3p~R[bIYb*Z7]w#;3AGA4 Q YLnj,G#f?9SK)3N<[:x\#R.P[2V^ cGC=GQ n6⒰[(*Y^FJy(#nkre}-$MlRSHNfɻi8i.^UҍWQRSTľ@#%Ce2`?N+i ۓ#P[gZGDXN5:I>n ]T< ZOMS[GS2Gb`U%.rC<ɂ$ہxYs9v'`LNkzX  '#gؑz:iKJI}$iqg OJ9E΢+tqbêQnкYe3M iX'Yfm NSQ$k7W X( 82qucI Ushi*Z9SeE`Q=]@:K2m,M`~[**`h*%մ6HI>q%q:YW>\6H=A'5rWiCb zŋb3ۧZge1O2#͐2=56uQ"R4l)SC`ዀ8߶Okwg-1;2RPVG]Frt2jO7B"T>QNue5F8be*t G9W͓~ZJB0L8clWlm]ޢ32ž8 | ֘G!!57}'| Ht֢2R$n=6 mҹ^U zیgb/E&I,%e%{zgn AgDI[$>TqXT@v]4@|_AŵrU=qvz3qqk8R1) 26s]4EQ?/ZV`W;gnz#捔O|QRYw%lҫ,r8PNB6= /w F [Iij9QOy[ P42}őcHT:nDXd*}N).7yR#) :vzpa$ BHˋY&7 !vÇcHRm[]c}])y%EA[<+) !\g<ZY< ^։f9#A9STg"cV\` ^vNpȎ?O 4#@Eǀ VA_JV.b}.P{uWhLP:eU:# K72n{O3±FTTCNtp FC #; g% vzybus@ %^HN[, ۾= S +9njQ5H#p}x?>[+O*#iMPNpϯĂɫzhYM$Fx Ȝ VBue >bG}ǿxF1Z|6#'f{q +%Tm SQHcFc8 cn4ƚb]/d)ɧ-3T p#Iz4`cKƮ81Ԫ]_ v`^u钴b3(8;04hXtDl_~m^x_Eɩ*.'4ZR ʬꥦ aU݆NQt.@[A:aQˊ|,S K+LLX#c~:Kݿ ZKaԣ.Đ41m7յ ;̕lߎxcJjh>J)"r!IN#ӆC!ZoWkh9j,z,If',|.<QnQGQH渼2 8P6r;; )/\(JFiDW=0zpBr֙eg 24S|=r6Z[/tLFV IlI{M˴5+WշӺS:F-C';椪Zi$ IeU$ AǮ h.I_Dh))cTJ` (0bw{dpp--@bʙh.uPyrۅVdha*fU`ucf_7j^)z  raCH`7pOg-kU Y9S"udf)W'Wie,>F/݅ ,]bhD4 jU2 0$0H7ཞUO3Jƒ$ &7!QwGO9=;q_j `1.1w ?/SR:M&d>7y8/njHgT$jgң8BVrU5Q?le˕V/(`ǧ”1 S@cy 7iqfP&R22N$omQ ,LkEuAoa,JYtV7:;woTW, MP}㣏% rZ$n2p4|GX wvo)i%r}BCj$d\)~ff'u-2 A)]8̱?c1m5El07qM_uy:dfNW‘Rj`*OۊsQ]alKlN !Tܨ}B4H)ӍC?q͜uzڛK.s+bZOA[QK)Z3oT?ˍXfilջBV]hk#|[w;jLv*b*$zekʖ65=vl]H0>~Al^%-3Do#"2,锅IjLRDt*qӎ`c qZG)D,pq$ӌ n'ٞFh4i*2oƸG`@qgV]k9e\mJ c'$aHV$GTh2\)iY Td7';gZJ[mrK^0+qn˟}imoHUMw嫓`i阸VHːF- d s=Yzt*bHi&B 6N6ᛞu7":Etɑpd)BDzhNbQq8*Uɕ Tb7uhI2+d'e3㥵UiX#i#YF6c R[Se]JBRܒw:P1.KBb3M~a,&`IϮ8ПI/DzJR'K$QFRY[0I- A4#QӮ g*5>q w{yx15*eHEo+;@>V~<= Z2EdFM;6*rrp}=8VlTTհ% ⚥iҧJJqrK:TSHجaT~a3sV//[FPQD`cbNw\2sq~s99W)zj$fܱK>\8e$ =8vW+&i(%e;8*Jca ջlL?n6Obxz&|@JjH@f'Rwu3W$t h9s 4vOlے!j]N}ۊ$d`۳!χX|YW:ȣF&p6oӍK[䀮SNgY˾+AAE ˣceWW++dv+Eؕt* DK㽎 KD:jݲ ӍexidR}Gi߉xڭSݭ5 y5h2Nr0q!ek5EAn X}L9D}/_QrkPF(H0w`?9n*P 49;aOazG:;fs%UXmi. ( w 1&O -nO=:|1[n-(KIju cߍZ֔|D*S~&٢/U6EKEmpb=/jb@K22۹"@Mٔn=xĻa|y,T1WZ8*]DQʿǯn,w+a˗\cу?_U+-W,r1J=,:=}oͼS͗ډGvv;_`>afFGqv$G'<Hem#:w?F ;eoz~zFc}8q:]I=0a߅Sa cN<˜;W2vlg4^)ӕo^覒-Rn#2dp{°9q/?77ެJxLJ_O5 +kdf#~;oj<6^2ƓetP AJf(^ӈg۶8N^[Ġ9g0|*cxá98p!|#}Ha?~)3`[덗TOzz>9ھAUnHDۍд[>H:}=xv nw¼1oŖIRf8xweMhGh؎?yn-%<2q۱.seZԠn[Σq#928!Q`{}` ƉaU܂v,146F0slCsh1ČIڶ~{=yImB RHT@FDeL9 B8?vUH:S#/ d|,SA m҆iupPea>lw6(8_#{I|PPE3f&h.FU%T\曥0g IW;E]R:> Rǰ'8sfm0V`cd'2qH=6]i}ڦ]EP LsNX F|c=MASI,$$%J6lsċSۄVqFe3,D%MCV p`6#n&i2@ FWH8SH|g{읡vhx]٤A|tĶOU[=t1sVʄ'cěMvj9Ldvu8oȻٶV~b$j>j9ؿ;9^dX>A 9QOU)KF$E?ś1cF7Z*,06$c$cc}5g秷XuW > UQ`Y+*^"R5kdhUns664$5Q].Z=^fl*=xyTZ[oZ b^BuaO{n7mUir.Щ"Yl8W9=;d%x uzv+SGMCNPjdgnr8a4=zpR`>;g/xEYwjv26pFv?~qc`X %dE@=ƮXd~vxXҟ m#oT>Xn,}h#z*WE[EWK4xd1ΣIo.OOIE4 T C9 1uaD"cu*jpJ7#A*DF",2aةd/Ce*"ROK$7'wY.#`-:CN`~sO-6~Qp#?1$rUA.DjX '̓5G|ܾ$2X2^,H2w_.'$lЏ2)H;`靇sUt5]Zv]/R؂vsn171RU:SƥZ(Hq*ϮA{W٧lP$pbU[[PKG.t GPˌ`nEnە5vhDB2F `#mg帡W.qH#Q|Us'P`Ī^ezY/U5K7^G;AWɐ;͎`+ᩪ #3%<хE#%W lch#8E1t@3GL2FN9%NJCO;gIX}>|璖RiV+!`ԙ!RI.WFH;z}xqXn@uDsh(U@s3ێ0bi$6 H+&p`ڊuij!`8Q,w?HdV#=25m}=CqrԲuU&Se.0 osſd)Zoh5I8 ӋEYմbĩL ]I;g45R8d0nH]o +"2c)*jḃ;0RB۾]RPOotz!CE 9ܟ*))ӎx%Ļ}-}ZTr4dvv>m󃃿!^챗b ,J`uFǦpOJA@u8* `Vc8ǯ#Q]Y]qkY$Q[L1]C;*\ lT0ApOuO#?̫IUXGVmAǔC}A8#~aW%Ne:ŎoTmM0Pqb|P}kVyRVC #'7 9z^Uqv;bL=pJkফN .eMXs߇[]}gK $I0Hp@0si~eE t*),EKXUEZzB8ii2+jRWIbm}ZCR}$jz [@K'CQWfD/t=$;*I;RVjI! AW p+_5uUDumz"$_Isp\] ) h&T&hd2ɠCVwc`@Jz# )ҮO !IB0 Guc%'W; B`B2p{l} Ye;oSpJc7?9+m5-ڟML *ߘ$~6/9LYga(sqnڻݢh`$IH'GCt??|r_y*LUT:nē^+ogdgu@5FX,KWI1ώ,r_o4<-\/n㫹SssIn4s~4="{G8}I-q޺ 7%D8$|Om\V\i(L3c w#˼$6WUEt=U|[@ sW(J!-AS$yu  $r2!R3FO~ɮNacbF ˆ6ijmYJ#z"H9:@~を ;zb0K7 UI %'w#wH2m;e-(I"PTIҧpfUt$P0IdP9w]灩9M!I3HAWuzt#K']RU }HZr%- vOC%*Z-:;A4yH0#}/si]:Hazy'`~lg6Y\ҢIZݔGl7Hv~bW5iqR;V֙>3n/SIY؆ǖ#qװ +znT# zEA&&a;LGFp1\UGwdhVCD 8Pn4錴VUQU !#MWGc"۶v@8ū- 29g #-K6N}SƵm*G +G.Qi7A@]9*wtZL4EVض/^:̶ihe;(#0 2_*t@ ᗃrk=$\-q 3*gw-nT y"C3"e< 311>Pّ>bxϑZGL T+TżR¬N@qAxZx6$O[3=;OXcV]8lt)={eEMXKJm,1FNxj˜1WMи;jٛm"fvi*DWH(UR5sӜqShw5޺%sQUJ @"Sjӻ.Q870^ڜ4C34CdLH;.sm=9 2GOTe#1&l |ZT%+ rC8]69c:EzV T,`P:F`e ;Y SG3P/V.6aՎ/QZjP$1*hW(I#EEך꧖Y4dI#qjc|p=%,uj^je6:G~fzK\\褑,W5>c$dl,X;0d/tUQ5]G L">V:|:p-G.a\^u+b p\N̤-0yJj[+]*MU'"+(,@WX9`@+K-Ҽa;#Z'|IuMtOo''^(tIp:p v>ZVV+uE3QZ>zV@TN`؂H9&*z,M4:]QʔQM"ޟ榏Kaԑrc½蜻t_J'bKuVT.$(<<._J I $!PHـ Kk庚4+QE4z8\c Ԫ H-k5ǝ3Ha$Y0\38P}xQU꩕:JXnqsEo1rقh^UeMGNPӒ A$q;n6jd^TI&#J\CpuO{b{& (CN2vǿ ^ܢ#q폷 KJ2H^=%>ȷ"b b6=ҟÔ|m4G 4C)#sH1V@R?ʯ9ڧH$icW*:! # o.*؉[~#W\D,!#OHxLYp[QaW IUpp26c8b Cɺ;D+LC c]=l־`UVuɂAv*5 zG3lJc|EtZƬ9:69=A:]uwǎZ(m' ӎ/KW4-r;t2FM#N0[zjUFY^3Ӳ`F5NV*GxIRP+#HYwf H{mTՑ=L0X+6JcbJoZ`DQIwHl{O%(j5DT*!ĚJ^mJ5*+az c' Mdi<-o[rEsSr*#oMGj+tG'\ ҳp@e*Om1۟+|OY 5RA$ԉҏ9>`Iq%y -Q$[F4QRK )\~~tv|*0W^pPP^IAbW  0b3qCM dr*wI$w}2) [voԊ[<1 , $~9%-T2DG3ui 5mveyRV*eO3 EK;(9@=U-s_`237P66W9hG\Q)|] ;0tjV;J{%$un̈́e* 8d\mS$Rxi9&o#wl8a/YtZRпTy*:*˔wJKB xVc/o{\LE|,*5$؜q|9i;UmZUI"PDr +%Nq|0P~ 9C??J(9gI$R:'pnb1Z䋼YjkUnAHhKI|sy a c4 (:u$ Ƭ۳V?mEGTTU҈O,sÓXlǞH7R#=,lHwe㖡TuI*jɪ)Jad,rAT8__ qEtڪyv#J)5l s N/?Aω$jtB[={B5O흲mِĚ`?ύ܌Lu%78ZxEPH9)%PVy%Ck08mL2)C=p=8(T|MEe=XIy e8;8Ƿ>rsTVSMY*e w`mm7RTXZ:Yo ~w,Zn6DEuezCONKZj)9$ϊVUN5?r; 3H.YMrCNNBwevqϷf$pZ+jtH ˜c{z,[9|ԗMl J$M??0T#3`!Lvcc q.GbdybtPWKJ"6w* Ҽ"C,5 Qqk** 4.MM{q5Wj6z)4$>`UAp=v 2Cr ԙ\1U6bE7\g#n'X5WK=¤U:%"j>2ʠ2αAϔb{੫& RI)VSK2]@sJی)'xkBI ZePcNw9 tþ.TP%m35DR,L.NیbMi޹_)JU X@Hg UY^u#aJ0H΃K;w.GhhᒑNJFf3u QߍxsiW zZhݣ QGmmK ԎTŁӬl9' g7מdj.]9^f)LST.WI' .{Rd*&a5qK!A#'RG.1*j,"VP$ZYZ, #Y ! 8zxA[Rs FsѽM2*λڊ{Ég-TQ))gugED͌eƜa}Xy&,tMS-MEE<$Q Tϥ[RV=p ՒH;:J+n q \2ǾsjCm/1RMD<2RGP#h˳56,T{ bf Կ+D;eAA*@ {6hgJIC"BH6A#Q|wݲxdıٞ"i"0UԘ˫$ 8l-2\S+,+E$) $ ' IzXVS֤e*ƃÓBT\Mx<4{}DEXٔ"QWN}~u-@#SI IME)mabadQOSʴ.h؜{FcԍOsv[|$0XN!+#eǨ@C0OG0GK'y⊢P F7ع9Ӿ=GQ٨Lt5%̦֭ J#dQeZT;Mt`51_(J#aT=[#C ž2Dtba;DsJ8V}Wvϟ~HqACM3ZF a\n54]Fᫎ~cqj)؟N:SSJ( PN <մgit&tVi;CzԦYX$ Հ `pϒ8 ,1dZx4m$\ ]]}MKP*%)Tw+YR۝'<}U2@dP̄5w=5؆yZ>CMFVYN[vntmz_ rz~ s +r1ljX !A<ʪ(ƒˀ31 3Zy#jCjW| . v9vWr6j9B-6;($T3N70r}\7T^K,̚T0j8c4 WJh #C %g8CO%#,/50C* daldَܩx)H-g 7ƒ6$}8<5*Դ7&FU8v,a?neOf1O0QQθ1  7ӶNG;.\rچ8kQ)e@ Xݗ9O9|n`}\ND5" I,c9o7xtiu\B+t8DZf#GPֺc=4m>V!}HFC! QA8,btl79ڲg)rG4]Yk,;W9 sZ>G$Ue51Ă~ՐtΏ @K-4ti=5[ -W 8thHԪ HeV풙چB2m8=9ܬ×]G\@OJǦ0 Aq|i'XPa^5*j`k*%TXb3bs;aAVIY)K=\ȫQW p1 nbp=`O/](R|IP;24QPm4^REx$ƉeoApi5ei t# 2F`8O[3_f:d-'SN#m 8845vjUTjV==ϩ9ǧ ƕjh m%yi]^Rjcm:I5dK7P+j)zѢӥfƭxb1Jْ&IQ+7ApX r8w8yRLadGˣ ,sJDuxLIE\0^t _ANS> CtCn:& AMH0(?9ZJHK(I3ϺJ$bABqW8[motN"ʝhC`a[/LOC=AoYkmqӞPaA&N{pzWSKnK4 >IbK :AR  ==5"ҬTJinH#@`2)}Q9wᬤW^͗JOV;" {Em:KEV$JREZLؑlI~3+Cq\X)ZHH"]~WՏ`}G:dD9b=̖Ȫ@žW8/Pdk/DgC In>5jJd; a! )^&Ys#; *vAoI9IK;N#0*bmG?lp|DYT3RUKF >pAƓ;}q K,6zC% 4lcԦc\btDViQ.Q*H˥5{cKw 暞%-T9U|`WeMJGRm2̵adUSS0 #8RI&J[]ts^IDzW,2ܐ_a_됃v-4pVT5rt)RHme5{z).}Lڎv~;Q5((Fa*#9(-#Qr?r)x )[c'NN@ܝx3ۉʎר' cLVj*2\z~|j!uW;cPR]u_%LR78_]ۍcz~aZ rMG!SݘlˎK> lwyO '92#[^0¦=x=UΦ/WhAI)$ >ur+u"oKOR(X6Wqū%M%"2 3`Fˎ$tg+uMtSҍzyW\2c\?75eLPԈ$`ʤlRls2Q\.4vM8t$eu) w0ؑePRG6:$p.>Ǯxo$HSRm-5+KK#4uoO7N}H iՁ,=~~)MXpT's63U,ѴlZHv]MPp7u@I|EYRAOS8h†sg>pMWSTKYo _0sQ$,MϜ)N$aZng{J KRҝIo; #ϨpeiitV%@ŝ;/lIS?Q*1R `Œ`o+þQ7A[ s;9R-XɼRF4v 88 X5NNy*GӜ xU]%3ԄS8Duc V&E/;H4 8$2w'mV|u|Z Zii$WBips`g:MiEACo9"J. ډGa8FOx[me-QVG<cOQ!GRi W}yJUqY*i@DkF!xz)t8"?Ð?M'Te@X;xZSMRDL8s8ۧ_|A]$ DA@#nۉ/ {WS9& acHW󖦄'KċI=9OZ$yFmMh+ٽ&W${hGѩXZ9u9S]N)ZBZVpB R6F1wYT0L^O(1Xor7۷[X^WI[dBxvLc8'mTTMR0KzTTlUE\V2"˜,[ެۖnzi IǎHg.Y#a %C'do +9Xm%9~e"EX$RR9$}rx4/P6?1FIXwepve_(9s#MMDII<*)@#ca?7ܪ5ĵ%=hAW9-caG1d?䚡^ JM$3(@^18ϧXp K`{$P2/.])"ju0MatmQT ULkmm4+fN:vBRrH8G`8.ZT/?MJiA9qg<jV$iC0BHէV 'pb*-ڹƓJOF>\[TRrddl8 W1sjKc)e-Ӱ*sr4 ih*ՑA#nAF=0pJΡթ2SKy;,oAW9udzҝWr5o9P@ w$xTIFxȉ#Ɛ;đx zUmBWgV)gPn ڎHM\-aHs% KD*@$.6=nMPmB bF$H:E'N㎪FsP:pw(j JH*| 1 Q~eVW0hrDm7}C9#8zMzIYB1v(*O'>̓zhd{+H]h֣ѨzrކpKLi.!=Ex FHerp ѯ7VIj 8;dǷ3wĹ#{sHXIL4'U$ig]gQ_G_qh_ioѥ542;&#$6HWg?Q~/5-F|u4)c2N%Y @aܜ<73Smjhi!q1!#PTv{UEdAAKN**dR,`H:/rd+`1SfI#_LU'! \8'g X>?4TW5@-M1S39xrѴQ tfC H_Lw؍r]CS2ڨ6'ƬwM:>e_5ein3IES, ղ*&!B\q{Nj2n)[5,#ԫHa- ><~qj;m=jHCS稣IJd@8֪TIXFJ&rќ)AA9:-YluԦ{3TOSCHЀlA;@8?Ĺ=S=~u|M$UCWR{M:#y9FBL`0'K8 ~2X熚چ@RCR zJPm˜I=x33t:R7e]';pkZKm*b!槤u55QNd3i"==b=MH،|sӝ^"װK=}zCpx%g֒%$@1Zn/[\_.ĂAþ]~Q[40:SHcИ >N;%%×kR9bb適2F0qId5{+,5|SL˦&_Al;UźI)n7E9oR5g^|R'1V|%J1 J;|2K=4YUN&q(VPUq/lk^bI hB4S{)0Ż^WT[kc(p!d+ɐ]@A+RO,]iq,0:ܞzi櫩I`sۇIި;— ~r6h`Kz*v= RKK0Ya_u9ݸqs9`,)2l@*1;PCsBCQA\c!bKN0r1@=r Xh_4 J\88g0>Jue:`h+avһ9 ך)Qz\Fac` Cy;c>ċiZ9VW2y8qH&.zH$`zcHժas@0![)%9>`[9FSru\w_I# 28\;lJ'*niSQr8* }8)gs~-vU\EE/M0wde$g#ҢfTZkGGI3Ϳ17rv e$7$z*3͸$vᛕjOsP%Zѫ `0I߶#5wI) "ʁc=8-qT)xeJ^\ۭD"4&unA`6n._:s)Cg-\>E‚; V)TR1 $c8Vep3q>tnNB*:hiD( 6b1K?|{ѫ'=~䜫m QrZk4ULZyI-,%Pa[H~Qxw+IEh<@rglĪNHOj"8j82 #p͕XL臫Na`HaF=J8rQ1Ji+2,[3DBSeyv9$j"jվc9q2v͍Y'cs S=lK.ȫU 9 WOp4O?8]JixGX.!r p3s,yx7tt?UӭT]'EB1JrG9REpG$t*bDPUS;;0x :[M؎jI[ ζ] wk_%3W#ѕ|or>!6Rٮ"´0K'"0r9''߂6u(MU*=¢ƢPt u LO-S|#G'!p8u`I8$ ï7yȶ EhDS#Owi5rh7U]E-~1N+1:9NAPI##'!xsh9.a:h "ʁ#=¼uӤu!ian E_%=sWxXr?`IM5=ޭ6QK4a>C`Ɲ܂aYp#'П+\hhaD$ J"1| ڣO+4MdFp'mrU\IL@'mqV Bsm|"UtZIQY /g=#9 Ρ[| , sv:H/s/rh@ĭb.%7'cS DIScnt"\9)nRѹ]a@}FpmRYNbF eR46w#툼JV80RXs=lE G;D9rxWpelican-3.7.1/pelican/tests/output/custom/pictures/Sushi.jpg000066400000000000000000000705001303525152100242160ustar00rootroot00000000000000JFIFHHExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:31:09 PrintIM0250$"' 0220     &|n.0100,   L&d2010:01:09 14:09:082010:01:09 14:09:08 ddqddFddFUJIFILM 0130>^ f !"#012S100 S100 %A592D34383231100603D7050TR73277NORMAL d^^R98010008(@`HHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?'X|z?kݟmV__:T{hd ($Ojr)@檌} Pּ)ggj һ1i2*Ji% ˡ?hlyWfVjB}y[G~ οζRgu oƦ:,yFڐJ2}5F>4RtȬ}8ttvcZekEҴ@YJziR>( /^E2* 3~j*Yc5!΃).%$v9г:\&1E#Y'+h.Ϲ+/aUL dݞMiiХy\T0H_)0Os @w??[~+:q>foTOs5|a 6'5{'ziN~+4MS% G9edLgY2XoVp#SQԧroIAE"=c_ߛeb`qW6d<ϩ5a\1PUx/Ҧ@LkM^!VC͵ ӊԃF IK@j7!4Ơ IQL MQ@Kuyi|Otc5AB,c~5˹>"ԼWoG}mfSvb WeE#~{7Ʊ|nUt(`+`YZx֤\sE)Zi IPH>iJy[?Z>h%}gV֧C& >nc:~ [qwöZ]̫hAþyYb 9?mEyWC #[szVG~T Jk;Ry:i:kJ/b|i'YAVAٸ>j]#L]jIS&9xCWCN}CN̬}77վz`?ƺ1iO,;xb9Zݟ, tdmn-mC°j>eK#5]hWKr#^ 5iI$qXS'.թqa MI0ga"brGM[50$:T6yO4ots6E9k0(@sf *iR曚3@5$l!P7|MEUMEMxn]2h]#W\5'4uݎ@F̨߾>⯈:Ɣ֖}*346=m6yf1)]iC76A`1/!w)95*lxaaZ2_#"kǥqS|4Ax䚕#GRMTݦP?:owA)<(=~$PjW"X:(OrZ]045{Llm?,_M8P34 v |˭vV$M <¼ u,'daЩ xޣ}׎i30Aƶ7R`sN.9&5Š0Njcj#oRyz#S P=3sNbѾL7Q {QXqw-k) :T~uޗ]>jsJ@>Ĝ&ơw@޸m~nˈ G.vө W`[$PB_:Dv/]bqA=t$LU4OX=4qRwٮ:TfoX]EXѴZrU~e$hrH0 [!DTmSK BFG u9>6M Ӿ(`HR_1V  V~ʧҧO ;n(a)Cu?"ao fi5ı*Cii @ (4S㈏EXU}xqҥ@B>ԦqV!^*@We42w~ U䉱̭"{U )ugP9qYznjƯhae ׭>b+}Fhoun@U'hO}e+鱼˳(~Q5qXx}TS68R5] : HGw=qF dzVq4 k&|T-9ff8Z qֵ$BNW1m;*:*ݸQl} p;SmbhS9_t,T=N{RC?FZ?S[R;TlE+z}iCAՅL  2zus[Y7(%WZǏcPdE;ŜEtXۻh)}ާZ(vEYӎh+!5P2xȼ62XČ$ܠQEHx瘬QEKB.~袊cE㊜*P!GHj(Ҋ(QڪG(@V~(C        C  ,"  O!1A"Qa2q #B$R 4Cbr%3c5S&DTd/!1AQ"2aq#3RBC ?RK*RB9$풄$iUc7hܸ)f`xZݍI$҇X\ O4idTRFk Il~K=ؿ#]!Oꘪѷ-kv5kb=f;k[ckC,6lZzLRSLӇ [دHKqI&-f- FQ\}߁Z!85  WM:Kmn jǗWOPt}vǶX_҆s~bT8wJ QL5fY0.#ܐJm.;=R>$.+\1uAIǝMrZOT2̂LLq]KE IJ@@#-RNEWM>2jL(*U uۼs5*G@;)IsNuʍ;q![ˊ=3 {$lDHM3)@aǥcQ^t#"Rƽ& l$’`Uئ:@n,wmo-%1KAz^ _Á̆+2(1cHm_EFTe<*yo4@ K,"ΒH XUT޴;Wxok--y+&P%ޥl!m6RZN&i5#?W8Y|} Ŗ7-z<[]v-aq +շ2 (~D@+c!6l"? oq{MI6ܝN[gp|F VR-³r4GM8UG}L٘ř1풻 .!q-7%Cf؃@2vcO\I 3J('kknf1yʍGDG%;1n9IbJTʹIlИ0{|Aմk$ZL5D@+ʛӨRW&f@R1HmS&|""\BHwVLR 'ΑNtPSA£Y0vfiߨ.{<ጃƁYrx[  P'h@J-se%;7>ad1Wy%cI'cmg4BR7Ջv9I:ެ\Mi^Iv#c}Qujn3TcHVsg d%bim・*R7#\/hU}0:_ whnTzvڢwLi3)fk{63ew)$<5zM<2r{3u9HXǷWeHзyA )R+8ڙO,%| `]kQPbz!ӠPbRze$5Lwڥyy1ԓ\zGr?.dc<)2XLD^@W"k0IZ-u#sk!?Z^tC%%Php?ZK4Sl>z?JFYy>)O2X*plyC"M Y0ِkŃh qiBwQ>݂cx^"E >5`I%i(uD!#DDcw>W$OA۞j8U-ԗ-9BkB;A4遷R!3؎i;rBW3ȓeK$y ¾1 7ӀO@iXu)eV  6: /!Q+o oDӛyH,Gc-ߎ(ѷ@ mӴDdIُQ>/ 9L+־V@3޽@DfLH |?&$)[HEtvISc Nj\qQ۶qgR*HtGO7CzUf7 h=f4SӅbD_=$=n?MA='2>Llֽ6[8* xߝ[(tW))ROjQVΒ)8)Ĥ]7˃3b-Cg߬$0vHv2v#C*?Bop!eKRk_wqzTiE٥mɠV,x v IvN}~W/u4ӄu"zcs$ _-Y(U,@[ƚ]#?qLy FH1ϕ>/,#sǕzFS8ns'H0u)e>cRXߧF1ԧВWܠoz? ?n}®:7qSAܑ.$eR~kW]kFG1$8hÔF JgNxOd$$IR@\$F}t >i@|GjyXfmJv{x Z`uvz ^$BUGsb 6.K RxHc}r\?EŬ@n屰W?ΧQx1Y'ƕk-Km=i8ى~2)iK[W~4h:1՞^X- \j`ch 'Oz-= O#p[6R }$(YRJ%J@Nf5{q+K]kKk$w&׼Վ8 \}ݎ5p?*r]VmXB)Rǝd25L+4qk~Y`>ӄRAnաvv#z_JHzԒ=䄂w˵^&S#M+ =Χ.HQF6Űɏ81޸emJ(DΏa[i1$ANmJzvlA v22|)&Iz׊0mdTh~]贲bLV." Dw.T-NOpIVBD 3R  1mO]lt9&қ{"3O: P).$γ_s7LSܽ"+ '>y!m<*٢mVn3e8`6KRStտZV[Ob2>$LrK(@;W&Gmqx|-F -O}k{IMR\Կ*.woha ]g,e?#>~@^hk$MC = Uz$蒜 V#ﴚs'+-ͻC.+GS= "yG~ڕ#*&  LRȑyoI-ς4|"CSuo%"uU'n M[5LV-Y2:AS.XILDENBBD ʟG10a?ؓve^q/f#(qa? 1F#΀nI= R(iE &Ihd7b1;M &h@(܎7Qa@*xۊ)d(Fd4&FLnP~( =CΦWXp@!3@ix {Ri0DsADɐo{]Oqz>FFP蒦$?r?$C7oyr Nιիluj:mMt+v1ppUtI#yt{O`oXW B}Tuzv'}_'.ݒ?},һ_Wƺuf.+%g{{MHlZ^&~_#a3RlЗFfݻ$R)#4h}M?W,Rr > Wn!)JEj$ ,μpd A2NՙБC{ObHJ.8[(m2zFy$-͸>P*E׬kR>v(Kh-mB06U&]xF=TZ[;*b Vbw JȑƧ9[G>(Wlaiz՟>5ԽD0c*tyVRp _zsT>[7&3Fss uA%@ '&7y,4[z*B<|=+TdZdF֔!! v\F",&Ugԁ*VJZEXIDGTz' &[[1g`ݛfIAc2*M*oy@jJƸ4buܺ2MJ|Wˆ X8jaa%5o=av/;[CtH.1zIq GnϾ ْmX_:[)`i]HmA)m %~ILO#[y0P< Arh?)D )&? >|edMs_+eA#m3QjPyhyvP0'IEV`r-@e`򪗬MJ$Ӟ^[2ۈwܩHRRfcҙ/M)'OW{68]&ŦQQ@|dfؾ[\cXV#t-Qnw>.j(Xmݕ d%v%1&k~^Ŷ-__`wiĐ[A'K&cm+{Ŗqj,[2K QkghQze,Ǚm#Z6 J؟g/}sn +mIdj'Mkt ˙iAe*Af{X{(}iM}jGcrL?4cVxZպVm6g0,Ʉ%\NZS)wN_uGZ $JLb6ELrԾSٟc9wn\?5JhG"QMjj>_XE$8d!Q7n˖̙aG}*=rChP ?o O0&Evaᬍ#<9N,󟐚ط &MI!ISZDFȝo(:w`2ew' R~{ӻj%Sk̔wcЮ"N6ǁ"=i܅w$SJDҺcD&$jBʭ4~5Vd@W(>QZaD,$N0^PH <5+DhI(>;$S~N>YH}3c1i΍I0wI;yW+)j,AH'B'x|0biځI'y߶by۽vI܈ނn|Ccڼ㝉@fy^[M߆yi 3RfsgA" \eǕQftx|vބ,߸`,pneszZNռ5sC˷O1[f KY) GyO3OA6$zWΠq3XVۯXf%v'גZy[D~ Gta[%ZDlLW2}c! ?qePr6P#K돖Ⱦ=Yv0#kiP_POʽAřʉ?h4.|Icg8:ǖ椕ʐ{S]Pm*u{$S˙|6]7$ZNLq (עf'RJJʌ4򕚚umE^T l9no{S@jq([^^{\KG u௬qxHe'{Ueu MJAjW^P .+q}+T6OP=0% FgRcT@b˒j:;b#^ϽFb)KIIq qWN-0l&Bw^ge'8mɑXL8/KV`-^fo4S(;(sl?RHALӹK̘WmNl D: -mҷmPm0%;D $; ?ae| [x$(H+˽,y8n!v]2۶3=j m12/Xġ{SA[ipa-D$v[Hbw=Qo,e ;AOk#YYEI:F ;NH5E̺GMѰs_*±w4NRk<&`o3ޜ&DG4f: RM ޡ]؋3%ډS)p njɋJw Lի ֬dH2:oMp&7ޡ8;F)=  E`{ic146&&0|3{Pp7ξ8+'EDھ"UǔPTa1x~tY_1H,lw.M^qr!'FOttPԤj־t6̿mhIq+SNG#6xRQJ0ՅI^H-qzp?e=fҤAT G%Y{ҍ)Z]Sl}"ُ3ߗC,8ts_ C_fuPُ=/zXaJ!k&'W~m=dvV~+^H/:1D#H@;VuG4^FIWhȑ54V#x& <մ@OD@ZJ&ciʂw1 ;Vi[ipRw +CuҜ1_f+QR?:FtQ=aHAK.nҋ6\:NX6tɩ1{0mPjDj'AT*#VUG*1\l g0amreAIu"HfėsTAM~c%eZWu Opp< (bx`_JU;x1`y dW qR{,weŊoܰ Y_Mg̣ZvPz&.uj;np+(O_RsIM$觱M/.[w!W"$~utWoMV#&70VLǐ8 l֤ FR}Xa(qQ b̠KA3ю%}6&B+ }y'o'[L_ m֮o] IiQ31^*јscڷ ?rD=ԗq;7.}fmsBi'QR JI>%\.*/-z`Ű8` ; \ôTI*R6^[!KvB ?^U.eKiW=%ut; 'jOh5[YH>U\RIBIZdˊM祰E%gU@-i b|/lMیIyP%^+D d02;|J:I?4ƔغIZ q1+| P.*qBA4hܧھ#> b|"0ukHpS)XR'Ęyh[[y^Uil Q}X 0ObRt<\޷sir&PN(B7}o??uyŲ%͜GW) yikƈ@(GA2.8-Wwʁ~GߌVj-ˁI#kCVqyTۦ6\DZ 3IM![_R cVN0O@7ul냦UбGʶwCzsM#VXE}~46]k󥭺*N⩼1 KR+BҐV'Ν2x;LׁP=ǝ2X\(94ᵫe J{0JI普j'I!-J0G_I%DQOlQ۲Hj1:Ҝ:&xT ~jWEg OjOW-x[}a k*Q!x-KZu($7\$%H(_\PIH>:~A'$pjp*ޓXnCF#iJ`nCq Ӿ8w)ni&#qTmGr{zM<R!#jqˆ6ʇʊ b)CYp#<`*"S"J@$G6U~t{J'ϊv?jUczSfmŶ*R="O_*5& xڗEh>dǙeix̓1v Cl lmu.Ip#+(Q& ɣN#r{sSځ/Na^%hFapG4  ) zιft`??WoUnFU ;8&k>F'eejR-ݤCI*ZH3DkDv%E$m-a0ND.Р(r@4C΀$y~xYgYڟ0A?O:,L(N|TA*RE H$ X*vZdv#s)jLsP9k~=Ήtt-J^q!;IүGa4#ʈu ia4'~tCNxL:ni#!BފMSt!@Iߵi3;[RV[1$V`9Z}1S2۹h#SscSE)&usE"FHGJ zfL~t@PX*hr ɥXkK@hޟ fS j@)D qIoR`FE`(ē";zP &HQ́;D6|`>Q'I$2(䄄I'z$ ;AB9%\Q{ bR;oVwIs# _oo]ywB*ovFjSQ'AZ7F}նlî0 >|IQ۩8duX }LnԻ,b" Fw >w3̀i>rjQu.\?~qed1,)>aCcA q4Ø{Ր>z7 OIY5FMvj&arD)7Tcu+!I2q# p}+2 n3 ?YQ&FxZH$ԕy ˮfg:|źJD wI׆$\I^e~0{?Z'>Q PV6#mPw"s6 (گm]>ֆy LoU“f[6]H>oj^j3 LɈ|,ff;[,:B4S VdQx@|Аk&'D-!Bvj^-` X=*Z.8$ڤJ:-%)KɒLN" v ϠN]^S,($8eEw]aRK [H"ƒ{dt9\]c>Fc}w +_3UU=d爟!ZbYwreXo u̎Ԭ[mv[ گ--YZťtWԐI;9H[=AT 4cL,yn.Jd87zoHNǥj=YȯuP )i*) X[[): T/С D7\B EylA);=K "G~ņ))V4x BL T4$z:uaGh@(XQޘ DlG:A|0R$̐GNdӺgHBL*v-V r)*W5jBQpH#OaN~";RpN=*(Warho)0~h;ұDo 3h>I'֔ „KAv8zccT61?)4*ȏ lkL'5wS\ց$$|ALH1IAEXY(Cv=;[ •y@y*7M⵴Gcbb>ٵ)6"5ܒ|(sq<߉ڟT_RuUA7D FG<[ GrNT@ 7 VQa)|P)6 D-'xFZAq>T[ :gS;>RHJEz-.GuGm{TEvp%$ڂ'IsޛSN:@2Lq^y_ yDsVBݱsoQ?.#iO]*ٍ@ALmU Uj1ԩ?Edj~;97 e {ũP7*ڬN%Z[ưPuT6~|oy}Na#iSX6/,wPTI>uqH:RBɔqYwnӨnv/&,Q C1U[{V:wtMdl|Fm6Q<'VF?\6xp$Y0?i4TvUM&\n.%M5\%H)$I/'Lv&{քn(zP4ΨBm> ^| *IRG]O 1E)d 擻YiC*֞ґAyD1:jwfۤ5IRmgΎH@h"#hhHǠGпȤ۸ "A3?ƏmA(%; H7$D70j}@Hpyo>ce$#ʄ -8ITڌB'`͙& 44+lBTNW@dDWs\\$mҐÒA D%#1(@UI:gqڀ[|L<'a$*T* ;PTuH$fTiyVCqg'ݐb'MlLnR&Ѹ$ 8;i=/rf,c&݃ - ;Vc+$psG7R R F+GOV-֠v2)=3sUu*J`g-G3 QJDϙڒf+ɷ-{f ;kA)鋮!*J #?Z (u'eų+w mùmS;Rp~ۥ һ~&`m"F -x%唇7h{7}Ko  V$WݑrƎՕ8)cN󠜮 ~5CFNOOm̔(p-̄\}b4j(I ߎ);QL '!z2yW1%1FYK HZb)YB\Jé)$XH252NLTʓa-- *NbΡl3+i/j kj@\*.%nPFW5zkQ0+Q>LW{75eT`>vlc֙ A:PzbKIRK,2x6/?`ҢLqsoe8K C.%Dpk+y꧵/1<\C.FGkCl{%6SDNyV mŏlɀ`zLM|YZl)w%+s'VCq4!jdKZCVR4[^[@)64$Ĉ D oRw;!1MӀ h$mjJJ; T=;`SBMAB"I!0#j-FRwzH؀&dj;Dn$T}\ހAĈ6vx@TC7cοvš#jq`~TɊX\O&h Cc p1ێT( $1YpB{wPӲ~f(O|֤goZL=(b6iæv۬L(iKP)zPu+ZRDROz*1?>mpu`$ldQR84jGo^[1o@ bLJmn(Sw,No#ȧD[m@$yw惐'54fn%';_C-.{NԸ\aQ!!1A i֕2854zq=rȸ a.n:]Edʖ#ZȍB+OB+i&70PK 𔈮kf*(Ƶ@_@rp%\m6PQܟ*z09QƔ{rBJ}~9Oʮ>.:dP73t9O +d%upF/oN/['W!z>\hV;rJye }+i lxI jW?<^Ze`$Wsr"`S'F yuI:&ۥ\ )$#L{:).A Wy:I(P7 %Tؓ<ԃ0`)~$OqLaM L+PUk\)y:EsRmP.2N5LON7Q*h#ҿv [FƶAJ,.(Ѕ¼Bg`{P`4kТ]( %Kӿ"[ WiM(+?]jKkd(LbgP @#J;#Zwc`|8a9SBVœ cЈ#($#b&*}eӼbSߏOXwM&=fy܊]F%$RHx0 " 1#C{gKZIR=zwm %=Hښp&x+QU@[k?qK'.դJhR'ҏnS*ʛ/p^:?Kq{YYz'4XLݔ9ړYbnV0'$P&onk.c*vnb`Sb߻R;ȯRKTBv >g_e'Y@u6! 4";#G>lXm{&;aOpOud Uw Yט.?&q ׎IH%ŠX-4Kxa:T|?xW"}J=h~ozBH*3!.lɰQǞYe5)KNpqҧ4$vγfcc_4)dEj,Yq԰ Y{ }Uon/Xiaܒ89ݎ={ dg.ڼU7\Ԍ6+y|!>d* 8Yð뛤2%\ZdMA8.>T<>UJ]џC0ίaH]M;xޭ!D:!oqwՌ隱^VvN(U 8>:j"gqhtUGiU4 Q9ئą'Wz~叉jmTԧ:SL\zE|u!6"fHV~<Oʺwda,Ut~x%XsL >z !I@wT‹vN3B}Lwcב1)e-nx#r*&E*!IVzݣE!RNT/9l)@]oW5e^JS2pNiWh&"x,_YwRqqJFVص*b啰{)+AIIꤘmE (J 4SNDEPQeV VO[ B@ [l$B`w{T[<2tz:;Q0cp' vZSQ.FyagTj2=}Z֕#SB fc; A$xOoFV]MtDn&0iL*Dq%kRLGSuIJNbjWI)  I;ԣ|@ژq$hUƆgVs@.(9{$$zP$"( 938~YƆ Y4%nȝ5zιa8XI:_SE_4]$p8$jXBk#Hs˽iN%]L6gVk\] wROmie>Qܫ̘=Sjm$|e?rkqct/u֮[ҳҴ?|'2,cĭ!8pR!R s/N0mo I)'Ư {^%ְ,Ջ.Fa^%q :/ZP\S/ۀH'aO~j7Xmˎ4XN;bYS[H_ U3.L*)EԅJyTpl]+;|pWN+&*&V{8Uob7܁xM8rdG/Ef_(SdT`4?rI䊻u+Q9JHmwWr*sszӊET"cVeqbnw@+SSD[_ #T 7ؙV&I1{jNn]taB _΅$ցJH?Z!/i jW5;~! "+{$:0*"ͅ^̀;Ҝٳ| +$)wy(oCTQcB&Q>&;R)Rc,x~TՂ!Zp)ySD2{OvXYH ƑNNO&%h +n <'B;*27B\+RV!I$Mȵp?NԽx oEj6/nЗ$G:[ez%ۣJ˱S en4j hP1W+%rVIr5BR n8ډC @hnn(sܫU%}]5XQL*D*5p3e(,Z~8Qȩ 9)偪PyR ?:tI s!T9YpC w^[;nƴ<RJSw\fыT-6Vv-Hm46]htFzZjI|Gw5@q%DsɚmBBN;JTIާG$$5%HП *3 HDRKDp'WΦPbc)ї)iq@RS?*YtPANPІ;ʜ$+6/ґuR+zd `o&N@QUcQjc $K$p V1DIT҇Y@I7{h6 A Wե)"@!*MHfP-7D_:INõGW2f4=o Kd_:IGHP 鳭YGVkN'b‘8T *L$j;؂L`+{±vL.H4แ1GL<5>IqvHn`di؉iaމiϦ{Fe ژVmZ6aͶ^ҙ!PN-Y?rҝ`Uq\%K19qĠQ b/M)D6}kaCݍC BA/^JI,X]6獕|?vXrH6)^))Qw dJ||v/ S.0NQb!?YaħA>RQ 6ݍ?$ڒ6,ک ? 5:v͔8'T|fϹJDӷo]{S!mX@H'ϵ:a A R{&`>tef)HڦQ~F,d#zӭ ;$m?I-lw[ :TÒ%((F (⤈i`;Qݰ|F7ЮrO=j,4*P$ ZB)M6;9)6 AۓF&#`*vm,%P|₶ 'iޫEۥI;|藭N ХF I& Q](RgҰP ԕbwtRƭkDZShBS.J%ˤ)ċTI2|nбJQܓM%DD(K~<2 3]:TwLed˥))PwIʛYm?Bcz?pelican-3.7.1/pelican/tests/output/custom/pictures/Sushi_Macro.jpg000066400000000000000000001133021303525152100253350ustar00rootroot00000000000000JFIFHHExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:30:38 PrintIM0250$"'@0220    I &|z.0100,   |d2010:01:09 14:10:302010:01:09 14:10:30 :ddddFdzdFUJIFILM 0130Jj r !"#012S100 S100 A592D34383231100603D7050TR73277NORMAL d^^R980100<D(LHHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?qc~tcjSHJy)3ADz{P^+d/RsS&$ś-ЖCֳVF+"?Jk|K9beĈU=9ONj&Zظel̕lTm42-P[CZ8ɧtrFX`#"5\t5"21V" G^ơ#8{NVh~՟$ma+[֜`KEZV*<q+dqLG_UqYxby (hGB: )"%CꢊLwb&+@iR;RHH@:ᳱmdTVngQ~I5-gQJ;k}UE q\wgDWI<@+dJm[H^1X#ظ>7<#Ɓ4Z^;gk;Zٶkl=JxRd*[Eh*٫W6;Eis3;b#nwX#h?h1SH1ڐJ@Gc`)=JEdZ^$%*D`c3tɑwB8RŪ_XVegup\{eOC9E?'޴;eqYoǣoAΝ]g~ec. gyFMlX|rqu1opJ.yj&elqϥvu:B۠ng#5E{O:5JWN=͕XqcH7 g8k|"}F&+H2 wW1qS:SݣDAD\zMa+զeL^9NZd$h–U*+8( 3VsP8w2.eOV5͜\u*qL6(|@)W>BX?2=E+X#SE7#֊b>BSXSJ} g$;R+tx%TH?xǭirؙjb푾Fc{׎R[ZS$P^4/!c;T$>קH_Pk܌U8]$B}1mig~,\1U'iXq¯m<瑎%\W(T3 ae)#ҴU^K ilPʤ3F5kD|nBz?,-͒AC ʽF"(UFYA\+}-mFsRrFo8Չo<s|DeG 8V'**d.*ڠzb+@a꼔Wzҁz] E)E =ΎF3h֭BAqPW+Ib] Bʐ8T'! \J5܃XEf*V#*0RDwP$7b*RZ!isU5b29 gb׼ vai9%j-\_˷+~͏yo-HK`h]W?vUzV%YPIXӖ)1d^k]Ϊ911ZEGV=JXٲ. ZsEJ%N85ׯ1 V߽ـsʚN#%~P=0 zwڠz5asE9ƒ-CWͿʟ 7jԏ}*YD6ɌWhW*xc0{Ԍch)柼*M:Z@U'BYSR@Deq]?is4yԕ.dy~Mn$2I"NJ {l9 p&@ŠApep'u ]C e1 p5;.wbC?Z2AT"'P9@@3@zz'Pv3~ÓV N1"7.Rh"@|,N3fj8mwH F *~qR׊֠CKjB:2>ю %*Cee,MjjWm Q*K_ܼQU$#/-z0U=']«7;J*8tb70SsȨg aEz5mǺ&U=EXs^pYyH]fAFl㪚sP9\P9^j@S9zB"')Z(H?Eh8򤞴QR \RaR@;BIZ(@7 7&)̚{B'R4QL DII U,I 4QHv[\ !r(z=5O!̠Nz(()(C      C  ,"  B!1A"Qaq2B #Rb3$Cr(Sc/!1AQ"a2qB# ?`pTͺzy:"O'q* +>$ c#,7rf+b@Y.WԶJ~#ijzUWaSWw+8qF A+k7RD:\ m O(K}QS{ZW/L%%8!AKz$Z1dc0mKZ@,/M:)$V@X ;1|+  x$]Wmfi Ѹ [?Dַ{zI,$y=14Sqe@1@ ~1[-~zcJmm +<)X 7o'#9AcnĞC(Ak,} Ԙ"T '\~Sf:I-̱ {Q%Tl~cLf ؈7*2&i<6;+o 5 䣾ܲL0SP h:uij99)a1 }ttVA#'QR,T@A$lzL-2 TPxLd2 C:iۡY#+<6Iۮ{S<[tqV-z=v^w0,{О;C޸Ʀڜy0S QOrK(E1Oq̬YM#qtGw {i"ÄћK}/8Q]N/qd`x27|w@*bZ 6~FYFGk)J0!Daס&?Kx\2<;+|P\ ão勮 S2ͲƠxt;{7eVpBf_ ꌆ>K|~exz[ISIc|YEhl$V0,L3$ʪCE![~XFcച' s3,BLn\S),  a3^-`K|ӓ XML-2j,f[ *SMzധTiUn,I&g[hbG^`ʁK# k5 Gdԧ@`l Hr V;HB="3Gf26pzԞYc [zza'"Y ˸/q37*ۑpS)jmG#>0.M%yAEBY43yK7q<~ZI$zxiPߦt6|AR> duI4Gp#錥Sf^8ZUsb=[ju[vlѰ>z%j,Q~Q>[_G|J%po@"q{•;HZTs};-7oĩΪX@"R96 Pkj޿R̺JWGYH#W\)KME>\<`EdסR;"Ƞ6J f5*)0~D%'qTG)xMb>sȲU؋or,DY* R_+0ѧx._?5jN-*0T!d!ߌe.]OzH= E5^9+|0ri SrùZL03Ru C2F_F[ _q$DƊ7b,FoVРZtiř<8=pRT:mLdSUNHU-p?KHJ:Ix*R2*˱t>x]3ht{PM[*6aRBd߶${]6xX\,>N&=0{e[(ڧҨh_t?cS ZʛS;5i\?|Г plGCr ^bZEǡaosr,Ѳl%va1Od8}_ f Bp6a9S}Ɩ.:Qw eu/$lbgi"EL$vl8Ҙ aJi8&H.0GlX[G1;E e;!?S+3#^LZF\n@p@uSs?;Ta#F -ۧ?Հ7Ӫڏ}sc؎񆉒2A)υYC*17:z"-fv=?})  2,R!A_킵}$'jYX=`0-%.HqJ ) ɿKcH,z=tU^ *# uSWju2T0>}l؆ctSPc|5MYYR:zDvf=H|cI}@esZnXcU @ @G 6=qF|ps(^no59hd2ibߡ7܁`~XxGN$I'ῖLq$ ۩$oGPӏðPLdfʨmyD/Lj A׹ۭ Y}W. .WEgѲF[c`G]7%R a.o:c`Āǧ8||vG}Z1m鹷s8N#e޾?["Ӆ-xƻ@~΀*\?;z OsƧb$ΠmfoLs%P`_T=خ8!~G4Saj/;KzᏋ.M:"gÄQBuKcXKS}= 2eG\KI6A 5'I` *o3$ {ៈ8S.j2*飔-bH?UQmהe>/>$fFwOL;g>yDQ cq=z Y&m@نckoyRlenYTpI ѹ>w3)dřXu7̎WÓ=U*cӺ|ǒgQa+VvlhR*C78% kuũج;%ozbOI#qxr:pX n+.+iB",Kjecƒw YK$dy[}z~>rC{$cSN/,*4N"Cc/ nMz2Umv8n e>`V8c_2vN%D" F;3(doc>cꎗp Dv7N8BIK $hbWWs:c7kav@`6ٮ7O\|0rĒmkC[^Zphy-e* f=YT(1#LF c/f9Lلæ*O5eI0z,oyskJ#6!CR=~>$x~)2hv{"F5$˛F\xO#*q5Tg{$ڔ ?t;u= "7*/3*-E4e,*Le_OLz'ʎ!2Ĥ/tM.vQ v1T4dhl$hF]o| V_+I;`MnaŸ#h I(e=cJ;~[}`ًV7eH'AyIH%IFn-qX8%"{`*Tu,AsyͲ, o%jp29dDWD%cAdP,0mܵ4 +xNqQ]v8t -k,V؋mS` ü/ U]lTS u=qh6O3V1cA nL\,N~Z8MvcE#v(`T JwDB#bmo#R|Mk|/7T|~+"yYW{to`YSk2l'$(7ߋ1;I-N/Dgģ/ Nt҂L[^U{c"u e|)iɖ2Sp;oZj.fpzawÙ:H{[όVڴ[kH;=BI}>)@cՐ56Q _CpZJ 7{rۆʸ(|%6+4nhtLVo<`٢}.%(333[ț|y=By5KX/#f͙xS,BE#z$2gPQMWSU â`sk$ίęW䲵&iXo[DdgSGK[<0*%\;ѢTDسEq=VOLı'qkoD]=ln¥Pcm)dc{|PPgO5@Fǵp@mk?6u+MW4uGt1`` ڊWCY JFy3(, {_ǥϛɇl˾+r~ iAR#uK: },;o0ZLe.!+ T!77 [z193?R%\hM`ooo͔VTG!$Z]i-k ׶߆t`ԙA1Y n`SJ\;Y"ceom>GL5ѤJey_Ed#%vuCA7נ醬xYFڒGusss|6ief}FPJ@/~uGeһllն'lՏSm=='!Z{V(iݝH$[0s{z߉uJ%[I \jB SW0, xfk($3?sWy}Ln"C H; ;&Cfz{_Ϋ]RIV#֫m^ޘuW-ITEUKP. DfgE0`A٤vmqʪ)2ܿ0KBj٢[XX'nۓ)s͆1W%^J <:u?{;;-D.tq/DZ0"DGI6e` n],%Fu^ F(>u1xԵP-תˠ vhX3>Irtt:׃"3TcpE\/dsz0pdy Ga/ '7q~W g btۦt7MGP8); Cum1o :^>h~P[q(ٓ'91V&lMPwuīsa[BarLl=5iq}Kuʘ0Am$xHÈÙ>ux1^O[ '5=q[s+>=u yz=4%Rrkf⼒;6]]:u.htHڅ~0IUH7+cP @uy#F ov?<~ .P FB vOPqG5;C) Y}qÐ+n"mQCx]MmHlGK13Psr=/@VP::z΃Ǎ j_c N%KVc䑃sR?KmB@}=wʁT?fMNmr./܌Dž\ X<d:#xR@+fmL\s拔\d?0=:pUX[шp+ VNėg!jK@-ؐ}\Z'>i8C5GGSE<6߯^qGO M맒er4fI%Lhn,l`R=Um#Lw{1-rU_b;C.3?UgHe)+c:\\yp1AӢH%E؋i=Bw^^,TPDѪ2 8zͿc#q/ÖSjP5Ee ZdpJTW7RC8z^9cqgäfKxƿ4˫rx8ehf,F;&]z58l2 |HA_y>[WLI,5#š)5# }7,$ʑ+dyU_#NYVQr.nǖrJ_OGmJ0\rpiMMR1$u1 v[na2VB(rJ,Eگ)5_ TC*<߾jjkgZrJN_t1%[6/s*5(A;auiWHkl u#YOD~52crUIV]:Cm$a4WqUe xx :|1~Crj܋4rjX$á|Ζ# nE#!y|WfUW8\ڊ}W@GN@:+9Ӧz\xu16,-Eʟi ؎MQ!Um6=ͮOoW F.JllYXfVO`5K-juH5=?.h\Z-&aͬ*cj_G3oj1RxURX3,{uo~>+vs|’xwP9 WoF<35%/xS@bMofYQ,-2C;ۿ]q74; S-5ė#'1r/V1AMh 7Yu|sS}#'%7X:ma=ŴU<t<\RMp_s3iᣎ3U$EdEzcf'Vx;ekURb pG3&3v*$̫'yݏ}1γΜOGRAx#hwgp O}NU52Nni,f[Zm&dg% %M07Yum9eNT$>a 075ĆGrf<A= ҙFj,lyʯPEkQ I))O>ht QQek_(N ;4M.L0̳gZ%42n}X6;uw9sR-%JO")]MU;,n #cs%dvf?fR0ɸ$A w-s̚ϘHiژDenHۍa~)$)T[`'IEVR&Ljw n÷m]Jn{Q@]#%@]B}OAӾ|XڴGj)nvƺx_HH`z{\aƢҥZkKRdCM0*CuP U`I}@6ۥÄ ĂG@oЃ²1a_H<7ߖ#HUDLm=Dy!0z* -r{,@αv#K<8`j~$ {h-stR@ }LF]p/(Ob7}dff#O\8<+,lPyi:PC""4PUG2o:VSAW$FWQbp>dfJc _lUk3YWhw}4L0q@9VQykai{(ƚͺ0ű`g F_DI`=: |fUi0սN {I2($%dT) jj. _E:H5Z(:[\`V!uw ʣ6:{ h*'U7-Ols "r5C20]C1^8)e@\rb@B1&66*j(*"v̦Zey5H|b/Y'~*3 O, ؋5 {XERc%|#=|zs,5h¡w5_GfAî`Z5ԋ[p[lꖉVrXȱqQGK] }԰{k[ӸScF ӌiQ$5Yc2]dҦ"TU,q $ar׸'Mv~e90,2 “t 'o1׾3LX'yG_IH(db/{5MI9Iey9D2PEֹrl- >.LuH YtTBłByuF:wA7N/%T:^KFA>"lAN#fa;ANҊY&iZ5'LàìME^[9e*d`gPAl5lpG sMuuS&$ "ȪCqe+WㅣEKdU]F`zF6˗MfeYcc榆-tjQy9(csIg熞 |"Y(#Hk[5MȺ**a$j]gUu7m{á#eGWY-Ud)'6QbYGB:˸3˹˘d]~\Bl* of [{< >Jͥˣ0-o=xL MYFp_# 5QBng?Gu/.U$|)m+E9A,akgQqj[;ȩk"j@PSXPѳ-sxk1>+e.*P񈦍]j@|_^5e-$NѢxPS, E-eb hJ`bAɊ^`KeveSBd14x:>Ug=C1yaQMĵrVMYUExk*b!OJ\)vٝE'QK 859iB#xm7w>P]ݭq_o|o M_U 1hdib%'Fo]%MHaȒĻv:=ln9enH9U|'F)O`!+8."{w$|c>Id5JɤcS'xPE:QmH#t~?F[_^a{@fl6# $`F6]nŁ aʦ;G_ᨷskc\{tþ{tFI#{ ȴn㯾t16RY؟ŜtMm]/6U7;b uCk\^pXwUHXoA4ؑ 0K(#uV빾,o,r)Wgc"~UB1akHE;بVzKn=o:dSqF8,c#xN7]4Iob m^XȦXqIu :uX;ځD)b`FacKx7޿}iU^zc}Ur _'mWP6[ @DNV"{X.7qe(b*" {x]F&[o# ;xk3E5,o#'dM[4r( ͳ4)a@ Hc"؋xw¹MQ%C$㰂QI_P#k k%Y⭥iq~eKT&SN#KNΞ:1/_%K>I$fY:JC$jڵ+\@ rG! %`T @.=,|MK4g+Ry]&CO1I *ƁUrr(ʤ!wi v}zqy\-ʞCE̺$֘M1/! F,H&OE䦆\`y-d+BtSl|sagUqHycer{{FFoo|O8蹫YeɒpSTC5d64P~"-lFxW9} mM6c*c@ST(@Z1W%\$#{N #p[^v{cDU䈤 [p6<T\ aү/ ; [vm]*Oe:w#ÍT~"0OE&{oda{Q7bv6ÕXTɰ>ownww$۶T )'צn5K1۠N9T Qa $z2(y 7 ^{¡P|BX2MJ E=:iaab06TS~2Ynm~N$‹c4$z^Sө1,\{)s=/0u>70 ߱Ft^l}y\e .ŷzc' o:PUd_>>Hߡ\FII%1mКA+:} Al'REUVz a8"BCװg.O#HIWR?yc,lik}qsCVjdT!4^+guj改nqDA#FI!麒m-^{C=.iSm=$LReF71)moRvq+Qx Fve]o$lqx$h*,֙5eJk Y;*"7&9S*#=շihy^Ur1V#S6lH9ʼlM#22?1jq9`M7~gTM^Sf,kxf Lma8ӈ<F2TV14,YK P-pF`3i%NL @pWeɛd-IUQ +ebHlĵ= j3RDf"/o2iu$` 1KX67P FQ•R sFyGRPɭtZ7V]PüKC-%htxU!¬^ok[kthv%-i2C 8ڶHdGNY@ٙرGђ-W&~~ЦZvh.ch Y!=2(5͢=u>,Rl'CI &Up -isG:3J~*rt7)`V{4rhn8Z΀:VH;$R@Rg6a%Y VfS#↪c`C4; [k.ְ(o'3Z@󶆣 Hď˪/M6,J^Lr(1/8u[6W2$w,.ɹ#NgEļAFki>QzuxKO%a=9eyMSG]I;Iӣ$5QQ"IckZzJwaZ*R+%&[_K *i#G-ɲ-`:[J0!K\JgnUk*n+bܟ(M7:V0Tj\j+WPP1[G*JK 2؍x#{ƵbA ?;}s>̣Ulk؎3\:4@s|Y9EzdqWuYhh&tdo"*/\H`fT43橤jk3,*j7DcdEež},beg;WI, pU^!QrMȳỘKQ|MCMFˣԩ't:T|FA ~ 11Ǥ HL- *SpО RaY%7d6;t=~:UZ8HcH&m*[?M+’Ҭ˷Eߦ,Q*8M*hy&bQvrm"bJR/=-`ՒҒ9^b! I |\_tkU<4eq,}a<ɳ_h:)i-v7v~7%_SJ!Xf^Ť a{3'4k_6V@-a u|RW BI%=lo:7BE*R'Iˏ o.?L<8ϗR\u @~؀'F\^DR2s^g@!-bܛikXi% iJe?<2fj@Z_doϿ0w4ƎFrٍu%-n[Wʃ\ M ]*Mƃpm^e<|59Z,{Yɵc$.K1z9pCx1x}}l1!j Ow&Qk|tv4"//rܦdSJOP@j?\OxBAEFPuQEAoKa8̒2]X4>lwyaB%Rjw]t R]%PO96UH]co#.wf9u62*~`a@l5t?Q-N?uRwZfV6m;`sRʓ\1\C(㈶^Pg>*ʾ;sdH5G5*#(:6Qzr/~ج99giQQFTC4bHV! lQ Gk50,>~pw/.i3z&ԉULK06"b+oːT= |(KCÙm.YI b( (1 ϸ?&`"c^ R}|aHe $mÏ7+#rܖ6TyKYnYD\iZIH.M'v3e͛PdA",/0k\u"ܱ<M-sÇy̼ۇ.c02x C{G}a8Z/$+OQ |0,]5*\ /!̳y(*3]B- c2R (M54c/\Hzk*M&>?zS+~#/5:I?y,eeg(`|:v|Mh&Τ~R>% ]tm9הCNI\N#kT˅8e %PUw>bݷw!QS5lK*nsji#ȬJʲ̒MP/^qڗU[4S=@Y,fZނl#wŚ˾[/T I*Uo"E()WʲȖEd 7=E)I*T(\Qo|;e1%IJ߿n` r ~&ir)\EҲ*{?[W UU4vUHk0}cnUsLQ HTaoc ý~qgнE}g04Ff$ (+}n+(0O=2̎YI}P*\l#(%5 \?TiRRT(cv= #A-jBс(o w6 AQ @.>[N iߨrs~_PsjوٮcZ'v;z[ t 7Sߖ܎6HacsܐU.g}p}`!K_MVV逈RM$-A9 =NB7qcmRMLRl-{g٭|:kӶ[3>mBڻob p'}ӣ 8O #J.-`3YJM_YDCK]wmmI 먞KQoa?LK,o&b;Ls:BxZnǨ%e ]aA:j&d聊>I{~.4e+n5Ǯۛ3&E[U5 7R%7W8Dv !3ᯰAUH)䥖y%fLW9%WGEQ'0) ],>egtZd&4ooyP,!FIdEukP\a_ѹ"{aq2=J@[.&|)G`-G-o`;bX U+"$RH6#bН)S {Ķ,EE-Ѹ%9?vK57k4 `ͭvg&WצcSLM cܝzEtoadʠa/3\GdF -ܓ?C"SQKeAk/bIk_lfO3dGU$5MEBm($MbS\&.eQG> J_`B6ܱQnqc?VQrȪi* Wkȭ#ZCpK{^\+' i1Rөg$SQ Ё{߷λSF ɨtې:8U2(Zt#F㏭˙>cE(/fdq}rZ,,6Y<$շMU.&U]{X]bIƫyTsĩ *;Zn}A?3N,bHַЏKa1gDר͆[.|zꪅZhы.Z@vܑΏZ?2xlC)PȄea/RG7?OC?WMf1,bdu*M+]Ǫŕ-ݞK4nM, DWY$zY$#FJaVFF,1v圾"VHBVq_z ʟUT& 0Pw+kX W#,|QNz ȥo}޿ 噛2 M4QN)'I+f pzXw\yd9Tڥ۳`ceR[{Q+e; 4)v )2X2\&L)!!ʪJzȎSH:{`څ.j<"VNp]1o7,.=nqSrJQFl }8Y&ki[F-E,Bbc,mfĪ[nG\YgUP5 '!6zdD Qm}_<3-H}!TV6`P*T#뀪7KeGUv6 6dB%Y*7; .؛ų{ R M]1~U]_v'W^S> NB ηA _F0 éX jFL8)+rlpRCF CXmT#*cB Ấmm[]z[`1.Z@l|Y+K [%W9V-َ;v' iTq pD;ujXQ/e>qԔ$Uk/=>xi)B؝iڬ'ШFDd*l7&<3BPtrXEŃp$* M6^ߞ%+.u\j*Ac`87\B,A؜g_>$Q-.I cE oqI*'DS ? TE"QO0U^JTY%]z'Y3DU0.F%8o/[CU+ en#r>uNՊ F^Jl(Ά6zaCU*nޞE)ե25VE @e %DzI%ԍSU4 6$ )dL-S 9Tdep=CI0S2!q|E#n(ck؋6Wp&QyC㛋䬼z0T40e,=kXmw_}[)bI&ǰ{~{drvb_/Fd;ڈt9I4_Qwpn[S%%+@fP3uje$2 r?bU(| {G eKD0P[}}qD5%Hzἵs/!{ÒMY= #YڥQshR[J|Tei^bO`6Zibx|l{I`f*@'qka~Jƾ_O|VLx,\M2q6s i(;bkRo} 21})LJ_v=`n&Ϣ6tܜk8m1 o1n 8Q2!E,`v=0@Ih uPt*:x v62SʨU僳*ye+ka[^ذOp}:vttq*[Oq4"" \tq냩OknM_aW">ŭ S( Ǯ - 0PM670i"'s9,"fqˇ ib4k|w%#2{&ᕸv"iam`\&Jcxr|18QHksYA=S5Ni[&y<š5  1 HV/CKpXk|+#VW&@:}qpqi qv/ubԲcw_Eo,x4NWL!9d .OE*v#Ͼ[/38*ئP< f С`!6)7Di%VeR :6g%? ?M6\jId` axj3N1;-qo LS}1=YI56HVǔuHҍoN~:TKYmX[1g$ 1mm&DHfAp>кWq؜kYV3zZ!@퀪#)\zo*:Aa'ֈKӾ5\|7Ԓm;ԒXX\:dSٍPXsͮm J ][s0%Um0GI ll:PCb`S{2ߦ \U甎ְ5o cfbz/,$`*ۘi$5{uZKHGD(3-EL, ?7 aЗUc(Ƒ#2H^ֽAt`GQ877 hvLxw%Vӵ\ _eZpH bk쨍/@ҚGٝ5e4X&zTk c35F;XeN5݉z\EPQp}0J#1,{{a FQP-K];l֫l<"~v´A*\[vÕJdJ^/cױÞ^Α K>CAAN.z[ ,O1tzs-L_LM94  LNV&\tLE$YX]E݊H>PAZۭ`^D~Ȋm1&j ٘jlN@ l MΛl&ҷop&p}Q̵ =mmjjYnЌw[Na-F^ø=1 }:Enen;_Aǥ׶3Kb.!,l8!H3j:,WF_q5j Z&6+n:QG*wPQnwl}03 mWn'{\60̢3=FpkyYvUl],.|QJ)+i` 2bmЂ?ы<x1$:`QqFtn{ nmۦ _[qR˭X7]]z\Grç HWK7 7[Z`MԜ@6 Q!=i}Sjv\`N㵰ě^-;aֿN:I?M6aUwc|D@iIѵ©ڑe$v6܌}. (>2aropV :sA+:ܒ0lH # @ms .NUe"=D o|#4` LmeSIcpma Rʫ!>6qP=y6)r}R$tTPGzoc폕 Lҝq wl1|S!eف6P/}p/o2JھfRE%8Ъs|ٕ2 xSbz*R5̀|k&-ar*蜎NUYlO>7' .An,t3\W0rډ>eU@ܞvv@1lA0I'aHi2P,_Y&oTHͲ^pZvFfA>22 .8h:2cMEтb}0"Y:F pA7=oERgĐ쑛8R(NLJdbؔ"g mѠ,,cL SK:߯% TOᎠv ; z,Kc]XkZ,@P'7`z*ڋlA㻛'<4%b=:R|0fBwlk]LFޘ8`L,FX F3XT?|UC1L % H"AIBi:W-sw3<:t4cE`]UY5 K_T+iYYTKP z8 5\.4YZ*jf0xp=Kcq@4yY|,f[/xij>XPA M{ W9_Y2嚙>27}$ն̦[k?sViha;ٴnl;܅GSF4&:u[#~Ew|sSG d!MDz{bǜtMYj|r0?x^o¬E52*`E,7#lTWezGMR Ql4$%q5r4F˥6*" ߦ67UK,oX,M>P>u ;`ݏU2PK{ lߦ4q6 )$ ܀:7lBL,: "$n~"V lp DF$ -b `*F`;zગ=WG|BUc;V w5. V~$nЍT>a'u^ǥધ%s V04-T5`*b Nĭ[5 C,ucOiI(aj@{㥣FtY-eF[#YaO#; jSGB9[$R;b4۠< fl~Xy™%{f܃D;ᛍj-I+k'`CM#1 ߥ7JzYUQM}X yp9 g01PKXZn3䎑YB .̰duXљEKԴMك7R{3Eh30;퉝 CC [ ?p[@W_^"lM1ʩ9H[[c$y|;($ ; `栍{aVG*aH 큳H Ttd%$â6Ds|\#L),fF7km_ ;cZǶ#~I:8\m۵­p &T06c*U  Rb4 0 e$b/!@a]Dܜq #tu2F"no|Fd #)}7_ n g+=gX$e,;V H\pr̶2R6w; w7Liglchg_ x_{!MBK -6?/F^!hsxRZtU1UYbni187橚JE[ex@Гw#yJ]TV-MAQ#hB$AsMWf|9&dE] jF05n; x⊶>YBSؐI@߄8]]Q+0r ':!AlXZ|I]/ -+Z`9bRK-4bsfҵ5"4pEَ#]MT\AFua;(@"6"xw6nO<"-u7~f|D)#(GHY*T^-Zz*$Jo~v:rڹVUSc}¸rH7,:wV X:)`7%;0ːfV0f4bw#I`/EKd lJaqon5Lh_Yc3}mߕy!XI@o({'SUPLuڷ6F+:LTGŰn͕mvJ=(9ôP< .MV6z$ /6\ Deuxième article Fork me on GitHub

    Deuxième article

    Ceci est un article, en français.

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/second-article.html000066400000000000000000000130051303525152100243420ustar00rootroot00000000000000 Second article Fork me on GitHub

    Second article

    This is some article, in english

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/tag/000077500000000000000000000000001303525152100213345ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/tag/bar.html000066400000000000000000000174331303525152100227760ustar00rootroot00000000000000 Alexis' log - bar Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom/tag/baz.html000066400000000000000000000125611303525152100230030ustar00rootroot00000000000000 The baz tag Fork me on GitHub

    The baz tag

    This article overrides the listening of the articles under the baz tag.

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/tag/foo.html000066400000000000000000000146721303525152100230170ustar00rootroot00000000000000 Alexis' log - foo Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom/tag/foobar.html000066400000000000000000000127411303525152100234770ustar00rootroot00000000000000 Alexis' log - foobar Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom/tag/oh.html000066400000000000000000000101061303525152100226260ustar00rootroot00000000000000 Oh Oh Oh Fork me on GitHub

    Oh Oh Oh

    This page overrides the listening of the articles under the oh tag.

    pelican-3.7.1/pelican/tests/output/custom/tag/yeah.html000066400000000000000000000120241303525152100231470ustar00rootroot00000000000000 Alexis' log - yeah Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom/tags.html000066400000000000000000000104611303525152100224070ustar00rootroot00000000000000 Alexis' log - Tags Fork me on GitHub

    Tags for Alexis' log

    pelican-3.7.1/pelican/tests/output/custom/theme/000077500000000000000000000000001303525152100216635ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/theme/css/000077500000000000000000000000001303525152100224535ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/theme/css/main.css000066400000000000000000000254161303525152100241210ustar00rootroot00000000000000/* Name: Smashing HTML5 Date: July 2009 Description: Sample layout for HTML5 and CSS3 goodness. Version: 1.0 License: MIT Licensed by: Smashing Media GmbH Original author: Enrique Ramírez */ /* Imports */ @import url("reset.css"); @import url("pygment.css"); @import url("typogrify.css"); @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); /***** Global *****/ /* Body */ body { background: #F5F4EF; color: #000305; font-size: 87.5%; /* Base font size: 14px */ font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; line-height: 1.429; margin: 0; padding: 0; text-align: left; } /* Headings */ h1 {font-size: 2em } h2 {font-size: 1.571em} /* 22px */ h3 {font-size: 1.429em} /* 20px */ h4 {font-size: 1.286em} /* 18px */ h5 {font-size: 1.143em} /* 16px */ h6 {font-size: 1em} /* 14px */ h1, h2, h3, h4, h5, h6 { font-weight: 400; line-height: 1.1; margin-bottom: .8em; font-family: 'Yanone Kaffeesatz', arial, serif; } h3, h4, h5, h6 { margin-top: .8em; } hr { border: 2px solid #EEEEEE; } /* Anchors */ a {outline: 0;} a img {border: 0px; text-decoration: none;} a:link, a:visited { color: #C74350; padding: 0 1px; text-decoration: underline; } a:hover, a:active { background-color: #C74350; color: #fff; text-decoration: none; text-shadow: 1px 1px 1px #333; } h1 a:hover { background-color: inherit } /* Paragraphs */ div.line-block, p { margin-top: 1em; margin-bottom: 1em;} strong, b {font-weight: bold;} em, i {font-style: italic;} /* Lists */ ul { list-style: outside disc; margin: 0em 0 0 1.5em; } ol { list-style: outside decimal; margin: 0em 0 0 1.5em; } li { margin-top: 0.5em; margin-bottom: 1em; } .post-info { float:right; margin:10px; padding:5px; } .post-info p{ margin-top: 1px; margin-bottom: 1px; } .readmore { float: right } dl {margin: 0 0 1.5em 0;} dt {font-weight: bold;} dd {margin-left: 1.5em;} pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} /* Quotes */ blockquote { margin: 20px; font-style: italic; } cite {} q {} div.note { float: right; margin: 5px; font-size: 85%; max-width: 300px; } /* Tables */ table {margin: .5em auto 1.5em auto; width: 98%;} /* Thead */ thead th {padding: .5em .4em; text-align: left;} thead td {} /* Tbody */ tbody td {padding: .5em .4em;} tbody th {} tbody .alt td {} tbody .alt th {} /* Tfoot */ tfoot th {} tfoot td {} /* HTML5 tags */ header, section, footer, aside, nav, article, figure { display: block; } /***** Layout *****/ .body {clear: both; margin: 0 auto; width: 800px;} img.right, figure.right {float: right; margin: 0 0 2em 2em;} img.left, figure.left {float: left; margin: 0 2em 2em 0;} /* Header *****************/ #banner { margin: 0 auto; padding: 2.5em 0 0 0; } /* Banner */ #banner h1 {font-size: 3.571em; line-height: 0;} #banner h1 a:link, #banner h1 a:visited { color: #000305; display: block; font-weight: bold; margin: 0 0 .6em .2em; text-decoration: none; } #banner h1 a:hover, #banner h1 a:active { background: none; color: #C74350; text-shadow: none; } #banner h1 strong {font-size: 0.36em; font-weight: normal;} /* Main Nav */ #banner nav { background: #000305; font-size: 1.143em; height: 40px; line-height: 30px; margin: 0 auto 2em auto; padding: 0; text-align: center; width: 800px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #banner nav ul {list-style: none; margin: 0 auto; width: 800px;} #banner nav li {float: left; display: inline; margin: 0;} #banner nav a:link, #banner nav a:visited { color: #fff; display: inline-block; height: 30px; padding: 5px 1.5em; text-decoration: none; } #banner nav a:hover, #banner nav a:active, #banner nav .active a:link, #banner nav .active a:visited { background: #C74451; color: #fff; text-shadow: none !important; } #banner nav li:first-child a { border-top-left-radius: 5px; -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; } /* Featured *****************/ #featured { background: #fff; margin-bottom: 2em; overflow: hidden; padding: 20px; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } #featured figure { border: 2px solid #eee; float: right; margin: 0.786em 2em 0 5em; width: 248px; } #featured figure img {display: block; float: right;} #featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} #featured h3 {font-size: 1.429em; margin-bottom: .5em;} #featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} #featured h3 a:hover, #featured h3 a:active {color: #fff;} /* Body *****************/ #content { background: #fff; margin-bottom: 2em; overflow: hidden; padding: 20px 20px; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } /* Extras *****************/ #extras {margin: 0 auto 3em auto; overflow: hidden;} #extras ul {list-style: none; margin: 0;} #extras li {border-bottom: 1px solid #fff;} #extras h2 { color: #C74350; font-size: 1.429em; margin-bottom: .25em; padding: 0 3px; } #extras a:link, #extras a:visited { color: #444; display: block; border-bottom: 1px solid #F4E3E3; text-decoration: none; padding: .3em .25em; } #extras a:hover, #extras a:active {color: #fff;} /* Blogroll */ #extras .blogroll { float: left; width: 615px; } #extras .blogroll li {float: left; margin: 0 20px 0 0; width: 185px;} /* Social */ #extras .social { float: right; width: 175px; } #extras div[class='social'] a { background-repeat: no-repeat; background-position: 3px 6px; padding-left: 25px; } /* Icons */ .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} .social a[href*='github.com'], .social a[href*='git.io'] { background-image: url('../images/icons/github.png'); background-size: 16px 16px; } .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} .social a[href*='news.ycombinator.com'], .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} .social a[href*='stackoverflow.com'] {background-image: url('../images/icons/stackoverflow.png');} .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} /* About *****************/ #about { background: #fff; font-style: normal; margin-bottom: 2em; overflow: hidden; padding: 20px; text-align: left; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } #about .primary {float: left; width: 165px;} #about .primary strong {color: #C64350; display: block; font-size: 1.286em;} #about .photo {float: left; margin: 5px 20px;} #about .url:link, #about .url:visited {text-decoration: none;} #about .bio {float: right; width: 500px;} /* Footer *****************/ #contentinfo {padding-bottom: 2em; text-align: right;} /***** Sections *****/ /* Blog */ .hentry { display: block; clear: both; border-bottom: 1px solid #eee; padding: 1.5em 0; } li:last-child .hentry, #content > .hentry {border: 0; margin: 0;} #content > .hentry {padding: 1em 0;} .hentry img{display : none ;} .entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} .entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} .entry-title a:visited {background-color: #fff;} .hentry .post-info * {font-style: normal;} /* Content */ .hentry footer {margin-bottom: 2em;} .hentry footer address {display: inline;} #posts-list footer address {display: block;} /* Blog Index */ #posts-list {list-style: none; margin: 0;} #posts-list .hentry {padding-left: 10px; position: relative;} #posts-list footer { left: 10px; position: relative; float: left; top: 0.5em; width: 190px; } /* About the Author */ #about-author { background: #f9f9f9; clear: both; font-style: normal; margin: 2em 0; padding: 10px 20px 15px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #about-author strong { color: #C64350; clear: both; display: block; font-size: 1.429em; } #about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} /* Comments */ #comments-list {list-style: none; margin: 0 1em;} #comments-list blockquote { background: #f8f8f8; clear: both; font-style: normal; margin: 0; padding: 15px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} #comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} /* Add a Comment */ #add-comment label {clear: left; float: left; text-align: left; width: 150px;} #add-comment input[type='text'], #add-comment input[type='email'], #add-comment input[type='url'] {float: left; width: 200px;} #add-comment textarea {float: left; height: 150px; width: 495px;} #add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} #add-comment input[type='submit'] {float: right; margin: 0 .5em;} #add-comment * {margin-bottom: .5em;} pelican-3.7.1/pelican/tests/output/custom/theme/css/pygment.css000066400000000000000000000034521303525152100246540ustar00rootroot00000000000000.hll { background-color:#eee; } .c { color:#408090; font-style:italic; } .err { border:1px solid #FF0000; } .k { color:#007020; font-weight:bold; } .o { color:#666666; } .cm { color:#408090; font-style:italic; } .cp { color:#007020; } .c1 { color:#408090; font-style:italic; } .cs { background-color:#FFF0F0; color:#408090; } .gd { color:#A00000; } .ge { font-style:italic; } .gr { color:#FF0000; } .gh { color:#000080; font-weight:bold; } .gi { color:#00A000; } .go { color:#303030; } .gp { color:#C65D09; font-weight:bold; } .gs { font-weight:bold; } .gu { color:#800080; font-weight:bold; } .gt { color:#0040D0; } .kc { color:#007020; font-weight:bold; } .kd { color:#007020; font-weight:bold; } .kn { color:#007020; font-weight:bold; } .kp { color:#007020; } .kr { color:#007020; font-weight:bold; } .kt { color:#902000; } .m { color:#208050; } .s { color:#4070A0; } .na { color:#4070A0; } .nb { color:#007020; } .nc { color:#0E84B5; font-weight:bold; } .no { color:#60ADD5; } .nd { color:#555555; font-weight:bold; } .ni { color:#D55537; font-weight:bold; } .ne { color:#007020; } .nf { color:#06287E; } .nl { color:#002070; font-weight:bold; } .nn { color:#0E84B5; font-weight:bold; } .nt { color:#062873; font-weight:bold; } .nv { color:#BB60D5; } .ow { color:#007020; font-weight:bold; } .w { color:#BBBBBB; } .mf { color:#208050; } .mh { color:#208050; } .mi { color:#208050; } .mo { color:#208050; } .sb { color:#4070A0; } .sc { color:#4070A0; } .sd { color:#4070A0; font-style:italic; } .s2 { color:#4070A0; } .se { color:#4070A0; font-weight:bold; } .sh { color:#4070A0; } .si { color:#70A0D0; font-style:italic; } .sx { color:#C65D09; } .sr { color:#235388; } .s1 { color:#4070A0; } .ss { color:#517918; } .bp { color:#007020; } .vc { color:#BB60D5; } .vg { color:#BB60D5; } .vi { color:#BB60D5; } .il { color:#208050; } pelican-3.7.1/pelican/tests/output/custom/theme/css/reset.css000066400000000000000000000021171303525152100243100ustar00rootroot00000000000000/* Name: Reset Stylesheet Description: Resets browser's default CSS Author: Eric Meyer Author URI: http://meyerweb.com/eric/tools/css/reset/ */ /* v1.0 | 20080212 */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { background: transparent; border: 0; font-size: 100%; margin: 0; outline: 0; padding: 0; vertical-align: baseline; } body {line-height: 1;} ol, ul {list-style: none;} blockquote, q {quotes: none;} blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } /* remember to define focus styles! */ :focus { outline: 0; } /* remember to highlight inserts somehow! */ ins {text-decoration: none;} del {text-decoration: line-through;} /* tables still need 'cellspacing="0"' in the markup */ table { border-collapse: collapse; border-spacing: 0; }pelican-3.7.1/pelican/tests/output/custom/theme/css/typogrify.css000066400000000000000000000002761303525152100252260ustar00rootroot00000000000000.caps {font-size:.92em;} .amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} .dquo {margin-left:-.38em;} pelican-3.7.1/pelican/tests/output/custom/theme/css/wide.css000066400000000000000000000011501303525152100241120ustar00rootroot00000000000000@import url("main.css"); body { font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; } .post-info{ display: none; } #banner nav { display: none; -moz-border-radius: 0px; margin-bottom: 20px; overflow: hidden; font-size: 1em; background: #F5F4EF; } #banner nav ul{ padding-right: 50px; } #banner nav li{ float: right; color: #000; } #banner nav li a { color: #000; } #banner h1 { margin-bottom: -18px; } #featured, #extras { padding: 50px; } #featured { padding-top: 20px; } #extras { padding-top: 0px; padding-bottom: 0px; } pelican-3.7.1/pelican/tests/output/custom/theme/images/000077500000000000000000000000001303525152100231305ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/000077500000000000000000000000001303525152100242435ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/aboutme.png000066400000000000000000000013571303525152100264130ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ< PLTE >b :\a``__^][XNz 8Y]\\ZZXVS Js Ch 6UXXWVUTRQ~N{ Lw El @d4S P} O| Nz Mx Lw Ku Js Hq Fn Ek @e >a2O Mw3 Ip Dj Bg >a <]0L Hp Ho Gn Bg Cg;]9Y ;[.I Dk :ZAf 7U=_0K,F@e(>=_%:6U"4*D2O'@/K &=-G#:*D!7(@4%=1k/tRNS@f pHYsHHFk>IDATURPEcJP t(P)RcB]7p $YpܪHWUU?9'g^DXz&[|y6:dd#'r7_4L˚7L?`ZW|;h%tEXtdate:create2013-03-15T18:16:20-07:00#6%tEXtdate:modify2013-03-15T18:16:16-07:00SIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/bitbucket.png000066400000000000000000000072021303525152100267260ustar00rootroot00000000000000PNG  IHDRh6 AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  niTXtXML:com.adobe.xmp ? AmIDAT(ERkAtIݐۤ?jִPЖRD {$xP"1FlҺ>t GTЂ}FD%BdD,>[ēPR@+*ȌFՍJpL +x~,*p*K$ћBJ{iqne6;Ĉv}vpn`k KӲW7ͅ'tՅ |ZWotL,(w,}+WҩP8d״ˍJsP\ C$IAk筕sGt*JB\׆\08Sֿ#/9bSs\&_t@z8vIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/delicious.png000066400000000000000000000016761303525152100267430ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS4ӠtEXtCreation Time20/7/09zcIDAT8ou}Kn6IKb*K D(B1/ 1Ll,t@JtCDڦIIS׉o{}yX,Vq#jKZxwv~}z;mgӃ`ڮfOk̙{~5޻~~n4i3/}{׃g½cW=>֚./}p B:m&tkJFLi_ ?ԓIrR "&bi?3$bZ)Hէڲ @8L !:(NDm2yqrK)I%dCesG J) ?ϧJ>2pF> 6`CAsJﳽG7qG52/}Cca@\Ş.M[9rʲ W*YR=*;{"""H$""_}47u6wD*x~8Q3̱P!L4֖j$FH|q  ƾJg0.q!`x@0^5"1"`E^'81ZB`0Kׯh'a.W Ox^8G,b89.~/T+^`c`j )efЩ2},W${{b1}x'mmnko}w㰻u`}?=}yf;wZ?W.72 䭘fIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/facebook.png000066400000000000000000000003121303525152100265160ustar00rootroot00000000000000PNG  IHDRRPLTE;Y;Y`xEbmgtRNSACbKGDH pHYsHHFk>=IDATc`F%0``0 e C%P RBeBT\Cp0K 0ef>IENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/github.png000066400000000000000000000032621303525152100262360ustar00rootroot00000000000000PNG  IHDR szztEXtSoftwareAdobe ImageReadyqe<$iTXtXML:com.adobe.xmp $IDATxėmhayL30A+R#f>IHکy(M)_o5 0+0Ėl&o{i^]u<{Yws}=uC>$L, }<w}8^ AO?p! xaяPKI3`'B>0QT1<+`}^nvkp^ƅF|1"Gp.*oO׀Vp ]߅jc8K$q 8jV`#`vmpGѢu!#}#:U_?_yhE $=;c*xNOo+&w)%K-R%6n'o">j/t³qoGW7j%2q GX?woibCÐAzbǰt \14|S.DZ]# b|H$(ʕohmqͱRP셣$,0Z20 tNvRW3K8Xk2 IO6LbIDAT}1 % h#"#M 홴z)} .?_"{B4!>}HVU8T% )mu CbD, F IIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/gittip.png000066400000000000000000000007471303525152100262610ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME  mgIDAT8c`o0cm=H_P| *0CF`1d=6_LԄj.d*LsHg#MM@v7S!0lÕs' m`=-oqEv 4plٰl$.4g4ܴb)f ā@,`.&@yjB P q7!UA?~p11?FhhDd"EDm j4'$MOH(I%^V8ǟ)LfgoǑXIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/google-groups.png000066400000000000000000000014431303525152100275440ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<5PLTE,r#bFEB@>=:875}3{1zDB@<7~4|CA>=986~?>6~4|2{1x>2z0x=98;9/w1y0w2{.v3|.uʡ-ṭ,s+qtRNS}abKGD-IDAT5y[QW-q̄13p}(B/繞j;.{`(E( )-O$9dAL#B /$Jryu]Bpp2OiR.;7EBpNb>cã}%bP}fC}(,ggxE)_Oz70Yn`-:9@ 3$%ts%tEXtdate:create2013-01-13T02:11:01-08:00̕%tEXtdate:modify2013-01-13T02:10:36-08:00&zIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/google-plus.png000066400000000000000000000010171303525152100272050ustar00rootroot00000000000000PNG  IHDRh6IDAT(cmIbeq&nt9@ A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  niTXtXML:com.adobe.xmp ? AIDAT8cD^V4?PAuLU?7g0arp m3Fpu06L.d s`]8bw3lfd ьP#<= Is aLd6\<(A_&#Ft6ab/$eqoIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/lastfm.png000066400000000000000000000017171303525152100262450ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS4ӠtEXtCreation Time20/7/09zc(IDAT8OlU{v6*U(D Qc@#'ăO=sp1 ϩD--4Pv{??=~.KxNyfƤTH'*"1֮Br:i$k.>7HXy?؁s(I HrwL.Ig~ Ig9R  (%c5y@F6CH,D ? N6(!cQ6{dPȡpsJ0j0e$pNU.x " 8zZ^5˫3uh`{#at0:Nh`/F1%쑔}#l̮qo2^'#rxqS'ɽshb@c;2I~7;{U,J,yoɾq[ bYBE2'y:fIMw.);#,8vmJK"",7%KRd'""6Q,yJ泓'w>׍j﯒ܹ.P.3_XDz]e?n g_)G_{!bGժԡhvdKAg^䋅kwЕ!dOCPY.cЉ#[{AbXM~bѻD\k-3rUe<$7V%-e?O=k;ʆQFxD0UmTgjzϯ|psO?ϕsݪCIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/linkedin.png000066400000000000000000000016001303525152100265430ustar00rootroot00000000000000PNG  IHDR(-S7PLTEhiklklmmoommnnoonopqoqprrpqstsutv vw w v w y yx y yy { {zzzz{|{|~ !"#$%&',-21223E9:9::<=~^|^X۳~#rӯ#"{:(#u;p )*R)j NA^AT kk1HgO\(vo84QImÏY`e)S IENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/reddit.png000066400000000000000000000012651303525152100262300ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTER[eeq}bjsdeg|_ju_lz`][JNSiup|VZ^ߍy)/6w]dknyo~djm{[aflpv><:w{qpoGGG20nprS\eɨFJNˁ~~~U^gjklգxgscmx6 pHYsHHFk>IDATePﵻ;X("6蠎s!/^`4-V-r{>]44"O$S > b\8!Vo4[xj65Bڝ.z6!0'c`4ԢS|j|,sMō6spy /R1$ DBTr\ߤ0^|xfNܸ !bT S<~C# %g;$/)QEuM"I`^~.:%n課~| wV :&15R§w 3OPvmd)$ỵ_%YBڶȦ3_JndW|Ui#5Lf:JS8d$7ԈPwɸ^?3u}ȜmEfS쮉 A*bk;K/T1UcDjVz_3:T80}wNpJɠAke,}:{m;?[/4E5[񮺱馕ny'}^8+` x<IENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/slideshare.png000066400000000000000000000010271303525152100270740ustar00rootroot00000000000000PNG  IHDR(-SPLTEâz既d{o˦K>dHk;}unw;97o&wE4fpA,]_z|r]+,$zqfmaHtRNS-)IDATNP^oea01Hc\iGL89qM,n$$LzROQ ]vgchKl#u_וb?oQܔ! . k;GW/ JD44!9ԛIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/speakerdeck.png000066400000000000000000000020311303525152100272260ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTE9,2tU7]6~\6\7]3uU.qSF~G/qS.vW(qS(pS#kO"jNeKdK_I`I[GXFXETDQCOAMAM@K@I?H?I@A;`VaVB;$!F@F@E??|>{>{@|?{?|;x7u6u6u6t7v;y6u4s3r3q3r4s2r/o0p0q1q,m,l*i*h*g)g)g)f+j,m)j'f\FP>O<VCYGUCN<\F(g%g#bM<K3A7Dd]@d\Ed^A8 =2G:|bv_r\^MXHXHUEUFVGVF_Ns]o\n[p\o\o[n[hXgXgWgXfWfWhYbVaU`T `TcV^U ]U ]T ]S \SǶ(tRNS{{m pHYsHHFk> IDATc``dbfaef&6v M-m]-mN.n=}}C}C#c}nS333s KKKs+3+S^>k[ "[{~G'gWW77wgOA!/o_? /aаȨظ$Դ̬d1¢⒒ҲJqںƦ*Iֶ֎ֶήVi }d&MIDATHT;H+A3;dU (AĀ [(#l"Z GVjaF% PPD$dd;!Oŧ»a̜{a|exc)]^ Cnw4LrtW ݛ&ơ_(r:_6ndkcTRgR@@ W>Ez8>8;0Gi!D)c oԌ󳢌vu qÍeGi|ee.'F_ `l!XE|v TՍ BfgE㹻BHr9!R}Aq==E"T[kO` cR)t] Tt]Υ[JK eYL@J)憳WW$oo׽ssD6{yrUUe##V+!>5c`LmߗM`?ZZLbRJ(eLI4fRBU֦iU.! d2vN3qGg;;!!Ðee]7 !qE'`0dw$ jQ盛 hכl ''PO5(6V\Q(u>~ [e(~@~;IɅT%tEXtdate:create2013-07-03T22:30:09-07:001D%tEXtdate:modify2013-07-01T14:56:54-07:00IENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/twitter.png000066400000000000000000000027451303525152100264630ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp ]ivIDATxb?%BrC~$q#P#C&Ffq@7(w࿨>7 }|?O]} @ (ceM1K10p301W6gP*`V1TĤ/deCy }h|@JHɀmF, U1odpMD0ڧ!`^10zt,,Dde`AU`aQ~3AL0Sce Ɠцe`be`,@p988|*}\_n\ϟ?<4+r3h2; )1-9%Zu@@1(u$eX>p2bռɂ3^{HiH[xP:#}浽: ,CgFokL旿*ϿWfgf"RN2Ka@O5 yix/cd;{@IENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/vimeo.png000066400000000000000000000010401303525152100260630ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTE ; +ۆwٕJwIۃi {5{ ϲE ΡrdD|b uCw[stRNS@fbKGD ٥IDATU D.*]k< b[!'3"HHnI ::.zaxlIX X`7[`xpS@vֱ7xݛ Szʺz ۿxϛ%tEXtdate:create2013-01-13T02:07:08-08:00&%tEXtdate:modify2013-01-13T02:06:39-08:00.hIENDB`pelican-3.7.1/pelican/tests/output/custom/theme/images/icons/youtube.png000066400000000000000000000007121303525152100264450ustar00rootroot00000000000000PNG  IHDR_*?tEXtSoftwareAdobe ImageReadyqe<lPLTE#UO#"DfGJ pկnfȹGծnf֯ng9$tRNSX, IDATxbPf``d ~ @ lLL @1&q8X  ,  UƀYA200*@4h0#@2jab7XIAIAd B@[!0hV fdf`p000H0aIe;}1cIENDB`pelican-3.7.1/pelican/tests/output/custom/this-is-a-super-article.html000066400000000000000000000142701303525152100260260ustar00rootroot00000000000000 This is a super article ! Fork me on GitHub

    This is a super article !

    Some content here !

    This is a simple title

    And here comes the cool stuff.

    alternate text alternate text
    >>> from ipdb import set_trace
    >>> set_trace()
    

    → And now try with some utf8 hell: ééé

    Comments !

    pelican-3.7.1/pelican/tests/output/custom/unbelievable.html000066400000000000000000000354511303525152100241140ustar00rootroot00000000000000 Unbelievable ! Fork me on GitHub

    Unbelievable !

    Or completely awesome. Depends the needs.

    a root-relative link to markdown-article a file-relative link to markdown-article

    Testing sourcecode directive

    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Testing another case

    This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.

    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Lovely.

    Testing more sourcecode directives

     8 def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]

    Lovely.

    Testing even more sourcecode directives

    formatter = self.options and VARIANTS[self.options.keys()[0]]

    Lovely.

    Testing overriding config defaults

    Even if the default is line numbers, we can override it here

    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Lovely.

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/000077500000000000000000000000001303525152100221005ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/archives.html000066400000000000000000000120561303525152100245760ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    Archives for Alexis' log

    30 novembre 2012
    FILENAME_METADATA example
    29 février 2012
    Second article
    20 avril 2011
    A markdown powered article
    17 février 2011
    Article 1
    17 février 2011
    Article 2
    17 février 2011
    Article 3
    02 décembre 2010
    This is a super article !
    20 octobre 2010
    Oh yeah !
    15 octobre 2010
    Unbelievable !
    14 mars 2010
    The baz tag
    pelican-3.7.1/pelican/tests/output/custom_locale/author/000077500000000000000000000000001303525152100234025ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/author/alexis-metaireau.html000066400000000000000000000210351303525152100275300ustar00rootroot00000000000000 Alexis' log - Alexis Métaireau Fork me on GitHub

    Other articles


    Page 1 / 3 »

    pelican-3.7.1/pelican/tests/output/custom_locale/author/alexis-metaireau2.html000066400000000000000000000220421303525152100276110ustar00rootroot00000000000000 Alexis' log - Alexis Métaireau Fork me on GitHub

    « Page 2 / 3 »

    pelican-3.7.1/pelican/tests/output/custom_locale/author/alexis-metaireau3.html000066400000000000000000000166141303525152100276220ustar00rootroot00000000000000 Alexis' log - Alexis Métaireau Fork me on GitHub

    « Page 3 / 3

    pelican-3.7.1/pelican/tests/output/custom_locale/authors.html000066400000000000000000000101011303525152100244440ustar00rootroot00000000000000 Alexis' log - Authors Fork me on GitHub

    Authors on Alexis' log

    pelican-3.7.1/pelican/tests/output/custom_locale/categories.html000066400000000000000000000101271303525152100251140ustar00rootroot00000000000000 Alexis' log Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom_locale/category/000077500000000000000000000000001303525152100237155ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/category/bar.html000066400000000000000000000121021303525152100253430ustar00rootroot00000000000000 Alexis' log - bar Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom_locale/category/cat1.html000066400000000000000000000201741303525152100254370ustar00rootroot00000000000000 Alexis' log - cat1 Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom_locale/category/misc.html000066400000000000000000000225711303525152100255450ustar00rootroot00000000000000 Alexis' log - misc Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom_locale/category/yeah.html000066400000000000000000000130171303525152100255330ustar00rootroot00000000000000 Alexis' log - yeah Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom_locale/drafts/000077500000000000000000000000001303525152100233635ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/drafts/a-draft-article.html000066400000000000000000000113641303525152100272150ustar00rootroot00000000000000 A draft article Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom_locale/feeds/000077500000000000000000000000001303525152100231665ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/feeds/alexis-metaireau.atom.xml000066400000000000000000000546701303525152100301220ustar00rootroot00000000000000 Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> <p>This is some article, in english</p> A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/alexis-metaireau.rss.xml000066400000000000000000000156741303525152100277720ustar00rootroot00000000000000 Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/Second articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/foobarbazA markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/foobarfoobarOh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/ohbaryeahUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/The baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlpelican-3.7.1/pelican/tests/output/custom_locale/feeds/all-en.atom.xml000066400000000000000000000546321303525152100260310ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> <p>This is some article, in english</p> A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/all-fr.atom.xml000066400000000000000000000026151303525152100260300ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/2012-03-02T14:01:01+01:00Trop bien !2012-03-02T14:01:01+01:002012-03-02T14:01:01+01:00Alexis Métaireautag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html<p>Et voila du contenu en français</p> <p>Et voila du contenu en français</p> Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> <p>Ceci est un article, en français.</p> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/all.atom.xml000066400000000000000000000567251303525152100254360ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> <p>Some cool stuff!</p> Trop bien !2012-03-02T14:01:01+01:002012-03-02T14:01:01+01:00Alexis Métaireautag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html<p>Et voila du contenu en français</p> <p>Et voila du contenu en français</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> <p>This is some article, in english</p> Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> <p>Ceci est un article, en français.</p> A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> <p>Article 3</p> This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/all.rss.xml000066400000000000000000000174241303525152100252760ustar00rootroot00000000000000 Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/Trop bien !http://blog.notmyidea.org/oh-yeah-fr.html<p>Et voila du contenu en français</p> Alexis MétaireauFri, 02 Mar 2012 14:01:01 +0100tag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.htmlSecond articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/foobarbazDeuxième articlehttp://blog.notmyidea.org/second-article-fr.html<p>Ceci est un article, en français.</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article-fr.htmlfoobarbazA markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/foobarfoobarOh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/ohbaryeahUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/The baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlpelican-3.7.1/pelican/tests/output/custom_locale/feeds/bar.atom.xml000066400000000000000000000027511303525152100254200ustar00rootroot00000000000000 Alexis' log - barhttp://blog.notmyidea.org/2010-10-20T10:14:00+02:00Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> <div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/bar.rss.xml000066400000000000000000000017721303525152100252710ustar00rootroot00000000000000 Alexis' log - barhttp://blog.notmyidea.org/Wed, 20 Oct 2010 10:14:00 +0200Oh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/ohbaryeahpelican-3.7.1/pelican/tests/output/custom_locale/feeds/cat1.atom.xml000066400000000000000000000054431303525152100255050ustar00rootroot00000000000000 Alexis' log - cat1http://blog.notmyidea.org/2011-04-20T00:00:00+02:00A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p><p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> <p>Article 1</p> Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> <p>Article 2</p> Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> <p>Article 3</p> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/cat1.rss.xml000066400000000000000000000042221303525152100253460ustar00rootroot00000000000000 Alexis' log - cat1http://blog.notmyidea.org/Wed, 20 Apr 2011 00:00:00 +0200A markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> <p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> <a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/pelican-3.7.1/pelican/tests/output/custom_locale/feeds/misc.atom.xml000066400000000000000000000426121303525152100256070ustar00rootroot00000000000000 Alexis' log - mischttp://blog.notmyidea.org/2012-11-30T00:00:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> <p>Some cool stuff!</p> Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> <p>This is some article, in english</p> Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.</p> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table><p>Lovely.</p> </div> <div class="section" id="testing-more-sourcecode-directives"> <h2>Testing more sourcecode directives</h2> <div class="highlight"><pre><span></span><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8 </span><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10 </span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12 </span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14 </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span><br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16 </span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span><br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20 </span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22 </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span><br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24 </span> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26 </span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> <p>Lovely.</p> </div> <div class="section" id="testing-even-more-sourcecode-directives"> <h2>Testing even more sourcecode directives</h2> <span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> <p>Lovely.</p> </div> <div class="section" id="testing-overriding-config-defaults"> <h2>Testing overriding config defaults</h2> <p>Even if the default is line numbers, we can override it here</p> <div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> <p>Lovely.</p> </div> The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> <p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/misc.rss.xml000066400000000000000000000072231303525152100254550ustar00rootroot00000000000000 Alexis' log - mischttp://blog.notmyidea.org/Fri, 30 Nov 2012 00:00:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/Second articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/foobarbazUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> <p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> <a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> <div class="section" id="testing-sourcecode-directive"> <h2>Testing sourcecode directive</h2> <table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> </pre></div> </td></tr></table></div> <div class="section" id="testing-another-case"> <h2>Testing another case</h2> <p>This will now have a line number in 'custom' since it's the default in pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/The baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlpelican-3.7.1/pelican/tests/output/custom_locale/feeds/yeah.atom.xml000066400000000000000000000034031303525152100255750ustar00rootroot00000000000000 Alexis' log - yeahhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> <p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> <img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> pelican-3.7.1/pelican/tests/output/custom_locale/feeds/yeah.rss.xml000066400000000000000000000015531303525152100254500ustar00rootroot00000000000000 Alexis' log - yeahhttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported as well as <strong>inline markup</strong>.</p> Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/foobarfoobarpelican-3.7.1/pelican/tests/output/custom_locale/index.html000066400000000000000000000207241303525152100241020ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    Other articles


    Page 1 / 3 »

    pelican-3.7.1/pelican/tests/output/custom_locale/index2.html000066400000000000000000000217031303525152100241620ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    « Page 2 / 3 »

    pelican-3.7.1/pelican/tests/output/custom_locale/index3.html000066400000000000000000000165201303525152100241640ustar00rootroot00000000000000 Alexis' log Fork me on GitHub

    « Page 3 / 3

    pelican-3.7.1/pelican/tests/output/custom_locale/jinja2_template.html000066400000000000000000000076061303525152100260470ustar00rootroot00000000000000 Alexis' log Fork me on GitHub Some text
    pelican-3.7.1/pelican/tests/output/custom_locale/oh-yeah-fr.html000066400000000000000000000126001303525152100247240ustar00rootroot00000000000000 Trop bien ! Fork me on GitHub

    Trop bien !

    Et voila du contenu en français

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/override/000077500000000000000000000000001303525152100237175ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/override/index.html000066400000000000000000000101651303525152100257170ustar00rootroot00000000000000 Override url/save_as Fork me on GitHub

    Override url/save_as

    Test page which overrides save_as and url so that this page will be generated at a custom location.

    pelican-3.7.1/pelican/tests/output/custom_locale/pages/000077500000000000000000000000001303525152100231775ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/pages/this-is-a-test-hidden-page.html000066400000000000000000000101671303525152100310100ustar00rootroot00000000000000 This is a test hidden page Fork me on GitHub

    This is a test hidden page

    This is great for things like error(404) pages Anyone can see this page but it's not linked to anywhere!

    pelican-3.7.1/pelican/tests/output/custom_locale/pages/this-is-a-test-page.html000066400000000000000000000101761303525152100275570ustar00rootroot00000000000000 This is a test page Fork me on GitHub

    This is a test page

    Just an image.

    alternate text
    pelican-3.7.1/pelican/tests/output/custom_locale/pictures/000077500000000000000000000000001303525152100237365ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/pictures/Fat_Cat.jpg000066400000000000000000001723231303525152100257510ustar00rootroot00000000000000JFIFHHOExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:31:29 PrintIM0250$"'@0220    I &|z.0100,   Dd2010:01:09 14:55:402010:01:09 14:55:40 Ndd%ddFddFUJIFILM 0130Jj r !"#012S100 S100 A592D34383231100603D7050TR73277NORMAL d^^R980100<D(LHHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?6LOn7SoCW,6tĠ>*IwrJp@]~&hFx应FNsSX$4:02~lnOp~\Қ2pR%HQL`tiͅ?r j\n+.AvLpG 9PXtMKL x9 *%T0h$H9??E(A81.cʰ;pDnXRC+F;֠Vx _zIo?́8ֆ\IN!"%T=2"$֎O 攜 B.8Jb"\ɹ`RGZ[;F!Kq}(M~l֔_ 9}ji2sv)Kހ OHԕA1ɖҁꭆݑh2l=r3(X_hRR)Ҡ0{Rc>EP‡"1b[硦/ݷ$*nAp{@;if I':Rݸ=N=i8A=+a*pcTЕ;PWV} ?漺ھOxc;Efn5jr= ;+!jnt\L~\\!_Ą=/ҵ 26v?+ώdz4r=mܾ67 ҷS37VRU]nCNa!D>Rz{.#s֑{p知fh%u-̠d{VAP8 9CE 'U$d*G]オO&BLň ?VFi XOC؋7N}N#Gpbp׵DmAnwcSYXg$6MyQWǽG#Q+)`@dž2 :əFǓȥ9Է;<*2T4Qj@g $f`hD+⢝_3MXx|5)+e= 1]0Xٽw?%W#v\Nj5!on.zw4 ;O$ pNYg͹;*;}X"$`҂۹Jl"}pF=iF3Xɤi oq9曚z.rzUv23WWn{g4ˉ|zk+اyWaEF#aG^^Tu" ($yhU >F9.;K;Tt#0)rLOovJ1+Y-3fWi;0ҹGC9Y"ǣ}* ''TzV`cmޒEl8( N}м_C2ntURXkIr\OJMXW ~vIG˟Zs:,@&F$Rfd5GҐ HLEW4TOcןE^ivaZH%wkIHćS~nZxRI>ILj.bϩEuI'JQ}>f˜Cʫiq\0OLSzdyiIT6uJC>f\}}BA{p@H:uSXc+&h@c f'= qJ7(,FUv$ = P`F =)J8jr>.TyՔ~}҈nW|@1cmrp+"$4=qZb71/`8ϭ7y-m^G]*yK.T]yqܲ)8k#A]J𝸻 Uqj.$rƊ<4?oƾdp'[-"gԛmR#qֹh%u=M р7׊z.t qm, xkt Y\[rḲ-8{=.V%e돧^6,1oZJQ'K0{bgGԮ8OSj*XqWEd8 u>Rܵu7FӌHQֲ|x]z+48ۓҢxAhW* ~EDLR1UN@doW/hjM'BN[HW>S;oO;YanUsB |߅hM#S, &UHdI^'iچ7ZJN8F *C""P5Ic{-d$4ȱtV@46C>m"[u] FᎢdb{qszy3ՑMUWfB#@Nl1Ou. q)d8ʝՖՆbr 7C`=hzX@mM,s %Ipǰ- bܢҲQ7mF7E<)NcE#ieA؂B g-WRTRRAC&xm@ 9u(ձW, Qs7D䠐2FبFG~ Vz,DaA4QJ.@}*t~@[GTTuSȩ  h,lH8W.S;MQ<ҿʄBGQlnq.4B# ($l#p)‰O]5*ƱL`p7g`ŚjU5BFgx+)*~mq2.0rN؝ * s42T>vji6P_g׷!}=54Mh]^%K.4> x}9ռt֮4gCCrdNݻ`mk3-\h'֥d֪ 8f=xQ|K,QPڥʨBG>n?a }-Lk׫G ױ RA;G߫ޫx$gd:(.*w's gbQԜk*BV)%He )99䡧K:UT7Yj$AvM"i:F~`m'8MM=55E0EIvtg'-QyU' FdG;/PpoV`}5-ʞ8xv=Mbu01dVx9lza\Ji>uI#Tr/T$M,ȑHd(2k}1sۆ9,R\&q]::A4T=N891 kJ15U"Fj&]1kgbr[ n<9çHl7rKԎ* ]bDBA՝)r"ϢJzVfX%hDzRz/HKY'`̬ʺ|20; cpmKJr5]ٚdC2 {\c$@?).w&枔 C+yYrs6A;-jZR‘I#i$ֲarA/YmցN1ަثH\f7+H,u,2MIrIH;1Y&%P|P|( FGN c1 M(^6ZbHKrq~~]k4RJ`*?Bvlt-fJ:e"j9]{$ؚ|+ ix~;8O lM?+s];KE*@+3,c꽻 mǵvVGPM&T6R6%-9?I#з b&Gu"jJ@" *p9=Ǿ1{=u-4"zr<ͤX6|!̐Ʊ=-5XQ)rL#" 8ReB0#`0Fޜ`JɋS^zd|+$7Ս2dIRH [r(Q{Q`2٠\vQ vB٭b)fՐN|Һ7m=$9`q/1J`ؖܖ۹>$M4G3T*aX i=<әT M׸6qFzy)by)TOdHUvR@ )y`J5h Ab1r5mi"{!jI6$%B0[l ce.,T+MtY`) }8*Պ2Fj]C '}d_^2S,sK$ÍXa#Lyv4DRB$h,]2X;'z9!f3(+$O aF>^T3T뒑r:UePIl Rt؝;x)l)V\^x%dxԹsf!q A8qWIWC ku {y|lGہkDCױ-E,늳[L>5܁'t&Q(%q؁뇈5 ssWA, #Ï./ԢkXh\dc'|lr\x{`s=Rَ߰|r_ARֶvP^{wӌ.+&SCӌe.DZZCcGgP ԈbH N |qB >U v:9%ȵª\eAOӍG`qW r+,=^@ C m.iSҕe뢡U %YJ7/Y-]B *q_^ &KdQ%5%ae!DB)6w]#gH#Hs* Z@ƮqmE=tBzP ~e j,NV)SC,фM.cM Q;cmMk#y(jMR9ܕFOm7&-7V*$"yΘt @ eOSOSVy%OD!oΕ=p: g#,**n1[β@WT(p~/Y FezyJk|¿~trrX(g)C4}1'PC&vmƱ\h)gHG U@%4w%N7#2t0[TLi#U-*W`c$v` ʙEGU5yDŃĽ5g T:5w:*{|F ST6 9$d03 QEUT¢%.R<*pO~[V5:_2TKA2G<3YũD.1'.FANN M+;ȏ*N>XvSܗLs*\ qjw6Z^QS+*, %\n.(SFfjEcG`No =QU ȵz]##$7ǣf:I::S WsvF%Y ZV1t0V\ [60}dbGJDQLjeEIfl #s8 TRܨ0)=m?I cըRrb}8o }M%LeGs i ۊi$TYm!E0/!XcnI:$[O[Jid! َ?1<#x-6[^u!Y$\'a07'\9o \=tQ ?1UV_RF}#I~EJAJ>;5 ,6#9`^ُr Sa4cELIիP*.G2)s3STuqYj) CN@2{nK-'ڷZz9F[*\MƬnN8J(*nvB2^̯I\vI=25%XS"q#)Qΐ8i.G^ ١Zp*dy v{i؟~R[hy%X~qׅ$wEuHӍazRK@6 'ԦL~=[SOU:Tav#HܑOrqvvhtXds(.ñ@A#|qlUQOye,z!tҬO0vCTubZDe>m {Qz'VUH Yf %W;0r r~nFs[I3dv6")n6yDi[RƯ0PՋAVX*DŖXŽ3AӰ%z<5Қ\VպTNCI5a70T ةxޮ:Ί5,Jls&sX g_GQQFRW0),aFvsK|[h!H<8wr#f\nRdOY6k,Z&g8 UjuLf*24{'ok>c xH &bJm ~f6C~ڸoAfz\cj1P$(Q$?V@ gOrX)Nu.#"AW@%}lA μg\N̕idZa JuzNOlm=Kд_Ω ;3dۀ ^ԼH,0bޞHNHՐ*%˵:T+Z1uw}oX\+TF$sG0p:`3ܩaevK|P"RuF3$;?n%ؠP^Y9zl428]W *$U"%Umi}Mv%hj֥UZws3Gm̖ieq3ըzV;ar3hlek'DJш8X@Q;6#.28:{\'jx#fAL3+!й8n/ZBdft@~Y.Z,KH"ȳ6@9Q&lgxt.K:S3"H͆ʔ;`bu<>^==)AP0PX_A_&DyʳǔT}Ďn. zQJ{@RF #IZӴSMbWdv#)錏0[ Xg.&A}yǶcwe`&z^fFpq$R)yb\*uEYP9vZ_N S]]e#e$Nv'H5AO _UD꘦(Nlq`mxoq4x6=҂iޟLDW1Vh6;sj =VRCJUlNA jR@N@0LUl -Tȸe8탿O흸 5ӣ4H@9m#auی=,UBP!ETn`1a-zkE%hf3n!Iv"j =]U5S/Q l0 lL2S*Q$# 6c=eƑFHbΈ9}3I\LM!=6m0pj~"۫bDuelH;9 (5y Z@Ә2v9+k<Lx 7pOiZfzxLSc?H l\VV{Q]^SW!zWf `201-W[.J q":`'q*Lky办:LH4UQ ƜwZ"H$Z cpPM QB6֧LdigtfVu6̧|8|vCrL 庤noBp_o^$mt$ #:UP`sRב,< Qr$3DyFFs;q$Z-UtR,TnO@ m-HSz;^)9L+"B9: v~b.ecKUy:"B%+Ldum +^JP2emI6>wG=١ʺIVEG%S;@)8'pp3iuri$g%9]AI8cNl3y o*BP4 ye 27wlr14 ey%edhT is%)7zlPƢJ D]3t ^X/ 2l1W߭j/Xѻ?1)rF M;:u1@(3"iܗj)sTub2T9aP3،PwI'b5UAF3 e(G.=PZijzY0Ơ}x9УQ9oz٩y f&),l9bNJGJiB0F78p6BTOO-2s]JZzr"NČyHT-m_LdQM# 9=~GH)nQ6MZ]{$t0H騍STQuH¡I!۸'h{ ع_5=M- 7S$:@Ab+KId(˩!Sl8z`p/DyoEA$#x 4 ye$6DwDLӤq:UK a$;nRÎ0ꑰ'Nވ8WGgL 5} \axVUtIK Y5T% ۩##9jϔZQ#\~^ emz@P6$>#)y{NU[KBSNᖼ 6 3"y/Co-Ti32N'FY;.u.·I<5yiPU C- YИNi*b&*zC8;,mƎH.L@F}Hx3gᐒKn팏sCeic_|Q7`MNĔf25 H3gڝ0㨆E'NF5~gm*Aԑâ~C)tC&,]2ZP@'.!K_M%n% bɝ nu @5B 0XGc$ "G!iT::\ǿ*(^Ǿxlf(1lOۏ>]$'Vqۂ-nC.1∧%|Jf\F@3L~ ǯIM4).YC0 (|zʆQ4 O֕VD}'x-r#w83GY\W G:~N+udS_j'/..8GSA շ5YHm敜ySO,-N,1 ' 4E* ah@4A VʺyHJA:N7+qɏ?;xGP.T~sM/XZ^\@y::1 6VϦ|KC :wvuhs@0RAzytq7"%rJAKmJ@8ܮ}fC]h.si.mSd`9j85dQGOMFx؉F|n{^r4qQOѢыTS87]v[QHt@,2GBR"ՊZp@ TGZ.96Ⱦwʋ4BfO(|OxrO*%3:$EePXt./9S\',tR8$1{7$xy t:z̪A ylμ5V# Jp3wرU7-:: P6݆GDde* NHLi#iRN;j=gfv#`ldy;Kd -ec?NMA#vn#H ]]ۦHSwp6˗I硯e0"A؍8pr924jZT\c, `ocm|US :2H''#ntn(h"$\eJNIՌ3@F$ SU B%H|O|*zW+43u`$KA PcBH*䧐nv`pW m9p\i*rgQJ/۝?ڊ+)ɅT$ I&Wv^ۓn۫Rq2Je {NH(N] B`}aq6 0?5?W%]%UIBP ˰`(%}>%~(y[ồ~HjDIj'C!ϓ$|g:]m9¹X Dq䞜`)tgϖ۫GH-6ey ߑx/Q"FM*wl{q6[xCyq>8YE! ;9Y51\(hL$8C* $d}Ś )Tly2OxѴX1\[ r! V8e `|r㐖b e0= ~ ,"}9} Bi]И d߷C,Ta ?]ĉ!8s۾?t$1ó1 7w~#6ZE_HJw9g{I1 K"H䃝ĝ7!B&~.];ln܍Dڷʟ{~\TYܴѶCn7Rvu5bfVӑ^,Er{B] q2L:]Cf?}c1eSE$lP9Fc  8tc/#X֙d9Ks8~Wpab!,I ߊ.0*eݖWW $' i獁P|9aˌ%+/iPw{uODs?p2?~/r3uޖJJ)h&de %u/̮: 9< _W:##mnӍ14ugGX gG--%+ZwWIQ`dn5HeCK4I-<$eBKV8DA_.Uu-$ R9S"W_n5KY@"<S%FVRr g0pYLUutUVS"w(!2Cd|cՂ+6/ hz-%QIx{Q# 5ltW\Kf[*UDc;)bXce< .hIuS)3ȚdfLww ̶bGG⩋C5$u1rt`l+.bh+MeBC;SL :6Lef >~aIbog7Cx\lA̎w:C}G1-]3,1T -^I a$ 1gH>*ս嬚{ETϟ#3CSiZ=O@ROW;a2G?)/wTRi3Xb)Ol~A[+m5WCXqRg%rHw?0U\uKTTC<ñUʜ,h"u`Pb csr 2m vRY+@KDFWJI=VÃIvAⒺ 0aoAHg$3~ZhV4RpP3 $wj4ZTb S1Gu[]u5-&  2urU:O}~%XtꠍTC/P4 )b ʐtoyUG]piɊD^[*mGAҚ9%סKd6 'mEBnȟeA3)qNc N !`J"bpb~翧-a@i@Q)0N9 ;ߑij&jQEsB1Iv9< L쮞5*2̡BVg͆0>y .pK*ERqty\m"+XXq14ŋo9y`(m29y9#H>9YIKъv'}+MIN7u1Y%J"|rN/gOjُ5rH[M.*++ce9cfy0sn+0R{joۿ@Rj:u$y2\ @{L_8Fc ;r{zkj`θ$~\,5* 1b L۶ |.zK{qi '?޼\QIneUf]*V}0wu'*L:tăwG37m1* JFΘm}غtsD?n < ƧVŽ}dJO1߶='5IGeu*Hg66ʜU*T A'ޥJy|>ۊLi:#T79oPYI2TJL>*`v6TfΜ x67dq(N `Ԝpknnk=4ST,sB$pA~6/|aEEtUdx$m=ԕmGcR2IR=8 w:c@#Qrq/|o{ɗZ;3,u[!S02YwpbTrqcѥ"'_:r墮ZkaOC4*#tǕt)H'r*9;j$5`VpNIo̓;xH$P f8 UNˬi;|A)*" \"V:@*8.Y7φǶkg /(X€6OSs&rYm,0u2lѨ]MN3xW21t&# r;~@wKB*lx!)t`E! qfOOy#k5nr(iD朂AHBz빅REM * pGprzp{U]%m2EԮV6Rce +(㊦*B H-*ap}TT1U4 $vg9O~#G6ARO|嶶zeMAd:Jc`4$%rw F~ dTF& 4_Sj685,<%&һ32Nܓoi9Xjе`FtzvSrNGscL| 8=2Jݠ-mjR,Jw[Y? "ڕP߶UIv=P?∩E=IE;OvtbUtz~lۿsRۂ|Η{tjڊBŋ= ~`e`ѱ`Tv=͑(*67Om&%5\:M B2lQTg*(\1l?kR/b\4%!i]Yp;nus$dƥ̘`Cq [=|W Yt:ib[љlkpj`ÒI9nZZ]IkYհs(=;pJu{E}}BH6 ϯo^5ۑ|,V*r; QLz~d_u8꫕8u8MNs΄%zaRuI@W#2T7mAk-=ʉ&zE%1|En5o&t'`!߯|uNc0<];3lv;QETV%3 k$h .Cߴ.Gr$ctfQOqj 4P e`;n%b(s7S教ʪ)Lgn+)U hJ7X {xsH%P"7A R*+v66 c!=ꡩ- 3RHS@U1Bb| Jj{Ⲇ#%NNi  4^BM z~Y$әחʐCM )A,q;{Ċ[5cY8Z3"VDAm9 <^-MR믎K,Lnb=P1QdH]!#7hWPncb0xMF4βڨ)eԘ`BĐDzU,E@Cber2FGs`q?5U=(ڐyֱ֌ru*ccgǷL+g.nUϜtC<7*IY|ؽCtNnk ¡G؞݉ny8ҖCPe)?n:5mʈ唸ƈ|Vf18xM}b3.+SH CFH*3Y;`KU1n#bO[p*`l*p}9GV2C 7Ʀ@9߿2 @ebTs>p"! C guH@ ԍ!׀9#nG8rN#==E&BdbsrxO^b${`p|&,] U'$=lTVFrHɬ#Y9=yРe* -~]xYq4tx؏HQ97.1/I[/s)ߋy1N!Q{NnN&2}%ʹr;ct9qEbbT|{ot7 {qXF5cǴUUu>e*37f7.f{]Y32T$>`{jS)"*`gV0duIgc'>| oG}ĿҴeE|8#o\ovl6rQQ 213〴Va:Q%\䗔,I!lؗe򒛗o-H(=!!;psէ)kj:y$ɼ)Rw*T6Oߊe7"ND~J$,KPtΕ~rebF ؜yG vxf&xS!+ap>ns{o|)ynJEt.u>-a/?>*Aɒ:xmˉK{H$|&`[`0=ۇ{#[y^1z+dMt+ض5wH*b )tЦ?8ggL7t?~&IZ$3p~R[bIYb*Z7]w#;3AGA4 Q YLnj,G#f?9SK)3N<[:x\#R.P[2V^ cGC=GQ n6⒰[(*Y^FJy(#nkre}-$MlRSHNfɻi8i.^UҍWQRSTľ@#%Ce2`?N+i ۓ#P[gZGDXN5:I>n ]T< ZOMS[GS2Gb`U%.rC<ɂ$ہxYs9v'`LNkzX  '#gؑz:iKJI}$iqg OJ9E΢+tqbêQnкYe3M iX'Yfm NSQ$k7W X( 82qucI Ushi*Z9SeE`Q=]@:K2m,M`~[**`h*%մ6HI>q%q:YW>\6H=A'5rWiCb zŋb3ۧZge1O2#͐2=56uQ"R4l)SC`ዀ8߶Okwg-1;2RPVG]Frt2jO7B"T>QNue5F8be*t G9W͓~ZJB0L8clWlm]ޢ32ž8 | ֘G!!57}'| Ht֢2R$n=6 mҹ^U zیgb/E&I,%e%{zgn AgDI[$>TqXT@v]4@|_AŵrU=qvz3qqk8R1) 26s]4EQ?/ZV`W;gnz#捔O|QRYw%lҫ,r8PNB6= /w F [Iij9QOy[ P42}őcHT:nDXd*}N).7yR#) :vzpa$ BHˋY&7 !vÇcHRm[]c}])y%EA[<+) !\g<ZY< ^։f9#A9STg"cV\` ^vNpȎ?O 4#@Eǀ VA_JV.b}.P{uWhLP:eU:# K72n{O3±FTTCNtp FC #; g% vzybus@ %^HN[, ۾= S +9njQ5H#p}x?>[+O*#iMPNpϯĂɫzhYM$Fx Ȝ VBue >bG}ǿxF1Z|6#'f{q +%Tm SQHcFc8 cn4ƚb]/d)ɧ-3T p#Iz4`cKƮ81Ԫ]_ v`^u钴b3(8;04hXtDl_~m^x_Eɩ*.'4ZR ʬꥦ aU݆NQt.@[A:aQˊ|,S K+LLX#c~:Kݿ ZKaԣ.Đ41m7յ ;̕lߎxcJjh>J)"r!IN#ӆC!ZoWkh9j,z,If',|.<QnQGQH渼2 8P6r;; )/\(JFiDW=0zpBr֙eg 24S|=r6Z[/tLFV IlI{M˴5+WշӺS:F-C';椪Zi$ IeU$ AǮ h.I_Dh))cTJ` (0bw{dpp--@bʙh.uPyrۅVdha*fU`ucf_7j^)z  raCH`7pOg-kU Y9S"udf)W'Wie,>F/݅ ,]bhD4 jU2 0$0H7ཞUO3Jƒ$ &7!QwGO9=;q_j `1.1w ?/SR:M&d>7y8/njHgT$jgң8BVrU5Q?le˕V/(`ǧ”1 S@cy 7iqfP&R22N$omQ ,LkEuAoa,JYtV7:;woTW, MP}㣏% rZ$n2p4|GX wvo)i%r}BCj$d\)~ff'u-2 A)]8̱?c1m5El07qM_uy:dfNW‘Rj`*OۊsQ]alKlN !Tܨ}B4H)ӍC?q͜uzڛK.s+bZOA[QK)Z3oT?ˍXfilջBV]hk#|[w;jLv*b*$zekʖ65=vl]H0>~Al^%-3Do#"2,锅IjLRDt*qӎ`c qZG)D,pq$ӌ n'ٞFh4i*2oƸG`@qgV]k9e\mJ c'$aHV$GTh2\)iY Td7';gZJ[mrK^0+qn˟}imoHUMw嫓`i阸VHːF- d s=Yzt*bHi&B 6N6ᛞu7":Etɑpd)BDzhNbQq8*Uɕ Tb7uhI2+d'e3㥵UiX#i#YF6c R[Se]JBRܒw:P1.KBb3M~a,&`IϮ8ПI/DzJR'K$QFRY[0I- A4#QӮ g*5>q w{yx15*eHEo+;@>V~<= Z2EdFM;6*rrp}=8VlTTհ% ⚥iҧJJqrK:TSHجaT~a3sV//[FPQD`cbNw\2sq~s99W)zj$fܱK>\8e$ =8vW+&i(%e;8*Jca ջlL?n6Obxz&|@JjH@f'Rwu3W$t h9s 4vOlے!j]N}ۊ$d`۳!χX|YW:ȣF&p6oӍK[䀮SNgY˾+AAE ˣceWW++dv+Eؕt* DK㽎 KD:jݲ ӍexidR}Gi߉xڭSݭ5 y5h2Nr0q!ek5EAn X}L9D}/_QrkPF(H0w`?9n*P 49;aOazG:;fs%UXmi. ( w 1&O -nO=:|1[n-(KIju cߍZ֔|D*S~&٢/U6EKEmpb=/jb@K22۹"@Mٔn=xĻa|y,T1WZ8*]DQʿǯn,w+a˗\cу?_U+-W,r1J=,:=}oͼS͗ډGvv;_`>afFGqv$G'<Hem#:w?F ;eoz~zFc}8q:]I=0a߅Sa cN<˜;W2vlg4^)ӕo^覒-Rn#2dp{°9q/?77ެJxLJ_O5 +kdf#~;oj<6^2ƓetP AJf(^ӈg۶8N^[Ġ9g0|*cxá98p!|#}Ha?~)3`[덗TOzz>9ھAUnHDۍд[>H:}=xv nw¼1oŖIRf8xweMhGh؎?yn-%<2q۱.seZԠn[Σq#928!Q`{}` ƉaU܂v,146F0slCsh1ČIڶ~{=yImB RHT@FDeL9 B8?vUH:S#/ d|,SA m҆iupPea>lw6(8_#{I|PPE3f&h.FU%T\曥0g IW;E]R:> Rǰ'8sfm0V`cd'2qH=6]i}ڦ]EP LsNX F|c=MASI,$$%J6lsċSۄVqFe3,D%MCV p`6#n&i2@ FWH8SH|g{읡vhx]٤A|tĶOU[=t1sVʄ'cěMvj9Ldvu8oȻٶV~b$j>j9ؿ;9^dX>A 9QOU)KF$E?ś1cF7Z*,06$c$cc}5g秷XuW > UQ`Y+*^"R5kdhUns664$5Q].Z=^fl*=xyTZ[oZ b^BuaO{n7mUir.Щ"Yl8W9=;d%x uzv+SGMCNPjdgnr8a4=zpR`>;g/xEYwjv26pFv?~qc`X %dE@=ƮXd~vxXҟ m#oT>Xn,}h#z*WE[EWK4xd1ΣIo.OOIE4 T C9 1uaD"cu*jpJ7#A*DF",2aةd/Ce*"ROK$7'wY.#`-:CN`~sO-6~Qp#?1$rUA.DjX '̓5G|ܾ$2X2^,H2w_.'$lЏ2)H;`靇sUt5]Zv]/R؂vsn171RU:SƥZ(Hq*ϮA{W٧lP$pbU[[PKG.t GPˌ`nEnە5vhDB2F `#mg帡W.qH#Q|Us'P`Ī^ezY/U5K7^G;AWɐ;͎`+ᩪ #3%<хE#%W lch#8E1t@3GL2FN9%NJCO;gIX}>|璖RiV+!`ԙ!RI.WFH;z}xqXn@uDsh(U@s3ێ0bi$6 H+&p`ڊuij!`8Q,w?HdV#=25m}=CqrԲuU&Se.0 osſd)Zoh5I8 ӋEYմbĩL ]I;g45R8d0nH]o +"2c)*jḃ;0RB۾]RPOotz!CE 9ܟ*))ӎx%Ļ}-}ZTr4dvv>m󃃿!^챗b ,J`uFǦpOJA@u8* `Vc8ǯ#Q]Y]qkY$Q[L1]C;*\ lT0ApOuO#?̫IUXGVmAǔC}A8#~aW%Ne:ŎoTmM0Pqb|P}kVyRVC #'7 9z^Uqv;bL=pJkফN .eMXs߇[]}gK $I0Hp@0si~eE t*),EKXUEZzB8ii2+jRWIbm}ZCR}$jz [@K'CQWfD/t=$;*I;RVjI! AW p+_5uUDumz"$_Isp\] ) h&T&hd2ɠCVwc`@Jz# )ҮO !IB0 Guc%'W; B`B2p{l} Ye;oSpJc7?9+m5-ڟML *ߘ$~6/9LYga(sqnڻݢh`$IH'GCt??|r_y*LUT:nē^+ogdgu@5FX,KWI1ώ,r_o4<-\/n㫹SssIn4s~4="{G8}I-q޺ 7%D8$|Om\V\i(L3c w#˼$6WUEt=U|[@ sW(J!-AS$yu  $r2!R3FO~ɮNacbF ˆ6ijmYJ#z"H9:@~を ;zb0K7 UI %'w#wH2m;e-(I"PTIҧpfUt$P0IdP9w]灩9M!I3HAWuzt#K']RU }HZr%- vOC%*Z-:;A4yH0#}/si]:Hazy'`~lg6Y\ҢIZݔGl7Hv~bW5iqR;V֙>3n/SIY؆ǖ#qװ +znT# zEA&&a;LGFp1\UGwdhVCD 8Pn4錴VUQU !#MWGc"۶v@8ū- 29g #-K6N}SƵm*G +G.Qi7A@]9*wtZL4EVض/^:̶ihe;(#0 2_*t@ ᗃrk=$\-q 3*gw-nT y"C3"e< 311>Pّ>bxϑZGL T+TżR¬N@qAxZx6$O[3=;OXcV]8lt)={eEMXKJm,1FNxj˜1WMи;jٛm"fvi*DWH(UR5sӜqShw5޺%sQUJ @"Sjӻ.Q870^ڜ4C34CdLH;.sm=9 2GOTe#1&l |ZT%+ rC8]69c:EzV T,`P:F`e ;Y SG3P/V.6aՎ/QZjP$1*hW(I#EEך꧖Y4dI#qjc|p=%,uj^je6:G~fzK\\褑,W5>c$dl,X;0d/tUQ5]G L">V:|:p-G.a\^u+b p\N̤-0yJj[+]*MU'"+(,@WX9`@+K-Ҽa;#Z'|IuMtOo''^(tIp:p v>ZVV+uE3QZ>zV@TN`؂H9&*z,M4:]QʔQM"ޟ榏Kaԑrc½蜻t_J'bKuVT.$(<<._J I $!PHـ Kk庚4+QE4z8\c Ԫ H-k5ǝ3Ha$Y0\38P}xQU꩕:JXnqsEo1rقh^UeMGNPӒ A$q;n6jd^TI&#J\CpuO{b{& (CN2vǿ ^ܢ#q폷 KJ2H^=%>ȷ"b b6=ҟÔ|m4G 4C)#sH1V@R?ʯ9ڧH$icW*:! # o.*؉[~#W\D,!#OHxLYp[QaW IUpp26c8b Cɺ;D+LC c]=l־`UVuɂAv*5 zG3lJc|EtZƬ9:69=A:]uwǎZ(m' ӎ/KW4-r;t2FM#N0[zjUFY^3Ӳ`F5NV*GxIRP+#HYwf H{mTՑ=L0X+6JcbJoZ`DQIwHl{O%(j5DT*!ĚJ^mJ5*+az c' Mdi<-o[rEsSr*#oMGj+tG'\ ҳp@e*Om1۟+|OY 5RA$ԉҏ9>`Iq%y -Q$[F4QRK )\~~tv|*0W^pPP^IAbW  0b3qCM dr*wI$w}2) [voԊ[<1 , $~9%-T2DG3ui 5mveyRV*eO3 EK;(9@=U-s_`237P66W9hG\Q)|] ;0tjV;J{%$un̈́e* 8d\mS$Rxi9&o#wl8a/YtZRпTy*:*˔wJKB xVc/o{\LE|,*5$؜q|9i;UmZUI"PDr +%Nq|0P~ 9C??J(9gI$R:'pnb1Z䋼YjkUnAHhKI|sy a c4 (:u$ Ƭ۳V?mEGTTU҈O,sÓXlǞH7R#=,lHwe㖡TuI*jɪ)Jad,rAT8__ qEtڪyv#J)5l s N/?Aω$jtB[={B5O흲mِĚ`?ύ܌Lu%78ZxEPH9)%PVy%Ck08mL2)C=p=8(T|MEe=XIy e8;8Ƿ>rsTVSMY*e w`mm7RTXZ:Yo ~w,Zn6DEuezCONKZj)9$ϊVUN5?r; 3H.YMrCNNBwevqϷf$pZ+jtH ˜c{z,[9|ԗMl J$M??0T#3`!Lvcc q.GbdybtPWKJ"6w* Ҽ"C,5 Qqk** 4.MM{q5Wj6z)4$>`UAp=v 2Cr ԙ\1U6bE7\g#n'X5WK=¤U:%"j>2ʠ2αAϔb{੫& RI)VSK2]@sJی)'xkBI ZePcNw9 tþ.TP%m35DR,L.NیbMi޹_)JU X@Hg UY^u#aJ0H΃K;w.GhhᒑNJFf3u QߍxsiW zZhݣ QGmmK ԎTŁӬl9' g7מdj.]9^f)LST.WI' .{Rd*&a5qK!A#'RG.1*j,"VP$ZYZ, #Y ! 8zxA[Rs FsѽM2*λڊ{Ég-TQ))gugED͌eƜa}Xy&,tMS-MEE<$Q Tϥ[RV=p ՒH;:J+n q \2ǾsjCm/1RMD<2RGP#h˳56,T{ bf Կ+D;eAA*@ {6hgJIC"BH6A#Q|wݲxdıٞ"i"0UԘ˫$ 8l-2\S+,+E$) $ ' IzXVS֤e*ƃÓBT\Mx<4{}DEXٔ"QWN}~u-@#SI IME)mabadQOSʴ.h؜{FcԍOsv[|$0XN!+#eǨ@C0OG0GK'y⊢P F7ع9Ӿ=GQ٨Lt5%̦֭ J#dQeZT;Mt`51_(J#aT=[#C ž2Dtba;DsJ8V}Wvϟ~HqACM3ZF a\n54]Fᫎ~cqj)؟N:SSJ( PN <մgit&tVi;CzԦYX$ Հ `pϒ8 ,1dZx4m$\ ]]}MKP*%)Tw+YR۝'<}U2@dP̄5w=5؆yZ>CMFVYN[vntmz_ rz~ s +r1ljX !A<ʪ(ƒˀ31 3Zy#jCjW| . v9vWr6j9B-6;($T3N70r}\7T^K,̚T0j8c4 WJh #C %g8CO%#,/50C* daldَܩx)H-g 7ƒ6$}8<5*Դ7&FU8v,a?neOf1O0QQθ1  7ӶNG;.\rچ8kQ)e@ Xݗ9O9|n`}\ND5" I,c9o7xtiu\B+t8DZf#GPֺc=4m>V!}HFC! QA8,btl79ڲg)rG4]Yk,;W9 sZ>G$Ue51Ă~ՐtΏ @K-4ti=5[ -W 8thHԪ HeV풙چB2m8=9ܬ×]G\@OJǦ0 Aq|i'XPa^5*j`k*%TXb3bs;aAVIY)K=\ȫQW p1 nbp=`O/](R|IP;24QPm4^REx$ƉeoApi5ei t# 2F`8O[3_f:d-'SN#m 8845vjUTjV==ϩ9ǧ ƕjh m%yi]^Rjcm:I5dK7P+j)zѢӥfƭxb1Jْ&IQ+7ApX r8w8yRLadGˣ ,sJDuxLIE\0^t _ANS> CtCn:& AMH0(?9ZJHK(I3ϺJ$bABqW8[motN"ʝhC`a[/LOC=AoYkmqӞPaA&N{pzWSKnK4 >IbK :AR  ==5"ҬTJinH#@`2)}Q9wᬤW^͗JOV;" {Em:KEV$JREZLؑlI~3+Cq\X)ZHH"]~WՏ`}G:dD9b=̖Ȫ@žW8/Pdk/DgC In>5jJd; a! )^&Ys#; *vAoI9IK;N#0*bmG?lp|DYT3RUKF >pAƓ;}q K,6zC% 4lcԦc\btDViQ.Q*H˥5{cKw 暞%-T9U|`WeMJGRm2̵adUSS0 #8RI&J[]ts^IDzW,2ܐ_a_됃v-4pVT5rt)RHme5{z).}Lڎv~;Q5((Fa*#9(-#Qr?r)x )[c'NN@ܝx3ۉʎר' cLVj*2\z~|j!uW;cPR]u_%LR78_]ۍcz~aZ rMG!SݘlˎK> lwyO '92#[^0¦=x=UΦ/WhAI)$ >ur+u"oKOR(X6Wqū%M%"2 3`Fˎ$tg+uMtSҍzyW\2c\?75eLPԈ$`ʤlRls2Q\.4vM8t$eu) w0ؑePRG6:$p.>Ǯxo$HSRm-5+KK#4uoO7N}H iՁ,=~~)MXpT's63U,ѴlZHv]MPp7u@I|EYRAOS8h†sg>pMWSTKYo _0sQ$,MϜ)N$aZng{J KRҝIo; #ϨpeiitV%@ŝ;/lIS?Q*1R `Œ`o+þQ7A[ s;9R-XɼRF4v 88 X5NNy*GӜ xU]%3ԄS8Duc V&E/;H4 8$2w'mV|u|Z Zii$WBips`g:MiEACo9"J. ډGa8FOx[me-QVG<cOQ!GRi W}yJUqY*i@DkF!xz)t8"?Ð?M'Te@X;xZSMRDL8s8ۧ_|A]$ DA@#nۉ/ {WS9& acHW󖦄'KċI=9OZ$yFmMh+ٽ&W${hGѩXZ9u9S]N)ZBZVpB R6F1wYT0L^O(1Xor7۷[X^WI[dBxvLc8'mTTMR0KzTTlUE\V2"˜,[ެۖnzi IǎHg.Y#a %C'do +9Xm%9~e"EX$RR9$}rx4/P6?1FIXwepve_(9s#MMDII<*)@#ca?7ܪ5ĵ%=hAW9-caG1d?䚡^ JM$3(@^18ϧXp K`{$P2/.])"ju0MatmQT ULkmm4+fN:vBRrH8G`8.ZT/?MJiA9qg<jV$iC0BHէV 'pb*-ڹƓJOF>\[TRrddl8 W1sjKc)e-Ӱ*sr4 ih*ՑA#nAF=0pJΡթ2SKy;,oAW9udzҝWr5o9P@ w$xTIFxȉ#Ɛ;đx zUmBWgV)gPn ڎHM\-aHs% KD*@$.6=nMPmB bF$H:E'N㎪FsP:pw(j JH*| 1 Q~eVW0hrDm7}C9#8zMzIYB1v(*O'>̓zhd{+H]h֣ѨzrކpKLi.!=Ex FHerp ѯ7VIj 8;dǷ3wĹ#{sHXIL4'U$ig]gQ_G_qh_ioѥ542;&#$6HWg?Q~/5-F|u4)c2N%Y @aܜ<73Smjhi!q1!#PTv{UEdAAKN**dR,`H:/rd+`1SfI#_LU'! \8'g X>?4TW5@-M1S39xrѴQ tfC H_Lw؍r]CS2ڨ6'ƬwM:>e_5ein3IES, ղ*&!B\q{Nj2n)[5,#ԫHa- ><~qj;m=jHCS稣IJd@8֪TIXFJ&rќ)AA9:-YluԦ{3TOSCHЀlA;@8?Ĺ=S=~u|M$UCWR{M:#y9FBL`0'K8 ~2X熚چ@RCR zJPm˜I=x33t:R7e]';pkZKm*b!槤u55QNd3i"==b=MH،|sӝ^"װK=}zCpx%g֒%$@1Zn/[\_.ĂAþ]~Q[40:SHcИ >N;%%×kR9bb適2F0qId5{+,5|SL˦&_Al;UźI)n7E9oR5g^|R'1V|%J1 J;|2K=4YUN&q(VPUq/lk^bI hB4S{)0Ż^WT[kc(p!d+ɐ]@A+RO,]iq,0:ܞzi櫩I`sۇIި;— ~r6h`Kz*v= RKK0Ya_u9ݸqs9`,)2l@*1;PCsBCQA\c!bKN0r1@=r Xh_4 J\88g0>Jue:`h+avһ9 ך)Qz\Fac` Cy;c>ċiZ9VW2y8qH&.zH$`zcHժas@0![)%9>`[9FSru\w_I# 28\;lJ'*niSQr8* }8)gs~-vU\EE/M0wde$g#ҢfTZkGGI3Ϳ17rv e$7$z*3͸$vᛕjOsP%Zѫ `0I߶#5wI) "ʁc=8-qT)xeJ^\ۭD"4&unA`6n._:s)Cg-\>E‚; V)TR1 $c8Vep3q>tnNB*:hiD( 6b1K?|{ѫ'=~䜫m QrZk4ULZyI-,%Pa[H~Qxw+IEh<@rglĪNHOj"8j82 #p͕XL臫Na`HaF=J8rQ1Ji+2,[3DBSeyv9$j"jվc9q2v͍Y'cs S=lK.ȫU 9 WOp4O?8]JixGX.!r p3s,yx7tt?UӭT]'EB1JrG9REpG$t*bDPUS;;0x :[M؎jI[ ζ] wk_%3W#ѕ|or>!6Rٮ"´0K'"0r9''߂6u(MU*=¢ƢPt u LO-S|#G'!p8u`I8$ ï7yȶ EhDS#Owi5rh7U]E-~1N+1:9NAPI##'!xsh9.a:h "ʁ#=¼uӤu!ian E_%=sWxXr?`IM5=ޭ6QK4a>C`Ɲ܂aYp#'П+\hhaD$ J"1| ڣO+4MdFp'mrU\IL@'mqV Bsm|"UtZIQY /g=#9 Ρ[| , sv:H/s/rh@ĭb.%7'cS DIScnt"\9)nRѹ]a@}FpmRYNbF eR46w#툼JV80RXs=lE G;D9rxWpelican-3.7.1/pelican/tests/output/custom_locale/pictures/Sushi.jpg000066400000000000000000000705001303525152100255350ustar00rootroot00000000000000JFIFHHExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:31:09 PrintIM0250$"' 0220     &|n.0100,   L&d2010:01:09 14:09:082010:01:09 14:09:08 ddqddFddFUJIFILM 0130>^ f !"#012S100 S100 %A592D34383231100603D7050TR73277NORMAL d^^R98010008(@`HHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?'X|z?kݟmV__:T{hd ($Ojr)@檌} Pּ)ggj һ1i2*Ji% ˡ?hlyWfVjB}y[G~ οζRgu oƦ:,yFڐJ2}5F>4RtȬ}8ttvcZekEҴ@YJziR>( /^E2* 3~j*Yc5!΃).%$v9г:\&1E#Y'+h.Ϲ+/aUL dݞMiiХy\T0H_)0Os @w??[~+:q>foTOs5|a 6'5{'ziN~+4MS% G9edLgY2XoVp#SQԧroIAE"=c_ߛeb`qW6d<ϩ5a\1PUx/Ҧ@LkM^!VC͵ ӊԃF IK@j7!4Ơ IQL MQ@Kuyi|Otc5AB,c~5˹>"ԼWoG}mfSvb WeE#~{7Ʊ|nUt(`+`YZx֤\sE)Zi IPH>iJy[?Z>h%}gV֧C& >nc:~ [qwöZ]̫hAþyYb 9?mEyWC #[szVG~T Jk;Ry:i:kJ/b|i'YAVAٸ>j]#L]jIS&9xCWCN}CN̬}77վz`?ƺ1iO,;xb9Zݟ, tdmn-mC°j>eK#5]hWKr#^ 5iI$qXS'.թqa MI0ga"brGM[50$:T6yO4ots6E9k0(@sf *iR曚3@5$l!P7|MEUMEMxn]2h]#W\5'4uݎ@F̨߾>⯈:Ɣ֖}*346=m6yf1)]iC76A`1/!w)95*lxaaZ2_#"kǥqS|4Ax䚕#GRMTݦP?:owA)<(=~$PjW"X:(OrZ]045{Llm?,_M8P34 v |˭vV$M <¼ u,'daЩ xޣ}׎i30Aƶ7R`sN.9&5Š0Njcj#oRyz#S P=3sNbѾL7Q {QXqw-k) :T~uޗ]>jsJ@>Ĝ&ơw@޸m~nˈ G.vө W`[$PB_:Dv/]bqA=t$LU4OX=4qRwٮ:TfoX]EXѴZrU~e$hrH0 [!DTmSK BFG u9>6M Ӿ(`HR_1V  V~ʧҧO ;n(a)Cu?"ao fi5ı*Cii @ (4S㈏EXU}xqҥ@B>ԦqV!^*@We42w~ U䉱̭"{U )ugP9qYznjƯhae ׭>b+}Fhoun@U'hO}e+鱼˳(~Q5qXx}TS68R5] : HGw=qF dzVq4 k&|T-9ff8Z qֵ$BNW1m;*:*ݸQl} p;SmbhS9_t,T=N{RC?FZ?S[R;TlE+z}iCAՅL  2zus[Y7(%WZǏcPdE;ŜEtXۻh)}ާZ(vEYӎh+!5P2xȼ62XČ$ܠQEHx瘬QEKB.~袊cE㊜*P!GHj(Ҋ(QڪG(@V~(C        C  ,"  O!1A"Qa2q #B$R 4Cbr%3c5S&DTd/!1AQ"2aq#3RBC ?RK*RB9$풄$iUc7hܸ)f`xZݍI$҇X\ O4idTRFk Il~K=ؿ#]!Oꘪѷ-kv5kb=f;k[ckC,6lZzLRSLӇ [دHKqI&-f- FQ\}߁Z!85  WM:Kmn jǗWOPt}vǶX_҆s~bT8wJ QL5fY0.#ܐJm.;=R>$.+\1uAIǝMrZOT2̂LLq]KE IJ@@#-RNEWM>2jL(*U uۼs5*G@;)IsNuʍ;q![ˊ=3 {$lDHM3)@aǥcQ^t#"Rƽ& l$’`Uئ:@n,wmo-%1KAz^ _Á̆+2(1cHm_EFTe<*yo4@ K,"ΒH XUT޴;Wxok--y+&P%ޥl!m6RZN&i5#?W8Y|} Ŗ7-z<[]v-aq +շ2 (~D@+c!6l"? oq{MI6ܝN[gp|F VR-³r4GM8UG}L٘ř1풻 .!q-7%Cf؃@2vcO\I 3J('kknf1yʍGDG%;1n9IbJTʹIlИ0{|Aմk$ZL5D@+ʛӨRW&f@R1HmS&|""\BHwVLR 'ΑNtPSA£Y0vfiߨ.{<ጃƁYrx[  P'h@J-se%;7>ad1Wy%cI'cmg4BR7Ջv9I:ެ\Mi^Iv#c}Qujn3TcHVsg d%bim・*R7#\/hU}0:_ whnTzvڢwLi3)fk{63ew)$<5zM<2r{3u9HXǷWeHзyA )R+8ڙO,%| `]kQPbz!ӠPbRze$5Lwڥyy1ԓ\zGr?.dc<)2XLD^@W"k0IZ-u#sk!?Z^tC%%Php?ZK4Sl>z?JFYy>)O2X*plyC"M Y0ِkŃh qiBwQ>݂cx^"E >5`I%i(uD!#DDcw>W$OA۞j8U-ԗ-9BkB;A4遷R!3؎i;rBW3ȓeK$y ¾1 7ӀO@iXu)eV  6: /!Q+o oDӛyH,Gc-ߎ(ѷ@ mӴDdIُQ>/ 9L+־V@3޽@DfLH |?&$)[HEtvISc Nj\qQ۶qgR*HtGO7CzUf7 h=f4SӅbD_=$=n?MA='2>Llֽ6[8* xߝ[(tW))ROjQVΒ)8)Ĥ]7˃3b-Cg߬$0vHv2v#C*?Bop!eKRk_wqzTiE٥mɠV,x v IvN}~W/u4ӄu"zcs$ _-Y(U,@[ƚ]#?qLy FH1ϕ>/,#sǕzFS8ns'H0u)e>cRXߧF1ԧВWܠoz? ?n}®:7qSAܑ.$eR~kW]kFG1$8hÔF JgNxOd$$IR@\$F}t >i@|GjyXfmJv{x Z`uvz ^$BUGsb 6.K RxHc}r\?EŬ@n屰W?ΧQx1Y'ƕk-Km=i8ى~2)iK[W~4h:1՞^X- \j`ch 'Oz-= O#p[6R }$(YRJ%J@Nf5{q+K]kKk$w&׼Վ8 \}ݎ5p?*r]VmXB)Rǝd25L+4qk~Y`>ӄRAnաvv#z_JHzԒ=䄂w˵^&S#M+ =Χ.HQF6Űɏ81޸emJ(DΏa[i1$ANmJzvlA v22|)&Iz׊0mdTh~]贲bLV." Dw.T-NOpIVBD 3R  1mO]lt9&қ{"3O: P).$γ_s7LSܽ"+ '>y!m<*٢mVn3e8`6KRStտZV[Ob2>$LrK(@;W&Gmqx|-F -O}k{IMR\Կ*.woha ]g,e?#>~@^hk$MC = Uz$蒜 V#ﴚs'+-ͻC.+GS= "yG~ڕ#*&  LRȑyoI-ς4|"CSuo%"uU'n M[5LV-Y2:AS.XILDENBBD ʟG10a?ؓve^q/f#(qa? 1F#΀nI= R(iE &Ihd7b1;M &h@(܎7Qa@*xۊ)d(Fd4&FLnP~( =CΦWXp@!3@ix {Ri0DsADɐo{]Oqz>FFP蒦$?r?$C7oyr Nιիluj:mMt+v1ppUtI#yt{O`oXW B}Tuzv'}_'.ݒ?},һ_Wƺuf.+%g{{MHlZ^&~_#a3RlЗFfݻ$R)#4h}M?W,Rr > Wn!)JEj$ ,μpd A2NՙБC{ObHJ.8[(m2zFy$-͸>P*E׬kR>v(Kh-mB06U&]xF=TZ[;*b Vbw JȑƧ9[G>(Wlaiz՟>5ԽD0c*tyVRp _zsT>[7&3Fss uA%@ '&7y,4[z*B<|=+TdZdF֔!! v\F",&Ugԁ*VJZEXIDGTz' &[[1g`ݛfIAc2*M*oy@jJƸ4buܺ2MJ|Wˆ X8jaa%5o=av/;[CtH.1zIq GnϾ ْmX_:[)`i]HmA)m %~ILO#[y0P< Arh?)D )&? >|edMs_+eA#m3QjPyhyvP0'IEV`r-@e`򪗬MJ$Ӟ^[2ۈwܩHRRfcҙ/M)'OW{68]&ŦQQ@|dfؾ[\cXV#t-Qnw>.j(Xmݕ d%v%1&k~^Ŷ-__`wiĐ[A'K&cm+{Ŗqj,[2K QkghQze,Ǚm#Z6 J؟g/}sn +mIdj'Mkt ˙iAe*Af{X{(}iM}jGcrL?4cVxZպVm6g0,Ʉ%\NZS)wN_uGZ $JLb6ELrԾSٟc9wn\?5JhG"QMjj>_XE$8d!Q7n˖̙aG}*=rChP ?o O0&Evaᬍ#<9N,󟐚ط &MI!ISZDFȝo(:w`2ew' R~{ӻj%Sk̔wcЮ"N6ǁ"=i܅w$SJDҺcD&$jBʭ4~5Vd@W(>QZaD,$N0^PH <5+DhI(>;$S~N>YH}3c1i΍I0wI;yW+)j,AH'B'x|0biځI'y߶by۽vI܈ނn|Ccڼ㝉@fy^[M߆yi 3RfsgA" \eǕQftx|vބ,߸`,pneszZNռ5sC˷O1[f KY) GyO3OA6$zWΠq3XVۯXf%v'גZy[D~ Gta[%ZDlLW2}c! ?qePr6P#K돖Ⱦ=Yv0#kiP_POʽAřʉ?h4.|Icg8:ǖ椕ʐ{S]Pm*u{$S˙|6]7$ZNLq (עf'RJJʌ4򕚚umE^T l9no{S@jq([^^{\KG u௬qxHe'{Ueu MJAjW^P .+q}+T6OP=0% FgRcT@b˒j:;b#^ϽFb)KIIq qWN-0l&Bw^ge'8mɑXL8/KV`-^fo4S(;(sl?RHALӹK̘WmNl D: -mҷmPm0%;D $; ?ae| [x$(H+˽,y8n!v]2۶3=j m12/Xġ{SA[ipa-D$v[Hbw=Qo,e ;AOk#YYEI:F ;NH5E̺GMѰs_*±w4NRk<&`o3ޜ&DG4f: RM ޡ]؋3%ډS)p njɋJw Lի ֬dH2:oMp&7ޡ8;F)=  E`{ic146&&0|3{Pp7ξ8+'EDھ"UǔPTa1x~tY_1H,lw.M^qr!'FOttPԤj־t6̿mhIq+SNG#6xRQJ0ՅI^H-qzp?e=fҤAT G%Y{ҍ)Z]Sl}"ُ3ߗC,8ts_ C_fuPُ=/zXaJ!k&'W~m=dvV~+^H/:1D#H@;VuG4^FIWhȑ54V#x& <մ@OD@ZJ&ciʂw1 ;Vi[ipRw +CuҜ1_f+QR?:FtQ=aHAK.nҋ6\:NX6tɩ1{0mPjDj'AT*#VUG*1\l g0amreAIu"HfėsTAM~c%eZWu Opp< (bx`_JU;x1`y dW qR{,weŊoܰ Y_Mg̣ZvPz&.uj;np+(O_RsIM$觱M/.[w!W"$~utWoMV#&70VLǐ8 l֤ FR}Xa(qQ b̠KA3ю%}6&B+ }y'o'[L_ m֮o] IiQ31^*јscڷ ?rD=ԗq;7.}fmsBi'QR JI>%\.*/-z`Ű8` ; \ôTI*R6^[!KvB ?^U.eKiW=%ut; 'jOh5[YH>U\RIBIZdˊM祰E%gU@-i b|/lMیIyP%^+D d02;|J:I?4ƔغIZ q1+| P.*qBA4hܧھ#> b|"0ukHpS)XR'Ęyh[[y^Uil Q}X 0ObRt<\޷sir&PN(B7}o??uyŲ%͜GW) yikƈ@(GA2.8-Wwʁ~GߌVj-ˁI#kCVqyTۦ6\DZ 3IM![_R cVN0O@7ul냦UбGʶwCzsM#VXE}~46]k󥭺*N⩼1 KR+BҐV'Ν2x;LׁP=ǝ2X\(94ᵫe J{0JI普j'I!-J0G_I%DQOlQ۲Hj1:Ҝ:&xT ~jWEg OjOW-x[}a k*Q!x-KZu($7\$%H(_\PIH>:~A'$pjp*ޓXnCF#iJ`nCq Ӿ8w)ni&#qTmGr{zM<R!#jqˆ6ʇʊ b)CYp#<`*"S"J@$G6U~t{J'ϊv?jUczSfmŶ*R="O_*5& xڗEh>dǙeix̓1v Cl lmu.Ip#+(Q& ɣN#r{sSځ/Na^%hFapG4  ) zιft`??WoUnFU ;8&k>F'eejR-ݤCI*ZH3DkDv%E$m-a0ND.Р(r@4C΀$y~xYgYڟ0A?O:,L(N|TA*RE H$ X*vZdv#s)jLsP9k~=Ήtt-J^q!;IүGa4#ʈu ia4'~tCNxL:ni#!BފMSt!@Iߵi3;[RV[1$V`9Z}1S2۹h#SscSE)&usE"FHGJ zfL~t@PX*hr ɥXkK@hޟ fS j@)D qIoR`FE`(ē";zP &HQ́;D6|`>Q'I$2(䄄I'z$ ;AB9%\Q{ bR;oVwIs# _oo]ywB*ovFjSQ'AZ7F}նlî0 >|IQ۩8duX }LnԻ,b" Fw >w3̀i>rjQu.\?~qed1,)>aCcA q4Ø{Ր>z7 OIY5FMvj&arD)7Tcu+!I2q# p}+2 n3 ?YQ&FxZH$ԕy ˮfg:|źJD wI׆$\I^e~0{?Z'>Q PV6#mPw"s6 (گm]>ֆy LoU“f[6]H>oj^j3 LɈ|,ff;[,:B4S VdQx@|Аk&'D-!Bvj^-` X=*Z.8$ڤJ:-%)KɒLN" v ϠN]^S,($8eEw]aRK [H"ƒ{dt9\]c>Fc}w +_3UU=d爟!ZbYwreXo u̎Ԭ[mv[ گ--YZťtWԐI;9H[=AT 4cL,yn.Jd87zoHNǥj=YȯuP )i*) X[[): T/С D7\B EylA);=K "G~ņ))V4x BL T4$z:uaGh@(XQޘ DlG:A|0R$̐GNdӺgHBL*v-V r)*W5jBQpH#OaN~";RpN=*(Warho)0~h;ұDo 3h>I'֔ „KAv8zccT61?)4*ȏ lkL'5wS\ց$$|ALH1IAEXY(Cv=;[ •y@y*7M⵴Gcbb>ٵ)6"5ܒ|(sq<߉ڟT_RuUA7D FG<[ GrNT@ 7 VQa)|P)6 D-'xFZAq>T[ :gS;>RHJEz-.GuGm{TEvp%$ڂ'IsޛSN:@2Lq^y_ yDsVBݱsoQ?.#iO]*ٍ@ALmU Uj1ԩ?Edj~;97 e {ũP7*ڬN%Z[ưPuT6~|oy}Na#iSX6/,wPTI>uqH:RBɔqYwnӨnv/&,Q C1U[{V:wtMdl|Fm6Q<'VF?\6xp$Y0?i4TvUM&\n.%M5\%H)$I/'Lv&{քn(zP4ΨBm> ^| *IRG]O 1E)d 擻YiC*֞ґAyD1:jwfۤ5IRmgΎH@h"#hhHǠGпȤ۸ "A3?ƏmA(%; H7$D70j}@Hpyo>ce$#ʄ -8ITڌB'`͙& 44+lBTNW@dDWs\\$mҐÒA D%#1(@UI:gqڀ[|L<'a$*T* ;PTuH$fTiyVCqg'ݐb'MlLnR&Ѹ$ 8;i=/rf,c&݃ - ;Vc+$psG7R R F+GOV-֠v2)=3sUu*J`g-G3 QJDϙڒf+ɷ-{f ;kA)鋮!*J #?Z (u'eų+w mùmS;Rp~ۥ һ~&`m"F -x%唇7h{7}Ko  V$WݑrƎՕ8)cN󠜮 ~5CFNOOm̔(p-̄\}b4j(I ߎ);QL '!z2yW1%1FYK HZb)YB\Jé)$XH252NLTʓa-- *NbΡl3+i/j kj@\*.%nPFW5zkQ0+Q>LW{75eT`>vlc֙ A:PzbKIRK,2x6/?`ҢLqsoe8K C.%Dpk+y꧵/1<\C.FGkCl{%6SDNyV mŏlɀ`zLM|YZl)w%+s'VCq4!jdKZCVR4[^[@)64$Ĉ D oRw;!1MӀ h$mjJJ; T=;`SBMAB"I!0#j-FRwzH؀&dj;Dn$T}\ހAĈ6vx@TC7cοvš#jq`~TɊX\O&h Cc p1ێT( $1YpB{wPӲ~f(O|֤goZL=(b6iæv۬L(iKP)zPu+ZRDROz*1?>mpu`$ldQR84jGo^[1o@ bLJmn(Sw,No#ȧD[m@$yw惐'54fn%';_C-.{NԸ\aQ!!1A i֕2854zq=rȸ a.n:]Edʖ#ZȍB+OB+i&70PK 𔈮kf*(Ƶ@_@rp%\m6PQܟ*z09QƔ{rBJ}~9Oʮ>.:dP73t9O +d%upF/oN/['W!z>\hV;rJye }+i lxI jW?<^Ze`$Wsr"`S'F yuI:&ۥ\ )$#L{:).A Wy:I(P7 %Tؓ<ԃ0`)~$OqLaM L+PUk\)y:EsRmP.2N5LON7Q*h#ҿv [FƶAJ,.(Ѕ¼Bg`{P`4kТ]( %Kӿ"[ WiM(+?]jKkd(LbgP @#J;#Zwc`|8a9SBVœ cЈ#($#b&*}eӼbSߏOXwM&=fy܊]F%$RHx0 " 1#C{gKZIR=zwm %=Hښp&x+QU@[k?qK'.դJhR'ҏnS*ʛ/p^:?Kq{YYz'4XLݔ9ړYbnV0'$P&onk.c*vnb`Sb߻R;ȯRKTBv >g_e'Y@u6! 4";#G>lXm{&;aOpOud Uw Yט.?&q ׎IH%ŠX-4Kxa:T|?xW"}J=h~ozBH*3!.lɰQǞYe5)KNpqҧ4$vγfcc_4)dEj,Yq԰ Y{ }Uon/Xiaܒ89ݎ={ dg.ڼU7\Ԍ6+y|!>d* 8Yð뛤2%\ZdMA8.>T<>UJ]џC0ίaH]M;xޭ!D:!oqwՌ隱^VvN(U 8>:j"gqhtUGiU4 Q9ئą'Wz~叉jmTԧ:SL\zE|u!6"fHV~<Oʺwda,Ut~x%XsL >z !I@wT‹vN3B}Lwcב1)e-nx#r*&E*!IVzݣE!RNT/9l)@]oW5e^JS2pNiWh&"x,_YwRqqJFVص*b啰{)+AIIꤘmE (J 4SNDEPQeV VO[ B@ [l$B`w{T[<2tz:;Q0cp' vZSQ.FyagTj2=}Z֕#SB fc; A$xOoFV]MtDn&0iL*Dq%kRLGSuIJNbjWI)  I;ԣ|@ژq$hUƆgVs@.(9{$$zP$"( 938~YƆ Y4%nȝ5zιa8XI:_SE_4]$p8$jXBk#Hs˽iN%]L6gVk\] wROmie>Qܫ̘=Sjm$|e?rkqct/u֮[ҳҴ?|'2,cĭ!8pR!R s/N0mo I)'Ư {^%ְ,Ջ.Fa^%q :/ZP\S/ۀH'aO~j7Xmˎ4XN;bYS[H_ U3.L*)EԅJyTpl]+;|pWN+&*&V{8Uob7܁xM8rdG/Ef_(SdT`4?rI䊻u+Q9JHmwWr*sszӊET"cVeqbnw@+SSD[_ #T 7ؙV&I1{jNn]taB _΅$ցJH?Z!/i jW5;~! "+{$:0*"ͅ^̀;Ҝٳ| +$)wy(oCTQcB&Q>&;R)Rc,x~TՂ!Zp)ySD2{OvXYH ƑNNO&%h +n <'B;*27B\+RV!I$Mȵp?NԽx oEj6/nЗ$G:[ez%ۣJ˱S en4j hP1W+%rVIr5BR n8ډC @hnn(sܫU%}]5XQL*D*5p3e(,Z~8Qȩ 9)偪PyR ?:tI s!T9YpC w^[;nƴ<RJSw\fыT-6Vv-Hm46]htFzZjI|Gw5@q%DsɚmBBN;JTIާG$$5%HП *3 HDRKDp'WΦPbc)ї)iq@RS?*YtPANPІ;ʜ$+6/ґuR+zd `o&N@QUcQjc $K$p V1DIT҇Y@I7{h6 A Wե)"@!*MHfP-7D_:INõGW2f4=o Kd_:IGHP 鳭YGVkN'b‘8T *L$j;؂L`+{±vL.H4แ1GL<5>IqvHn`di؉iaމiϦ{Fe ژVmZ6aͶ^ҙ!PN-Y?rҝ`Uq\%K19qĠQ b/M)D6}kaCݍC BA/^JI,X]6獕|?vXrH6)^))Qw dJ||v/ S.0NQb!?YaħA>RQ 6ݍ?$ڒ6,ک ? 5:v͔8'T|fϹJDӷo]{S!mX@H'ϵ:a A R{&`>tef)HڦQ~F,d#zӭ ;$m?I-lw[ :TÒ%((F (⤈i`;Qݰ|F7ЮrO=j,4*P$ ZB)M6;9)6 AۓF&#`*vm,%P|₶ 'iޫEۥI;|藭N ХF I& Q](RgҰP ԕbwtRƭkDZShBS.J%ˤ)ċTI2|nбJQܓM%DD(K~<2 3]:TwLed˥))PwIʛYm?Bcz?pelican-3.7.1/pelican/tests/output/custom_locale/pictures/Sushi_Macro.jpg000066400000000000000000001133021303525152100266540ustar00rootroot00000000000000JFIFHHExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:30:38 PrintIM0250$"'@0220    I &|z.0100,   |d2010:01:09 14:10:302010:01:09 14:10:30 :ddddFdzdFUJIFILM 0130Jj r !"#012S100 S100 A592D34383231100603D7050TR73277NORMAL d^^R980100<D(LHHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?qc~tcjSHJy)3ADz{P^+d/RsS&$ś-ЖCֳVF+"?Jk|K9beĈU=9ONj&Zظel̕lTm42-P[CZ8ɧtrFX`#"5\t5"21V" G^ơ#8{NVh~՟$ma+[֜`KEZV*<q+dqLG_UqYxby (hGB: )"%CꢊLwb&+@iR;RHH@:ᳱmdTVngQ~I5-gQJ;k}UE q\wgDWI<@+dJm[H^1X#ظ>7<#Ɓ4Z^;gk;Zٶkl=JxRd*[Eh*٫W6;Eis3;b#nwX#h?h1SH1ڐJ@Gc`)=JEdZ^$%*D`c3tɑwB8RŪ_XVegup\{eOC9E?'޴;eqYoǣoAΝ]g~ec. gyFMlX|rqu1opJ.yj&elqϥvu:B۠ng#5E{O:5JWN=͕XqcH7 g8k|"}F&+H2 wW1qS:SݣDAD\zMa+զeL^9NZd$h–U*+8( 3VsP8w2.eOV5͜\u*qL6(|@)W>BX?2=E+X#SE7#֊b>BSXSJ} g$;R+tx%TH?xǭirؙjb푾Fc{׎R[ZS$P^4/!c;T$>קH_Pk܌U8]$B}1mig~,\1U'iXq¯m<瑎%\W(T3 ae)#ҴU^K ilPʤ3F5kD|nBz?,-͒AC ʽF"(UFYA\+}-mFsRrFo8Չo<s|DeG 8V'**d.*ڠzb+@a꼔Wzҁz] E)E =ΎF3h֭BAqPW+Ib] Bʐ8T'! \J5܃XEf*V#*0RDwP$7b*RZ!isU5b29 gb׼ vai9%j-\_˷+~͏yo-HK`h]W?vUzV%YPIXӖ)1d^k]Ϊ911ZEGV=JXٲ. ZsEJ%N85ׯ1 V߽ـsʚN#%~P=0 zwڠz5asE9ƒ-CWͿʟ 7jԏ}*YD6ɌWhW*xc0{Ԍch)柼*M:Z@U'BYSR@Deq]?is4yԕ.dy~Mn$2I"NJ {l9 p&@ŠApep'u ]C e1 p5;.wbC?Z2AT"'P9@@3@zz'Pv3~ÓV N1"7.Rh"@|,N3fj8mwH F *~qR׊֠CKjB:2>ю %*Cee,MjjWm Q*K_ܼQU$#/-z0U=']«7;J*8tb70SsȨg aEz5mǺ&U=EXs^pYyH]fAFl㪚sP9\P9^j@S9zB"')Z(H?Eh8򤞴QR \RaR@;BIZ(@7 7&)̚{B'R4QL DII U,I 4QHv[\ !r(z=5O!̠Nz(()(C      C  ,"  B!1A"Qaq2B #Rb3$Cr(Sc/!1AQ"a2qB# ?`pTͺzy:"O'q* +>$ c#,7rf+b@Y.WԶJ~#ijzUWaSWw+8qF A+k7RD:\ m O(K}QS{ZW/L%%8!AKz$Z1dc0mKZ@,/M:)$V@X ;1|+  x$]Wmfi Ѹ [?Dַ{zI,$y=14Sqe@1@ ~1[-~zcJmm +<)X 7o'#9AcnĞC(Ak,} Ԙ"T '\~Sf:I-̱ {Q%Tl~cLf ؈7*2&i<6;+o 5 䣾ܲL0SP h:uij99)a1 }ttVA#'QR,T@A$lzL-2 TPxLd2 C:iۡY#+<6Iۮ{S<[tqV-z=v^w0,{О;C޸Ʀڜy0S QOrK(E1Oq̬YM#qtGw {i"ÄћK}/8Q]N/qd`x27|w@*bZ 6~FYFGk)J0!Daס&?Kx\2<;+|P\ ão勮 S2ͲƠxt;{7eVpBf_ ꌆ>K|~exz[ISIc|YEhl$V0,L3$ʪCE![~XFcച' s3,BLn\S),  a3^-`K|ӓ XML-2j,f[ *SMzധTiUn,I&g[hbG^`ʁK# k5 Gdԧ@`l Hr V;HB="3Gf26pzԞYc [zza'"Y ˸/q37*ۑpS)jmG#>0.M%yAEBY43yK7q<~ZI$zxiPߦt6|AR> duI4Gp#錥Sf^8ZUsb=[ju[vlѰ>z%j,Q~Q>[_G|J%po@"q{•;HZTs};-7oĩΪX@"R96 Pkj޿R̺JWGYH#W\)KME>\<`EdסR;"Ƞ6J f5*)0~D%'qTG)xMb>sȲU؋or,DY* R_+0ѧx._?5jN-*0T!d!ߌe.]OzH= E5^9+|0ri SrùZL03Ru C2F_F[ _q$DƊ7b,FoVРZtiř<8=pRT:mLdSUNHU-p?KHJ:Ix*R2*˱t>x]3ht{PM[*6aRBd߶${]6xX\,>N&=0{e[(ڧҨh_t?cS ZʛS;5i\?|Г plGCr ^bZEǡaosr,Ѳl%va1Od8}_ f Bp6a9S}Ɩ.:Qw eu/$lbgi"EL$vl8Ҙ aJi8&H.0GlX[G1;E e;!?S+3#^LZF\n@p@uSs?;Ta#F -ۧ?Հ7Ӫڏ}sc؎񆉒2A)υYC*17:z"-fv=?})  2,R!A_킵}$'jYX=`0-%.HqJ ) ɿKcH,z=tU^ *# uSWju2T0>}l؆ctSPc|5MYYR:zDvf=H|cI}@esZnXcU @ @G 6=qF|ps(^no59hd2ibߡ7܁`~XxGN$I'ῖLq$ ۩$oGPӏðPLdfʨmyD/Lj A׹ۭ Y}W. .WEgѲF[c`G]7%R a.o:c`Āǧ8||vG}Z1m鹷s8N#e޾?["Ӆ-xƻ@~΀*\?;z OsƧb$ΠmfoLs%P`_T=خ8!~G4Saj/;KzᏋ.M:"gÄQBuKcXKS}= 2eG\KI6A 5'I` *o3$ {ៈ8S.j2*飔-bH?UQmהe>/>$fFwOL;g>yDQ cq=z Y&m@نckoyRlenYTpI ѹ>w3)dřXu7̎WÓ=U*cӺ|ǒgQa+VvlhR*C78% kuũج;%ozbOI#qxr:pX n+.+iB",Kjecƒw YK$dy[}z~>rC{$cSN/,*4N"Cc/ nMz2Umv8n e>`V8c_2vN%D" F;3(doc>cꎗp Dv7N8BIK $hbWWs:c7kav@`6ٮ7O\|0rĒmkC[^Zphy-e* f=YT(1#LF c/f9Lلæ*O5eI0z,oyskJ#6!CR=~>$x~)2hv{"F5$˛F\xO#*q5Tg{$ڔ ?t;u= "7*/3*-E4e,*Le_OLz'ʎ!2Ĥ/tM.vQ v1T4dhl$hF]o| V_+I;`MnaŸ#h I(e=cJ;~[}`ًV7eH'AyIH%IFn-qX8%"{`*Tu,AsyͲ, o%jp29dDWD%cAdP,0mܵ4 +xNqQ]v8t -k,V؋mS` ü/ U]lTS u=qh6O3V1cA nL\,N~Z8MvcE#v(`T JwDB#bmo#R|Mk|/7T|~+"yYW{to`YSk2l'$(7ߋ1;I-N/Dgģ/ Nt҂L[^U{c"u e|)iɖ2Sp;oZj.fpzawÙ:H{[όVڴ[kH;=BI}>)@cՐ56Q _CpZJ 7{rۆʸ(|%6+4nhtLVo<`٢}.%(333[ț|y=By5KX/#f͙xS,BE#z$2gPQMWSU â`sk$ίęW䲵&iXo[DdgSGK[<0*%\;ѢTDسEq=VOLı'qkoD]=ln¥Pcm)dc{|PPgO5@Fǵp@mk?6u+MW4uGt1`` ڊWCY JFy3(, {_ǥϛɇl˾+r~ iAR#uK: },;o0ZLe.!+ T!77 [z193?R%\hM`ooo͔VTG!$Z]i-k ׶߆t`ԙA1Y n`SJ\;Y"ceom>GL5ѤJey_Ed#%vuCA7נ醬xYFڒGusss|6ief}FPJ@/~uGeһllն'lՏSm=='!Z{V(iݝH$[0s{z߉uJ%[I \jB SW0, xfk($3?sWy}Ln"C H; ;&Cfz{_Ϋ]RIV#֫m^ޘuW-ITEUKP. DfgE0`A٤vmqʪ)2ܿ0KBj٢[XX'nۓ)s͆1W%^J <:u?{;;-D.tq/DZ0"DGI6e` n],%Fu^ F(>u1xԵP-תˠ vhX3>Irtt:׃"3TcpE\/dsz0pdy Ga/ '7q~W g btۦt7MGP8); Cum1o :^>h~P[q(ٓ'91V&lMPwuīsa[BarLl=5iq}Kuʘ0Am$xHÈÙ>ux1^O[ '5=q[s+>=u yz=4%Rrkf⼒;6]]:u.htHڅ~0IUH7+cP @uy#F ov?<~ .P FB vOPqG5;C) Y}qÐ+n"mQCx]MmHlGK13Psr=/@VP::z΃Ǎ j_c N%KVc䑃sR?KmB@}=wʁT?fMNmr./܌Dž\ X<d:#xR@+fmL\s拔\d?0=:pUX[шp+ VNėg!jK@-ؐ}\Z'>i8C5GGSE<6߯^qGO M맒er4fI%Lhn,l`R=Um#Lw{1-rU_b;C.3?UgHe)+c:\\yp1AӢH%E؋i=Bw^^,TPDѪ2 8zͿc#q/ÖSjP5Ee ZdpJTW7RC8z^9cqgäfKxƿ4˫rx8ehf,F;&]z58l2 |HA_y>[WLI,5#š)5# }7,$ʑ+dyU_#NYVQr.nǖrJ_OGmJ0\rpiMMR1$u1 v[na2VB(rJ,Eگ)5_ TC*<߾jjkgZrJN_t1%[6/s*5(A;auiWHkl u#YOD~52crUIV]:Cm$a4WqUe xx :|1~Crj܋4rjX$á|Ζ# nE#!y|WfUW8\ڊ}W@GN@:+9Ӧz\xu16,-Eʟi ؎MQ!Um6=ͮOoW F.JllYXfVO`5K-juH5=?.h\Z-&aͬ*cj_G3oj1RxURX3,{uo~>+vs|’xwP9 WoF<35%/xS@bMofYQ,-2C;ۿ]q74; S-5ė#'1r/V1AMh 7Yu|sS}#'%7X:ma=ŴU<t<\RMp_s3iᣎ3U$EdEzcf'Vx;ekURb pG3&3v*$̫'yݏ}1γΜOGRAx#hwgp O}NU52Nni,f[Zm&dg% %M07Yum9eNT$>a 075ĆGrf<A= ҙFj,lyʯPEkQ I))O>ht QQek_(N ;4M.L0̳gZ%42n}X6;uw9sR-%JO")]MU;,n #cs%dvf?fR0ɸ$A w-s̚ϘHiژDenHۍa~)$)T[`'IEVR&Ljw n÷m]Jn{Q@]#%@]B}OAӾ|XڴGj)nvƺx_HH`z{\aƢҥZkKRdCM0*CuP U`I}@6ۥÄ ĂG@oЃ²1a_H<7ߖ#HUDLm=Dy!0z* -r{,@αv#K<8`j~$ {h-stR@ }LF]p/(Ob7}dff#O\8<+,lPyi:PC""4PUG2o:VSAW$FWQbp>dfJc _lUk3YWhw}4L0q@9VQykai{(ƚͺ0ű`g F_DI`=: |fUi0սN {I2($%dT) jj. _E:H5Z(:[\`V!uw ʣ6:{ h*'U7-Ols "r5C20]C1^8)e@\rb@B1&66*j(*"v̦Zey5H|b/Y'~*3 O, ؋5 {XERc%|#=|zs,5h¡w5_GfAî`Z5ԋ[p[lꖉVrXȱqQGK] }԰{k[ӸScF ӌiQ$5Yc2]dҦ"TU,q $ar׸'Mv~e90,2 “t 'o1׾3LX'yG_IH(db/{5MI9Iey9D2PEֹrl- >.LuH YtTBłByuF:wA7N/%T:^KFA>"lAN#fa;ANҊY&iZ5'LàìME^[9e*d`gPAl5lpG sMuuS&$ "ȪCqe+WㅣEKdU]F`zF6˗MfeYcc榆-tjQy9(csIg熞 |"Y(#Hk[5MȺ**a$j]gUu7m{á#eGWY-Ud)'6QbYGB:˸3˹˘d]~\Bl* of [{< >Jͥˣ0-o=xL MYFp_# 5QBng?Gu/.U$|)m+E9A,akgQqj[;ȩk"j@PSXPѳ-sxk1>+e.*P񈦍]j@|_^5e-$NѢxPS, E-eb hJ`bAɊ^`KeveSBd14x:>Ug=C1yaQMĵrVMYUExk*b!OJ\)vٝE'QK 859iB#xm7w>P]ݭq_o|o M_U 1hdib%'Fo]%MHaȒĻv:=ln9enH9U|'F)O`!+8."{w$|c>Id5JɤcS'xPE:QmH#t~?F[_^a{@fl6# $`F6]nŁ aʦ;G_ᨷskc\{tþ{tFI#{ ȴn㯾t16RY؟ŜtMm]/6U7;b uCk\^pXwUHXoA4ؑ 0K(#uV빾,o,r)Wgc"~UB1akHE;بVzKn=o:dSqF8,c#xN7]4Iob m^XȦXqIu :uX;ځD)b`FacKx7޿}iU^zc}Ur _'mWP6[ @DNV"{X.7qe(b*" {x]F&[o# ;xk3E5,o#'dM[4r( ͳ4)a@ Hc"؋xw¹MQ%C$㰂QI_P#k k%Y⭥iq~eKT&SN#KNΞ:1/_%K>I$fY:JC$jڵ+\@ rG! %`T @.=,|MK4g+Ry]&CO1I *ƁUrr(ʤ!wi v}zqy\-ʞCE̺$֘M1/! F,H&OE䦆\`y-d+BtSl|sagUqHycer{{FFoo|O8蹫YeɒpSTC5d64P~"-lFxW9} mM6c*c@ST(@Z1W%\$#{N #p[^v{cDU䈤 [p6<T\ aү/ ; [vm]*Oe:w#ÍT~"0OE&{oda{Q7bv6ÕXTɰ>ownww$۶T )'צn5K1۠N9T Qa $z2(y 7 ^{¡P|BX2MJ E=:iaab06TS~2Ynm~N$‹c4$z^Sө1,\{)s=/0u>70 ߱Ft^l}y\e .ŷzc' o:PUd_>>Hߡ\FII%1mКA+:} Al'REUVz a8"BCװg.O#HIWR?yc,lik}qsCVjdT!4^+guj改nqDA#FI!麒m-^{C=.iSm=$LReF71)moRvq+Qx Fve]o$lqx$h*,֙5eJk Y;*"7&9S*#=շihy^Ur1V#S6lH9ʼlM#22?1jq9`M7~gTM^Sf,kxf Lma8ӈ<F2TV14,YK P-pF`3i%NL @pWeɛd-IUQ +ebHlĵ= j3RDf"/o2iu$` 1KX67P FQ•R sFyGRPɭtZ7V]PüKC-%htxU!¬^ok[kthv%-i2C 8ڶHdGNY@ٙرGђ-W&~~ЦZvh.ch Y!=2(5͢=u>,Rl'CI &Up -isG:3J~*rt7)`V{4rhn8Z΀:VH;$R@Rg6a%Y VfS#↪c`C4; [k.ְ(o'3Z@󶆣 Hď˪/M6,J^Lr(1/8u[6W2$w,.ɹ#NgEļAFki>QzuxKO%a=9eyMSG]I;Iӣ$5QQ"IckZzJwaZ*R+%&[_K *i#G-ɲ-`:[J0!K\JgnUk*n+bܟ(M7:V0Tj\j+WPP1[G*JK 2؍x#{ƵbA ?;}s>̣Ulk؎3\:4@s|Y9EzdqWuYhh&tdo"*/\H`fT43橤jk3,*j7DcdEež},beg;WI, pU^!QrMȳỘKQ|MCMFˣԩ't:T|FA ~ 11Ǥ HL- *SpО RaY%7d6;t=~:UZ8HcH&m*[?M+’Ҭ˷Eߦ,Q*8M*hy&bQvrm"bJR/=-`ՒҒ9^b! I |\_tkU<4eq,}a<ɳ_h:)i-v7v~7%_SJ!Xf^Ť a{3'4k_6V@-a u|RW BI%=lo:7BE*R'Iˏ o.?L<8ϗR\u @~؀'F\^DR2s^g@!-bܛikXi% iJe?<2fj@Z_doϿ0w4ƎFrٍu%-n[Wʃ\ M ]*Mƃpm^e<|59Z,{Yɵc$.K1z9pCx1x}}l1!j Ow&Qk|tv4"//rܦdSJOP@j?\OxBAEFPuQEAoKa8̒2]X4>lwyaB%Rjw]t R]%PO96UH]co#.wf9u62*~`a@l5t?Q-N?uRwZfV6m;`sRʓ\1\C(㈶^Pg>*ʾ;sdH5G5*#(:6Qzr/~ج99giQQFTC4bHV! lQ Gk50,>~pw/.i3z&ԉULK06"b+oːT= |(KCÙm.YI b( (1 ϸ?&`"c^ R}|aHe $mÏ7+#rܖ6TyKYnYD\iZIH.M'v3e͛PdA",/0k\u"ܱ<M-sÇy̼ۇ.c02x C{G}a8Z/$+OQ |0,]5*\ /!̳y(*3]B- c2R (M54c/\Hzk*M&>?zS+~#/5:I?y,eeg(`|:v|Mh&Τ~R>% ]tm9הCNI\N#kT˅8e %PUw>bݷw!QS5lK*nsji#ȬJʲ̒MP/^qڗU[4S=@Y,fZނl#wŚ˾[/T I*Uo"E()WʲȖEd 7=E)I*T(\Qo|;e1%IJ߿n` r ~&ir)\EҲ*{?[W UU4vUHk0}cnUsLQ HTaoc ý~qgнE}g04Ff$ (+}n+(0O=2̎YI}P*\l#(%5 \?TiRRT(cv= #A-jBс(o w6 AQ @.>[N iߨrs~_PsjوٮcZ'v;z[ t 7Sߖ܎6HacsܐU.g}p}`!K_MVV逈RM$-A9 =NB7qcmRMLRl-{g٭|:kӶ[3>mBڻob p'}ӣ 8O #J.-`3YJM_YDCK]wmmI 먞KQoa?LK,o&b;Ls:BxZnǨ%e ]aA:j&d聊>I{~.4e+n5Ǯۛ3&E[U5 7R%7W8Dv !3ᯰAUH)䥖y%fLW9%WGEQ'0) ],>egtZd&4ooyP,!FIdEukP\a_ѹ"{aq2=J@[.&|)G`-G-o`;bX U+"$RH6#bН)S {Ķ,EE-Ѹ%9?vK57k4 `ͭvg&WצcSLM cܝzEtoadʠa/3\GdF -ܓ?C"SQKeAk/bIk_lfO3dGU$5MEBm($MbS\&.eQG> J_`B6ܱQnqc?VQrȪi* Wkȭ#ZCpK{^\+' i1Rөg$SQ Ё{߷λSF ɨtې:8U2(Zt#F㏭˙>cE(/fdq}rZ,,6Y<$շMU.&U]{X]bIƫyTsĩ *;Zn}A?3N,bHַЏKa1gDר͆[.|zꪅZhы.Z@vܑΏZ?2xlC)PȄea/RG7?OC?WMf1,bdu*M+]Ǫŕ-ݞK4nM, DWY$zY$#FJaVFF,1v圾"VHBVq_z ʟUT& 0Pw+kX W#,|QNz ȥo}޿ 噛2 M4QN)'I+f pzXw\yd9Tڥ۳`ceR[{Q+e; 4)v )2X2\&L)!!ʪJzȎSH:{`څ.j<"VNp]1o7,.=nqSrJQFl }8Y&ki[F-E,Bbc,mfĪ[nG\YgUP5 '!6zdD Qm}_<3-H}!TV6`P*T#뀪7KeGUv6 6dB%Y*7; .؛ų{ R M]1~U]_v'W^S> NB ηA _F0 éX jFL8)+rlpRCF CXmT#*cB Ấmm[]z[`1.Z@l|Y+K [%W9V-َ;v' iTq pD;ujXQ/e>qԔ$Uk/=>xi)B؝iڬ'ШFDd*l7&<3BPtrXEŃp$* M6^ߞ%+.u\j*Ac`87\B,A؜g_>$Q-.I cE oqI*'DS ? TE"QO0U^JTY%]z'Y3DU0.F%8o/[CU+ en#r>uNՊ F^Jl(Ά6zaCU*nޞE)ե25VE @e %DzI%ԍSU4 6$ )dL-S 9Tdep=CI0S2!q|E#n(ck؋6Wp&QyC㛋䬼z0T40e,=kXmw_}[)bI&ǰ{~{drvb_/Fd;ڈt9I4_Qwpn[S%%+@fP3uje$2 r?bU(| {G eKD0P[}}qD5%Hzἵs/!{ÒMY= #YڥQshR[J|Tei^bO`6Zibx|l{I`f*@'qka~Jƾ_O|VLx,\M2q6s i(;bkRo} 21})LJ_v=`n&Ϣ6tܜk8m1 o1n 8Q2!E,`v=0@Ih uPt*:x v62SʨU僳*ye+ka[^ذOp}:vttq*[Oq4"" \tq냩OknM_aW">ŭ S( Ǯ - 0PM670i"'s9,"fqˇ ib4k|w%#2{&ᕸv"iam`\&Jcxr|18QHksYA=S5Ni[&y<š5  1 HV/CKpXk|+#VW&@:}qpqi qv/ubԲcw_Eo,x4NWL!9d .OE*v#Ͼ[/38*ئP< f С`!6)7Di%VeR :6g%? ?M6\jId` axj3N1;-qo LS}1=YI56HVǔuHҍoN~:TKYmX[1g$ 1mm&DHfAp>кWq؜kYV3zZ!@퀪#)\zo*:Aa'ֈKӾ5\|7Ԓm;ԒXX\:dSٍPXsͮm J ][s0%Um0GI ll:PCb`S{2ߦ \U甎ְ5o cfbz/,$`*ۘi$5{uZKHGD(3-EL, ?7 aЗUc(Ƒ#2H^ֽAt`GQ877 hvLxw%Vӵ\ _eZpH bk쨍/@ҚGٝ5e4X&zTk c35F;XeN5݉z\EPQp}0J#1,{{a FQP-K];l֫l<"~v´A*\[vÕJdJ^/cױÞ^Α K>CAAN.z[ ,O1tzs-L_LM94  LNV&\tLE$YX]E݊H>PAZۭ`^D~Ȋm1&j ٘jlN@ l MΛl&ҷop&p}Q̵ =mmjjYnЌw[Na-F^ø=1 }:Enen;_Aǥ׶3Kb.!,l8!H3j:,WF_q5j Z&6+n:QG*wPQnwl}03 mWn'{\60̢3=FpkyYvUl],.|QJ)+i` 2bmЂ?ы<x1$:`QqFtn{ nmۦ _[qR˭X7]]z\Grç HWK7 7[Z`MԜ@6 Q!=i}Sjv\`N㵰ě^-;aֿN:I?M6aUwc|D@iIѵ©ڑe$v6܌}. (>2aropV :sA+:ܒ0lH # @ms .NUe"=D o|#4` LmeSIcpma Rʫ!>6qP=y6)r}R$tTPGzoc폕 Lҝq wl1|S!eف6P/}p/o2JھfRE%8Ъs|ٕ2 xSbz*R5̀|k&-ar*蜎NUYlO>7' .An,t3\W0rډ>eU@ܞvv@1lA0I'aHi2P,_Y&oTHͲ^pZvFfA>22 .8h:2cMEтb}0"Y:F pA7=oERgĐ쑛8R(NLJdbؔ"g mѠ,,cL SK:߯% TOᎠv ; z,Kc]XkZ,@P'7`z*ڋlA㻛'<4%b=:R|0fBwlk]LFޘ8`L,FX F3XT?|UC1L % H"AIBi:W-sw3<:t4cE`]UY5 K_T+iYYTKP z8 5\.4YZ*jf0xp=Kcq@4yY|,f[/xij>XPA M{ W9_Y2嚙>27}$ն̦[k?sViha;ٴnl;܅GSF4&:u[#~Ew|sSG d!MDz{bǜtMYj|r0?x^o¬E52*`E,7#lTWezGMR Ql4$%q5r4F˥6*" ߦ67UK,oX,M>P>u ;`ݏU2PK{ lߦ4q6 )$ ܀:7lBL,: "$n~"V lp DF$ -b `*F`;zગ=WG|BUc;V w5. V~$nЍT>a'u^ǥધ%s V04-T5`*b Nĭ[5 C,ucOiI(aj@{㥣FtY-eF[#YaO#; jSGB9[$R;b4۠< fl~Xy™%{f܃D;ᛍj-I+k'`CM#1 ߥ7JzYUQM}X yp9 g01PKXZn3䎑YB .̰duXљEKԴMك7R{3Eh30;퉝 CC [ ?p[@W_^"lM1ʩ9H[[c$y|;($ ; `栍{aVG*aH 큳H Ttd%$â6Ds|\#L),fF7km_ ;cZǶ#~I:8\m۵­p &T06c*U  Rb4 0 e$b/!@a]Dܜq #tu2F"no|Fd #)}7_ n g+=gX$e,;V H\pr̶2R6w; w7Liglchg_ x_{!MBK -6?/F^!hsxRZtU1UYbni187橚JE[ex@Гw#yJ]TV-MAQ#hB$AsMWf|9&dE] jF05n; x⊶>YBSؐI@߄8]]Q+0r ':!AlXZ|I]/ -+Z`9bRK-4bsfҵ5"4pEَ#]MT\AFua;(@"6"xw6nO<"-u7~f|D)#(GHY*T^-Zz*$Jo~v:rڹVUSc}¸rH7,:wV X:)`7%;0ːfV0f4bw#I`/EKd lJaqon5Lh_Yc3}mߕy!XI@o({'SUPLuڷ6F+:LTGŰn͕mvJ=(9ôP< .MV6z$ /6\ This is a super article ! Fork me on GitHub

    This is a super article !

    Some content here !

    This is a simple title

    And here comes the cool stuff.

    alternate text alternate text
    >>> from ipdb import set_trace
    >>> set_trace()
    

    → And now try with some utf8 hell: ééé

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2010/octobre/000077500000000000000000000000001303525152100252675ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2010/octobre/15/000077500000000000000000000000001303525152100255145ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/000077500000000000000000000000001303525152100301515ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/index.html000066400000000000000000000360761303525152100321620ustar00rootroot00000000000000 Unbelievable ! Fork me on GitHub

    Unbelievable !

    Or completely awesome. Depends the needs.

    a root-relative link to markdown-article a file-relative link to markdown-article

    Testing sourcecode directive

    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Testing another case

    This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default.

    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Lovely.

    Testing more sourcecode directives

     8 def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]

    Lovely.

    Testing even more sourcecode directives

    formatter = self.options and VARIANTS[self.options.keys()[0]]

    Lovely.

    Testing overriding config defaults

    Even if the default is line numbers, we can override it here

    formatter = self.options and VARIANTS[self.options.keys()[0]]
    

    Lovely.

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2010/octobre/20/000077500000000000000000000000001303525152100255105ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/000077500000000000000000000000001303525152100270425ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/index.html000066400000000000000000000137311303525152100310440ustar00rootroot00000000000000 Oh yeah ! Fork me on GitHub

    Oh yeah !

    Why not ?

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !

    alternate text

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/000077500000000000000000000000001303525152100236335ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/avril/000077500000000000000000000000001303525152100247505ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/avril/20/000077500000000000000000000000001303525152100251715ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article/000077500000000000000000000000001303525152100323155ustar00rootroot00000000000000index.html000066400000000000000000000134731303525152100342430ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article A markdown powered article Fork me on GitHub

    A markdown powered article

    You're mutually oblivious.

    a root-relative link to unbelievable a file-relative link to unbelievable

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/000077500000000000000000000000001303525152100257045ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/17/000077500000000000000000000000001303525152100261335ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/000077500000000000000000000000001303525152100277145ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/index.html000066400000000000000000000127761303525152100317260ustar00rootroot00000000000000 Article 1 Fork me on GitHub

    Article 1

    Article 1

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/000077500000000000000000000000001303525152100277155ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/index.html000066400000000000000000000127761303525152100317270ustar00rootroot00000000000000 Article 2 Fork me on GitHub

    Article 2

    Article 2

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/000077500000000000000000000000001303525152100277165ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/index.html000066400000000000000000000127761303525152100317300ustar00rootroot00000000000000 Article 3 Fork me on GitHub

    Article 3

    Article 3

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/000077500000000000000000000000001303525152100236345ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/février/000077500000000000000000000000001303525152100257055ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/février/29/000077500000000000000000000000001303525152100261375ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/000077500000000000000000000000001303525152100310335ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/index.html000066400000000000000000000134271303525152100330370ustar00rootroot00000000000000 Second article Fork me on GitHub

    Second article

    This is some article, in english

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/novembre/000077500000000000000000000000001303525152100254515ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/novembre/30/000077500000000000000000000000001303525152100256735ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example/000077500000000000000000000000001303525152100327445ustar00rootroot00000000000000index.html000066400000000000000000000131451303525152100346660ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example FILENAME_METADATA example Fork me on GitHub

    FILENAME_METADATA example

    Some cool stuff!

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/robots.txt000066400000000000000000000000421303525152100241450ustar00rootroot00000000000000User-agent: * Disallow: /pictures pelican-3.7.1/pelican/tests/output/custom_locale/second-article-fr.html000066400000000000000000000130451303525152100262720ustar00rootroot00000000000000 Deuxième article Fork me on GitHub

    Deuxième article

    Ceci est un article, en français.

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/tag/000077500000000000000000000000001303525152100226535ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/tag/bar.html000066400000000000000000000176441303525152100243210ustar00rootroot00000000000000 Alexis' log - bar Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom_locale/tag/baz.html000066400000000000000000000125541303525152100243240ustar00rootroot00000000000000 The baz tag Fork me on GitHub

    The baz tag

    This article overrides the listening of the articles under the baz tag.

    Comments !

    pelican-3.7.1/pelican/tests/output/custom_locale/tag/foo.html000066400000000000000000000150211303525152100243230ustar00rootroot00000000000000 Alexis' log - foo Fork me on GitHub

    Other articles


    pelican-3.7.1/pelican/tests/output/custom_locale/tag/foobar.html000066400000000000000000000130021303525152100250050ustar00rootroot00000000000000 Alexis' log - foobar Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom_locale/tag/oh.html000066400000000000000000000101061303525152100241450ustar00rootroot00000000000000 Oh Oh Oh Fork me on GitHub

    Oh Oh Oh

    This page overrides the listening of the articles under the oh tag.

    pelican-3.7.1/pelican/tests/output/custom_locale/tag/yeah.html000066400000000000000000000120641303525152100244720ustar00rootroot00000000000000 Alexis' log - yeah Fork me on GitHub
    pelican-3.7.1/pelican/tests/output/custom_locale/tags.html000066400000000000000000000104611303525152100237260ustar00rootroot00000000000000 Alexis' log - Tags Fork me on GitHub

    Tags for Alexis' log

    pelican-3.7.1/pelican/tests/output/custom_locale/theme/000077500000000000000000000000001303525152100232025ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/theme/css/000077500000000000000000000000001303525152100237725ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/theme/css/main.css000066400000000000000000000254161303525152100254400ustar00rootroot00000000000000/* Name: Smashing HTML5 Date: July 2009 Description: Sample layout for HTML5 and CSS3 goodness. Version: 1.0 License: MIT Licensed by: Smashing Media GmbH Original author: Enrique Ramírez */ /* Imports */ @import url("reset.css"); @import url("pygment.css"); @import url("typogrify.css"); @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); /***** Global *****/ /* Body */ body { background: #F5F4EF; color: #000305; font-size: 87.5%; /* Base font size: 14px */ font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; line-height: 1.429; margin: 0; padding: 0; text-align: left; } /* Headings */ h1 {font-size: 2em } h2 {font-size: 1.571em} /* 22px */ h3 {font-size: 1.429em} /* 20px */ h4 {font-size: 1.286em} /* 18px */ h5 {font-size: 1.143em} /* 16px */ h6 {font-size: 1em} /* 14px */ h1, h2, h3, h4, h5, h6 { font-weight: 400; line-height: 1.1; margin-bottom: .8em; font-family: 'Yanone Kaffeesatz', arial, serif; } h3, h4, h5, h6 { margin-top: .8em; } hr { border: 2px solid #EEEEEE; } /* Anchors */ a {outline: 0;} a img {border: 0px; text-decoration: none;} a:link, a:visited { color: #C74350; padding: 0 1px; text-decoration: underline; } a:hover, a:active { background-color: #C74350; color: #fff; text-decoration: none; text-shadow: 1px 1px 1px #333; } h1 a:hover { background-color: inherit } /* Paragraphs */ div.line-block, p { margin-top: 1em; margin-bottom: 1em;} strong, b {font-weight: bold;} em, i {font-style: italic;} /* Lists */ ul { list-style: outside disc; margin: 0em 0 0 1.5em; } ol { list-style: outside decimal; margin: 0em 0 0 1.5em; } li { margin-top: 0.5em; margin-bottom: 1em; } .post-info { float:right; margin:10px; padding:5px; } .post-info p{ margin-top: 1px; margin-bottom: 1px; } .readmore { float: right } dl {margin: 0 0 1.5em 0;} dt {font-weight: bold;} dd {margin-left: 1.5em;} pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} /* Quotes */ blockquote { margin: 20px; font-style: italic; } cite {} q {} div.note { float: right; margin: 5px; font-size: 85%; max-width: 300px; } /* Tables */ table {margin: .5em auto 1.5em auto; width: 98%;} /* Thead */ thead th {padding: .5em .4em; text-align: left;} thead td {} /* Tbody */ tbody td {padding: .5em .4em;} tbody th {} tbody .alt td {} tbody .alt th {} /* Tfoot */ tfoot th {} tfoot td {} /* HTML5 tags */ header, section, footer, aside, nav, article, figure { display: block; } /***** Layout *****/ .body {clear: both; margin: 0 auto; width: 800px;} img.right, figure.right {float: right; margin: 0 0 2em 2em;} img.left, figure.left {float: left; margin: 0 2em 2em 0;} /* Header *****************/ #banner { margin: 0 auto; padding: 2.5em 0 0 0; } /* Banner */ #banner h1 {font-size: 3.571em; line-height: 0;} #banner h1 a:link, #banner h1 a:visited { color: #000305; display: block; font-weight: bold; margin: 0 0 .6em .2em; text-decoration: none; } #banner h1 a:hover, #banner h1 a:active { background: none; color: #C74350; text-shadow: none; } #banner h1 strong {font-size: 0.36em; font-weight: normal;} /* Main Nav */ #banner nav { background: #000305; font-size: 1.143em; height: 40px; line-height: 30px; margin: 0 auto 2em auto; padding: 0; text-align: center; width: 800px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #banner nav ul {list-style: none; margin: 0 auto; width: 800px;} #banner nav li {float: left; display: inline; margin: 0;} #banner nav a:link, #banner nav a:visited { color: #fff; display: inline-block; height: 30px; padding: 5px 1.5em; text-decoration: none; } #banner nav a:hover, #banner nav a:active, #banner nav .active a:link, #banner nav .active a:visited { background: #C74451; color: #fff; text-shadow: none !important; } #banner nav li:first-child a { border-top-left-radius: 5px; -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; } /* Featured *****************/ #featured { background: #fff; margin-bottom: 2em; overflow: hidden; padding: 20px; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } #featured figure { border: 2px solid #eee; float: right; margin: 0.786em 2em 0 5em; width: 248px; } #featured figure img {display: block; float: right;} #featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} #featured h3 {font-size: 1.429em; margin-bottom: .5em;} #featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} #featured h3 a:hover, #featured h3 a:active {color: #fff;} /* Body *****************/ #content { background: #fff; margin-bottom: 2em; overflow: hidden; padding: 20px 20px; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } /* Extras *****************/ #extras {margin: 0 auto 3em auto; overflow: hidden;} #extras ul {list-style: none; margin: 0;} #extras li {border-bottom: 1px solid #fff;} #extras h2 { color: #C74350; font-size: 1.429em; margin-bottom: .25em; padding: 0 3px; } #extras a:link, #extras a:visited { color: #444; display: block; border-bottom: 1px solid #F4E3E3; text-decoration: none; padding: .3em .25em; } #extras a:hover, #extras a:active {color: #fff;} /* Blogroll */ #extras .blogroll { float: left; width: 615px; } #extras .blogroll li {float: left; margin: 0 20px 0 0; width: 185px;} /* Social */ #extras .social { float: right; width: 175px; } #extras div[class='social'] a { background-repeat: no-repeat; background-position: 3px 6px; padding-left: 25px; } /* Icons */ .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} .social a[href*='github.com'], .social a[href*='git.io'] { background-image: url('../images/icons/github.png'); background-size: 16px 16px; } .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} .social a[href*='news.ycombinator.com'], .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} .social a[href*='stackoverflow.com'] {background-image: url('../images/icons/stackoverflow.png');} .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} /* About *****************/ #about { background: #fff; font-style: normal; margin-bottom: 2em; overflow: hidden; padding: 20px; text-align: left; width: 760px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } #about .primary {float: left; width: 165px;} #about .primary strong {color: #C64350; display: block; font-size: 1.286em;} #about .photo {float: left; margin: 5px 20px;} #about .url:link, #about .url:visited {text-decoration: none;} #about .bio {float: right; width: 500px;} /* Footer *****************/ #contentinfo {padding-bottom: 2em; text-align: right;} /***** Sections *****/ /* Blog */ .hentry { display: block; clear: both; border-bottom: 1px solid #eee; padding: 1.5em 0; } li:last-child .hentry, #content > .hentry {border: 0; margin: 0;} #content > .hentry {padding: 1em 0;} .hentry img{display : none ;} .entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} .entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} .entry-title a:visited {background-color: #fff;} .hentry .post-info * {font-style: normal;} /* Content */ .hentry footer {margin-bottom: 2em;} .hentry footer address {display: inline;} #posts-list footer address {display: block;} /* Blog Index */ #posts-list {list-style: none; margin: 0;} #posts-list .hentry {padding-left: 10px; position: relative;} #posts-list footer { left: 10px; position: relative; float: left; top: 0.5em; width: 190px; } /* About the Author */ #about-author { background: #f9f9f9; clear: both; font-style: normal; margin: 2em 0; padding: 10px 20px 15px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #about-author strong { color: #C64350; clear: both; display: block; font-size: 1.429em; } #about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} /* Comments */ #comments-list {list-style: none; margin: 0 1em;} #comments-list blockquote { background: #f8f8f8; clear: both; font-style: normal; margin: 0; padding: 15px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} #comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} /* Add a Comment */ #add-comment label {clear: left; float: left; text-align: left; width: 150px;} #add-comment input[type='text'], #add-comment input[type='email'], #add-comment input[type='url'] {float: left; width: 200px;} #add-comment textarea {float: left; height: 150px; width: 495px;} #add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} #add-comment input[type='submit'] {float: right; margin: 0 .5em;} #add-comment * {margin-bottom: .5em;} pelican-3.7.1/pelican/tests/output/custom_locale/theme/css/pygment.css000066400000000000000000000034521303525152100261730ustar00rootroot00000000000000.hll { background-color:#eee; } .c { color:#408090; font-style:italic; } .err { border:1px solid #FF0000; } .k { color:#007020; font-weight:bold; } .o { color:#666666; } .cm { color:#408090; font-style:italic; } .cp { color:#007020; } .c1 { color:#408090; font-style:italic; } .cs { background-color:#FFF0F0; color:#408090; } .gd { color:#A00000; } .ge { font-style:italic; } .gr { color:#FF0000; } .gh { color:#000080; font-weight:bold; } .gi { color:#00A000; } .go { color:#303030; } .gp { color:#C65D09; font-weight:bold; } .gs { font-weight:bold; } .gu { color:#800080; font-weight:bold; } .gt { color:#0040D0; } .kc { color:#007020; font-weight:bold; } .kd { color:#007020; font-weight:bold; } .kn { color:#007020; font-weight:bold; } .kp { color:#007020; } .kr { color:#007020; font-weight:bold; } .kt { color:#902000; } .m { color:#208050; } .s { color:#4070A0; } .na { color:#4070A0; } .nb { color:#007020; } .nc { color:#0E84B5; font-weight:bold; } .no { color:#60ADD5; } .nd { color:#555555; font-weight:bold; } .ni { color:#D55537; font-weight:bold; } .ne { color:#007020; } .nf { color:#06287E; } .nl { color:#002070; font-weight:bold; } .nn { color:#0E84B5; font-weight:bold; } .nt { color:#062873; font-weight:bold; } .nv { color:#BB60D5; } .ow { color:#007020; font-weight:bold; } .w { color:#BBBBBB; } .mf { color:#208050; } .mh { color:#208050; } .mi { color:#208050; } .mo { color:#208050; } .sb { color:#4070A0; } .sc { color:#4070A0; } .sd { color:#4070A0; font-style:italic; } .s2 { color:#4070A0; } .se { color:#4070A0; font-weight:bold; } .sh { color:#4070A0; } .si { color:#70A0D0; font-style:italic; } .sx { color:#C65D09; } .sr { color:#235388; } .s1 { color:#4070A0; } .ss { color:#517918; } .bp { color:#007020; } .vc { color:#BB60D5; } .vg { color:#BB60D5; } .vi { color:#BB60D5; } .il { color:#208050; } pelican-3.7.1/pelican/tests/output/custom_locale/theme/css/reset.css000066400000000000000000000021171303525152100256270ustar00rootroot00000000000000/* Name: Reset Stylesheet Description: Resets browser's default CSS Author: Eric Meyer Author URI: http://meyerweb.com/eric/tools/css/reset/ */ /* v1.0 | 20080212 */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { background: transparent; border: 0; font-size: 100%; margin: 0; outline: 0; padding: 0; vertical-align: baseline; } body {line-height: 1;} ol, ul {list-style: none;} blockquote, q {quotes: none;} blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } /* remember to define focus styles! */ :focus { outline: 0; } /* remember to highlight inserts somehow! */ ins {text-decoration: none;} del {text-decoration: line-through;} /* tables still need 'cellspacing="0"' in the markup */ table { border-collapse: collapse; border-spacing: 0; }pelican-3.7.1/pelican/tests/output/custom_locale/theme/css/typogrify.css000066400000000000000000000002761303525152100265450ustar00rootroot00000000000000.caps {font-size:.92em;} .amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} .dquo {margin-left:-.38em;} pelican-3.7.1/pelican/tests/output/custom_locale/theme/css/wide.css000066400000000000000000000011501303525152100254310ustar00rootroot00000000000000@import url("main.css"); body { font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; } .post-info{ display: none; } #banner nav { display: none; -moz-border-radius: 0px; margin-bottom: 20px; overflow: hidden; font-size: 1em; background: #F5F4EF; } #banner nav ul{ padding-right: 50px; } #banner nav li{ float: right; color: #000; } #banner nav li a { color: #000; } #banner h1 { margin-bottom: -18px; } #featured, #extras { padding: 50px; } #featured { padding-top: 20px; } #extras { padding-top: 0px; padding-bottom: 0px; } pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/000077500000000000000000000000001303525152100244475ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/000077500000000000000000000000001303525152100255625ustar00rootroot00000000000000pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/aboutme.png000066400000000000000000000013571303525152100277320ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ< PLTE >b :\a``__^][XNz 8Y]\\ZZXVS Js Ch 6UXXWVUTRQ~N{ Lw El @d4S P} O| Nz Mx Lw Ku Js Hq Fn Ek @e >a2O Mw3 Ip Dj Bg >a <]0L Hp Ho Gn Bg Cg;]9Y ;[.I Dk :ZAf 7U=_0K,F@e(>=_%:6U"4*D2O'@/K &=-G#:*D!7(@4%=1k/tRNS@f pHYsHHFk>IDATURPEcJP t(P)RcB]7p $YpܪHWUU?9'g^DXz&[|y6:dd#'r7_4L˚7L?`ZW|;h%tEXtdate:create2013-03-15T18:16:20-07:00#6%tEXtdate:modify2013-03-15T18:16:16-07:00SIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/bitbucket.png000066400000000000000000000072021303525152100302450ustar00rootroot00000000000000PNG  IHDRh6 AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  niTXtXML:com.adobe.xmp ? AmIDAT(ERkAtIݐۤ?jִPЖRD {$xP"1FlҺ>t GTЂ}FD%BdD,>[ēPR@+*ȌFՍJpL +x~,*p*K$ћBJ{iqne6;Ĉv}vpn`k KӲW7ͅ'tՅ |ZWotL,(w,}+WҩP8d״ˍJsP\ C$IAk筕sGt*JB\׆\08Sֿ#/9bSs\&_t@z8vIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/delicious.png000066400000000000000000000016761303525152100302620ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS4ӠtEXtCreation Time20/7/09zcIDAT8ou}Kn6IKb*K D(B1/ 1Ll,t@JtCDڦIIS׉o{}yX,Vq#jKZxwv~}z;mgӃ`ڮfOk̙{~5޻~~n4i3/}{׃g½cW=>֚./}p B:m&tkJFLi_ ?ԓIrR "&bi?3$bZ)Hէڲ @8L !:(NDm2yqrK)I%dCesG J) ?ϧJ>2pF> 6`CAsJﳽG7qG52/}Cca@\Ş.M[9rʲ W*YR=*;{"""H$""_}47u6wD*x~8Q3̱P!L4֖j$FH|q  ƾJg0.q!`x@0^5"1"`E^'81ZB`0Kׯh'a.W Ox^8G,b89.~/T+^`c`j )efЩ2},W${{b1}x'mmnko}w㰻u`}?=}yf;wZ?W.72 䭘fIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/facebook.png000066400000000000000000000003121303525152100300350ustar00rootroot00000000000000PNG  IHDRRPLTE;Y;Y`xEbmgtRNSACbKGDH pHYsHHFk>=IDATc`F%0``0 e C%P RBeBT\Cp0K 0ef>IENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/github.png000066400000000000000000000032621303525152100275550ustar00rootroot00000000000000PNG  IHDR szztEXtSoftwareAdobe ImageReadyqe<$iTXtXML:com.adobe.xmp $IDATxėmhayL30A+R#f>IHکy(M)_o5 0+0Ėl&o{i^]u<{Yws}=uC>$L, }<w}8^ AO?p! xaяPKI3`'B>0QT1<+`}^nvkp^ƅF|1"Gp.*oO׀Vp ]߅jc8K$q 8jV`#`vmpGѢu!#}#:U_?_yhE $=;c*xNOo+&w)%K-R%6n'o">j/t³qoGW7j%2q GX?woibCÐAzbǰt \14|S.DZ]# b|H$(ʕohmqͱRP셣$,0Z20 tNvRW3K8Xk2 IO6LbIDAT}1 % h#"#M 홴z)} .?_"{B4!>}HVU8T% )mu CbD, F IIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/gittip.png000066400000000000000000000007471303525152100276000ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME  mgIDAT8c`o0cm=H_P| *0CF`1d=6_LԄj.d*LsHg#MM@v7S!0lÕs' m`=-oqEv 4plٰl$.4g4ܴb)f ā@,`.&@yjB P q7!UA?~p11?FhhDd"EDm j4'$MOH(I%^V8ǟ)LfgoǑXIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/google-groups.png000066400000000000000000000014431303525152100310630ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<5PLTE,r#bFEB@>=:875}3{1zDB@<7~4|CA>=986~?>6~4|2{1x>2z0x=98;9/w1y0w2{.v3|.uʡ-ṭ,s+qtRNS}abKGD-IDAT5y[QW-q̄13p}(B/繞j;.{`(E( )-O$9dAL#B /$Jryu]Bpp2OiR.;7EBpNb>cã}%bP}fC}(,ggxE)_Oz70Yn`-:9@ 3$%ts%tEXtdate:create2013-01-13T02:11:01-08:00̕%tEXtdate:modify2013-01-13T02:10:36-08:00&zIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/google-plus.png000066400000000000000000000010171303525152100305240ustar00rootroot00000000000000PNG  IHDRh6IDAT(cmIbeq&nt9@ A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  niTXtXML:com.adobe.xmp ? AIDAT8cD^V4?PAuLU?7g0arp m3Fpu06L.d s`]8bw3lfd ьP#<= Is aLd6\<(A_&#Ft6ab/$eqoIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/lastfm.png000066400000000000000000000017171303525152100275640ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS4ӠtEXtCreation Time20/7/09zc(IDAT8OlU{v6*U(D Qc@#'ăO=sp1 ϩD--4Pv{??=~.KxNyfƤTH'*"1֮Br:i$k.>7HXy?؁s(I HrwL.Ig~ Ig9R  (%c5y@F6CH,D ? N6(!cQ6{dPȡpsJ0j0e$pNU.x " 8zZ^5˫3uh`{#at0:Nh`/F1%쑔}#l̮qo2^'#rxqS'ɽshb@c;2I~7;{U,J,yoɾq[ bYBE2'y:fIMw.);#,8vmJK"",7%KRd'""6Q,yJ泓'w>׍j﯒ܹ.P.3_XDz]e?n g_)G_{!bGժԡhvdKAg^䋅kwЕ!dOCPY.cЉ#[{AbXM~bѻD\k-3rUe<$7V%-e?O=k;ʆQFxD0UmTgjzϯ|psO?ϕsݪCIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/linkedin.png000066400000000000000000000016001303525152100300620ustar00rootroot00000000000000PNG  IHDR(-S7PLTEhiklklmmoommnnoonopqoqprrpqstsutv vw w v w y yx y yy { {zzzz{|{|~ !"#$%&',-21223E9:9::<=~^|^X۳~#rӯ#"{:(#u;p )*R)j NA^AT kk1HgO\(vo84QImÏY`e)S IENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/reddit.png000066400000000000000000000012651303525152100275470ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTER[eeq}bjsdeg|_ju_lz`][JNSiup|VZ^ߍy)/6w]dknyo~djm{[aflpv><:w{qpoGGG20nprS\eɨFJNˁ~~~U^gjklգxgscmx6 pHYsHHFk>IDATePﵻ;X("6蠎s!/^`4-V-r{>]44"O$S > b\8!Vo4[xj65Bڝ.z6!0'c`4ԢS|j|,sMō6spy /R1$ DBTr\ߤ0^|xfNܸ !bT S<~C# %g;$/)QEuM"I`^~.:%n課~| wV :&15R§w 3OPvmd)$ỵ_%YBڶȦ3_JndW|Ui#5Lf:JS8d$7ԈPwɸ^?3u}ȜmEfS쮉 A*bk;K/T1UcDjVz_3:T80}wNpJɠAke,}:{m;?[/4E5[񮺱馕ny'}^8+` x<IENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/slideshare.png000066400000000000000000000010271303525152100304130ustar00rootroot00000000000000PNG  IHDR(-SPLTEâz既d{o˦K>dHk;}unw;97o&wE4fpA,]_z|r]+,$zqfmaHtRNS-)IDATNP^oea01Hc\iGL89qM,n$$LzROQ ]vgchKl#u_וb?oQܔ! . k;GW/ JD44!9ԛIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/speakerdeck.png000066400000000000000000000020311303525152100305450ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTE9,2tU7]6~\6\7]3uU.qSF~G/qS.vW(qS(pS#kO"jNeKdK_I`I[GXFXETDQCOAMAM@K@I?H?I@A;`VaVB;$!F@F@E??|>{>{@|?{?|;x7u6u6u6t7v;y6u4s3r3q3r4s2r/o0p0q1q,m,l*i*h*g)g)g)f+j,m)j'f\FP>O<VCYGUCN<\F(g%g#bM<K3A7Dd]@d\Ed^A8 =2G:|bv_r\^MXHXHUEUFVGVF_Ns]o\n[p\o\o[n[hXgXgWgXfWfWhYbVaU`T `TcV^U ]U ]T ]S \SǶ(tRNS{{m pHYsHHFk> IDATc``dbfaef&6v M-m]-mN.n=}}C}C#c}nS333s KKKs+3+S^>k[ "[{~G'gWW77wgOA!/o_? /aаȨظ$Դ̬d1¢⒒ҲJqںƦ*Iֶ֎ֶήVi }d&MIDATHT;H+A3;dU (AĀ [(#l"Z GVjaF% PPD$dd;!Oŧ»a̜{a|exc)]^ Cnw4LrtW ݛ&ơ_(r:_6ndkcTRgR@@ W>Ez8>8;0Gi!D)c oԌ󳢌vu qÍeGi|ee.'F_ `l!XE|v TՍ BfgE㹻BHr9!R}Aq==E"T[kO` cR)t] Tt]Υ[JK eYL@J)憳WW$oo׽ssD6{yrUUe##V+!>5c`LmߗM`?ZZLbRJ(eLI4fRBU֦iU.! d2vN3qGg;;!!Ðee]7 !qE'`0dw$ jQ盛 hכl ''PO5(6V\Q(u>~ [e(~@~;IɅT%tEXtdate:create2013-07-03T22:30:09-07:001D%tEXtdate:modify2013-07-01T14:56:54-07:00IENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/twitter.png000066400000000000000000000027451303525152100300020ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp ]ivIDATxb?%BrC~$q#P#C&Ffq@7(w࿨>7 }|?O]} @ (ceM1K10p301W6gP*`V1TĤ/deCy }h|@JHɀmF, U1odpMD0ڧ!`^10zt,,Dde`AU`aQ~3AL0Sce Ɠцe`be`,@p988|*}\_n\ϟ?<4+r3h2; )1-9%Zu@@1(u$eX>p2bռɂ3^{HiH[xP:#}浽: ,CgFokL旿*ϿWfgf"RN2Ka@O5 yix/cd;{@IENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/vimeo.png000066400000000000000000000010401303525152100274020ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTE ; +ۆwٕJwIۃi {5{ ϲE ΡrdD|b uCw[stRNS@fbKGD ٥IDATU D.*]k< b[!'3"HHnI ::.zaxlIX X`7[`xpS@vֱ7xݛ Szʺz ۿxϛ%tEXtdate:create2013-01-13T02:07:08-08:00&%tEXtdate:modify2013-01-13T02:06:39-08:00.hIENDB`pelican-3.7.1/pelican/tests/output/custom_locale/theme/images/icons/youtube.png000066400000000000000000000007121303525152100277640ustar00rootroot00000000000000PNG  IHDR_*?tEXtSoftwareAdobe ImageReadyqe<lPLTE#UO#"DfGJ pկnfȹGծnf֯ng9$tRNSX, IDATxbPf``d ~ @ lLL @1&q8X  ,  UƀYA200*@4h0#@2jab7XIAIAd B@[!0hV fdf`p000H0aIe;}1cIENDB`pelican-3.7.1/pelican/tests/support.py000066400000000000000000000127651303525152100200100ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import locale import logging import os import re import subprocess import sys import unittest from contextlib import contextmanager from functools import wraps from logging.handlers import BufferingHandler from shutil import rmtree from tempfile import mkdtemp from six import StringIO from pelican.contents import Article from pelican.settings import DEFAULT_CONFIG __all__ = ['get_article', 'unittest', ] @contextmanager def temporary_folder(): """creates a temporary folder, return it and delete it afterwards. This allows to do something like this in tests: >>> with temporary_folder() as d: # do whatever you want """ tempdir = mkdtemp() try: yield tempdir finally: rmtree(tempdir) def isplit(s, sep=None): """Behaves like str.split but returns a generator instead of a list. >>> list(isplit('\tUse the force\n')) == '\tUse the force\n'.split() True >>> list(isplit('\tUse the force\n')) == ['Use', 'the', 'force'] True >>> (list(isplit('\tUse the force\n', "e")) == '\tUse the force\n'.split("e")) True >>> list(isplit('Use the force', "e")) == 'Use the force'.split("e") True >>> list(isplit('Use the force', "e")) == ['Us', ' th', ' forc', ''] True """ sep, hardsep = r'\s+' if sep is None else re.escape(sep), sep is not None exp, pos, l = re.compile(sep), 0, len(s) while True: m = exp.search(s, pos) if not m: if pos < l or hardsep: # ^ mimic "split()": ''.split() returns [] yield s[pos:] break start = m.start() if pos < start or hardsep: # ^ mimic "split()": includes trailing empty string yield s[pos:start] pos = m.end() def mute(returns_output=False): """Decorate a function that prints to stdout, intercepting the output. If "returns_output" is True, the function will return a generator yielding the printed lines instead of the return values. The decorator literally hijack sys.stdout during each function execution, so be careful with what you apply it to. >>> def numbers(): print "42" print "1984" ... >>> numbers() 42 1984 >>> mute()(numbers)() >>> list(mute(True)(numbers)()) ['42', '1984'] """ def decorator(func): @wraps(func) def wrapper(*args, **kwargs): saved_stdout = sys.stdout sys.stdout = StringIO() try: out = func(*args, **kwargs) if returns_output: out = isplit(sys.stdout.getvalue().strip()) finally: sys.stdout = saved_stdout return out return wrapper return decorator def get_article(title, slug, content, lang, extra_metadata=None): metadata = {'slug': slug, 'title': title, 'lang': lang} if extra_metadata is not None: metadata.update(extra_metadata) return Article(content, metadata=metadata) def skipIfNoExecutable(executable): """Skip test if `executable` is not found Tries to run `executable` with subprocess to make sure it's in the path, and skips the tests if not found (if subprocess raises a `OSError`). """ with open(os.devnull, 'w') as fnull: try: res = subprocess.call(executable, stdout=fnull, stderr=fnull) except OSError: res = None if res is None: return unittest.skip('{0} executable not found'.format(executable)) return lambda func: func def module_exists(module_name): """Test if a module is importable.""" try: __import__(module_name) except ImportError: return False else: return True def locale_available(locale_): old_locale = locale.setlocale(locale.LC_TIME) try: locale.setlocale(locale.LC_TIME, str(locale_)) except locale.Error: return False else: locale.setlocale(locale.LC_TIME, old_locale) return True def get_settings(**kwargs): """Provide tweaked setting dictionaries for testing Set keyword arguments to override specific settings. """ settings = DEFAULT_CONFIG.copy() for key, value in kwargs.items(): settings[key] = value return settings class LogCountHandler(BufferingHandler): """Capturing and counting logged messages.""" def __init__(self, capacity=1000): logging.handlers.BufferingHandler.__init__(self, capacity) def count_logs(self, msg=None, level=None): return len([ l for l in self.buffer if (msg is None or re.match(msg, l.getMessage())) and (level is None or l.levelno == level) ]) class LoggedTestCase(unittest.TestCase): """A test case that captures log messages.""" def setUp(self): super(LoggedTestCase, self).setUp() self._logcount_handler = LogCountHandler() logging.getLogger().addHandler(self._logcount_handler) def tearDown(self): logging.getLogger().removeHandler(self._logcount_handler) super(LoggedTestCase, self).tearDown() def assertLogCountEqual(self, count=None, msg=None, **kwargs): actual = self._logcount_handler.count_logs(msg=msg, **kwargs) self.assertEqual( actual, count, msg='expected {} occurrences of {!r}, but found {}'.format( count, msg, actual)) pelican-3.7.1/pelican/tests/test_cache.py000066400000000000000000000263741303525152100203770ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import os from shutil import rmtree from tempfile import mkdtemp from pelican.generators import ArticlesGenerator, PagesGenerator from pelican.tests.support import get_settings, unittest try: from unittest.mock import MagicMock except ImportError: try: from mock import MagicMock except ImportError: MagicMock = False CUR_DIR = os.path.dirname(__file__) CONTENT_DIR = os.path.join(CUR_DIR, 'content') class TestCache(unittest.TestCase): def setUp(self): self.temp_cache = mkdtemp(prefix='pelican_cache.') def tearDown(self): rmtree(self.temp_cache) def _get_cache_enabled_settings(self): settings = get_settings(filenames={}) settings['CACHE_CONTENT'] = True settings['LOAD_CONTENT_CACHE'] = True settings['CACHE_PATH'] = self.temp_cache return settings def test_generator_caching(self): """Test that cached and uncached content is same in generator level""" settings = self._get_cache_enabled_settings() settings['CONTENT_CACHING_LAYER'] = 'generator' settings['PAGE_PATHS'] = ['TestPages'] settings['DEFAULT_DATE'] = (1970, 1, 1) settings['READERS'] = {'asc': None} def sorted_titles(items): return sorted(item.title for item in items) # Articles generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() uncached_articles = sorted_titles(generator.articles) uncached_drafts = sorted_titles(generator.drafts) generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() cached_articles = sorted_titles(generator.articles) cached_drafts = sorted_titles(generator.drafts) self.assertEqual(uncached_articles, cached_articles) self.assertEqual(uncached_drafts, cached_drafts) # Pages generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() uncached_pages = sorted_titles(generator.pages) uncached_hidden_pages = sorted_titles(generator.hidden_pages) generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() cached_pages = sorted_titles(generator.pages) cached_hidden_pages = sorted_titles(generator.hidden_pages) self.assertEqual(uncached_pages, cached_pages) self.assertEqual(uncached_hidden_pages, cached_hidden_pages) def test_reader_caching(self): """Test that cached and uncached content is same in reader level""" settings = self._get_cache_enabled_settings() settings['CONTENT_CACHING_LAYER'] = 'reader' settings['PAGE_PATHS'] = ['TestPages'] settings['DEFAULT_DATE'] = (1970, 1, 1) settings['READERS'] = {'asc': None} def sorted_titles(items): return sorted(item.title for item in items) # Articles generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() uncached_articles = sorted_titles(generator.articles) uncached_drafts = sorted_titles(generator.drafts) generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() cached_articles = sorted_titles(generator.articles) cached_drafts = sorted_titles(generator.drafts) self.assertEqual(uncached_articles, cached_articles) self.assertEqual(uncached_drafts, cached_drafts) # Pages generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() uncached_pages = sorted_titles(generator.pages) uncached_hidden_pages = sorted_titles(generator.hidden_pages) generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() cached_pages = sorted_titles(generator.pages) cached_hidden_pages = sorted_titles(generator.hidden_pages) self.assertEqual(uncached_pages, cached_pages) self.assertEqual(uncached_hidden_pages, cached_hidden_pages) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_article_object_caching(self): """Test Article objects caching at the generator level""" settings = self._get_cache_enabled_settings() settings['CONTENT_CACHING_LAYER'] = 'generator' settings['DEFAULT_DATE'] = (1970, 1, 1) settings['READERS'] = {'asc': None} generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator, '_cache')) generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() """ 6 files don't get cached because they were not valid - article_with_attributes_containing_double_quotes.html - article_with_comments.html - article_with_null_attributes.html - 2012-11-30_md_w_filename_meta#foo-bar.md - empty.md - empty_with_bom.md """ self.assertEqual(generator.readers.read_file.call_count, 6) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_article_reader_content_caching(self): """Test raw article content caching at the reader level""" settings = self._get_cache_enabled_settings() settings['READERS'] = {'asc': None} generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator.readers, '_cache')) generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) readers = generator.readers.readers for reader in readers.values(): reader.read = MagicMock() generator.generate_context() for reader in readers.values(): self.assertEqual(reader.read.call_count, 0) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_article_ignore_cache(self): """Test that all the articles are read again when not loading cache used in --ignore-cache or autoreload mode""" settings = self._get_cache_enabled_settings() settings['READERS'] = {'asc': None} generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() self.assertTrue(hasattr(generator, '_cache_open')) orig_call_count = generator.readers.read_file.call_count settings['LOAD_CONTENT_CACHE'] = False generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() self.assertEqual( generator.readers.read_file.call_count, orig_call_count) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_page_object_caching(self): """Test Page objects caching at the generator level""" settings = self._get_cache_enabled_settings() settings['CONTENT_CACHING_LAYER'] = 'generator' settings['PAGE_PATHS'] = ['TestPages'] settings['READERS'] = {'asc': None} generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator, '_cache')) generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() """ 1 File doesn't get cached because it was not valid - bad_page.rst """ self.assertEqual(generator.readers.read_file.call_count, 1) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_page_reader_content_caching(self): """Test raw page content caching at the reader level""" settings = self._get_cache_enabled_settings() settings['PAGE_PATHS'] = ['TestPages'] settings['READERS'] = {'asc': None} generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator.readers, '_cache')) generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) readers = generator.readers.readers for reader in readers.values(): reader.read = MagicMock() generator.generate_context() for reader in readers.values(): self.assertEqual(reader.read.call_count, 0) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_page_ignore_cache(self): """Test that all the pages are read again when not loading cache used in --ignore_cache or autoreload mode""" settings = self._get_cache_enabled_settings() settings['PAGE_PATHS'] = ['TestPages'] settings['READERS'] = {'asc': None} generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() self.assertTrue(hasattr(generator, '_cache_open')) orig_call_count = generator.readers.read_file.call_count settings['LOAD_CONTENT_CACHE'] = False generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() self.assertEqual( generator.readers.read_file.call_count, orig_call_count) pelican-3.7.1/pelican/tests/test_contents.py000066400000000000000000000700711303525152100211620ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals import locale import logging import os.path from posixpath import join as posix_join from sys import platform from jinja2.utils import generate_lorem_ipsum import six from pelican.contents import Article, Author, Category, Page, Static, Tag from pelican.settings import DEFAULT_CONFIG from pelican.signals import content_object_init from pelican.tests.support import LoggedTestCase, get_settings, unittest from pelican.utils import SafeDatetime, path_to_url, truncate_html_words # generate one paragraph, enclosed with

    TEST_CONTENT = str(generate_lorem_ipsum(n=1)) TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) class TestPage(LoggedTestCase): def setUp(self): super(TestPage, self).setUp() self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) self.page_kwargs = { 'content': TEST_CONTENT, 'context': { 'localsiteurl': '', }, 'metadata': { 'summary': TEST_SUMMARY, 'title': 'foo bar', 'author': Author('Blogger', DEFAULT_CONFIG), }, 'source_path': '/path/to/file/foo.ext' } self._disable_limit_filter() def tearDown(self): locale.setlocale(locale.LC_ALL, self.old_locale) self._enable_limit_filter() def _disable_limit_filter(self): from pelican.contents import logger logger.disable_filter() def _enable_limit_filter(self): from pelican.contents import logger logger.enable_filter() def test_use_args(self): # Creating a page with arguments passed to the constructor should use # them to initialise object's attributes. metadata = {'foo': 'bar', 'foobar': 'baz', 'title': 'foobar', } page = Page(TEST_CONTENT, metadata=metadata, context={'localsiteurl': ''}) for key, value in metadata.items(): self.assertTrue(hasattr(page, key)) self.assertEqual(value, getattr(page, key)) self.assertEqual(page.content, TEST_CONTENT) def test_mandatory_properties(self): # If the title is not set, must throw an exception. page = Page('content') with self.assertRaises(NameError): page.check_properties() page = Page('content', metadata={'title': 'foobar'}) page.check_properties() def test_summary_from_metadata(self): # If a :summary: metadata is given, it should be used page = Page(**self.page_kwargs) self.assertEqual(page.summary, TEST_SUMMARY) def test_summary_max_length(self): # If a :SUMMARY_MAX_LENGTH: is set, and there is no other summary, # generated summary should not exceed the given length. page_kwargs = self._copy_page_kwargs() settings = get_settings() page_kwargs['settings'] = settings del page_kwargs['metadata']['summary'] settings['SUMMARY_MAX_LENGTH'] = None page = Page(**page_kwargs) self.assertEqual(page.summary, TEST_CONTENT) settings['SUMMARY_MAX_LENGTH'] = 10 page = Page(**page_kwargs) self.assertEqual(page.summary, truncate_html_words(TEST_CONTENT, 10)) settings['SUMMARY_MAX_LENGTH'] = 0 page = Page(**page_kwargs) self.assertEqual(page.summary, '') def test_summary_get_summary_warning(self): """calling ._get_summary() should issue a warning""" page_kwargs = self._copy_page_kwargs() page = Page(**page_kwargs) self.assertEqual(page.summary, TEST_SUMMARY) self.assertEqual(page._get_summary(), TEST_SUMMARY) self.assertLogCountEqual( count=1, msg="_get_summary\(\) has been deprecated since 3\.6\.4\. " "Use the summary decorator instead", level=logging.WARNING) def test_slug(self): page_kwargs = self._copy_page_kwargs() settings = get_settings() page_kwargs['settings'] = settings settings['SLUGIFY_SOURCE'] = "title" page = Page(**page_kwargs) self.assertEqual(page.slug, 'foo-bar') settings['SLUGIFY_SOURCE'] = "basename" page = Page(**page_kwargs) self.assertEqual(page.slug, 'foo') def test_defaultlang(self): # If no lang is given, default to the default one. page = Page(**self.page_kwargs) self.assertEqual(page.lang, DEFAULT_CONFIG['DEFAULT_LANG']) # it is possible to specify the lang in the metadata infos self.page_kwargs['metadata'].update({'lang': 'fr', }) page = Page(**self.page_kwargs) self.assertEqual(page.lang, 'fr') def test_save_as(self): # If a lang is not the default lang, save_as should be set # accordingly. # if a title is defined, save_as should be set page = Page(**self.page_kwargs) self.assertEqual(page.save_as, "pages/foo-bar.html") # if a language is defined, save_as should include it accordingly self.page_kwargs['metadata'].update({'lang': 'fr', }) page = Page(**self.page_kwargs) self.assertEqual(page.save_as, "pages/foo-bar-fr.html") def test_metadata_url_format(self): # Arbitrary metadata should be passed through url_format() page = Page(**self.page_kwargs) self.assertIn('summary', page.url_format.keys()) page.metadata['directory'] = 'test-dir' page.settings = get_settings(PAGE_SAVE_AS='{directory}/{slug}') self.assertEqual(page.save_as, 'test-dir/foo-bar') def test_datetime(self): # If DATETIME is set to a tuple, it should be used to override LOCALE dt = SafeDatetime(2015, 9, 13) page_kwargs = self._copy_page_kwargs() # set its date to dt page_kwargs['metadata']['date'] = dt page = Page(**page_kwargs) # page.locale_date is a unicode string in both python2 and python3 dt_date = dt.strftime(DEFAULT_CONFIG['DEFAULT_DATE_FORMAT']) self.assertEqual(page.locale_date, dt_date) page_kwargs['settings'] = get_settings() # I doubt this can work on all platforms ... if platform == "win32": locale = 'jpn' else: locale = 'ja_JP.utf8' page_kwargs['settings']['DATE_FORMATS'] = {'jp': (locale, '%Y-%m-%d(%a)')} page_kwargs['metadata']['lang'] = 'jp' import locale as locale_module try: page = Page(**page_kwargs) self.assertEqual(page.locale_date, '2015-09-13(\u65e5)') except locale_module.Error: # The constructor of ``Page`` will try to set the locale to # ``ja_JP.utf8``. But this attempt will failed when there is no # such locale in the system. You can see which locales there are # in your system with ``locale -a`` command. # # Until we find some other method to test this functionality, we # will simply skip this test. unittest.skip("There is no locale %s in this system." % locale) def test_template(self): # Pages default to page, metadata overwrites default_page = Page(**self.page_kwargs) self.assertEqual('page', default_page.template) page_kwargs = self._copy_page_kwargs() page_kwargs['metadata']['template'] = 'custom' custom_page = Page(**page_kwargs) self.assertEqual('custom', custom_page.template) def _copy_page_kwargs(self): # make a deep copy of page_kwargs page_kwargs = dict([(key, self.page_kwargs[key]) for key in self.page_kwargs]) for key in page_kwargs: if not isinstance(page_kwargs[key], dict): break page_kwargs[key] = dict([(subkey, page_kwargs[key][subkey]) for subkey in page_kwargs[key]]) return page_kwargs def test_signal(self): def receiver_test_function(sender): receiver_test_function.has_been_called = True pass receiver_test_function.has_been_called = False content_object_init.connect(receiver_test_function) self.assertIn( receiver_test_function, content_object_init.receivers_for(Page)) self.assertFalse(receiver_test_function.has_been_called) Page(**self.page_kwargs) self.assertTrue(receiver_test_function.has_been_called) def test_get_content(self): # Test that the content is updated with the relative links to # filenames, tags and categories. settings = get_settings() args = self.page_kwargs.copy() args['settings'] = settings # Tag args['content'] = ('A simple test, with a ' 'link') page = Page(**args) content = page.get_content('http://notmyidea.org') self.assertEqual( content, ('A simple test, with a ' 'link')) # Category args['content'] = ('A simple test, with a ' 'link') page = Page(**args) content = page.get_content('http://notmyidea.org') self.assertEqual( content, ('A simple test, with a ' 'link')) def test_intrasite_link(self): # type does not take unicode in PY2 and bytes in PY3, which in # combination with unicode literals leads to following insane line: cls_name = '_DummyArticle' if six.PY3 else b'_DummyArticle' article = type(cls_name, (object,), {'url': 'article.html'}) args = self.page_kwargs.copy() args['settings'] = get_settings() args['source_path'] = 'content' args['context']['filenames'] = {'article.rst': article} # Classic intrasite link via filename args['content'] = ( 'A simple test, with a ' 'link' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'A simple test, with a ' 'link' ) # fragment args['content'] = ( 'A simple test, with a ' 'link' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'A simple test, with a ' 'link' ) # query args['content'] = ( 'A simple test, with a ' 'link' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'A simple test, with a ' 'link' ) # combination args['content'] = ( 'A simple test, with a ' 'link' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'A simple test, with a ' 'link' ) # also test for summary in metadata args['metadata']['summary'] = ( 'A simple summary test, with a ' 'link' ) args['context']['localsiteurl'] = 'http://notmyidea.org' p = Page(**args) self.assertEqual( p.summary, 'A simple summary test, with a ' 'link' ) def test_intrasite_link_more(self): # type does not take unicode in PY2 and bytes in PY3, which in # combination with unicode literals leads to following insane line: cls_name = '_DummyAsset' if six.PY3 else b'_DummyAsset' args = self.page_kwargs.copy() args['settings'] = get_settings() args['source_path'] = 'content' args['context']['filenames'] = { 'images/poster.jpg': type( cls_name, (object,), {'url': 'images/poster.jpg'}), 'assets/video.mp4': type( cls_name, (object,), {'url': 'assets/video.mp4'}), 'images/graph.svg': type( cls_name, (object,), {'url': 'images/graph.svg'}), 'reference.rst': type( cls_name, (object,), {'url': 'reference.html'}), } # video.poster args['content'] = ( 'There is a video with poster ' '' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'There is a video with poster ' '' ) # object.data args['content'] = ( 'There is a svg object ' '' '' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'There is a svg object ' '' '' ) # blockquote.cite args['content'] = ( 'There is a blockquote with cite attribute ' '

    blah blah
    ' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'There is a blockquote with cite attribute ' '
    ' 'blah blah' '
    ' ) def test_intrasite_link_markdown_spaces(self): # Markdown introduces %20 instead of spaces, this tests that # we support markdown doing this. cls_name = '_DummyArticle' if six.PY3 else b'_DummyArticle' article = type(cls_name, (object,), {'url': 'article-spaces.html'}) args = self.page_kwargs.copy() args['settings'] = get_settings() args['source_path'] = 'content' args['context']['filenames'] = {'article spaces.rst': article} # An intrasite link via filename with %20 as a space args['content'] = ( 'A simple test, with a ' 'link' ) content = Page(**args).get_content('http://notmyidea.org') self.assertEqual( content, 'A simple test, with a ' 'link' ) def test_multiple_authors(self): """Test article with multiple authors.""" args = self.page_kwargs.copy() content = Page(**args) assert content.authors == [content.author] args['metadata'].pop('author') args['metadata']['authors'] = [Author('First Author', DEFAULT_CONFIG), Author('Second Author', DEFAULT_CONFIG)] content = Page(**args) assert content.authors assert content.author == content.authors[0] class TestArticle(TestPage): def test_template(self): # Articles default to article, metadata overwrites default_article = Article(**self.page_kwargs) self.assertEqual('article', default_article.template) article_kwargs = self._copy_page_kwargs() article_kwargs['metadata']['template'] = 'custom' custom_article = Article(**article_kwargs) self.assertEqual('custom', custom_article.template) def test_slugify_category_author(self): settings = get_settings() settings['SLUG_SUBSTITUTIONS'] = [('C#', 'csharp')] settings['ARTICLE_URL'] = '{author}/{category}/{slug}/' settings['ARTICLE_SAVE_AS'] = '{author}/{category}/{slug}/index.html' article_kwargs = self._copy_page_kwargs() article_kwargs['metadata']['author'] = Author("O'Brien", settings) article_kwargs['metadata']['category'] = Category( 'C# & stuff', settings) article_kwargs['metadata']['title'] = 'fnord' article_kwargs['settings'] = settings article = Article(**article_kwargs) self.assertEqual(article.url, 'obrien/csharp-stuff/fnord/') self.assertEqual( article.save_as, 'obrien/csharp-stuff/fnord/index.html') def test_slugify_with_author_substitutions(self): settings = get_settings() settings['AUTHOR_SUBSTITUTIONS'] = [ ('Alexander Todorov', 'atodorov', False), ('Krasimir Tsonev', 'krasimir', False), ] settings['ARTICLE_URL'] = 'blog/{author}/{slug}/' settings['ARTICLE_SAVE_AS'] = 'blog/{author}/{slug}/index.html' article_kwargs = self._copy_page_kwargs() article_kwargs['metadata']['author'] = Author('Alexander Todorov', settings) article_kwargs['metadata']['title'] = 'fnord' article_kwargs['settings'] = settings article = Article(**article_kwargs) self.assertEqual(article.url, 'blog/atodorov/fnord/') self.assertEqual(article.save_as, 'blog/atodorov/fnord/index.html') def test_slugify_category_with_dots(self): settings = get_settings() settings['CATEGORY_SUBSTITUTIONS'] = [('Fedora QA', 'fedora.qa', True)] settings['ARTICLE_URL'] = '{category}/{slug}/' article_kwargs = self._copy_page_kwargs() article_kwargs['metadata']['category'] = Category('Fedora QA', settings) article_kwargs['metadata']['title'] = 'This Week in Fedora QA' article_kwargs['settings'] = settings article = Article(**article_kwargs) self.assertEqual(article.url, 'fedora.qa/this-week-in-fedora-qa/') def test_slugify_tags_with_dots(self): settings = get_settings() settings['TAG_SUBSTITUTIONS'] = [('Fedora QA', 'fedora.qa', True)] settings['ARTICLE_URL'] = '{tag}/{slug}/' article_kwargs = self._copy_page_kwargs() article_kwargs['metadata']['tag'] = Tag('Fedora QA', settings) article_kwargs['metadata']['title'] = 'This Week in Fedora QA' article_kwargs['settings'] = settings article = Article(**article_kwargs) self.assertEqual(article.url, 'fedora.qa/this-week-in-fedora-qa/') class TestStatic(LoggedTestCase): def setUp(self): super(TestStatic, self).setUp() self.settings = get_settings( STATIC_SAVE_AS='{path}', STATIC_URL='{path}', PAGE_SAVE_AS=os.path.join('outpages', '{slug}.html'), PAGE_URL='outpages/{slug}.html') self.context = self.settings.copy() self.static = Static(content=None, metadata={}, settings=self.settings, source_path=posix_join('dir', 'foo.jpg'), context=self.context) self.context['filenames'] = {self.static.source_path: self.static} def tearDown(self): pass def test_attach_to_same_dir(self): """attach_to() overrides a static file's save_as and url. """ page = Page( content="fake page", metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'fakepage.md')) self.static.attach_to(page) expected_save_as = os.path.join('outpages', 'foo.jpg') self.assertEqual(self.static.save_as, expected_save_as) self.assertEqual(self.static.url, path_to_url(expected_save_as)) def test_attach_to_parent_dir(self): """attach_to() preserves dirs inside the linking document dir. """ page = Page(content="fake page", metadata={'title': 'fakepage'}, settings=self.settings, source_path='fakepage.md') self.static.attach_to(page) expected_save_as = os.path.join('outpages', 'dir', 'foo.jpg') self.assertEqual(self.static.save_as, expected_save_as) self.assertEqual(self.static.url, path_to_url(expected_save_as)) def test_attach_to_other_dir(self): """attach_to() ignores dirs outside the linking document dir. """ page = Page(content="fake page", metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'otherdir', 'fakepage.md')) self.static.attach_to(page) expected_save_as = os.path.join('outpages', 'foo.jpg') self.assertEqual(self.static.save_as, expected_save_as) self.assertEqual(self.static.url, path_to_url(expected_save_as)) def test_attach_to_ignores_subsequent_calls(self): """attach_to() does nothing when called a second time. """ page = Page(content="fake page", metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'fakepage.md')) self.static.attach_to(page) otherdir_settings = self.settings.copy() otherdir_settings.update(dict( PAGE_SAVE_AS=os.path.join('otherpages', '{slug}.html'), PAGE_URL='otherpages/{slug}.html')) otherdir_page = Page( content="other page", metadata={'title': 'otherpage'}, settings=otherdir_settings, source_path=os.path.join('dir', 'otherpage.md')) self.static.attach_to(otherdir_page) otherdir_save_as = os.path.join('otherpages', 'foo.jpg') self.assertNotEqual(self.static.save_as, otherdir_save_as) self.assertNotEqual(self.static.url, path_to_url(otherdir_save_as)) def test_attach_to_does_nothing_after_save_as_referenced(self): """attach_to() does nothing if the save_as was already referenced. (For example, by a {filename} link an a document processed earlier.) """ original_save_as = self.static.save_as page = Page( content="fake page", metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'fakepage.md')) self.static.attach_to(page) self.assertEqual(self.static.save_as, original_save_as) self.assertEqual(self.static.url, path_to_url(original_save_as)) def test_attach_to_does_nothing_after_url_referenced(self): """attach_to() does nothing if the url was already referenced. (For example, by a {filename} link an a document processed earlier.) """ original_url = self.static.url page = Page( content="fake page", metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'fakepage.md')) self.static.attach_to(page) self.assertEqual(self.static.save_as, self.static.source_path) self.assertEqual(self.static.url, original_url) def test_attach_to_does_not_override_an_override(self): """attach_to() does not override paths that were overridden elsewhere. (For example, by the user with EXTRA_PATH_METADATA) """ customstatic = Static( content=None, metadata=dict(save_as='customfoo.jpg', url='customfoo.jpg'), settings=self.settings, source_path=os.path.join('dir', 'foo.jpg'), context=self.settings.copy()) page = Page( content="fake page", metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'fakepage.md')) customstatic.attach_to(page) self.assertEqual(customstatic.save_as, 'customfoo.jpg') self.assertEqual(customstatic.url, 'customfoo.jpg') def test_attach_link_syntax(self): """{attach} link syntax triggers output path override & url replacement. """ html = 'link' page = Page( content=html, metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'otherdir', 'fakepage.md'), context=self.context) content = page.get_content('') self.assertNotEqual( content, html, "{attach} link syntax did not trigger URL replacement.") expected_save_as = os.path.join('outpages', 'foo.jpg') self.assertEqual(self.static.save_as, expected_save_as) self.assertEqual(self.static.url, path_to_url(expected_save_as)) def test_tag_link_syntax(self): "{tag} link syntax triggers url replacement." html = 'link' page = Page( content=html, metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'otherdir', 'fakepage.md'), context=self.context) content = page.get_content('') self.assertNotEqual(content, html) def test_category_link_syntax(self): "{category} link syntax triggers url replacement." html = 'link' page = Page( content=html, metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'otherdir', 'fakepage.md'), context=self.context) content = page.get_content('') self.assertNotEqual(content, html) def test_author_link_syntax(self): "{author} link syntax triggers url replacement." html = 'link' page = Page( content=html, metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'otherdir', 'fakepage.md'), context=self.context) content = page.get_content('') self.assertNotEqual(content, html) def test_index_link_syntax(self): "{index} link syntax triggers url replacement." html = 'link' page = Page( content=html, metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'otherdir', 'fakepage.md'), context=self.context) content = page.get_content('') self.assertNotEqual(content, html) expected_html = ('link') self.assertEqual(content, expected_html) def test_unknown_link_syntax(self): "{unknown} link syntax should trigger warning." html = 'link' page = Page(content=html, metadata={'title': 'fakepage'}, settings=self.settings, source_path=os.path.join('dir', 'otherdir', 'fakepage.md'), context=self.context) content = page.get_content('') self.assertEqual(content, html) self.assertLogCountEqual( count=1, msg="Replacement Indicator 'unknown' not recognized, " "skipping replacement", level=logging.WARNING) pelican-3.7.1/pelican/tests/test_generators.py000066400000000000000000000771211303525152100215010ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import locale import os from codecs import open from shutil import rmtree from tempfile import mkdtemp from pelican.generators import (ArticlesGenerator, Generator, PagesGenerator, StaticGenerator, TemplatePagesGenerator) from pelican.tests.support import get_settings, unittest from pelican.writers import Writer try: from unittest.mock import MagicMock except ImportError: try: from mock import MagicMock except ImportError: MagicMock = False CUR_DIR = os.path.dirname(__file__) CONTENT_DIR = os.path.join(CUR_DIR, 'content') class TestGenerator(unittest.TestCase): def setUp(self): self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) self.settings = get_settings() self.settings['READERS'] = {'asc': None} self.generator = Generator(self.settings.copy(), self.settings, CUR_DIR, self.settings['THEME'], None) def tearDown(self): locale.setlocale(locale.LC_ALL, self.old_locale) def test_include_path(self): self.settings['IGNORE_FILES'] = {'ignored1.rst', 'ignored2.rst'} filename = os.path.join(CUR_DIR, 'content', 'article.rst') include_path = self.generator._include_path self.assertTrue(include_path(filename)) self.assertTrue(include_path(filename, extensions=('rst',))) self.assertFalse(include_path(filename, extensions=('md',))) ignored_file = os.path.join(CUR_DIR, 'content', 'ignored1.rst') self.assertFalse(include_path(ignored_file)) def test_get_files_exclude(self): """Test that Generator.get_files() properly excludes directories. """ # We use our own Generator so we can give it our own content path generator = Generator( context=self.settings.copy(), settings=self.settings, path=os.path.join(CUR_DIR, 'nested_content'), theme=self.settings['THEME'], output_path=None) filepaths = generator.get_files(paths=['maindir']) found_files = {os.path.basename(f) for f in filepaths} expected_files = {'maindir.md', 'subdir.md'} self.assertFalse( expected_files - found_files, "get_files() failed to find one or more files") # Test string as `paths` argument rather than list filepaths = generator.get_files(paths='maindir') found_files = {os.path.basename(f) for f in filepaths} expected_files = {'maindir.md', 'subdir.md'} self.assertFalse( expected_files - found_files, "get_files() failed to find one or more files") filepaths = generator.get_files(paths=[''], exclude=['maindir']) found_files = {os.path.basename(f) for f in filepaths} self.assertNotIn( 'maindir.md', found_files, "get_files() failed to exclude a top-level directory") self.assertNotIn( 'subdir.md', found_files, "get_files() failed to exclude a subdir of an excluded directory") filepaths = generator.get_files( paths=[''], exclude=[os.path.join('maindir', 'subdir')]) found_files = {os.path.basename(f) for f in filepaths} self.assertNotIn( 'subdir.md', found_files, "get_files() failed to exclude a subdirectory") filepaths = generator.get_files(paths=[''], exclude=['subdir']) found_files = {os.path.basename(f) for f in filepaths} self.assertIn( 'subdir.md', found_files, "get_files() excluded a subdirectory by name, ignoring its path") def test_custom_jinja_environment(self): """ Test that setting the JINJA_ENVIRONMENT properly gets set from the settings config """ settings = get_settings() comment_start_string = 'abc' comment_end_string = '/abc' settings['JINJA_ENVIRONMENT'] = { 'comment_start_string': comment_start_string, 'comment_end_string': comment_end_string } generator = Generator(settings.copy(), settings, CUR_DIR, settings['THEME'], None) self.assertEqual(comment_start_string, generator.env.comment_start_string) self.assertEqual(comment_end_string, generator.env.comment_end_string) class TestArticlesGenerator(unittest.TestCase): @classmethod def setUpClass(cls): settings = get_settings(filenames={}) settings['DEFAULT_CATEGORY'] = 'Default' settings['DEFAULT_DATE'] = (1970, 1, 1) settings['READERS'] = {'asc': None} settings['CACHE_CONTENT'] = False cls.generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) cls.generator.generate_context() cls.articles = cls.distill_articles(cls.generator.articles) def setUp(self): self.temp_cache = mkdtemp(prefix='pelican_cache.') def tearDown(self): rmtree(self.temp_cache) @staticmethod def distill_articles(articles): return [[article.title, article.status, article.category.name, article.template] for article in articles] @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_generate_feeds(self): settings = get_settings() settings['CACHE_PATH'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, path=None, theme=settings['THEME'], output_path=None) writer = MagicMock() generator.generate_feeds(writer) writer.write_feed.assert_called_with([], settings, 'feeds/all.atom.xml') generator = ArticlesGenerator( context=settings, settings=get_settings(FEED_ALL_ATOM=None), path=None, theme=settings['THEME'], output_path=None) writer = MagicMock() generator.generate_feeds(writer) self.assertFalse(writer.write_feed.called) def test_generate_context(self): articles_expected = [ ['Article title', 'published', 'Default', 'article'], ['Article with markdown and summary metadata multi', 'published', 'Default', 'article'], ['Article with markdown and summary metadata single', 'published', 'Default', 'article'], ['Article with markdown containing footnotes', 'published', 'Default', 'article'], ['Article with template', 'published', 'Default', 'custom'], ['Rst with filename metadata', 'published', 'yeah', 'article'], ['Test Markdown extensions', 'published', 'Default', 'article'], ['Test markdown File', 'published', 'test', 'article'], ['Test md File', 'published', 'test', 'article'], ['Test mdown File', 'published', 'test', 'article'], ['Test metadata duplicates', 'published', 'test', 'article'], ['Test mkd File', 'published', 'test', 'article'], ['This is a super article !', 'published', 'Yeah', 'article'], ['This is a super article !', 'published', 'Yeah', 'article'], ['Article with Nonconformant HTML meta tags', 'published', 'Default', 'article'], ['This is a super article !', 'published', 'yeah', 'article'], ['This is a super article !', 'published', 'yeah', 'article'], ['This is a super article !', 'published', 'yeah', 'article'], ['This is a super article !', 'published', 'Default', 'article'], ['This is an article with category !', 'published', 'yeah', 'article'], ['This is an article with multiple authors!', 'published', 'Default', 'article'], ['This is an article with multiple authors!', 'published', 'Default', 'article'], ['This is an article with multiple authors in list format!', 'published', 'Default', 'article'], ['This is an article with multiple authors in lastname, ' 'firstname format!', 'published', 'Default', 'article'], ['This is an article without category !', 'published', 'Default', 'article'], ['This is an article without category !', 'published', 'TestCategory', 'article'], ['An Article With Code Block To Test Typogrify Ignore', 'published', 'Default', 'article'], ['マックOS X 10.8でパイソンとVirtualenvをインストールと設定', 'published', '指導書', 'article'], ] self.assertEqual(sorted(articles_expected), sorted(self.articles)) def test_generate_categories(self): # test for name # categories are grouped by slug; if two categories have the same slug # but different names they will be grouped together, the first one in # terms of process order will define the name for that category categories = [cat.name for cat, _ in self.generator.categories] categories_alternatives = ( sorted(['Default', 'TestCategory', 'Yeah', 'test', '指導書']), sorted(['Default', 'TestCategory', 'yeah', 'test', '指導書']), ) self.assertIn(sorted(categories), categories_alternatives) # test for slug categories = [cat.slug for cat, _ in self.generator.categories] categories_expected = ['default', 'testcategory', 'yeah', 'test', 'zhi-dao-shu'] self.assertEqual(sorted(categories), sorted(categories_expected)) def test_do_not_use_folder_as_category(self): settings = get_settings(filenames={}) settings['DEFAULT_CATEGORY'] = 'Default' settings['DEFAULT_DATE'] = (1970, 1, 1) settings['USE_FOLDER_AS_CATEGORY'] = False settings['CACHE_PATH'] = self.temp_cache settings['READERS'] = {'asc': None} settings['filenames'] = {} generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() # test for name # categories are grouped by slug; if two categories have the same slug # but different names they will be grouped together, the first one in # terms of process order will define the name for that category categories = [cat.name for cat, _ in generator.categories] categories_alternatives = ( sorted(['Default', 'Yeah', 'test', '指導書']), sorted(['Default', 'yeah', 'test', '指導書']), ) self.assertIn(sorted(categories), categories_alternatives) # test for slug categories = [cat.slug for cat, _ in generator.categories] categories_expected = ['default', 'yeah', 'test', 'zhi-dao-shu'] self.assertEqual(sorted(categories), sorted(categories_expected)) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_direct_templates_save_as_default(self): settings = get_settings(filenames={}) settings['CACHE_PATH'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, path=None, theme=settings['THEME'], output_path=None) write = MagicMock() generator.generate_direct_templates(write) write.assert_called_with("archives.html", generator.get_template("archives"), settings, blog=True, paginated={}, page_name='archives') @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_direct_templates_save_as_modified(self): settings = get_settings() settings['DIRECT_TEMPLATES'] = ['archives'] settings['ARCHIVES_SAVE_AS'] = 'archives/index.html' settings['CACHE_PATH'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, path=None, theme=settings['THEME'], output_path=None) write = MagicMock() generator.generate_direct_templates(write) write.assert_called_with("archives/index.html", generator.get_template("archives"), settings, blog=True, paginated={}, page_name='archives/index') @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_direct_templates_save_as_false(self): settings = get_settings() settings['DIRECT_TEMPLATES'] = ['archives'] settings['ARCHIVES_SAVE_AS'] = False settings['CACHE_PATH'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, path=None, theme=settings['THEME'], output_path=None) write = MagicMock() generator.generate_direct_templates(write) self.assertEqual(write.call_count, 0) def test_per_article_template(self): """ Custom template articles get the field but standard/unset are None """ custom_template = ['Article with template', 'published', 'Default', 'custom'] standard_template = ['This is a super article !', 'published', 'Yeah', 'article'] self.assertIn(custom_template, self.articles) self.assertIn(standard_template, self.articles) @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_period_in_timeperiod_archive(self): """ Test that the context of a generated period_archive is passed 'period' : a tuple of year, month, day according to the time period """ old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) settings = get_settings(filenames={}) settings['YEAR_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/index.html' settings['CACHE_PATH'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() write = MagicMock() generator.generate_period_archives(write) dates = [d for d in generator.dates if d.date.year == 1970] self.assertEqual(len(dates), 1) # among other things it must have at least been called with this settings["period"] = (1970,) write.assert_called_with("posts/1970/index.html", generator.get_template("period_archives"), settings, blog=True, dates=dates) del settings["period"] settings['MONTH_ARCHIVE_SAVE_AS'] = \ 'posts/{date:%Y}/{date:%b}/index.html' generator = ArticlesGenerator( context=settings, settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() write = MagicMock() generator.generate_period_archives(write) dates = [d for d in generator.dates if d.date.year == 1970 and d.date.month == 1] self.assertEqual(len(dates), 1) settings["period"] = (1970, "January") # among other things it must have at least been called with this write.assert_called_with("posts/1970/Jan/index.html", generator.get_template("period_archives"), settings, blog=True, dates=dates) del settings["period"] settings['DAY_ARCHIVE_SAVE_AS'] = \ 'posts/{date:%Y}/{date:%b}/{date:%d}/index.html' generator = ArticlesGenerator( context=settings, settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() write = MagicMock() generator.generate_period_archives(write) dates = [ d for d in generator.dates if d.date.year == 1970 and d.date.month == 1 and d.date.day == 1 ] self.assertEqual(len(dates), 1) settings["period"] = (1970, "January", 1) # among other things it must have at least been called with this write.assert_called_with("posts/1970/Jan/01/index.html", generator.get_template("period_archives"), settings, blog=True, dates=dates) locale.setlocale(locale.LC_ALL, old_locale) def test_nonexistent_template(self): """Attempt to load a non-existent template""" settings = get_settings(filenames={}) generator = ArticlesGenerator( context=settings, settings=settings, path=None, theme=settings['THEME'], output_path=None) self.assertRaises(Exception, generator.get_template, "not_a_template") def test_generate_authors(self): """Check authors generation.""" authors = [author.name for author, _ in self.generator.authors] authors_expected = sorted( ['Alexis Métaireau', 'Author, First', 'Author, Second', 'First Author', 'Second Author']) self.assertEqual(sorted(authors), authors_expected) # test for slug authors = [author.slug for author, _ in self.generator.authors] authors_expected = ['alexis-metaireau', 'author-first', 'author-second', 'first-author', 'second-author'] self.assertEqual(sorted(authors), sorted(authors_expected)) def test_standard_metadata_in_default_metadata(self): settings = get_settings(filenames={}) settings['CACHE_CONTENT'] = False settings['DEFAULT_CATEGORY'] = 'Default' settings['DEFAULT_DATE'] = (1970, 1, 1) settings['DEFAULT_METADATA'] = (('author', 'Blogger'), # category will be ignored in favor of # DEFAULT_CATEGORY ('category', 'Random'), ('tags', 'general, untagged')) generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() authors = sorted([author.name for author, _ in generator.authors]) authors_expected = sorted(['Alexis Métaireau', 'Blogger', 'Author, First', 'Author, Second', 'First Author', 'Second Author']) self.assertEqual(authors, authors_expected) categories = sorted([category.name for category, _ in generator.categories]) categories_expected = [ sorted(['Default', 'TestCategory', 'yeah', 'test', '指導書']), sorted(['Default', 'TestCategory', 'Yeah', 'test', '指導書'])] self.assertIn(categories, categories_expected) tags = sorted([tag.name for tag in generator.tags]) tags_expected = sorted(['bar', 'foo', 'foobar', 'general', 'untagged', 'パイソン', 'マック']) self.assertEqual(tags, tags_expected) def test_article_order_by(self): settings = get_settings(filenames={}) settings['DEFAULT_CATEGORY'] = 'Default' settings['DEFAULT_DATE'] = (1970, 1, 1) settings['ARTICLE_ORDER_BY'] = 'title' generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() expected = [ 'An Article With Code Block To Test Typogrify Ignore', 'Article title', 'Article with Nonconformant HTML meta tags', 'Article with markdown and summary metadata multi', 'Article with markdown and summary metadata single', 'Article with markdown containing footnotes', 'Article with template', 'Rst with filename metadata', 'Test Markdown extensions', 'Test markdown File', 'Test md File', 'Test mdown File', 'Test metadata duplicates', 'Test mkd File', 'This is a super article !', 'This is a super article !', 'This is a super article !', 'This is a super article !', 'This is a super article !', 'This is a super article !', 'This is an article with category !', ('This is an article with multiple authors in lastname, ' 'firstname format!'), 'This is an article with multiple authors in list format!', 'This is an article with multiple authors!', 'This is an article with multiple authors!', 'This is an article without category !', 'This is an article without category !', 'マックOS X 10.8でパイソンとVirtualenvをインストールと設定'] articles = [article.title for article in generator.articles] self.assertEqual(articles, expected) # reversed title settings = get_settings(filenames={}) settings['DEFAULT_CATEGORY'] = 'Default' settings['DEFAULT_DATE'] = (1970, 1, 1) settings['ARTICLE_ORDER_BY'] = 'reversed-title' generator = ArticlesGenerator( context=settings.copy(), settings=settings, path=CONTENT_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() articles = [article.title for article in generator.articles] self.assertEqual(articles, list(reversed(expected))) class TestPageGenerator(unittest.TestCase): # Note: Every time you want to test for a new field; Make sure the test # pages in "TestPages" have all the fields Add it to distilled in # distill_pages Then update the assertEqual in test_generate_context # to match expected def setUp(self): self.temp_cache = mkdtemp(prefix='pelican_cache.') def tearDown(self): rmtree(self.temp_cache) def distill_pages(self, pages): return [[page.title, page.status, page.template] for page in pages] def test_generate_context(self): settings = get_settings(filenames={}) settings['CACHE_PATH'] = self.temp_cache settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR settings['DEFAULT_DATE'] = (1970, 1, 1) generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() pages = self.distill_pages(generator.pages) hidden_pages = self.distill_pages(generator.hidden_pages) pages_expected = [ ['This is a test page', 'published', 'page'], ['This is a markdown test page', 'published', 'page'], ['This is a test page with a preset template', 'published', 'custom'], ['Page with a bunch of links', 'published', 'page'], ['A Page (Test) for sorting', 'published', 'page'], ] hidden_pages_expected = [ ['This is a test hidden page', 'hidden', 'page'], ['This is a markdown test hidden page', 'hidden', 'page'], ['This is a test hidden page with a custom template', 'hidden', 'custom'] ] self.assertEqual(sorted(pages_expected), sorted(pages)) self.assertEqual( sorted(pages_expected), sorted(self.distill_pages(generator.context['pages']))) self.assertEqual(sorted(hidden_pages_expected), sorted(hidden_pages)) self.assertEqual( sorted(hidden_pages_expected), sorted(self.distill_pages(generator.context['hidden_pages']))) def test_generate_sorted(self): settings = get_settings(filenames={}) settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR settings['CACHE_PATH'] = self.temp_cache settings['DEFAULT_DATE'] = (1970, 1, 1) # default sort (filename) pages_expected_sorted_by_filename = [ ['This is a test page', 'published', 'page'], ['This is a markdown test page', 'published', 'page'], ['A Page (Test) for sorting', 'published', 'page'], ['Page with a bunch of links', 'published', 'page'], ['This is a test page with a preset template', 'published', 'custom'], ] generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() pages = self.distill_pages(generator.pages) self.assertEqual(pages_expected_sorted_by_filename, pages) # sort by title pages_expected_sorted_by_title = [ ['A Page (Test) for sorting', 'published', 'page'], ['Page with a bunch of links', 'published', 'page'], ['This is a markdown test page', 'published', 'page'], ['This is a test page', 'published', 'page'], ['This is a test page with a preset template', 'published', 'custom'], ] settings['PAGE_ORDER_BY'] = 'title' generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() pages = self.distill_pages(generator.pages) self.assertEqual(pages_expected_sorted_by_title, pages) # sort by title reversed pages_expected_sorted_by_title = [ ['This is a test page with a preset template', 'published', 'custom'], ['This is a test page', 'published', 'page'], ['This is a markdown test page', 'published', 'page'], ['Page with a bunch of links', 'published', 'page'], ['A Page (Test) for sorting', 'published', 'page'], ] settings['PAGE_ORDER_BY'] = 'reversed-title' generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() pages = self.distill_pages(generator.pages) self.assertEqual(pages_expected_sorted_by_title, pages) def test_tag_and_category_links_on_generated_pages(self): """ Test to ensure links of the form {tag}tagname and {category}catname are generated correctly on pages """ settings = get_settings(filenames={}) settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR settings['CACHE_PATH'] = self.temp_cache settings['DEFAULT_DATE'] = (1970, 1, 1) generator = PagesGenerator( context=settings.copy(), settings=settings, path=CUR_DIR, theme=settings['THEME'], output_path=None) generator.generate_context() pages_by_title = {p.title: p.content for p in generator.pages} test_content = pages_by_title['Page with a bunch of links'] self.assertIn('', test_content) self.assertIn('', test_content) class TestTemplatePagesGenerator(unittest.TestCase): TEMPLATE_CONTENT = "foo: {{ foo }}" def setUp(self): self.temp_content = mkdtemp(prefix='pelicantests.') self.temp_output = mkdtemp(prefix='pelicantests.') self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) def tearDown(self): rmtree(self.temp_content) rmtree(self.temp_output) locale.setlocale(locale.LC_ALL, self.old_locale) def test_generate_output(self): settings = get_settings() settings['STATIC_PATHS'] = ['static'] settings['TEMPLATE_PAGES'] = { 'template/source.html': 'generated/file.html' } generator = TemplatePagesGenerator( context={'foo': 'bar'}, settings=settings, path=self.temp_content, theme='', output_path=self.temp_output) # create a dummy template file template_dir = os.path.join(self.temp_content, 'template') template_path = os.path.join(template_dir, 'source.html') os.makedirs(template_dir) with open(template_path, 'w') as template_file: template_file.write(self.TEMPLATE_CONTENT) writer = Writer(self.temp_output, settings=settings) generator.generate_output(writer) output_path = os.path.join(self.temp_output, 'generated', 'file.html') # output file has been generated self.assertTrue(os.path.exists(output_path)) # output content is correct with open(output_path, 'r') as output_file: self.assertEqual(output_file.read(), 'foo: bar') class TestStaticGenerator(unittest.TestCase): def setUp(self): self.content_path = os.path.join(CUR_DIR, 'mixed_content') def test_static_excludes(self): """Test that StaticGenerator respects STATIC_EXCLUDES. """ settings = get_settings( STATIC_EXCLUDES=['subdir'], PATH=self.content_path, STATIC_PATHS=[''], filenames={}) context = settings.copy() StaticGenerator( context=context, settings=settings, path=settings['PATH'], output_path=None, theme=settings['THEME']).generate_context() staticnames = [os.path.basename(c.source_path) for c in context['staticfiles']] self.assertNotIn( 'subdir_fake_image.jpg', staticnames, "StaticGenerator processed a file in a STATIC_EXCLUDES directory") self.assertIn( 'fake_image.jpg', staticnames, "StaticGenerator skipped a file that it should have included") def test_static_exclude_sources(self): """Test that StaticGenerator respects STATIC_EXCLUDE_SOURCES. """ settings = get_settings( STATIC_EXCLUDE_SOURCES=True, PATH=self.content_path, PAGE_PATHS=[''], STATIC_PATHS=[''], CACHE_CONTENT=False, filenames={}) context = settings.copy() for generator_class in (PagesGenerator, StaticGenerator): generator_class( context=context, settings=settings, path=settings['PATH'], output_path=None, theme=settings['THEME']).generate_context() staticnames = [os.path.basename(c.source_path) for c in context['staticfiles']] self.assertFalse( any(name.endswith(".md") for name in staticnames), "STATIC_EXCLUDE_SOURCES=True failed to exclude a markdown file") settings.update(STATIC_EXCLUDE_SOURCES=False) context = settings.copy() context['filenames'] = {} for generator_class in (PagesGenerator, StaticGenerator): generator_class( context=context, settings=settings, path=settings['PATH'], output_path=None, theme=settings['THEME']).generate_context() staticnames = [os.path.basename(c.source_path) for c in context['staticfiles']] self.assertTrue( any(name.endswith(".md") for name in staticnames), "STATIC_EXCLUDE_SOURCES=False failed to include a markdown file") pelican-3.7.1/pelican/tests/test_importer.py000066400000000000000000000370521303525152100211700ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import locale import os import re from codecs import open from pelican.tests.support import (mute, skipIfNoExecutable, temporary_folder, unittest) from pelican.tools.pelican_import import (build_header, build_markdown_header, decode_wp_content, download_attachments, fields2pelican, get_attachments, wp2fields) from pelican.utils import path_to_file_url, slugify CUR_DIR = os.path.abspath(os.path.dirname(__file__)) WORDPRESS_XML_SAMPLE = os.path.join(CUR_DIR, 'content', 'wordpressexport.xml') WORDPRESS_ENCODED_CONTENT_SAMPLE = os.path.join(CUR_DIR, 'content', 'wordpress_content_encoded') WORDPRESS_DECODED_CONTENT_SAMPLE = os.path.join(CUR_DIR, 'content', 'wordpress_content_decoded') try: from bs4 import BeautifulSoup except ImportError: BeautifulSoup = False # NOQA try: import bs4.builder._lxml as LXML except ImportError: LXML = False @skipIfNoExecutable(['pandoc', '--version']) @unittest.skipUnless(BeautifulSoup, 'Needs BeautifulSoup module') class TestWordpressXmlImporter(unittest.TestCase): def setUp(self): self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) self.posts = list(wp2fields(WORDPRESS_XML_SAMPLE)) self.custposts = list(wp2fields(WORDPRESS_XML_SAMPLE, True)) def tearDown(self): locale.setlocale(locale.LC_ALL, self.old_locale) def test_ignore_empty_posts(self): self.assertTrue(self.posts) for (title, content, fname, date, author, categ, tags, status, kind, format) in self.posts: self.assertTrue(title.strip()) def test_recognise_page_kind(self): """ Check that we recognise pages in wordpress, as opposed to posts """ self.assertTrue(self.posts) # Collect (title, filename, kind) of non-empty posts recognised as page pages_data = [] for (title, content, fname, date, author, categ, tags, status, kind, format) in self.posts: if kind == 'page': pages_data.append((title, fname)) self.assertEqual(2, len(pages_data)) self.assertEqual(('Page', 'contact'), pages_data[0]) self.assertEqual(('Empty Page', 'empty'), pages_data[1]) def test_dirpage_directive_for_page_kind(self): silent_f2p = mute(True)(fields2pelican) test_post = filter(lambda p: p[0].startswith("Empty Page"), self.posts) with temporary_folder() as temp: fname = list(silent_f2p(test_post, 'markdown', temp, dirpage=True))[0] self.assertTrue(fname.endswith('pages%sempty.md' % os.path.sep)) def test_dircat(self): silent_f2p = mute(True)(fields2pelican) test_posts = [] for post in self.posts: # check post kind if len(post[5]) > 0: # Has a category test_posts.append(post) with temporary_folder() as temp: fnames = list(silent_f2p(test_posts, 'markdown', temp, dircat=True)) index = 0 for post in test_posts: name = post[2] category = slugify(post[5][0]) name += '.md' filename = os.path.join(category, name) out_name = fnames[index] self.assertTrue(out_name.endswith(filename)) index += 1 def test_unless_custom_post_all_items_should_be_pages_or_posts(self): self.assertTrue(self.posts) pages_data = [] for (title, content, fname, date, author, categ, tags, status, kind, format) in self.posts: if kind == 'page' or kind == 'article': pass else: pages_data.append((title, fname)) self.assertEqual(0, len(pages_data)) def test_recognise_custom_post_type(self): self.assertTrue(self.custposts) cust_data = [] for (title, content, fname, date, author, categ, tags, status, kind, format) in self.custposts: if kind == 'article' or kind == 'page': pass else: cust_data.append((title, kind)) self.assertEqual(3, len(cust_data)) self.assertEqual( ('A custom post in category 4', 'custom1'), cust_data[0]) self.assertEqual( ('A custom post in category 5', 'custom1'), cust_data[1]) self.assertEqual( ('A 2nd custom post type also in category 5', 'custom2'), cust_data[2]) def test_custom_posts_put_in_own_dir(self): silent_f2p = mute(True)(fields2pelican) test_posts = [] for post in self.custposts: # check post kind if post[8] == 'article' or post[8] == 'page': pass else: test_posts.append(post) with temporary_folder() as temp: fnames = list(silent_f2p(test_posts, 'markdown', temp, wp_custpost=True)) index = 0 for post in test_posts: name = post[2] kind = post[8] name += '.md' filename = os.path.join(kind, name) out_name = fnames[index] self.assertTrue(out_name.endswith(filename)) index += 1 def test_custom_posts_put_in_own_dir_and_catagory_sub_dir(self): silent_f2p = mute(True)(fields2pelican) test_posts = [] for post in self.custposts: # check post kind if post[8] == 'article' or post[8] == 'page': pass else: test_posts.append(post) with temporary_folder() as temp: fnames = list(silent_f2p(test_posts, 'markdown', temp, wp_custpost=True, dircat=True)) index = 0 for post in test_posts: name = post[2] kind = post[8] category = slugify(post[5][0]) name += '.md' filename = os.path.join(kind, category, name) out_name = fnames[index] self.assertTrue(out_name.endswith(filename)) index += 1 def test_wp_custpost_true_dirpage_false(self): # pages should only be put in their own directory when dirpage = True silent_f2p = mute(True)(fields2pelican) test_posts = [] for post in self.custposts: # check post kind if post[8] == 'page': test_posts.append(post) with temporary_folder() as temp: fnames = list(silent_f2p(test_posts, 'markdown', temp, wp_custpost=True, dirpage=False)) index = 0 for post in test_posts: name = post[2] name += '.md' filename = os.path.join('pages', name) out_name = fnames[index] self.assertFalse(out_name.endswith(filename)) def test_can_toggle_raw_html_code_parsing(self): def r(f): with open(f, encoding='utf-8') as infile: return infile.read() silent_f2p = mute(True)(fields2pelican) with temporary_folder() as temp: rst_files = (r(f) for f in silent_f2p(self.posts, 'markdown', temp)) self.assertTrue(any(' entities in " "the title. You can't miss them.") self.assertNotIn('&', title) def test_decode_wp_content_returns_empty(self): """ Check that given an empty string we return an empty string.""" self.assertEqual(decode_wp_content(""), "") def test_decode_wp_content(self): """ Check that we can decode a wordpress content string.""" with open(WORDPRESS_ENCODED_CONTENT_SAMPLE, 'r') as encoded_file: encoded_content = encoded_file.read() with open(WORDPRESS_DECODED_CONTENT_SAMPLE, 'r') as decoded_file: decoded_content = decoded_file.read() self.assertEqual( decode_wp_content(encoded_content, br=False), decoded_content) def test_preserve_verbatim_formatting(self): def r(f): with open(f, encoding='utf-8') as infile: return infile.read() silent_f2p = mute(True)(fields2pelican) test_post = filter( lambda p: p[0].startswith("Code in List"), self.posts) with temporary_folder() as temp: md = [r(f) for f in silent_f2p(test_post, 'markdown', temp)][0] self.assertTrue(re.search(r'\s+a = \[1, 2, 3\]', md)) self.assertTrue(re.search(r'\s+b = \[4, 5, 6\]', md)) for_line = re.search(r'\s+for i in zip\(a, b\):', md).group(0) print_line = re.search(r'\s+print i', md).group(0) self.assertTrue( for_line.rindex('for') < print_line.rindex('print')) def test_code_in_list(self): def r(f): with open(f, encoding='utf-8') as infile: return infile.read() silent_f2p = mute(True)(fields2pelican) test_post = filter( lambda p: p[0].startswith("Code in List"), self.posts) with temporary_folder() as temp: md = [r(f) for f in silent_f2p(test_post, 'markdown', temp)][0] sample_line = re.search(r'- This is a code sample', md).group(0) code_line = re.search(r'\s+a = \[1, 2, 3\]', md).group(0) self.assertTrue(sample_line.rindex('This') < code_line.rindex('a')) class TestBuildHeader(unittest.TestCase): def test_build_header(self): header = build_header('test', None, None, None, None, None) self.assertEqual(header, 'test\n####\n\n') def test_build_header_with_fields(self): header_data = [ 'Test Post', '2014-11-04', 'Alexis Métaireau', ['Programming'], ['Pelican', 'Python'], 'test-post', ] expected_docutils = '\n'.join([ 'Test Post', '#########', ':date: 2014-11-04', ':author: Alexis Métaireau', ':category: Programming', ':tags: Pelican, Python', ':slug: test-post', '\n', ]) expected_md = '\n'.join([ 'Title: Test Post', 'Date: 2014-11-04', 'Author: Alexis Métaireau', 'Category: Programming', 'Tags: Pelican, Python', 'Slug: test-post', '\n', ]) self.assertEqual(build_header(*header_data), expected_docutils) self.assertEqual(build_markdown_header(*header_data), expected_md) def test_build_header_with_east_asian_characters(self): header = build_header('これは広い幅の文字だけで構成されたタイトルです', None, None, None, None, None) self.assertEqual(header, ('これは広い幅の文字だけで構成されたタイトルです\n' '##############################################' '\n\n')) def test_galleries_added_to_header(self): header = build_header('test', None, None, None, None, None, attachments=['output/test1', 'output/test2']) self.assertEqual(header, ('test\n####\n' ':attachments: output/test1, ' 'output/test2\n\n')) def test_galleries_added_to_markdown_header(self): header = build_markdown_header('test', None, None, None, None, None, attachments=['output/test1', 'output/test2']) self.assertEqual( header, 'Title: test\nAttachments: output/test1, output/test2\n\n') @unittest.skipUnless(BeautifulSoup, 'Needs BeautifulSoup module') @unittest.skipUnless(LXML, 'Needs lxml module') class TestWordpressXMLAttachements(unittest.TestCase): def setUp(self): self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) self.attachments = get_attachments(WORDPRESS_XML_SAMPLE) def tearDown(self): locale.setlocale(locale.LC_ALL, self.old_locale) def test_recognise_attachments(self): self.assertTrue(self.attachments) self.assertTrue(len(self.attachments.keys()) == 3) def test_attachments_associated_with_correct_post(self): self.assertTrue(self.attachments) for post in self.attachments.keys(): if post is None: expected = ('https://upload.wikimedia.org/wikipedia/commons/' 'thumb/2/2c/Pelican_lakes_entrance02.jpg/' '240px-Pelican_lakes_entrance02.jpg') self.assertEqual(self.attachments[post][0], expected) elif post == 'with-excerpt': expected_invalid = ('http://thisurlisinvalid.notarealdomain/' 'not_an_image.jpg') expected_pelikan = ('http://en.wikipedia.org/wiki/' 'File:Pelikan_Walvis_Bay.jpg') self.assertEqual(self.attachments[post][0], expected_invalid) self.assertEqual(self.attachments[post][1], expected_pelikan) elif post == 'with-tags': expected_invalid = ('http://thisurlisinvalid.notarealdomain') self.assertEqual(self.attachments[post][0], expected_invalid) else: self.fail('all attachments should match to a ' 'filename or None, {}' .format(post)) def test_download_attachments(self): real_file = os.path.join(CUR_DIR, 'content/article.rst') good_url = path_to_file_url(real_file) bad_url = 'http://localhost:1/not_a_file.txt' silent_da = mute()(download_attachments) with temporary_folder() as temp: locations = list(silent_da(temp, [good_url, bad_url])) self.assertEqual(1, len(locations)) directory = locations[0] self.assertTrue( directory.endswith(os.path.join('content', 'article.rst')), directory) pelican-3.7.1/pelican/tests/test_paginator.py000066400000000000000000000035571303525152100213160ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals import locale from jinja2.utils import generate_lorem_ipsum from pelican.contents import Article, Author from pelican.paginator import Paginator from pelican.settings import DEFAULT_CONFIG from pelican.tests.support import get_settings, unittest # generate one paragraph, enclosed with

    TEST_CONTENT = str(generate_lorem_ipsum(n=1)) TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) class TestPage(unittest.TestCase): def setUp(self): super(TestPage, self).setUp() self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) self.page_kwargs = { 'content': TEST_CONTENT, 'context': { 'localsiteurl': '', }, 'metadata': { 'summary': TEST_SUMMARY, 'title': 'foo bar', }, 'source_path': '/path/to/file/foo.ext' } def tearDown(self): locale.setlocale(locale.LC_ALL, self.old_locale) def test_save_as_preservation(self): settings = get_settings() # fix up pagination rules from pelican.paginator import PaginationRule pagination_rules = [ PaginationRule(*r) for r in settings.get( 'PAGINATION_PATTERNS', DEFAULT_CONFIG['PAGINATION_PATTERNS'], ) ] settings['PAGINATION_PATTERNS'] = sorted( pagination_rules, key=lambda r: r[0], ) self.page_kwargs['metadata']['author'] = Author('Blogger', settings) object_list = [Article(**self.page_kwargs), Article(**self.page_kwargs)] paginator = Paginator('foobar.foo', object_list, settings) page = paginator.page(1) self.assertEqual(page.save_as, 'foobar.foo') pelican-3.7.1/pelican/tests/test_pelican.py000066400000000000000000000212061303525152100207340ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import collections import locale import logging import os import subprocess import sys from shutil import rmtree from tempfile import mkdtemp from pelican import Pelican from pelican.generators import StaticGenerator from pelican.settings import read_settings from pelican.tests.support import (LoggedTestCase, locale_available, mute, unittest) CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) SAMPLES_PATH = os.path.abspath(os.path.join( CURRENT_DIR, os.pardir, os.pardir, 'samples')) OUTPUT_PATH = os.path.abspath(os.path.join(CURRENT_DIR, 'output')) INPUT_PATH = os.path.join(SAMPLES_PATH, "content") SAMPLE_CONFIG = os.path.join(SAMPLES_PATH, "pelican.conf.py") SAMPLE_FR_CONFIG = os.path.join(SAMPLES_PATH, "pelican.conf_FR.py") def recursiveDiff(dcmp): diff = { 'diff_files': [os.path.join(dcmp.right, f) for f in dcmp.diff_files], 'left_only': [os.path.join(dcmp.right, f) for f in dcmp.left_only], 'right_only': [os.path.join(dcmp.right, f) for f in dcmp.right_only], } for sub_dcmp in dcmp.subdirs.values(): for k, v in recursiveDiff(sub_dcmp).items(): diff[k] += v return diff class TestPelican(LoggedTestCase): # general functional testing for pelican. Basically, this test case tries # to run pelican in different situations and see how it behaves def setUp(self): super(TestPelican, self).setUp() self.temp_path = mkdtemp(prefix='pelicantests.') self.temp_cache = mkdtemp(prefix='pelican_cache.') self.maxDiff = None self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) def tearDown(self): rmtree(self.temp_path) rmtree(self.temp_cache) locale.setlocale(locale.LC_ALL, self.old_locale) super(TestPelican, self).tearDown() def assertDirsEqual(self, left_path, right_path): out, err = subprocess.Popen( ['git', 'diff', '--no-ext-diff', '--exit-code', '-w', left_path, right_path], env={str('PAGER'): str('')}, stdout=subprocess.PIPE, stderr=subprocess.PIPE ).communicate() def ignorable_git_crlf_errors(line): # Work around for running tests on Windows for msg in [ "LF will be replaced by CRLF", "The file will have its original line endings"]: if msg in line: return True return False if err: err = '\n'.join([l for l in err.decode('utf8').splitlines() if not ignorable_git_crlf_errors(l)]) assert not out, out assert not err, err def test_order_of_generators(self): # StaticGenerator must run last, so it can identify files that # were skipped by the other generators, and so static files can # have their output paths overridden by the {attach} link syntax. pelican = Pelican(settings=read_settings(path=None)) generator_classes = pelican.get_generator_classes() self.assertTrue( generator_classes[-1] is StaticGenerator, "StaticGenerator must be the last generator, but it isn't!") self.assertIsInstance( generator_classes, collections.Sequence, "get_generator_classes() must return a Sequence to preserve order") def test_basic_generation_works(self): # when running pelican without settings, it should pick up the default # ones and generate correct output without raising any exception settings = read_settings(path=None, override={ 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'CACHE_PATH': self.temp_cache, 'LOCALE': locale.normalize('en_US'), }) pelican = Pelican(settings=settings) mute(True)(pelican.run)() self.assertDirsEqual( self.temp_path, os.path.join(OUTPUT_PATH, 'basic')) self.assertLogCountEqual( count=3, msg="Unable to find.*skipping url replacement", level=logging.WARNING) def test_custom_generation_works(self): # the same thing with a specified set of settings should work settings = read_settings(path=SAMPLE_CONFIG, override={ 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'CACHE_PATH': self.temp_cache, 'LOCALE': locale.normalize('en_US'), }) pelican = Pelican(settings=settings) mute(True)(pelican.run)() self.assertDirsEqual( self.temp_path, os.path.join(OUTPUT_PATH, 'custom')) @unittest.skipUnless(locale_available('fr_FR.UTF-8') or locale_available('French'), 'French locale needed') def test_custom_locale_generation_works(self): '''Test that generation with fr_FR.UTF-8 locale works''' if sys.platform == 'win32': our_locale = str('French') else: our_locale = str('fr_FR.UTF-8') settings = read_settings(path=SAMPLE_FR_CONFIG, override={ 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'CACHE_PATH': self.temp_cache, 'LOCALE': our_locale, }) pelican = Pelican(settings=settings) mute(True)(pelican.run)() self.assertDirsEqual( self.temp_path, os.path.join(OUTPUT_PATH, 'custom_locale')) def test_theme_static_paths_copy(self): # the same thing with a specified set of settings should work settings = read_settings(path=SAMPLE_CONFIG, override={ 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'CACHE_PATH': self.temp_cache, 'THEME_STATIC_PATHS': [os.path.join(SAMPLES_PATH, 'very'), os.path.join(SAMPLES_PATH, 'kinda'), os.path.join(SAMPLES_PATH, 'theme_standard')] }) pelican = Pelican(settings=settings) mute(True)(pelican.run)() theme_output = os.path.join(self.temp_path, 'theme') extra_path = os.path.join(theme_output, 'exciting', 'new', 'files') for file in ['a_stylesheet', 'a_template']: self.assertTrue(os.path.exists(os.path.join(theme_output, file))) for file in ['wow!', 'boom!', 'bap!', 'zap!']: self.assertTrue(os.path.exists(os.path.join(extra_path, file))) def test_theme_static_paths_copy_single_file(self): # the same thing with a specified set of settings should work settings = read_settings(path=SAMPLE_CONFIG, override={ 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'CACHE_PATH': self.temp_cache, 'THEME_STATIC_PATHS': [os.path.join(SAMPLES_PATH, 'theme_standard')] }) pelican = Pelican(settings=settings) mute(True)(pelican.run)() theme_output = os.path.join(self.temp_path, 'theme') for file in ['a_stylesheet', 'a_template']: self.assertTrue(os.path.exists(os.path.join(theme_output, file))) def test_write_only_selected(self): """Test that only the selected files are written""" settings = read_settings(path=None, override={ 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'CACHE_PATH': self.temp_cache, 'WRITE_SELECTED': [ os.path.join(self.temp_path, 'oh-yeah.html'), os.path.join(self.temp_path, 'categories.html'), ], 'LOCALE': locale.normalize('en_US'), }) pelican = Pelican(settings=settings) logger = logging.getLogger() orig_level = logger.getEffectiveLevel() logger.setLevel(logging.INFO) mute(True)(pelican.run)() logger.setLevel(orig_level) self.assertLogCountEqual( count=2, msg="Writing .*", level=logging.INFO) def test_md_extensions_deprecation(self): """Test that a warning is issued if MD_EXTENSIONS is used""" settings = read_settings(path=None, override={ 'PATH': INPUT_PATH, 'OUTPUT_PATH': self.temp_path, 'CACHE_PATH': self.temp_cache, 'MD_EXTENSIONS': {}, }) pelican = Pelican(settings=settings) mute(True)(pelican.run)() self.assertLogCountEqual( count=1, msg="MD_EXTENSIONS is deprecated use MARKDOWN instead.", level=logging.WARNING) pelican-3.7.1/pelican/tests/test_readers.py000066400000000000000000000641471303525152100207610ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import os import six from pelican import readers from pelican.tests.support import get_settings, unittest from pelican.utils import SafeDatetime try: from unittest.mock import patch except ImportError: try: from mock import patch except ImportError: patch = False CUR_DIR = os.path.dirname(__file__) CONTENT_PATH = os.path.join(CUR_DIR, 'content') def _path(*args): return os.path.join(CONTENT_PATH, *args) class ReaderTest(unittest.TestCase): def read_file(self, path, **kwargs): # Isolate from future API changes to readers.read_file r = readers.Readers(settings=get_settings(**kwargs)) return r.read_file(base_path=CONTENT_PATH, path=path) def assertDictHasSubset(self, dictionary, subset): for key, value in subset.items(): if key in dictionary: real_value = dictionary.get(key) self.assertEqual( value, real_value, 'Expected %s to have value %s, but was %s' % (key, value, real_value)) else: self.fail( 'Expected %s to have value %s, but was not in Dict' % (key, value)) class TestAssertDictHasSubset(ReaderTest): def setUp(self): self.dictionary = { 'key-a': 'val-a', 'key-b': 'val-b' } def tearDown(self): self.dictionary = None def test_subset(self): self.assertDictHasSubset(self.dictionary, {'key-a': 'val-a'}) def test_equal(self): self.assertDictHasSubset(self.dictionary, self.dictionary) def test_fail_not_set(self): six.assertRaisesRegex( self, AssertionError, 'Expected.*key-c.*to have value.*val-c.*but was not in Dict', self.assertDictHasSubset, self.dictionary, {'key-c': 'val-c'}) def test_fail_wrong_val(self): six.assertRaisesRegex( self, AssertionError, 'Expected .*key-a.* to have value .*val-b.* but was .*val-a.*', self.assertDictHasSubset, self.dictionary, {'key-a': 'val-b'}) class DefaultReaderTest(ReaderTest): def test_readfile_unknown_extension(self): with self.assertRaises(TypeError): self.read_file(path='article_with_metadata.unknownextension') @unittest.skipUnless(patch, 'Needs Mock module') def test_find_empty_alt(self): with patch('pelican.readers.logger') as log_mock: content = ['', ''] for tag in content: readers.find_empty_alt(tag, '/test/path') log_mock.warning.assert_called_with( u'Empty alt attribute for image %s in %s', u'test-image.png', u'/test/path', extra={'limit_msg': 'Other images have empty alt attributes'} ) class RstReaderTest(ReaderTest): def test_article_with_metadata(self): page = self.read_file(path='article_with_metadata.rst') expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'This is a super article !', 'summary': '

    Multi-line metadata should be' ' supported\nas well as inline' ' markup and stuff to "typogrify' '"...

    \n', 'date': SafeDatetime(2010, 12, 2, 10, 14), 'modified': SafeDatetime(2010, 12, 2, 10, 20), 'tags': ['foo', 'bar', 'foobar'], 'custom_field': 'http://notmyidea.org', } self.assertDictHasSubset(page.metadata, expected) def test_article_with_filename_metadata(self): page = self.read_file( path='2012-11-29_rst_w_filename_meta#foo-bar.rst', FILENAME_METADATA=None) expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'Rst with filename metadata', 'reader': 'rst', } self.assertDictHasSubset(page.metadata, expected) page = self.read_file( path='2012-11-29_rst_w_filename_meta#foo-bar.rst', FILENAME_METADATA='(?P\d{4}-\d{2}-\d{2}).*') expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'Rst with filename metadata', 'date': SafeDatetime(2012, 11, 29), 'reader': 'rst', } self.assertDictHasSubset(page.metadata, expected) page = self.read_file( path='2012-11-29_rst_w_filename_meta#foo-bar.rst', FILENAME_METADATA=( '(?P\d{4}-\d{2}-\d{2})' '_(?P.*)' '#(?P.*)-(?P.*)')) expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'Rst with filename metadata', 'date': SafeDatetime(2012, 11, 29), 'slug': 'rst_w_filename_meta', 'mymeta': 'foo', 'reader': 'rst', } self.assertDictHasSubset(page.metadata, expected) def test_article_metadata_key_lowercase(self): # Keys of metadata should be lowercase. reader = readers.RstReader(settings=get_settings()) content, metadata = reader.read( _path('article_with_uppercase_metadata.rst')) self.assertIn('category', metadata, 'Key should be lowercase.') self.assertEqual('Yeah', metadata.get('category'), 'Value keeps case.') def test_article_extra_path_metadata(self): input_with_metadata = '2012-11-29_rst_w_filename_meta#foo-bar.rst' page_metadata = self.read_file( path=input_with_metadata, FILENAME_METADATA=( '(?P\d{4}-\d{2}-\d{2})' '_(?P.*)' '#(?P.*)-(?P.*)' ), EXTRA_PATH_METADATA={ input_with_metadata: { 'key-1a': 'value-1a', 'key-1b': 'value-1b' } } ) expected_metadata = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'Rst with filename metadata', 'date': SafeDatetime(2012, 11, 29), 'slug': 'rst_w_filename_meta', 'mymeta': 'foo', 'reader': 'rst', 'key-1a': 'value-1a', 'key-1b': 'value-1b' } self.assertDictHasSubset(page_metadata.metadata, expected_metadata) input_file_path_without_metadata = 'article.rst' page_without_metadata = self.read_file( path=input_file_path_without_metadata, EXTRA_PATH_METADATA={ input_file_path_without_metadata: { 'author': 'Charlès Overwrite' } } ) expected_without_metadata = { 'category': 'misc', 'author': 'Charlès Overwrite', 'title': 'Article title', 'reader': 'rst', } self.assertDictHasSubset( page_without_metadata.metadata, expected_without_metadata) def test_article_extra_path_metadata_dont_overwrite(self): # EXTRA_PATH_METADATA['author'] should get ignored # since we don't overwrite already set values input_file_path = '2012-11-29_rst_w_filename_meta#foo-bar.rst' page = self.read_file( path=input_file_path, FILENAME_METADATA=( '(?P\d{4}-\d{2}-\d{2})' '_(?P.*)' '#(?P.*)-(?P.*)' ), EXTRA_PATH_METADATA={ input_file_path: { 'author': 'Charlès Overwrite', 'key-1b': 'value-1b' } } ) expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'Rst with filename metadata', 'date': SafeDatetime(2012, 11, 29), 'slug': 'rst_w_filename_meta', 'mymeta': 'foo', 'reader': 'rst', 'key-1b': 'value-1b' } self.assertDictHasSubset(page.metadata, expected) def test_typogrify(self): # if nothing is specified in the settings, the content should be # unmodified page = self.read_file(path='article.rst') expected = ('

    THIS is some content. With some stuff to ' '"typogrify"...

    \n

    Now with added ' 'support for ' 'TLA.

    \n') self.assertEqual(page.content, expected) try: # otherwise, typogrify should be applied page = self.read_file(path='article.rst', TYPOGRIFY=True) expected = ( '

    THIS is some content. ' 'With some stuff to “typogrify”…

    \n' '

    Now with added support for TLA.

    \n') self.assertEqual(page.content, expected) except ImportError: return unittest.skip('need the typogrify distribution') def test_typogrify_summary(self): # if nothing is specified in the settings, the summary should be # unmodified page = self.read_file(path='article_with_metadata.rst') expected = ('

    Multi-line metadata should be' ' supported\nas well as inline' ' markup and stuff to "typogrify' '"...

    \n') self.assertEqual(page.metadata['summary'], expected) try: # otherwise, typogrify should be applied page = self.read_file(path='article_with_metadata.rst', TYPOGRIFY=True) expected = ('

    Multi-line metadata should be' ' supported\nas well as inline' ' markup and stuff to “typogrify' '”…

    \n') self.assertEqual(page.metadata['summary'], expected) except ImportError: return unittest.skip('need the typogrify distribution') def test_typogrify_ignore_tags(self): try: # typogrify should be able to ignore user specified tags, # but tries to be clever with widont extension page = self.read_file(path='article.rst', TYPOGRIFY=True, TYPOGRIFY_IGNORE_TAGS=['p']) expected = ('

    THIS is some content. With some stuff to ' '"typogrify"...

    \n

    Now with added ' 'support for ' 'TLA.

    \n') self.assertEqual(page.content, expected) # typogrify should ignore code blocks by default because # code blocks are composed inside the pre tag page = self.read_file(path='article_with_code_block.rst', TYPOGRIFY=True) expected = ('

    An article with some code

    \n' '
    '
                            'x'
                            ' &'
                            ' y\n
    \n' '

    A block quote:

    \n
    \nx ' '& y
    \n' '

    Normal:\nx' ' &' ' y' '

    \n') self.assertEqual(page.content, expected) # instruct typogrify to also ignore blockquotes page = self.read_file(path='article_with_code_block.rst', TYPOGRIFY=True, TYPOGRIFY_IGNORE_TAGS=['blockquote']) expected = ('

    An article with some code

    \n' '
    '
                            'x'
                            ' &'
                            ' y\n
    \n' '

    A block quote:

    \n
    \nx ' '& y
    \n' '

    Normal:\nx' ' &' ' y' '

    \n') self.assertEqual(page.content, expected) except ImportError: return unittest.skip('need the typogrify distribution') except TypeError: return unittest.skip('need typogrify version 2.0.4 or later') def test_article_with_multiple_authors(self): page = self.read_file(path='article_with_multiple_authors.rst') expected = { 'authors': ['First Author', 'Second Author'] } self.assertDictHasSubset(page.metadata, expected) def test_article_with_multiple_authors_semicolon(self): page = self.read_file( path='article_with_multiple_authors_semicolon.rst') expected = { 'authors': ['Author, First', 'Author, Second'] } self.assertDictHasSubset(page.metadata, expected) def test_article_with_multiple_authors_list(self): page = self.read_file(path='article_with_multiple_authors_list.rst') expected = { 'authors': ['Author, First', 'Author, Second'] } self.assertDictHasSubset(page.metadata, expected) def test_default_date_formats(self): tuple_date = self.read_file(path='article.rst', DEFAULT_DATE=(2012, 5, 1)) string_date = self.read_file(path='article.rst', DEFAULT_DATE='2012-05-01') self.assertEqual(tuple_date.metadata['date'], string_date.metadata['date']) @unittest.skipUnless(readers.Markdown, "markdown isn't installed") class MdReaderTest(ReaderTest): def test_article_with_metadata(self): reader = readers.MarkdownReader(settings=get_settings()) content, metadata = reader.read( _path('article_with_md_extension.md')) expected = { 'category': 'test', 'title': 'Test md File', 'summary': '

    I have a lot to test

    ', 'date': SafeDatetime(2010, 12, 2, 10, 14), 'modified': SafeDatetime(2010, 12, 2, 10, 20), 'tags': ['foo', 'bar', 'foobar'], } self.assertDictHasSubset(metadata, expected) content, metadata = reader.read( _path('article_with_markdown_and_nonascii_summary.md')) expected = { 'title': 'マックOS X 10.8でパイソンとVirtualenvをインストールと設定', 'summary': '

    パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。

    ', 'category': '指導書', 'date': SafeDatetime(2012, 12, 20), 'modified': SafeDatetime(2012, 12, 22), 'tags': ['パイソン', 'マック'], 'slug': 'python-virtualenv-on-mac-osx-mountain-lion-10.8', } self.assertDictHasSubset(metadata, expected) def test_article_with_footnote(self): reader = readers.MarkdownReader(settings=get_settings()) content, metadata = reader.read( _path('article_with_markdown_and_footnote.md')) expected_content = ( '

    This is some content' '1' ' with some footnotes' '2

    \n' '
    \n' '
    \n
      \n
    1. \n' '

      Numbered footnote ' '

      \n' '
    2. \n
    3. \n' '

      Named footnote ' '

      \n' '
    4. \n
    \n
    ') expected_metadata = { 'title': 'Article with markdown containing footnotes', 'summary': ( '

    Summary with inline markup ' 'should be supported.

    '), 'date': SafeDatetime(2012, 10, 31), 'modified': SafeDatetime(2012, 11, 1), 'multiline': [ 'Line Metadata should be handle properly.', 'See syntax of Meta-Data extension of ' 'Python Markdown package:', 'If a line is indented by 4 or more spaces,', 'that line is assumed to be an additional line of the value', 'for the previous keyword.', 'A keyword may have as many lines as desired.', ] } self.assertEqual(content, expected_content) self.assertDictHasSubset(metadata, expected_metadata) def test_article_with_file_extensions(self): reader = readers.MarkdownReader(settings=get_settings()) # test to ensure the md file extension is being processed by the # correct reader content, metadata = reader.read( _path('article_with_md_extension.md')) expected = ( "

    Test Markdown File Header

    \n" "

    Used for pelican test

    \n" "

    The quick brown fox jumped over the lazy dog's back.

    ") self.assertEqual(content, expected) # test to ensure the mkd file extension is being processed by the # correct reader content, metadata = reader.read( _path('article_with_mkd_extension.mkd')) expected = ("

    Test Markdown File Header

    \n

    Used for pelican" " test

    \n

    This is another markdown test file. Uses" " the mkd extension.

    ") self.assertEqual(content, expected) # test to ensure the markdown file extension is being processed by the # correct reader content, metadata = reader.read( _path('article_with_markdown_extension.markdown')) expected = ("

    Test Markdown File Header

    \n

    Used for pelican" " test

    \n

    This is another markdown test file. Uses" " the markdown extension.

    ") self.assertEqual(content, expected) # test to ensure the mdown file extension is being processed by the # correct reader content, metadata = reader.read( _path('article_with_mdown_extension.mdown')) expected = ("

    Test Markdown File Header

    \n

    Used for pelican" " test

    \n

    This is another markdown test file. Uses" " the mdown extension.

    ") self.assertEqual(content, expected) def test_article_with_markdown_markup_extension(self): # test to ensure the markdown markup extension is being processed as # expected page = self.read_file( path='article_with_markdown_markup_extensions.md', MARKDOWN={ 'extension_configs': { 'markdown.extensions.toc': {}, 'markdown.extensions.codehilite': {}, 'markdown.extensions.extra': {} } } ) expected = ('
    \n' '\n' '
    \n' '

    Level1

    \n' '

    Level2

    ') self.assertEqual(page.content, expected) def test_article_with_filename_metadata(self): page = self.read_file( path='2012-11-30_md_w_filename_meta#foo-bar.md', FILENAME_METADATA=None) expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', } self.assertDictHasSubset(page.metadata, expected) page = self.read_file( path='2012-11-30_md_w_filename_meta#foo-bar.md', FILENAME_METADATA='(?P\d{4}-\d{2}-\d{2}).*') expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'date': SafeDatetime(2012, 11, 30), } self.assertDictHasSubset(page.metadata, expected) page = self.read_file( path='2012-11-30_md_w_filename_meta#foo-bar.md', FILENAME_METADATA=( '(?P\d{4}-\d{2}-\d{2})' '_(?P.*)' '#(?P.*)-(?P.*)')) expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'date': SafeDatetime(2012, 11, 30), 'slug': 'md_w_filename_meta', 'mymeta': 'foo', } self.assertDictHasSubset(page.metadata, expected) def test_duplicate_tags_or_authors_are_removed(self): reader = readers.MarkdownReader(settings=get_settings()) content, metadata = reader.read( _path('article_with_duplicate_tags_authors.md')) expected = { 'tags': ['foo', 'bar', 'foobar'], 'authors': ['Author, First', 'Author, Second'], } self.assertDictHasSubset(metadata, expected) def test_empty_file(self): reader = readers.MarkdownReader(settings=get_settings()) content, metadata = reader.read( _path('empty.md')) self.assertEqual(metadata, {}) self.assertEqual(content, '') def test_empty_file_with_bom(self): reader = readers.MarkdownReader(settings=get_settings()) content, metadata = reader.read( _path('empty_with_bom.md')) self.assertEqual(metadata, {}) self.assertEqual(content, '') class HTMLReaderTest(ReaderTest): def test_article_with_comments(self): page = self.read_file(path='article_with_comments.html') self.assertEqual(''' Body content ''', page.content) def test_article_with_keywords(self): page = self.read_file(path='article_with_keywords.html') expected = { 'tags': ['foo', 'bar', 'foobar'], } self.assertDictHasSubset(page.metadata, expected) def test_article_with_metadata(self): page = self.read_file(path='article_with_metadata.html') expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'This is a super article !', 'summary': 'Summary and stuff', 'date': SafeDatetime(2010, 12, 2, 10, 14), 'tags': ['foo', 'bar', 'foobar'], 'custom_field': 'http://notmyidea.org', } self.assertDictHasSubset(page.metadata, expected) def test_article_with_multiple_authors(self): page = self.read_file(path='article_with_multiple_authors.html') expected = { 'authors': ['First Author', 'Second Author'] } self.assertDictHasSubset(page.metadata, expected) def test_article_with_metadata_and_contents_attrib(self): page = self.read_file(path='article_with_metadata_and_contents.html') expected = { 'category': 'yeah', 'author': 'Alexis Métaireau', 'title': 'This is a super article !', 'summary': 'Summary and stuff', 'date': SafeDatetime(2010, 12, 2, 10, 14), 'tags': ['foo', 'bar', 'foobar'], 'custom_field': 'http://notmyidea.org', } self.assertDictHasSubset(page.metadata, expected) def test_article_with_null_attributes(self): page = self.read_file(path='article_with_null_attributes.html') self.assertEqual(''' Ensure that empty attributes are copied properly. ''', page.content) def test_article_with_attributes_containing_double_quotes(self): page = self.read_file(path='article_with_attributes_containing_' + 'double_quotes.html') self.assertEqual(''' Ensure that if an attribute value contains a double quote, it is surrounded with single quotes, otherwise with double quotes. Span content Span content Span content ''', page.content) def test_article_metadata_key_lowercase(self): # Keys of metadata should be lowercase. page = self.read_file(path='article_with_uppercase_metadata.html') # Key should be lowercase self.assertIn('category', page.metadata, 'Key should be lowercase.') # Value should keep cases self.assertEqual('Yeah', page.metadata.get('category')) def test_article_with_nonconformant_meta_tags(self): page = self.read_file(path='article_with_nonconformant_meta_tags.html') expected = { 'summary': 'Summary and stuff', 'title': 'Article with Nonconformant HTML meta tags', } self.assertDictHasSubset(page.metadata, expected) pelican-3.7.1/pelican/tests/test_rstdirectives.py000066400000000000000000000024371303525152100222200ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals from pelican.tests.support import unittest try: from unittest.mock import Mock except ImportError: try: from mock import Mock except ImportError: Mock = False @unittest.skipUnless(Mock, 'Needs Mock module') class Test_abbr_role(unittest.TestCase): def call_it(self, text): from pelican.rstdirectives import abbr_role rawtext = text lineno = 42 inliner = Mock(name='inliner') nodes, system_messages = abbr_role( 'abbr', rawtext, text, lineno, inliner) self.assertEqual(system_messages, []) self.assertEqual(len(nodes), 1) return nodes[0] def test(self): node = self.call_it("Abbr (Abbreviation)") self.assertEqual(node.astext(), "Abbr") self.assertEqual(node['explanation'], "Abbreviation") def test_newlines_in_explanation(self): node = self.call_it("CUL (See you\nlater)") self.assertEqual(node.astext(), "CUL") self.assertEqual(node['explanation'], "See you\nlater") def test_newlines_in_abbr(self): node = self.call_it("US of\nA \n (USA)") self.assertEqual(node.astext(), "US of\nA") self.assertEqual(node['explanation'], "USA") pelican-3.7.1/pelican/tests/test_settings.py000066400000000000000000000137011303525152100211620ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import copy import locale import os from os.path import abspath, dirname, join from sys import platform from pelican.settings import (DEFAULT_CONFIG, DEFAULT_THEME, configure_settings, read_settings) from pelican.tests.support import unittest class TestSettingsConfiguration(unittest.TestCase): """Provided a file, it should read it, replace the default values, append new values to the settings (if any), and apply basic settings optimizations. """ def setUp(self): self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) self.PATH = abspath(dirname(__file__)) default_conf = join(self.PATH, 'default_conf.py') self.settings = read_settings(default_conf) def tearDown(self): locale.setlocale(locale.LC_ALL, self.old_locale) def test_overwrite_existing_settings(self): self.assertEqual(self.settings.get('SITENAME'), "Alexis' log") self.assertEqual( self.settings.get('SITEURL'), 'http://blog.notmyidea.org') def test_keep_default_settings(self): # Keep default settings if not defined. self.assertEqual( self.settings.get('DEFAULT_CATEGORY'), DEFAULT_CONFIG['DEFAULT_CATEGORY']) def test_dont_copy_small_keys(self): # Do not copy keys not in caps. self.assertNotIn('foobar', self.settings) def test_read_empty_settings(self): # Ensure an empty settings file results in default settings. settings = read_settings(None) expected = copy.deepcopy(DEFAULT_CONFIG) # Added by configure settings expected['FEED_DOMAIN'] = '' expected['ARTICLE_EXCLUDES'] = ['pages'] expected['PAGE_EXCLUDES'] = [''] self.maxDiff = None self.assertDictEqual(settings, expected) def test_settings_return_independent(self): # Make sure that the results from one settings call doesn't # effect past or future instances. self.PATH = abspath(dirname(__file__)) default_conf = join(self.PATH, 'default_conf.py') settings = read_settings(default_conf) settings['SITEURL'] = 'new-value' new_settings = read_settings(default_conf) self.assertNotEqual(new_settings['SITEURL'], settings['SITEURL']) def test_defaults_not_overwritten(self): # This assumes 'SITENAME': 'A Pelican Blog' settings = read_settings(None) settings['SITENAME'] = 'Not a Pelican Blog' self.assertNotEqual(settings['SITENAME'], DEFAULT_CONFIG['SITENAME']) def test_static_path_settings_safety(self): # Disallow static paths from being strings settings = { 'STATIC_PATHS': 'foo/bar', 'THEME_STATIC_PATHS': 'bar/baz', # These 4 settings are required to run configure_settings 'PATH': '.', 'THEME': DEFAULT_THEME, 'SITEURL': 'http://blog.notmyidea.org/', 'LOCALE': '', } configure_settings(settings) self.assertEqual( settings['STATIC_PATHS'], DEFAULT_CONFIG['STATIC_PATHS']) self.assertEqual( settings['THEME_STATIC_PATHS'], DEFAULT_CONFIG['THEME_STATIC_PATHS']) def test_configure_settings(self): # Manipulations to settings should be applied correctly. settings = { 'SITEURL': 'http://blog.notmyidea.org/', 'LOCALE': '', 'PATH': os.curdir, 'THEME': DEFAULT_THEME, } configure_settings(settings) # SITEURL should not have a trailing slash self.assertEqual(settings['SITEURL'], 'http://blog.notmyidea.org') # FEED_DOMAIN, if undefined, should default to SITEURL self.assertEqual(settings['FEED_DOMAIN'], 'http://blog.notmyidea.org') settings['FEED_DOMAIN'] = 'http://feeds.example.com' configure_settings(settings) self.assertEqual(settings['FEED_DOMAIN'], 'http://feeds.example.com') def test_theme_settings_exceptions(self): settings = self.settings # Check that theme lookup in "pelican/themes" functions as expected settings['THEME'] = os.path.split(settings['THEME'])[1] configure_settings(settings) self.assertEqual(settings['THEME'], DEFAULT_THEME) # Check that non-existent theme raises exception settings['THEME'] = 'foo' self.assertRaises(Exception, configure_settings, settings) def test_deprecated_dir_setting(self): settings = self.settings settings['ARTICLE_DIR'] = 'foo' settings['PAGE_DIR'] = 'bar' configure_settings(settings) self.assertEqual(settings['ARTICLE_PATHS'], ['foo']) self.assertEqual(settings['PAGE_PATHS'], ['bar']) with self.assertRaises(KeyError): settings['ARTICLE_DIR'] settings['PAGE_DIR'] @unittest.skipIf(platform == 'win32', "Doesn't work on Windows") def test_default_encoding(self): # Test that the default locale is set if not specified in settings # Reset locale to Python's default locale locale.setlocale(locale.LC_ALL, str('C')) self.assertEqual(self.settings['LOCALE'], DEFAULT_CONFIG['LOCALE']) configure_settings(self.settings) self.assertEqual(locale.getlocale(), locale.getdefaultlocale()) def test_invalid_settings_throw_exception(self): # Test that the path name is valid # test that 'PATH' is set settings = { } self.assertRaises(Exception, configure_settings, settings) # Test that 'PATH' is valid settings['PATH'] = '' self.assertRaises(Exception, configure_settings, settings) # Test nonexistent THEME settings['PATH'] = os.curdir settings['THEME'] = 'foo' self.assertRaises(Exception, configure_settings, settings) pelican-3.7.1/pelican/tests/test_testsuite.py000066400000000000000000000006661303525152100213610ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import sys import warnings from pelican.tests.support import unittest class TestSuiteTest(unittest.TestCase): @unittest.skipIf(sys.version_info[:2] == (3, 3), "does not throw an exception on python 3.3") def test_error_on_warning(self): with self.assertRaises(UserWarning): warnings.warn('test warning') pelican-3.7.1/pelican/tests/test_urlwrappers.py000066400000000000000000000065311303525152100217130ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals from pelican.tests.support import unittest from pelican.urlwrappers import Author, Category, Tag, URLWrapper class TestURLWrapper(unittest.TestCase): def test_ordering(self): # URLWrappers are sorted by name wrapper_a = URLWrapper(name='first', settings={}) wrapper_b = URLWrapper(name='last', settings={}) self.assertFalse(wrapper_a > wrapper_b) self.assertFalse(wrapper_a >= wrapper_b) self.assertFalse(wrapper_a == wrapper_b) self.assertTrue(wrapper_a != wrapper_b) self.assertTrue(wrapper_a <= wrapper_b) self.assertTrue(wrapper_a < wrapper_b) wrapper_b.name = 'first' self.assertFalse(wrapper_a > wrapper_b) self.assertTrue(wrapper_a >= wrapper_b) self.assertTrue(wrapper_a == wrapper_b) self.assertFalse(wrapper_a != wrapper_b) self.assertTrue(wrapper_a <= wrapper_b) self.assertFalse(wrapper_a < wrapper_b) wrapper_a.name = 'last' self.assertTrue(wrapper_a > wrapper_b) self.assertTrue(wrapper_a >= wrapper_b) self.assertFalse(wrapper_a == wrapper_b) self.assertTrue(wrapper_a != wrapper_b) self.assertFalse(wrapper_a <= wrapper_b) self.assertFalse(wrapper_a < wrapper_b) def test_equality(self): tag = Tag('test', settings={}) cat = Category('test', settings={}) author = Author('test', settings={}) # same name, but different class self.assertNotEqual(tag, cat) self.assertNotEqual(tag, author) # should be equal vs text representing the same name self.assertEqual(tag, u'test') # should not be equal vs binary self.assertNotEqual(tag, b'test') # Tags describing the same should be equal tag_equal = Tag('Test', settings={}) self.assertEqual(tag, tag_equal) # Author describing the same should be equal author_equal = Author('Test', settings={}) self.assertEqual(author, author_equal) cat_ascii = Category('指導書', settings={}) self.assertEqual(cat_ascii, u'zhi-dao-shu') def test_slugify_with_substitutions_and_dots(self): tag = Tag('Tag Dot', settings={ 'TAG_SUBSTITUTIONS': [('Tag Dot', 'tag.dot', True)] }) cat = Category('Category Dot', settings={ 'CATEGORY_SUBSTITUTIONS': (('Category Dot', 'cat.dot', True),) }) self.assertEqual(tag.slug, 'tag.dot') self.assertEqual(cat.slug, 'cat.dot') def test_author_slug_substitutions(self): settings = { 'AUTHOR_SUBSTITUTIONS': [ ('Alexander Todorov', 'atodorov', False), ('Krasimir Tsonev', 'krasimir', False), ] } author1 = Author('Mr. Senko', settings=settings) author2 = Author('Alexander Todorov', settings=settings) author3 = Author('Krasimir Tsonev', settings=settings) self.assertEqual(author1.slug, 'mr-senko') self.assertEqual(author2.slug, 'atodorov') self.assertEqual(author3.slug, 'krasimir') pelican-3.7.1/pelican/tests/test_utils.py000066400000000000000000000643011303525152100204640ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals import locale import logging import os import shutil import time from sys import platform from tempfile import mkdtemp import pytz from pelican import utils from pelican.generators import TemplatePagesGenerator from pelican.settings import read_settings from pelican.tests.support import (LoggedTestCase, get_article, locale_available, unittest) from pelican.writers import Writer class TestUtils(LoggedTestCase): _new_attribute = 'new_value' @utils.deprecated_attribute( old='_old_attribute', new='_new_attribute', since=(3, 1, 0), remove=(4, 1, 3)) def _old_attribute(): return None def test_deprecated_attribute(self): value = self._old_attribute self.assertEqual(value, self._new_attribute) self.assertLogCountEqual( count=1, msg=('_old_attribute has been deprecated since 3.1.0 and will be ' 'removed by version 4.1.3. Use _new_attribute instead'), level=logging.WARNING) def test_get_date(self): # valid ones date = utils.SafeDatetime(year=2012, month=11, day=22) date_hour = utils.SafeDatetime( year=2012, month=11, day=22, hour=22, minute=11) date_hour_z = utils.SafeDatetime( year=2012, month=11, day=22, hour=22, minute=11, tzinfo=pytz.timezone('UTC')) date_hour_est = utils.SafeDatetime( year=2012, month=11, day=22, hour=22, minute=11, tzinfo=pytz.timezone('EST')) date_hour_sec = utils.SafeDatetime( year=2012, month=11, day=22, hour=22, minute=11, second=10) date_hour_sec_z = utils.SafeDatetime( year=2012, month=11, day=22, hour=22, minute=11, second=10, tzinfo=pytz.timezone('UTC')) date_hour_sec_est = utils.SafeDatetime( year=2012, month=11, day=22, hour=22, minute=11, second=10, tzinfo=pytz.timezone('EST')) date_hour_sec_frac_z = utils.SafeDatetime( year=2012, month=11, day=22, hour=22, minute=11, second=10, microsecond=123000, tzinfo=pytz.timezone('UTC')) dates = { '2012-11-22': date, '2012/11/22': date, '2012-11-22 22:11': date_hour, '2012/11/22 22:11': date_hour, '22-11-2012': date, '22/11/2012': date, '22.11.2012': date, '22.11.2012 22:11': date_hour, '2012-11-22T22:11Z': date_hour_z, '2012-11-22T22:11-0500': date_hour_est, '2012-11-22 22:11:10': date_hour_sec, '2012-11-22T22:11:10Z': date_hour_sec_z, '2012-11-22T22:11:10-0500': date_hour_sec_est, '2012-11-22T22:11:10.123Z': date_hour_sec_frac_z, } # examples from http://www.w3.org/TR/NOTE-datetime iso_8601_date = utils.SafeDatetime(year=1997, month=7, day=16) iso_8601_date_hour_tz = utils.SafeDatetime( year=1997, month=7, day=16, hour=19, minute=20, tzinfo=pytz.timezone('CET')) iso_8601_date_hour_sec_tz = utils.SafeDatetime( year=1997, month=7, day=16, hour=19, minute=20, second=30, tzinfo=pytz.timezone('CET')) iso_8601_date_hour_sec_ms_tz = utils.SafeDatetime( year=1997, month=7, day=16, hour=19, minute=20, second=30, microsecond=450000, tzinfo=pytz.timezone('CET')) iso_8601 = { '1997-07-16': iso_8601_date, '1997-07-16T19:20+01:00': iso_8601_date_hour_tz, '1997-07-16T19:20:30+01:00': iso_8601_date_hour_sec_tz, '1997-07-16T19:20:30.45+01:00': iso_8601_date_hour_sec_ms_tz, } # invalid ones invalid_dates = ['2010-110-12', 'yay'] for value, expected in dates.items(): self.assertEqual(utils.get_date(value), expected, value) for value, expected in iso_8601.items(): self.assertEqual(utils.get_date(value), expected, value) for item in invalid_dates: self.assertRaises(ValueError, utils.get_date, item) def test_slugify(self): samples = (('this is a test', 'this-is-a-test'), ('this is a test', 'this-is-a-test'), ('this → is ← a ↑ test', 'this-is-a-test'), ('this--is---a test', 'this-is-a-test'), ('unicode測試許功蓋,你看到了嗎?', 'unicodece-shi-xu-gong-gai-ni-kan-dao-liao-ma'), ('大飯原発4号機、18日夜起動へ', 'da-fan-yuan-fa-4hao-ji-18ri-ye-qi-dong-he'),) for value, expected in samples: self.assertEqual(utils.slugify(value), expected) def test_slugify_substitute(self): samples = (('C++ is based on C', 'cpp-is-based-on-c'), ('C+++ test C+ test', 'cpp-test-c-test'), ('c++, c#, C#, C++', 'cpp-c-sharp-c-sharp-cpp'), ('c++-streams', 'cpp-streams'),) subs = (('C++', 'CPP'), ('C#', 'C-SHARP')) for value, expected in samples: self.assertEqual(utils.slugify(value, subs), expected) def test_slugify_substitute_and_keeping_non_alphanum(self): samples = (('Fedora QA', 'fedora.qa'), ('C++ is used by Fedora QA', 'cpp is used by fedora.qa'), ('C++ is based on C', 'cpp-is-based-on-c'), ('C+++ test C+ test', 'cpp-test-c-test'),) subs = (('Fedora QA', 'fedora.qa', True), ('c++', 'cpp'),) for value, expected in samples: self.assertEqual(utils.slugify(value, subs), expected) def test_get_relative_path(self): samples = ((os.path.join('test', 'test.html'), os.pardir), (os.path.join('test', 'test', 'test.html'), os.path.join(os.pardir, os.pardir)), ('test.html', os.curdir), (os.path.join('/test', 'test.html'), os.pardir), (os.path.join('/test', 'test', 'test.html'), os.path.join(os.pardir, os.pardir)), ('/test.html', os.curdir),) for value, expected in samples: self.assertEqual(utils.get_relative_path(value), expected) def test_truncate_html_words(self): # Plain text. self.assertEqual( utils.truncate_html_words('short string', 20), 'short string') self.assertEqual( utils.truncate_html_words('word ' * 100, 20), 'word ' * 20 + '…') # Words enclosed or intervaled by HTML tags. self.assertEqual( utils.truncate_html_words('

    ' + 'word ' * 100 + '

    ', 20), '

    ' + 'word ' * 20 + '…

    ') self.assertEqual( utils.truncate_html_words( '' + 'word ' * 100 + '', 20), '' + 'word ' * 20 + '…') self.assertEqual( utils.truncate_html_words('
    ' + 'word ' * 100, 20), '
    ' + 'word ' * 20 + '…') self.assertEqual( utils.truncate_html_words('' + 'word ' * 100, 20), '' + 'word ' * 20 + '…') # Words with hypens and apostrophes. self.assertEqual( utils.truncate_html_words("a-b " * 100, 20), "a-b " * 20 + '…') self.assertEqual( utils.truncate_html_words("it's " * 100, 20), "it's " * 20 + '…') # Words with HTML entity references. self.assertEqual( utils.truncate_html_words("é " * 100, 20), "é " * 20 + '…') self.assertEqual( utils.truncate_html_words("café " * 100, 20), "café " * 20 + '…') self.assertEqual( utils.truncate_html_words("èlite " * 100, 20), "èlite " * 20 + '…') self.assertEqual( utils.truncate_html_words("cafetiére " * 100, 20), "cafetiére " * 20 + '…') self.assertEqual( utils.truncate_html_words("∫dx " * 100, 20), "∫dx " * 20 + '…') # Words with HTML character references inside and outside # the ASCII range. self.assertEqual( utils.truncate_html_words("é " * 100, 20), "é " * 20 + '…') self.assertEqual( utils.truncate_html_words("∫dx " * 100, 20), "∫dx " * 20 + '…') def test_process_translations(self): fr_articles = [] en_articles = [] # create a bunch of articles # 0: no translation metadata fr_articles.append(get_article(lang='fr', slug='yay0', title='Titre', content='en français')) en_articles.append(get_article(lang='en', slug='yay0', title='Title', content='in english')) # 1: translation metadata on default lang fr_articles.append(get_article(lang='fr', slug='yay1', title='Titre', content='en français')) en_articles.append(get_article(lang='en', slug='yay1', title='Title', content='in english', extra_metadata={'translation': 'true'})) # 2: translation metadata not on default lang fr_articles.append(get_article(lang='fr', slug='yay2', title='Titre', content='en français', extra_metadata={'translation': 'true'})) en_articles.append(get_article(lang='en', slug='yay2', title='Title', content='in english')) # 3: back to default language detection if all items have the # translation metadata fr_articles.append(get_article(lang='fr', slug='yay3', title='Titre', content='en français', extra_metadata={'translation': 'yep'})) en_articles.append(get_article(lang='en', slug='yay3', title='Title', content='in english', extra_metadata={'translation': 'yes'})) # try adding articles in both orders for lang0_articles, lang1_articles in ((fr_articles, en_articles), (en_articles, fr_articles)): articles = lang0_articles + lang1_articles index, trans = utils.process_translations(articles) self.assertIn(en_articles[0], index) self.assertIn(fr_articles[0], trans) self.assertNotIn(en_articles[0], trans) self.assertNotIn(fr_articles[0], index) self.assertIn(fr_articles[1], index) self.assertIn(en_articles[1], trans) self.assertNotIn(fr_articles[1], trans) self.assertNotIn(en_articles[1], index) self.assertIn(en_articles[2], index) self.assertIn(fr_articles[2], trans) self.assertNotIn(en_articles[2], trans) self.assertNotIn(fr_articles[2], index) self.assertIn(en_articles[3], index) self.assertIn(fr_articles[3], trans) self.assertNotIn(en_articles[3], trans) self.assertNotIn(fr_articles[3], index) def test_watchers(self): # Test if file changes are correctly detected # Make sure to handle not getting any files correctly. dirname = os.path.join(os.path.dirname(__file__), 'content') folder_watcher = utils.folder_watcher(dirname, ['rst']) path = os.path.join(dirname, 'article_with_metadata.rst') file_watcher = utils.file_watcher(path) # first check returns True self.assertEqual(next(folder_watcher), True) self.assertEqual(next(file_watcher), True) # next check without modification returns False self.assertEqual(next(folder_watcher), False) self.assertEqual(next(file_watcher), False) # after modification, returns True t = time.time() os.utime(path, (t, t)) self.assertEqual(next(folder_watcher), True) self.assertEqual(next(file_watcher), True) # file watcher with None or empty path should return None self.assertEqual(next(utils.file_watcher('')), None) self.assertEqual(next(utils.file_watcher(None)), None) empty_path = os.path.join(os.path.dirname(__file__), 'empty') try: os.mkdir(empty_path) os.mkdir(os.path.join(empty_path, "empty_folder")) shutil.copy(__file__, empty_path) # if no files of interest, returns None watcher = utils.folder_watcher(empty_path, ['rst']) self.assertEqual(next(watcher), None) except OSError: self.fail("OSError Exception in test_files_changed test") finally: shutil.rmtree(empty_path, True) def test_clean_output_dir(self): retention = () test_directory = os.path.join(os.path.dirname(__file__), 'clean_output') content = os.path.join(os.path.dirname(__file__), 'content') shutil.copytree(content, test_directory) utils.clean_output_dir(test_directory, retention) self.assertTrue(os.path.isdir(test_directory)) self.assertListEqual([], os.listdir(test_directory)) shutil.rmtree(test_directory) def test_clean_output_dir_not_there(self): retention = () test_directory = os.path.join(os.path.dirname(__file__), 'does_not_exist') utils.clean_output_dir(test_directory, retention) self.assertFalse(os.path.exists(test_directory)) def test_clean_output_dir_is_file(self): retention = () test_directory = os.path.join(os.path.dirname(__file__), 'this_is_a_file') f = open(test_directory, 'w') f.write('') f.close() utils.clean_output_dir(test_directory, retention) self.assertFalse(os.path.exists(test_directory)) def test_strftime(self): d = utils.SafeDatetime(2012, 8, 29) # simple formatting self.assertEqual(utils.strftime(d, '%d/%m/%y'), '29/08/12') self.assertEqual(utils.strftime(d, '%d/%m/%Y'), '29/08/2012') # RFC 3339 self.assertEqual( utils.strftime(d, '%Y-%m-%dT%H:%M:%SZ'), '2012-08-29T00:00:00Z') # % escaped self.assertEqual(utils.strftime(d, '%d%%%m%%%y'), '29%08%12') self.assertEqual(utils.strftime(d, '%d %% %m %% %y'), '29 % 08 % 12') # not valid % formatter self.assertEqual(utils.strftime(d, '10% reduction in %Y'), '10% reduction in 2012') self.assertEqual(utils.strftime(d, '%10 reduction in %Y'), '%10 reduction in 2012') # with text self.assertEqual(utils.strftime(d, 'Published in %d-%m-%Y'), 'Published in 29-08-2012') # with non-ascii text self.assertEqual( utils.strftime(d, '%d/%m/%Y Øl trinken beim Besäufnis'), '29/08/2012 Øl trinken beim Besäufnis') # alternative formatting options self.assertEqual(utils.strftime(d, '%-d/%-m/%y'), '29/8/12') self.assertEqual(utils.strftime(d, '%-H:%-M:%-S'), '0:0:0') d = utils.SafeDatetime(2012, 8, 9) self.assertEqual(utils.strftime(d, '%-d/%-m/%y'), '9/8/12') # test the output of utils.strftime in a different locale # Turkish locale @unittest.skipUnless(locale_available('tr_TR.UTF-8') or locale_available('Turkish'), 'Turkish locale needed') def test_strftime_locale_dependent_turkish(self): # store current locale old_locale = locale.setlocale(locale.LC_ALL) if platform == 'win32': locale.setlocale(locale.LC_ALL, str('Turkish')) else: locale.setlocale(locale.LC_ALL, str('tr_TR.UTF-8')) d = utils.SafeDatetime(2012, 8, 29) # simple self.assertEqual(utils.strftime(d, '%d %B %Y'), '29 Ağustos 2012') self.assertEqual(utils.strftime(d, '%A, %d %B %Y'), 'Çarşamba, 29 Ağustos 2012') # with text self.assertEqual( utils.strftime(d, 'Yayınlanma tarihi: %A, %d %B %Y'), 'Yayınlanma tarihi: Çarşamba, 29 Ağustos 2012') # non-ascii format candidate (someone might pass it… for some reason) self.assertEqual( utils.strftime(d, '%Y yılında %üretim artışı'), '2012 yılında %üretim artışı') # restore locale back locale.setlocale(locale.LC_ALL, old_locale) # test the output of utils.strftime in a different locale # French locale @unittest.skipUnless(locale_available('fr_FR.UTF-8') or locale_available('French'), 'French locale needed') def test_strftime_locale_dependent_french(self): # store current locale old_locale = locale.setlocale(locale.LC_ALL) if platform == 'win32': locale.setlocale(locale.LC_ALL, str('French')) else: locale.setlocale(locale.LC_ALL, str('fr_FR.UTF-8')) d = utils.SafeDatetime(2012, 8, 29) # simple self.assertEqual(utils.strftime(d, '%d %B %Y'), '29 août 2012') # depending on OS, the first letter is m or M self.assertTrue(utils.strftime(d, '%A') in ('mercredi', 'Mercredi')) # with text self.assertEqual( utils.strftime(d, 'Écrit le %d %B %Y'), 'Écrit le 29 août 2012') # non-ascii format candidate (someone might pass it… for some reason) self.assertEqual( utils.strftime(d, '%écrits en %Y'), '%écrits en 2012') # restore locale back locale.setlocale(locale.LC_ALL, old_locale) def test_maybe_pluralize(self): self.assertEqual( utils.maybe_pluralize(0, 'Article', 'Articles'), '0 Articles') self.assertEqual( utils.maybe_pluralize(1, 'Article', 'Articles'), '1 Article') self.assertEqual( utils.maybe_pluralize(2, 'Article', 'Articles'), '2 Articles') class TestCopy(unittest.TestCase): '''Tests the copy utility''' def setUp(self): self.root_dir = mkdtemp(prefix='pelicantests.') self.old_locale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL, str('C')) def tearDown(self): shutil.rmtree(self.root_dir) locale.setlocale(locale.LC_ALL, self.old_locale) def _create_file(self, *path): with open(os.path.join(self.root_dir, *path), 'w') as f: f.write('42\n') def _create_dir(self, *path): os.makedirs(os.path.join(self.root_dir, *path)) def _exist_file(self, *path): path = os.path.join(self.root_dir, *path) self.assertTrue(os.path.isfile(path), 'File does not exist: %s' % path) def _exist_dir(self, *path): path = os.path.join(self.root_dir, *path) self.assertTrue(os.path.exists(path), 'Directory does not exist: %s' % path) def test_copy_file_same_path(self): self._create_file('a.txt') utils.copy(os.path.join(self.root_dir, 'a.txt'), os.path.join(self.root_dir, 'b.txt')) self._exist_file('b.txt') def test_copy_file_different_path(self): self._create_dir('a') self._create_dir('b') self._create_file('a', 'a.txt') utils.copy(os.path.join(self.root_dir, 'a', 'a.txt'), os.path.join(self.root_dir, 'b', 'b.txt')) self._exist_dir('b') self._exist_file('b', 'b.txt') def test_copy_file_create_dirs(self): self._create_file('a.txt') utils.copy( os.path.join(self.root_dir, 'a.txt'), os.path.join(self.root_dir, 'b0', 'b1', 'b2', 'b3', 'b.txt')) self._exist_dir('b0') self._exist_dir('b0', 'b1') self._exist_dir('b0', 'b1', 'b2') self._exist_dir('b0', 'b1', 'b2', 'b3') self._exist_file('b0', 'b1', 'b2', 'b3', 'b.txt') def test_copy_dir_same_path(self): self._create_dir('a') self._create_file('a', 'a.txt') utils.copy(os.path.join(self.root_dir, 'a'), os.path.join(self.root_dir, 'b')) self._exist_dir('b') self._exist_file('b', 'a.txt') def test_copy_dir_different_path(self): self._create_dir('a0') self._create_dir('a0', 'a1') self._create_file('a0', 'a1', 'a.txt') self._create_dir('b0') utils.copy(os.path.join(self.root_dir, 'a0', 'a1'), os.path.join(self.root_dir, 'b0', 'b1')) self._exist_dir('b0', 'b1') self._exist_file('b0', 'b1', 'a.txt') def test_copy_dir_create_dirs(self): self._create_dir('a') self._create_file('a', 'a.txt') utils.copy(os.path.join(self.root_dir, 'a'), os.path.join(self.root_dir, 'b0', 'b1', 'b2', 'b3', 'b')) self._exist_dir('b0') self._exist_dir('b0', 'b1') self._exist_dir('b0', 'b1', 'b2') self._exist_dir('b0', 'b1', 'b2', 'b3') self._exist_dir('b0', 'b1', 'b2', 'b3', 'b') self._exist_file('b0', 'b1', 'b2', 'b3', 'b', 'a.txt') class TestDateFormatter(unittest.TestCase): '''Tests that the output of DateFormatter jinja filter is same as utils.strftime''' def setUp(self): # prepare a temp content and output folder self.temp_content = mkdtemp(prefix='pelicantests.') self.temp_output = mkdtemp(prefix='pelicantests.') # prepare a template file template_dir = os.path.join(self.temp_content, 'template') template_path = os.path.join(template_dir, 'source.html') os.makedirs(template_dir) with open(template_path, 'w') as template_file: template_file.write('date = {{ date|strftime("%A, %d %B %Y") }}') self.date = utils.SafeDatetime(2012, 8, 29) def tearDown(self): shutil.rmtree(self.temp_content) shutil.rmtree(self.temp_output) # reset locale to default locale.setlocale(locale.LC_ALL, '') @unittest.skipUnless(locale_available('fr_FR.UTF-8') or locale_available('French'), 'French locale needed') def test_french_strftime(self): # This test tries to reproduce an issue that # occurred with python3.3 under macos10 only if platform == 'win32': locale.setlocale(locale.LC_ALL, str('French')) else: locale.setlocale(locale.LC_ALL, str('fr_FR.UTF-8')) date = utils.SafeDatetime(2014, 8, 14) # we compare the lower() dates since macos10 returns # "Jeudi" for %A whereas linux reports "jeudi" self.assertEqual( u'jeudi, 14 août 2014', utils.strftime(date, date_format="%A, %d %B %Y").lower()) df = utils.DateFormatter() self.assertEqual( u'jeudi, 14 août 2014', df(date, date_format="%A, %d %B %Y").lower()) # Let us now set the global locale to C: locale.setlocale(locale.LC_ALL, str('C')) # DateFormatter should still work as expected # since it is the whole point of DateFormatter # (This is where pre-2014/4/15 code fails on macos10) df_date = df(date, date_format="%A, %d %B %Y").lower() self.assertEqual(u'jeudi, 14 août 2014', df_date) @unittest.skipUnless(locale_available('fr_FR.UTF-8') or locale_available('French'), 'French locale needed') def test_french_locale(self): if platform == 'win32': locale_string = 'French' else: locale_string = 'fr_FR.UTF-8' settings = read_settings( override={ 'LOCALE': locale_string, 'TEMPLATE_PAGES': { 'template/source.html': 'generated/file.html' } }) generator = TemplatePagesGenerator( {'date': self.date}, settings, self.temp_content, '', self.temp_output) generator.env.filters.update({'strftime': utils.DateFormatter()}) writer = Writer(self.temp_output, settings=settings) generator.generate_output(writer) output_path = os.path.join( self.temp_output, 'generated', 'file.html') # output file has been generated self.assertTrue(os.path.exists(output_path)) # output content is correct with utils.pelican_open(output_path) as output_file: self.assertEqual(output_file, utils.strftime(self.date, 'date = %A, %d %B %Y')) @unittest.skipUnless(locale_available('tr_TR.UTF-8') or locale_available('Turkish'), 'Turkish locale needed') def test_turkish_locale(self): if platform == 'win32': locale_string = 'Turkish' else: locale_string = 'tr_TR.UTF-8' settings = read_settings( override={ 'LOCALE': locale_string, 'TEMPLATE_PAGES': { 'template/source.html': 'generated/file.html' } }) generator = TemplatePagesGenerator( {'date': self.date}, settings, self.temp_content, '', self.temp_output) generator.env.filters.update({'strftime': utils.DateFormatter()}) writer = Writer(self.temp_output, settings=settings) generator.generate_output(writer) output_path = os.path.join( self.temp_output, 'generated', 'file.html') # output file has been generated self.assertTrue(os.path.exists(output_path)) # output content is correct with utils.pelican_open(output_path) as output_file: self.assertEqual(output_file, utils.strftime(self.date, 'date = %A, %d %B %Y')) pelican-3.7.1/pelican/themes/000077500000000000000000000000001303525152100160325ustar00rootroot00000000000000pelican-3.7.1/pelican/themes/simple/000077500000000000000000000000001303525152100173235ustar00rootroot00000000000000pelican-3.7.1/pelican/themes/simple/templates/000077500000000000000000000000001303525152100213215ustar00rootroot00000000000000pelican-3.7.1/pelican/themes/simple/templates/archives.html000066400000000000000000000004141303525152100240120ustar00rootroot00000000000000{% extends "base.html" %} {% block content %}

    Archives for {{ SITENAME }}

    {% for article in dates %}
    {{ article.locale_date }}
    {{ article.title }}
    {% endfor %}
    {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/article.html000066400000000000000000000025001303525152100236270ustar00rootroot00000000000000{% extends "base.html" %} {% block head %} {{ super() }} {% if article.description %} {% endif %} {% for tag in article.tags %} {% endfor %} {% endblock %} {% block content %}

    {{ article.title }}

    {% import 'translations.html' as translations with context %} {{ translations.translations_for(article) }}
    {% if article.modified %} {% endif %} {% if article.authors %}
    By {% for author in article.authors %} {{ author }} {% endfor %}
    {% endif %}
    {{ article.content }}
    {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/author.html000066400000000000000000000002611303525152100235100ustar00rootroot00000000000000{% extends "index.html" %} {% block title %}{{ SITENAME }} - Articles by {{ author }}{% endblock %} {% block content_title %}

    Articles by {{ author }}

    {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/authors.html000066400000000000000000000005251303525152100236760ustar00rootroot00000000000000{% extends "base.html" %} {% block title %}{{ SITENAME }} - Authors{% endblock %} {% block content %}

    Authors on {{ SITENAME }}

      {%- for author, articles in authors|sort %}
    • {{ author }} ({{ articles|count }})
    • {% endfor %}
    {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/base.html000066400000000000000000000062361303525152100231300ustar00rootroot00000000000000 {% block head %} {% block title %}{{ SITENAME }}{% endblock title %} {% if FEED_ALL_ATOM %} {% endif %} {% if FEED_ALL_RSS %} {% endif %} {% if FEED_ATOM %} {% endif %} {% if FEED_RSS %} {% endif %} {% if CATEGORY_FEED_ATOM and category %} {% endif %} {% if CATEGORY_FEED_RSS and category %} {% endif %} {% if TAG_FEED_ATOM and tag %} {% endif %} {% if TAG_FEED_RSS and tag %} {% endif %} {% endblock head %} {% block content %} {% endblock %}
    Proudly powered by Pelican, which takes great advantage of Python.
    pelican-3.7.1/pelican/themes/simple/templates/categories.html000066400000000000000000000003131303525152100243310ustar00rootroot00000000000000{% extends "base.html" %} {% block content %}
      {% for category, articles in categories %}
    • {{ category }}
    • {% endfor %}
    {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/category.html000066400000000000000000000001661303525152100240270ustar00rootroot00000000000000{% extends "index.html" %} {% block content_title %}

    Articles in the {{ category }} category

    {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/gosquared.html000066400000000000000000000011341303525152100242000ustar00rootroot00000000000000{% if GOSQUARED_SITENAME %} {% endif %} pelican-3.7.1/pelican/themes/simple/templates/index.html000066400000000000000000000022771303525152100233260ustar00rootroot00000000000000{% extends "base.html" %} {% block content %}
    {% block content_title %}

    All articles

    {% endblock %}
      {% for article in articles_page.object_list %}
    1. {% endfor %}
    {% if articles_page.has_other_pages() %} {% include 'pagination.html' %} {% endif %}
    {% endblock content %} pelican-3.7.1/pelican/themes/simple/templates/page.html000066400000000000000000000005571303525152100231320ustar00rootroot00000000000000{% extends "base.html" %} {% block title %}{{ page.title }}{%endblock%} {% block content %}

    {{ page.title }}

    {% import 'translations.html' as translations with context %} {{ translations.translations_for(page) }} {{ page.content }} {% if page.modified %}

    Last updated: {{ page.locale_modified }}

    {% endif %} {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/pagination.html000066400000000000000000000006221303525152100243400ustar00rootroot00000000000000{% if DEFAULT_PAGINATION %}

    {% if articles_page.has_previous() %} « {% endif %} Page {{ articles_page.number }} / {{ articles_paginator.num_pages }} {% if articles_page.has_next() %} » {% endif %}

    {% endif %} pelican-3.7.1/pelican/themes/simple/templates/period_archives.html000066400000000000000000000004401303525152100253530ustar00rootroot00000000000000{% extends "base.html" %} {% block content %}

    Archives for {{ period | reverse | join(' ') }}

    {% for article in dates %}
    {{ article.locale_date }}
    {{ article.title }}
    {% endfor %}
    {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/tag.html000066400000000000000000000000001303525152100227500ustar00rootroot00000000000000pelican-3.7.1/pelican/themes/simple/templates/tags.html000066400000000000000000000004601303525152100231450ustar00rootroot00000000000000{% extends "base.html" %} {% block title %}{{ SITENAME }} - Tags{% endblock %} {% block content %}

    Tags for {{ SITENAME }}

    {%- for tag, articles in tags|sort %}
  • {{ tag }} ({{ articles|count }})
  • {% endfor %} {% endblock %} pelican-3.7.1/pelican/themes/simple/templates/translations.html000066400000000000000000000003631303525152100247320ustar00rootroot00000000000000{% macro translations_for(article) %} {% if article.translations %} Translations: {% for translation in article.translations %} {{ translation.lang }} {% endfor %} {% endif %} {% endmacro %} pelican-3.7.1/pelican/tools/000077500000000000000000000000001303525152100157055ustar00rootroot00000000000000pelican-3.7.1/pelican/tools/__init__.py000066400000000000000000000000001303525152100200040ustar00rootroot00000000000000pelican-3.7.1/pelican/tools/pelican_import.py000077500000000000000000001007771303525152100213030ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import argparse import logging import os import re import subprocess import sys import time from codecs import open from six.moves.urllib.error import URLError from six.moves.urllib.parse import urlparse from six.moves.urllib.request import urlretrieve # because logging.setLoggerClass has to be called before logging.getLogger from pelican.log import init from pelican.utils import SafeDatetime, slugify try: from html import unescape # py3.4+ except ImportError: from six.moves.html_parser import HTMLParser unescape = HTMLParser().unescape logger = logging.getLogger(__name__) def decode_wp_content(content, br=True): pre_tags = {} if content.strip() == "": return "" content += "\n" if "") last_pre = pre_parts.pop() content = "" pre_index = 0 for pre_part in pre_parts: start = pre_part.find("" content = content + pre_part[0:start] + name pre_index += 1 content = content + last_pre content = re.sub(r'
    \s*
    ', "\n\n", content) allblocks = ('(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|' 'td|th|div|dl|dd|dt|ul|ol|li|pre|select|option|form|' 'map|area|blockquote|address|math|style|p|h[1-6]|hr|' 'fieldset|noscript|samp|legend|section|article|aside|' 'hgroup|header|footer|nav|figure|figcaption|details|' 'menu|summary)') content = re.sub(r'(<' + allblocks + r'[^>]*>)', "\n\\1", content) content = re.sub(r'()', "\\1\n\n", content) # content = content.replace("\r\n", "\n") if " inside object/embed content = re.sub(r'\s*]*)>\s*', "", content) content = re.sub(r'\s*\s*', '', content) # content = re.sub(r'/\n\n+/', '\n\n', content) pgraphs = filter(lambda s: s != "", re.split(r'\n\s*\n', content)) content = "" for p in pgraphs: content = content + "

    " + p.strip() + "

    \n" # under certain strange conditions it could create # a P of entirely whitespace content = re.sub(r'

    \s*

    ', '', content) content = re.sub( r'

    ([^<]+)', "

    \\1

    ", content) # don't wrap tags content = re.sub( r'

    \s*(]*>)\s*

    ', "\\1", content) # problem with nested lists content = re.sub(r'

    (', "\\1", content) content = re.sub(r'

    ]*)>', "

    ", content) content = content.replace('

    ', '

    ') content = re.sub(r'

    \s*(]*>)', "\\1", content) content = re.sub(r'(]*>)\s*

    ', "\\1", content) if br: def _preserve_newline(match): return match.group(0).replace("\n", "") content = re.sub( r'/<(script|style).*?<\/\\1>/s', _preserve_newline, content) # optionally make line breaks content = re.sub(r'(?)\s*\n', "
    \n", content) content = content.replace("", "\n") content = re.sub( r'(]*>)\s*
    ', "\\1", content) content = re.sub( r'
    (\s*]*>)', '\\1', content) content = re.sub(r'\n

    ', "

    ", content) if pre_tags: def _multi_replace(dic, string): pattern = r'|'.join(map(re.escape, dic.keys())) return re.sub(pattern, lambda m: dic[m.group()], string) content = _multi_replace(pre_tags, content) return content def get_items(xml): """Opens a WordPress xml file and returns a list of items""" try: from bs4 import BeautifulSoup except ImportError: error = ('Missing dependency "BeautifulSoup4" and "lxml" required to ' 'import WordPress XML files.') sys.exit(error) with open(xml, encoding='utf-8') as infile: xmlfile = infile.read() soup = BeautifulSoup(xmlfile, "xml") items = soup.rss.channel.findAll('item') return items def get_filename(filename, post_id): if filename is not None: return filename else: return post_id def wp2fields(xml, wp_custpost=False): """Opens a wordpress XML file, and yield Pelican fields""" items = get_items(xml) for item in items: if item.find('status').string in ["publish", "draft"]: try: # Use HTMLParser due to issues with BeautifulSoup 3 title = unescape(item.title.contents[0]) except IndexError: title = 'No title [%s]' % item.find('post_name').string logger.warning('Post "%s" is lacking a proper title', title) filename = item.find('post_name').string post_id = item.find('post_id').string filename = get_filename(filename, post_id) content = item.find('encoded').string raw_date = item.find('post_date').string date_object = time.strptime(raw_date, '%Y-%m-%d %H:%M:%S') date = time.strftime('%Y-%m-%d %H:%M', date_object) author = item.find('creator').string categories = [cat.string for cat in item.findAll('category', {'domain': 'category'})] tags = [tag.string for tag in item.findAll('category', {'domain': 'post_tag'})] # To publish a post the status should be 'published' status = 'published' if item.find('status').string == "publish" \ else item.find('status').string kind = 'article' post_type = item.find('post_type').string if post_type == 'page': kind = 'page' elif wp_custpost: if post_type == 'post': pass # Old behaviour was to name everything not a page as an # article.Theoretically all attachments have status == inherit # so no attachments should be here. But this statement is to # maintain existing behaviour in case that doesn't hold true. elif post_type == 'attachment': pass else: kind = post_type yield (title, content, filename, date, author, categories, tags, status, kind, 'wp-html') def dc2fields(file): """Opens a Dotclear export file, and yield pelican fields""" try: from bs4 import BeautifulSoup except ImportError: error = ('Missing dependency ' '"BeautifulSoup4" and "lxml" required ' 'to import Dotclear files.') sys.exit(error) in_cat = False in_post = False category_list = {} posts = [] with open(file, 'r', encoding='utf-8') as f: for line in f: # remove final \n line = line[:-1] if line.startswith('[category'): in_cat = True elif line.startswith('[post'): in_post = True elif in_cat: fields = line.split('","') if not line: in_cat = False else: # remove 1st and last "" fields[0] = fields[0][1:] # fields[-1] = fields[-1][:-1] category_list[fields[0]] = fields[2] elif in_post: if not line: in_post = False break else: posts.append(line) print("%i posts read." % len(posts)) for post in posts: fields = post.split('","') # post_id = fields[0][1:] # blog_id = fields[1] # user_id = fields[2] cat_id = fields[3] # post_dt = fields[4] # post_tz = fields[5] post_creadt = fields[6] # post_upddt = fields[7] # post_password = fields[8] # post_type = fields[9] post_format = fields[10] # post_url = fields[11] # post_lang = fields[12] post_title = fields[13] post_excerpt = fields[14] post_excerpt_xhtml = fields[15] post_content = fields[16] post_content_xhtml = fields[17] # post_notes = fields[18] # post_words = fields[19] # post_status = fields[20] # post_selected = fields[21] # post_position = fields[22] # post_open_comment = fields[23] # post_open_tb = fields[24] # nb_comment = fields[25] # nb_trackback = fields[26] post_meta = fields[27] # redirect_url = fields[28][:-1] # remove seconds post_creadt = ':'.join(post_creadt.split(':')[0:2]) author = '' categories = [] tags = [] if cat_id: categories = [category_list[id].strip() for id in cat_id.split(',')] # Get tags related to a post tag = (post_meta.replace('{', '') .replace('}', '') .replace('a:1:s:3:\\"tag\\";a:', '') .replace('a:0:', '')) if len(tag) > 1: if int(len(tag[:1])) == 1: newtag = tag.split('"')[1] tags.append( BeautifulSoup( newtag, 'xml' ) # bs4 always outputs UTF-8 .decode('utf-8') ) else: i = 1 j = 1 while(i <= int(tag[:1])): newtag = tag.split('"')[j].replace('\\', '') tags.append( BeautifulSoup( newtag, 'xml' ) # bs4 always outputs UTF-8 .decode('utf-8') ) i = i + 1 if j < int(tag[:1]) * 2: j = j + 2 """ dotclear2 does not use markdown by default unless you use the markdown plugin Ref: http://plugins.dotaddict.org/dc2/details/formatting-markdown """ if post_format == "markdown": content = post_excerpt + post_content else: content = post_excerpt_xhtml + post_content_xhtml content = content.replace('\\n', '') post_format = "html" kind = 'article' # TODO: Recognise pages status = 'published' # TODO: Find a way for draft posts yield (post_title, content, slugify(post_title), post_creadt, author, categories, tags, status, kind, post_format) def posterous2fields(api_token, email, password): """Imports posterous posts""" import base64 from datetime import timedelta try: # py3k import import json except ImportError: # py2 import import simplejson as json try: # py3k import import urllib.request as urllib_request except ImportError: # py2 import import urllib2 as urllib_request def get_posterous_posts(api_token, email, password, page=1): base64string = base64.encodestring( ("%s:%s" % (email, password)).encode('utf-8')).replace('\n', '') url = ("http://posterous.com/api/v2/users/me/sites/primary/" "posts?api_token=%s&page=%d") % (api_token, page) request = urllib_request.Request(url) request.add_header('Authorization', 'Basic %s' % base64string.decode()) handle = urllib_request.urlopen(request) posts = json.loads(handle.read().decode('utf-8')) return posts page = 1 posts = get_posterous_posts(api_token, email, password, page) while len(posts) > 0: posts = get_posterous_posts(api_token, email, password, page) page += 1 for post in posts: slug = post.get('slug') if not slug: slug = slugify(post.get('title')) tags = [tag.get('name') for tag in post.get('tags')] raw_date = post.get('display_date') date_object = SafeDatetime.strptime( raw_date[:-6], '%Y/%m/%d %H:%M:%S') offset = int(raw_date[-5:]) delta = timedelta(hours=(offset / 100)) date_object -= delta date = date_object.strftime('%Y-%m-%d %H:%M') kind = 'article' # TODO: Recognise pages status = 'published' # TODO: Find a way for draft posts yield (post.get('title'), post.get('body_cleaned'), slug, date, post.get('user').get('display_name'), [], tags, status, kind, 'html') def tumblr2fields(api_key, blogname): """ Imports Tumblr posts (API v2)""" from time import strftime, localtime try: # py3k import import json except ImportError: # py2 import import simplejson as json try: # py3k import import urllib.request as urllib_request except ImportError: # py2 import import urllib2 as urllib_request def get_tumblr_posts(api_key, blogname, offset=0): url = ("http://api.tumblr.com/v2/blog/%s.tumblr.com/" "posts?api_key=%s&offset=%d&filter=raw") % ( blogname, api_key, offset) request = urllib_request.Request(url) handle = urllib_request.urlopen(request) posts = json.loads(handle.read().decode('utf-8')) return posts.get('response').get('posts') offset = 0 posts = get_tumblr_posts(api_key, blogname, offset) while len(posts) > 0: for post in posts: title = \ post.get('title') or \ post.get('source_title') or \ post.get('type').capitalize() slug = post.get('slug') or slugify(title) tags = post.get('tags') timestamp = post.get('timestamp') date = strftime("%Y-%m-%d %H:%M:%S", localtime(int(timestamp))) slug = strftime("%Y-%m-%d-", localtime(int(timestamp))) + slug format = post.get('format') content = post.get('body') type = post.get('type') if type == 'photo': if format == 'markdown': fmtstr = '![%s](%s)' else: fmtstr = '%s' content = '' for photo in post.get('photos'): content += '\n'.join( fmtstr % (photo.get('caption'), photo.get('original_size').get('url'))) content += '\n\n' + post.get('caption') elif type == 'quote': if format == 'markdown': fmtstr = '\n\n— %s' else: fmtstr = '

    — %s

    ' content = post.get('text') + fmtstr % post.get('source') elif type == 'link': if format == 'markdown': fmtstr = '[via](%s)\n\n' else: fmtstr = '

    via

    \n' content = fmtstr % post.get('url') + post.get('description') elif type == 'audio': if format == 'markdown': fmtstr = '[via](%s)\n\n' else: fmtstr = '

    via

    \n' content = fmtstr % post.get('source_url') + \ post.get('caption') + \ post.get('player') elif type == 'video': if format == 'markdown': fmtstr = '[via](%s)\n\n' else: fmtstr = '

    via

    \n' source = fmtstr % post.get('source_url') caption = post.get('caption') players = '\n'.join(player.get('embed_code') for player in post.get('player')) content = source + caption + players elif type == 'answer': title = post.get('question') content = ('

    ' '%s' ': %s' '

    \n' ' %s' % (post.get('asking_name'), post.get('asking_url'), post.get('question'), post.get('answer'))) content = content.rstrip() + '\n' kind = 'article' status = 'published' # TODO: Find a way for draft posts yield (title, content, slug, date, post.get('blog_name'), [type], tags, status, kind, format) offset += len(posts) posts = get_tumblr_posts(api_key, blogname, offset) def feed2fields(file): """Read a feed and yield pelican fields""" import feedparser d = feedparser.parse(file) for entry in d.entries: date = (time.strftime('%Y-%m-%d %H:%M', entry.updated_parsed) if hasattr(entry, 'updated_parsed') else None) author = entry.author if hasattr(entry, 'author') else None tags = ([e['term'] for e in entry.tags] if hasattr(entry, 'tags') else None) slug = slugify(entry.title) kind = 'article' yield (entry.title, entry.description, slug, date, author, [], tags, None, kind, 'html') def build_header(title, date, author, categories, tags, slug, status=None, attachments=None): """Build a header from a list of fields""" from docutils.utils import column_width header = '%s\n%s\n' % (title, '#' * column_width(title)) if date: header += ':date: %s\n' % date if author: header += ':author: %s\n' % author if categories: header += ':category: %s\n' % ', '.join(categories) if tags: header += ':tags: %s\n' % ', '.join(tags) if slug: header += ':slug: %s\n' % slug if status: header += ':status: %s\n' % status if attachments: header += ':attachments: %s\n' % ', '.join(attachments) header += '\n' return header def build_markdown_header(title, date, author, categories, tags, slug, status=None, attachments=None): """Build a header from a list of fields""" header = 'Title: %s\n' % title if date: header += 'Date: %s\n' % date if author: header += 'Author: %s\n' % author if categories: header += 'Category: %s\n' % ', '.join(categories) if tags: header += 'Tags: %s\n' % ', '.join(tags) if slug: header += 'Slug: %s\n' % slug if status: header += 'Status: %s\n' % status if attachments: header += 'Attachments: %s\n' % ', '.join(attachments) header += '\n' return header def get_ext(out_markup, in_markup='html'): if in_markup == 'markdown' or out_markup == 'markdown': ext = '.md' else: ext = '.rst' return ext def get_out_filename(output_path, filename, ext, kind, dirpage, dircat, categories, wp_custpost): filename = os.path.basename(filename) # Enforce filename restrictions for various filesystems at once; see # http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words # we do not need to filter words because an extension will be appended filename = re.sub(r'[<>:"/\\|?*^% ]', '-', filename) # invalid chars filename = filename.lstrip('.') # should not start with a dot if not filename: filename = '_' filename = filename[:249] # allow for 5 extra characters out_filename = os.path.join(output_path, filename + ext) # option to put page posts in pages/ subdirectory if dirpage and kind == 'page': pages_dir = os.path.join(output_path, 'pages') if not os.path.isdir(pages_dir): os.mkdir(pages_dir) out_filename = os.path.join(pages_dir, filename + ext) elif not dirpage and kind == 'page': pass # option to put wp custom post types in directories with post type # names. Custom post types can also have categories so option to # create subdirectories with category names elif kind != 'article': if wp_custpost: typename = slugify(kind) else: typename = '' kind = 'article' if dircat and (len(categories) > 0): catname = slugify(categories[0]) else: catname = '' out_filename = os.path.join(output_path, typename, catname, filename + ext) if not os.path.isdir(os.path.join(output_path, typename, catname)): os.makedirs(os.path.join(output_path, typename, catname)) # option to put files in directories with categories names elif dircat and (len(categories) > 0): catname = slugify(categories[0]) out_filename = os.path.join(output_path, catname, filename + ext) if not os.path.isdir(os.path.join(output_path, catname)): os.mkdir(os.path.join(output_path, catname)) return out_filename def get_attachments(xml): """returns a dictionary of posts that have attachments with a list of the attachment_urls """ items = get_items(xml) names = {} attachments = [] for item in items: kind = item.find('post_type').string filename = item.find('post_name').string post_id = item.find('post_id').string if kind == 'attachment': attachments.append((item.find('post_parent').string, item.find('attachment_url').string)) else: filename = get_filename(filename, post_id) names[post_id] = filename attachedposts = {} for parent, url in attachments: try: parent_name = names[parent] except KeyError: # attachment's parent is not a valid post parent_name = None try: attachedposts[parent_name].append(url) except KeyError: attachedposts[parent_name] = [] attachedposts[parent_name].append(url) return attachedposts def download_attachments(output_path, urls): """Downloads WordPress attachments and returns a list of paths to attachments that can be associated with a post (relative path to output directory). Files that fail to download, will not be added to posts""" locations = [] for url in urls: path = urlparse(url).path # teardown path and rebuild to negate any errors with # os.path.join and leading /'s path = path.split('/') filename = path.pop(-1) localpath = '' for item in path: if sys.platform != 'win32' or ':' not in item: localpath = os.path.join(localpath, item) full_path = os.path.join(output_path, localpath) if not os.path.exists(full_path): os.makedirs(full_path) print('downloading {}'.format(filename)) try: urlretrieve(url, os.path.join(full_path, filename)) locations.append(os.path.join(localpath, filename)) except (URLError, IOError) as e: # Python 2.7 throws an IOError rather Than URLError logger.warning("No file could be downloaded from %s\n%s", url, e) return locations def fields2pelican( fields, out_markup, output_path, dircat=False, strip_raw=False, disable_slugs=False, dirpage=False, filename_template=None, filter_author=None, wp_custpost=False, wp_attach=False, attachments=None): for (title, content, filename, date, author, categories, tags, status, kind, in_markup) in fields: if filter_author and filter_author != author: continue slug = not disable_slugs and filename or None if wp_attach and attachments: try: urls = attachments[filename] attached_files = download_attachments(output_path, urls) except KeyError: attached_files = None else: attached_files = None ext = get_ext(out_markup, in_markup) if ext == '.md': header = build_markdown_header( title, date, author, categories, tags, slug, status, attached_files) else: out_markup = 'rst' header = build_header(title, date, author, categories, tags, slug, status, attached_files) out_filename = get_out_filename( output_path, filename, ext, kind, dirpage, dircat, categories, wp_custpost) print(out_filename) if in_markup in ('html', 'wp-html'): html_filename = os.path.join(output_path, filename + '.html') with open(html_filename, 'w', encoding='utf-8') as fp: # Replace newlines with paragraphs wrapped with

    so # HTML is valid before conversion if in_markup == 'wp-html': new_content = decode_wp_content(content) else: paragraphs = content.splitlines() paragraphs = ['

    {0}

    '.format(p) for p in paragraphs] new_content = ''.join(paragraphs) fp.write(new_content) parse_raw = '--parse-raw' if not strip_raw else '' cmd = ('pandoc --normalize {0} --from=html' ' --to={1} -o "{2}" "{3}"') cmd = cmd.format(parse_raw, out_markup, out_filename, html_filename) try: rc = subprocess.call(cmd, shell=True) if rc < 0: error = 'Child was terminated by signal %d' % -rc exit(error) elif rc > 0: error = 'Please, check your Pandoc installation.' exit(error) except OSError as e: error = 'Pandoc execution failed: %s' % e exit(error) os.remove(html_filename) with open(out_filename, 'r', encoding='utf-8') as fs: content = fs.read() if out_markup == 'markdown': # In markdown, to insert a
    , end a line with two # or more spaces & then a end-of-line content = content.replace('\\\n ', ' \n') content = content.replace('\\\n', ' \n') with open(out_filename, 'w', encoding='utf-8') as fs: fs.write(header + content) if wp_attach and attachments and None in attachments: print("downloading attachments that don't have a parent post") urls = attachments[None] download_attachments(output_path, urls) def main(): parser = argparse.ArgumentParser( description="Transform feed, WordPress, Tumblr, Dotclear, or " "Posterous files into reST (rst) or Markdown (md) files. " "Be sure to have pandoc installed.", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( dest='input', help='The input file to read') parser.add_argument( '--wpfile', action='store_true', dest='wpfile', help='Wordpress XML export') parser.add_argument( '--dotclear', action='store_true', dest='dotclear', help='Dotclear export') parser.add_argument( '--posterous', action='store_true', dest='posterous', help='Posterous export') parser.add_argument( '--tumblr', action='store_true', dest='tumblr', help='Tumblr export') parser.add_argument( '--feed', action='store_true', dest='feed', help='Feed to parse') parser.add_argument( '-o', '--output', dest='output', default='output', help='Output path') parser.add_argument( '-m', '--markup', dest='markup', default='rst', help='Output markup format (supports rst & markdown)') parser.add_argument( '--dir-cat', action='store_true', dest='dircat', help='Put files in directories with categories name') parser.add_argument( '--dir-page', action='store_true', dest='dirpage', help=('Put files recognised as pages in "pages/" sub-directory' ' (wordpress import only)')) parser.add_argument( '--filter-author', dest='author', help='Import only post from the specified author') parser.add_argument( '--strip-raw', action='store_true', dest='strip_raw', help="Strip raw HTML code that can't be converted to " "markup such as flash embeds or iframes (wordpress import only)") parser.add_argument( '--wp-custpost', action='store_true', dest='wp_custpost', help='Put wordpress custom post types in directories. If used with ' '--dir-cat option directories will be created as ' '/post_type/category/ (wordpress import only)') parser.add_argument( '--wp-attach', action='store_true', dest='wp_attach', help='(wordpress import only) Download files uploaded to wordpress as ' 'attachments. Files will be added to posts as a list in the post ' 'header. All files will be downloaded, even if ' "they aren't associated with a post. Files with be downloaded " 'with their original path inside the output directory. ' 'e.g. output/wp-uploads/date/postname/file.jpg ' '-- Requires an internet connection --') parser.add_argument( '--disable-slugs', action='store_true', dest='disable_slugs', help='Disable storing slugs from imported posts within output. ' 'With this disabled, your Pelican URLs may not be consistent ' 'with your original posts.') parser.add_argument( '-e', '--email', dest='email', help="Email address (posterous import only)") parser.add_argument( '-p', '--password', dest='password', help="Password (posterous import only)") parser.add_argument( '-b', '--blogname', dest='blogname', help="Blog name (Tumblr import only)") args = parser.parse_args() input_type = None if args.wpfile: input_type = 'wordpress' elif args.dotclear: input_type = 'dotclear' elif args.posterous: input_type = 'posterous' elif args.tumblr: input_type = 'tumblr' elif args.feed: input_type = 'feed' else: error = ('You must provide either --wpfile, --dotclear, ' '--posterous, --tumblr or --feed options') exit(error) if not os.path.exists(args.output): try: os.mkdir(args.output) except OSError: error = 'Unable to create the output folder: ' + args.output exit(error) if args.wp_attach and input_type != 'wordpress': error = ('You must be importing a wordpress xml ' 'to use the --wp-attach option') exit(error) if input_type == 'wordpress': fields = wp2fields(args.input, args.wp_custpost or False) elif input_type == 'dotclear': fields = dc2fields(args.input) elif input_type == 'posterous': fields = posterous2fields(args.input, args.email, args.password) elif input_type == 'tumblr': fields = tumblr2fields(args.input, args.blogname) elif input_type == 'feed': fields = feed2fields(args.input) if args.wp_attach: attachments = get_attachments(args.input) else: attachments = None # init logging init() fields2pelican(fields, args.markup, args.output, dircat=args.dircat or False, dirpage=args.dirpage or False, strip_raw=args.strip_raw or False, disable_slugs=args.disable_slugs or False, filter_author=args.author, wp_custpost=args.wp_custpost or False, wp_attach=args.wp_attach or False, attachments=attachments or None) pelican-3.7.1/pelican/tools/pelican_quickstart.py000077500000000000000000000353661303525152100221640ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import argparse import codecs import locale import os import string import sys import pytz try: import tzlocal _DEFAULT_TIMEZONE = tzlocal.get_localzone().zone except: _DEFAULT_TIMEZONE = 'Europe/Paris' import six from pelican import __version__ locale.setlocale(locale.LC_ALL, '') _DEFAULT_LANGUAGE = locale.getlocale()[0] if _DEFAULT_LANGUAGE is None: _DEFAULT_LANGUAGE = 'English' else: _DEFAULT_LANGUAGE = _DEFAULT_LANGUAGE.split('_')[0] _TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates") _GITHUB_PAGES_BRANCHES = { 'personal': 'master', 'project': 'gh-pages' } CONF = { 'pelican': 'pelican', 'pelicanopts': '', 'basedir': os.curdir, 'ftp_host': 'localhost', 'ftp_user': 'anonymous', 'ftp_target_dir': '/', 'ssh_host': 'localhost', 'ssh_port': 22, 'ssh_user': 'root', 'ssh_target_dir': '/var/www', 's3_bucket': 'my_s3_bucket', 'cloudfiles_username': 'my_rackspace_username', 'cloudfiles_api_key': 'my_rackspace_api_key', 'cloudfiles_container': 'my_cloudfiles_container', 'dropbox_dir': '~/Dropbox/Public/', 'github_pages_branch': _GITHUB_PAGES_BRANCHES['project'], 'default_pagination': 10, 'siteurl': '', 'lang': _DEFAULT_LANGUAGE, 'timezone': _DEFAULT_TIMEZONE } # url for list of valid timezones _TZ_URL = 'http://en.wikipedia.org/wiki/List_of_tz_database_time_zones' def _input_compat(prompt): if six.PY3: r = input(prompt) else: r = raw_input(prompt) return r if six.PY3: str_compat = str else: str_compat = unicode # Create a 'marked' default path, to determine if someone has supplied # a path on the command-line. class _DEFAULT_PATH_TYPE(str_compat): is_default_path = True _DEFAULT_PATH = _DEFAULT_PATH_TYPE(os.curdir) def decoding_strings(f): def wrapper(*args, **kwargs): out = f(*args, **kwargs) if isinstance(out, six.string_types) and not six.PY3: # todo: make encoding configurable? if six.PY3: return out else: return out.decode(sys.stdin.encoding) return out return wrapper def get_template(name, as_encoding='utf-8'): template = os.path.join(_TEMPLATES_DIR, "{0}.in".format(name)) if not os.path.isfile(template): raise RuntimeError("Cannot open {0}".format(template)) with codecs.open(template, 'r', as_encoding) as fd: line = fd.readline() while line: yield line line = fd.readline() fd.close() @decoding_strings def ask(question, answer=str_compat, default=None, l=None): if answer == str_compat: r = '' while True: if default: r = _input_compat('> {0} [{1}] '.format(question, default)) else: r = _input_compat('> {0} '.format(question, default)) r = r.strip() if len(r) <= 0: if default: r = default break else: print('You must enter something') else: if l and len(r) != l: print('You must enter a {0} letters long string'.format(l)) else: break return r elif answer == bool: r = None while True: if default is True: r = _input_compat('> {0} (Y/n) '.format(question)) elif default is False: r = _input_compat('> {0} (y/N) '.format(question)) else: r = _input_compat('> {0} (y/n) '.format(question)) r = r.strip().lower() if r in ('y', 'yes'): r = True break elif r in ('n', 'no'): r = False break elif not r: r = default break else: print("You must answer 'yes' or 'no'") return r elif answer == int: r = None while True: if default: r = _input_compat('> {0} [{1}] '.format(question, default)) else: r = _input_compat('> {0} '.format(question)) r = r.strip() if not r: r = default break try: r = int(r) break except: print('You must enter an integer') return r else: raise NotImplemented( 'Argument `answer` must be str_compat, bool, or integer') def ask_timezone(question, default, tzurl): """Prompt for time zone and validate input""" lower_tz = [tz.lower() for tz in pytz.all_timezones] while True: r = ask(question, str_compat, default) r = r.strip().replace(' ', '_').lower() if r in lower_tz: r = pytz.all_timezones[lower_tz.index(r)] break else: print('Please enter a valid time zone:\n' ' (check [{0}])'.format(tzurl)) return r def main(): parser = argparse.ArgumentParser( description="A kickstarter for Pelican", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('-p', '--path', default=_DEFAULT_PATH, help="The path to generate the blog into") parser.add_argument('-t', '--title', metavar="title", help='Set the title of the website') parser.add_argument('-a', '--author', metavar="author", help='Set the author name of the website') parser.add_argument('-l', '--lang', metavar="lang", help='Set the default web site language') args = parser.parse_args() print('''Welcome to pelican-quickstart v{v}. This script will help you create a new Pelican-based website. Please answer the following questions so this script can generate the files needed by Pelican. '''.format(v=__version__)) project = os.path.join( os.environ.get('VIRTUAL_ENV', os.curdir), '.project') no_path_was_specified = hasattr(args.path, 'is_default_path') if os.path.isfile(project) and no_path_was_specified: CONF['basedir'] = open(project, 'r').read().rstrip("\n") print('Using project associated with current virtual environment.' 'Will save to:\n%s\n' % CONF['basedir']) else: CONF['basedir'] = os.path.abspath(os.path.expanduser( ask('Where do you want to create your new web site?', answer=str_compat, default=args.path))) CONF['sitename'] = ask('What will be the title of this web site?', answer=str_compat, default=args.title) CONF['author'] = ask('Who will be the author of this web site?', answer=str_compat, default=args.author) CONF['lang'] = ask('What will be the default language of this web site?', str_compat, args.lang or CONF['lang'], 2) if ask('Do you want to specify a URL prefix? e.g., http://example.com ', answer=bool, default=True): CONF['siteurl'] = ask('What is your URL prefix? (see ' 'above example; no trailing slash)', str_compat, CONF['siteurl']) CONF['with_pagination'] = ask('Do you want to enable article pagination?', bool, bool(CONF['default_pagination'])) if CONF['with_pagination']: CONF['default_pagination'] = ask('How many articles per page ' 'do you want?', int, CONF['default_pagination']) else: CONF['default_pagination'] = False CONF['timezone'] = ask_timezone('What is your time zone?', CONF['timezone'], _TZ_URL) automation = ask('Do you want to generate a Fabfile/Makefile ' 'to automate generation and publishing?', bool, True) develop = ask('Do you want an auto-reload & simpleHTTP script ' 'to assist with theme and site development?', bool, True) if automation: if ask('Do you want to upload your website using FTP?', answer=bool, default=False): CONF['ftp_host'] = ask('What is the hostname of your FTP server?', str_compat, CONF['ftp_host']) CONF['ftp_user'] = ask('What is your username on that server?', str_compat, CONF['ftp_user']) CONF['ftp_target_dir'] = ask('Where do you want to put your ' 'web site on that server?', str_compat, CONF['ftp_target_dir']) if ask('Do you want to upload your website using SSH?', answer=bool, default=False): CONF['ssh_host'] = ask('What is the hostname of your SSH server?', str_compat, CONF['ssh_host']) CONF['ssh_port'] = ask('What is the port of your SSH server?', int, CONF['ssh_port']) CONF['ssh_user'] = ask('What is your username on that server?', str_compat, CONF['ssh_user']) CONF['ssh_target_dir'] = ask('Where do you want to put your ' 'web site on that server?', str_compat, CONF['ssh_target_dir']) if ask('Do you want to upload your website using Dropbox?', answer=bool, default=False): CONF['dropbox_dir'] = ask('Where is your Dropbox directory?', str_compat, CONF['dropbox_dir']) if ask('Do you want to upload your website using S3?', answer=bool, default=False): CONF['s3_bucket'] = ask('What is the name of your S3 bucket?', str_compat, CONF['s3_bucket']) if ask('Do you want to upload your website using ' 'Rackspace Cloud Files?', answer=bool, default=False): CONF['cloudfiles_username'] = ask('What is your Rackspace ' 'Cloud username?', str_compat, CONF['cloudfiles_username']) CONF['cloudfiles_api_key'] = ask('What is your Rackspace ' 'Cloud API key?', str_compat, CONF['cloudfiles_api_key']) CONF['cloudfiles_container'] = ask('What is the name of your ' 'Cloud Files container?', str_compat, CONF['cloudfiles_container']) if ask('Do you want to upload your website using GitHub Pages?', answer=bool, default=False): if ask('Is this your personal page (username.github.io)?', answer=bool, default=False): CONF['github_pages_branch'] = \ _GITHUB_PAGES_BRANCHES['personal'] else: CONF['github_pages_branch'] = \ _GITHUB_PAGES_BRANCHES['project'] try: os.makedirs(os.path.join(CONF['basedir'], 'content')) except OSError as e: print('Error: {0}'.format(e)) try: os.makedirs(os.path.join(CONF['basedir'], 'output')) except OSError as e: print('Error: {0}'.format(e)) try: with codecs.open(os.path.join(CONF['basedir'], 'pelicanconf.py'), 'w', 'utf-8') as fd: conf_python = dict() for key, value in CONF.items(): conf_python[key] = repr(value) for line in get_template('pelicanconf.py'): template = string.Template(line) fd.write(template.safe_substitute(conf_python)) fd.close() except OSError as e: print('Error: {0}'.format(e)) try: with codecs.open(os.path.join(CONF['basedir'], 'publishconf.py'), 'w', 'utf-8') as fd: for line in get_template('publishconf.py'): template = string.Template(line) fd.write(template.safe_substitute(CONF)) fd.close() except OSError as e: print('Error: {0}'.format(e)) if automation: try: with codecs.open(os.path.join(CONF['basedir'], 'fabfile.py'), 'w', 'utf-8') as fd: for line in get_template('fabfile.py'): template = string.Template(line) fd.write(template.safe_substitute(CONF)) fd.close() except OSError as e: print('Error: {0}'.format(e)) try: with codecs.open(os.path.join(CONF['basedir'], 'Makefile'), 'w', 'utf-8') as fd: mkfile_template_name = 'Makefile' py_v = 'PY?=python' if six.PY3: py_v = 'PY?=python3' template = string.Template(py_v) fd.write(template.safe_substitute(CONF)) fd.write('\n') for line in get_template(mkfile_template_name): template = string.Template(line) fd.write(template.safe_substitute(CONF)) fd.close() except OSError as e: print('Error: {0}'.format(e)) if develop: conf_shell = dict() for key, value in CONF.items(): if isinstance(value, six.string_types) and ' ' in value: value = '"' + value.replace('"', '\\"') + '"' conf_shell[key] = value try: with codecs.open(os.path.join(CONF['basedir'], 'develop_server.sh'), 'w', 'utf-8') as fd: lines = list(get_template('develop_server.sh')) py_v = 'PY=${PY:-python}\n' if six.PY3: py_v = 'PY=${PY:-python3}\n' lines = lines[:4] + [py_v] + lines[4:] for line in lines: template = string.Template(line) fd.write(template.safe_substitute(conf_shell)) fd.close() # mode 0o755 os.chmod((os.path.join(CONF['basedir'], 'develop_server.sh')), 493) except OSError as e: print('Error: {0}'.format(e)) print('Done. Your new project is available at %s' % CONF['basedir']) if __name__ == "__main__": main() pelican-3.7.1/pelican/tools/pelican_themes.py000077500000000000000000000177601303525152100212550ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import argparse import os import shutil import sys def err(msg, die=None): """Print an error message and exits if an exit code is given""" sys.stderr.write(msg + '\n') if die: sys.exit((die if type(die) is int else 1)) try: import pelican except: err('Cannot import pelican.\nYou must ' 'install Pelican in order to run this script.', -1) global _THEMES_PATH _THEMES_PATH = os.path.join( os.path.dirname( os.path.abspath(pelican.__file__) ), 'themes' ) __version__ = '0.2' _BUILTIN_THEMES = ['simple', 'notmyidea'] def main(): """Main function""" parser = argparse.ArgumentParser( description="""Install themes for Pelican""") excl = parser.add_mutually_exclusive_group() excl.add_argument( '-l', '--list', dest='action', action="store_const", const='list', help="Show the themes already installed and exit") excl.add_argument( '-p', '--path', dest='action', action="store_const", const='path', help="Show the themes path and exit") excl.add_argument( '-V', '--version', action='version', version='pelican-themes v{0}'.format(__version__), help='Print the version of this script') parser.add_argument( '-i', '--install', dest='to_install', nargs='+', metavar="theme path", help='The themes to install') parser.add_argument( '-r', '--remove', dest='to_remove', nargs='+', metavar="theme name", help='The themes to remove') parser.add_argument( '-U', '--upgrade', dest='to_upgrade', nargs='+', metavar="theme path", help='The themes to upgrade') parser.add_argument( '-s', '--symlink', dest='to_symlink', nargs='+', metavar="theme path", help="Same as `--install', but create a symbolic link instead of " "copying the theme. Useful for theme development") parser.add_argument( '-c', '--clean', dest='clean', action="store_true", help="Remove the broken symbolic links of the theme path") parser.add_argument( '-v', '--verbose', dest='verbose', action="store_true", help="Verbose output") args = parser.parse_args() to_install = args.to_install or args.to_upgrade to_sym = args.to_symlink or args.clean if args.action: if args.action is 'list': list_themes(args.verbose) elif args.action is 'path': print(_THEMES_PATH) elif to_install or args.to_remove or to_sym: if args.to_remove: if args.verbose: print('Removing themes...') for i in args.to_remove: remove(i, v=args.verbose) if args.to_install: if args.verbose: print('Installing themes...') for i in args.to_install: install(i, v=args.verbose) if args.to_upgrade: if args.verbose: print('Upgrading themes...') for i in args.to_upgrade: install(i, v=args.verbose, u=True) if args.to_symlink: if args.verbose: print('Linking themes...') for i in args.to_symlink: symlink(i, v=args.verbose) if args.clean: if args.verbose: print('Cleaning the themes directory...') clean(v=args.verbose) else: print('No argument given... exiting.') def themes(): """Returns the list of the themes""" for i in os.listdir(_THEMES_PATH): e = os.path.join(_THEMES_PATH, i) if os.path.isdir(e): if os.path.islink(e): yield (e, os.readlink(e)) else: yield (e, None) def list_themes(v=False): """Display the list of the themes""" for t, l in themes(): if not v: t = os.path.basename(t) if l: if v: print(t + (" (symbolic link to `" + l + "')")) else: print(t + '@') else: print(t) def remove(theme_name, v=False): """Removes a theme""" theme_name = theme_name.replace('/', '') target = os.path.join(_THEMES_PATH, theme_name) if theme_name in _BUILTIN_THEMES: err(theme_name + ' is a builtin theme.\n' 'You cannot remove a builtin theme with this script, ' 'remove it by hand if you want.') elif os.path.islink(target): if v: print('Removing link `' + target + "'") os.remove(target) elif os.path.isdir(target): if v: print('Removing directory `' + target + "'") shutil.rmtree(target) elif os.path.exists(target): err(target + ' : not a valid theme') else: err(target + ' : no such file or directory') def install(path, v=False, u=False): """Installs a theme""" if not os.path.exists(path): err(path + ' : no such file or directory') elif not os.path.isdir(path): err(path + ' : not a directory') else: theme_name = os.path.basename(os.path.normpath(path)) theme_path = os.path.join(_THEMES_PATH, theme_name) exists = os.path.exists(theme_path) if exists and not u: err(path + ' : already exists') elif exists and u: remove(theme_name, v) install(path, v) else: if v: print("Copying '{p}' to '{t}' ...".format(p=path, t=theme_path)) try: shutil.copytree(path, theme_path) try: if os.name == 'posix': for root, dirs, files in os.walk(theme_path): for d in dirs: dname = os.path.join(root, d) os.chmod(dname, 493) # 0o755 for f in files: fname = os.path.join(root, f) os.chmod(fname, 420) # 0o644 except OSError as e: err("Cannot change permissions of files " "or directory in `{r}':\n{e}".format(r=theme_path, e=str(e)), die=False) except Exception as e: err("Cannot copy `{p}' to `{t}':\n{e}".format( p=path, t=theme_path, e=str(e))) def symlink(path, v=False): """Symbolically link a theme""" if not os.path.exists(path): err(path + ' : no such file or directory') elif not os.path.isdir(path): err(path + ' : not a directory') else: theme_name = os.path.basename(os.path.normpath(path)) theme_path = os.path.join(_THEMES_PATH, theme_name) if os.path.exists(theme_path): err(path + ' : already exists') else: if v: print("Linking `{p}' to `{t}' ...".format( p=path, t=theme_path)) try: os.symlink(path, theme_path) except Exception as e: err("Cannot link `{p}' to `{t}':\n{e}".format( p=path, t=theme_path, e=str(e))) def is_broken_link(path): """Returns True if the path given as is a broken symlink""" path = os.readlink(path) return not os.path.exists(path) def clean(v=False): """Removes the broken symbolic links""" c = 0 for path in os.listdir(_THEMES_PATH): path = os.path.join(_THEMES_PATH, path) if os.path.islink(path): if is_broken_link(path): if v: print('Removing {0}'.format(path)) try: os.remove(path) except OSError: print('Error: cannot remove {0}'.format(path)) else: c += 1 print("\nRemoved {0} broken links".format(c)) pelican-3.7.1/pelican/tools/templates/000077500000000000000000000000001303525152100177035ustar00rootroot00000000000000pelican-3.7.1/pelican/tools/templates/Makefile.in000066400000000000000000000105411303525152100217510ustar00rootroot00000000000000PELICAN?=$pelican PELICANOPTS=$pelicanopts BASEDIR=$$(CURDIR) INPUTDIR=$$(BASEDIR)/content OUTPUTDIR=$$(BASEDIR)/output CONFFILE=$$(BASEDIR)/pelicanconf.py PUBLISHCONF=$$(BASEDIR)/publishconf.py FTP_HOST=$ftp_host FTP_USER=$ftp_user FTP_TARGET_DIR=$ftp_target_dir SSH_HOST=$ssh_host SSH_PORT=$ssh_port SSH_USER=$ssh_user SSH_TARGET_DIR=$ssh_target_dir S3_BUCKET=$s3_bucket CLOUDFILES_USERNAME=$cloudfiles_username CLOUDFILES_API_KEY=$cloudfiles_api_key CLOUDFILES_CONTAINER=$cloudfiles_container DROPBOX_DIR=$dropbox_dir GITHUB_PAGES_BRANCH=$github_pages_branch DEBUG ?= 0 ifeq ($(DEBUG), 1) PELICANOPTS += -D endif RELATIVE ?= 0 ifeq ($(RELATIVE), 1) PELICANOPTS += --relative-urls endif help: @echo 'Makefile for a pelican Web site ' @echo ' ' @echo 'Usage: ' @echo ' make html (re)generate the web site ' @echo ' make clean remove the generated files ' @echo ' make regenerate regenerate files upon modification ' @echo ' make publish generate using production settings ' @echo ' make serve [PORT=8000] serve site at http://localhost:8000' @echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 ' @echo ' make devserver [PORT=8000] start/restart develop_server.sh ' @echo ' make stopserver stop local server ' @echo ' make ssh_upload upload the web site via SSH ' @echo ' make rsync_upload upload the web site via rsync+ssh ' @echo ' make dropbox_upload upload the web site via Dropbox ' @echo ' make ftp_upload upload the web site via FTP ' @echo ' make s3_upload upload the web site via S3 ' @echo ' make cf_upload upload the web site via Cloud Files' @echo ' make github upload the web site via gh-pages ' @echo ' ' @echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html ' @echo 'Set the RELATIVE variable to 1 to enable relative urls ' @echo ' ' html: $$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS) clean: [ ! -d $$(OUTPUTDIR) ] || rm -rf $$(OUTPUTDIR) regenerate: $$(PELICAN) -r $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS) serve: ifdef PORT cd $$(OUTPUTDIR) && $(PY) -m pelican.server $$(PORT) else cd $$(OUTPUTDIR) && $(PY) -m pelican.server endif serve-global: ifdef SERVER cd $$(OUTPUTDIR) && $(PY) -m pelican.server 80 $$(SERVER) else cd $$(OUTPUTDIR) && $(PY) -m pelican.server 80 0.0.0.0 endif devserver: ifdef PORT $$(BASEDIR)/develop_server.sh restart $$(PORT) else $$(BASEDIR)/develop_server.sh restart endif stopserver: $(BASEDIR)/develop_server.sh stop @echo 'Stopped Pelican and SimpleHTTPServer processes running in background.' publish: $$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(PUBLISHCONF) $$(PELICANOPTS) ssh_upload: publish scp -P $$(SSH_PORT) -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR) rsync_upload: publish rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --delete $(OUTPUTDIR)/ $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) --cvs-exclude dropbox_upload: publish cp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR) ftp_upload: publish lftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUTDIR) $$(FTP_TARGET_DIR) ; quit" s3_upload: publish s3cmd sync $(OUTPUTDIR)/ s3://$(S3_BUCKET) --acl-public --delete-removed --guess-mime-type --no-mime-magic --no-preserve cf_upload: publish cd $(OUTPUTDIR) && swift -v -A https://auth.api.rackspacecloud.com/v1.0 -U $(CLOUDFILES_USERNAME) -K $(CLOUDFILES_API_KEY) upload -c $(CLOUDFILES_CONTAINER) . github: publish ghp-import -m "Generate Pelican site" -b $(GITHUB_PAGES_BRANCH) $$(OUTPUTDIR) git push origin $(GITHUB_PAGES_BRANCH) .PHONY: html help clean regenerate serve serve-global devserver stopserver publish ssh_upload rsync_upload dropbox_upload ftp_upload s3_upload cf_upload github pelican-3.7.1/pelican/tools/templates/develop_server.sh.in000077500000000000000000000043341303525152100236770ustar00rootroot00000000000000#!/usr/bin/env bash ## # This section should match your Makefile ## PELICAN=$${PELICAN:-$pelican} PELICANOPTS=$pelicanopts BASEDIR=$$(pwd) INPUTDIR=$$BASEDIR/content OUTPUTDIR=$$BASEDIR/output CONFFILE=$$BASEDIR/pelicanconf.py ### # Don't change stuff below here unless you are sure ### SRV_PID=$$BASEDIR/srv.pid PELICAN_PID=$$BASEDIR/pelican.pid function usage(){ echo "usage: $$0 (stop) (start) (restart) [port]" echo "This starts Pelican in debug and reload mode and then launches" echo "an HTTP server to help site development. It doesn't read" echo "your Pelican settings, so if you edit any paths in your Makefile" echo "you will need to edit your settings as well." exit 3 } function alive() { kill -0 $$1 >/dev/null 2>&1 } function shut_down(){ PID=$$(cat $$SRV_PID) if [[ $$? -eq 0 ]]; then if alive $PID; then echo "Stopping HTTP server" kill $$PID else echo "Stale PID, deleting" fi rm $$SRV_PID else echo "HTTP server PIDFile not found" fi PID=$$(cat $$PELICAN_PID) if [[ $$? -eq 0 ]]; then if alive $$PID; then echo "Killing Pelican" kill $$PID else echo "Stale PID, deleting" fi rm $$PELICAN_PID else echo "Pelican PIDFile not found" fi } function start_up(){ local port=$$1 echo "Starting up Pelican and HTTP server" shift $$PELICAN --debug --autoreload -r $$INPUTDIR -o $$OUTPUTDIR -s $$CONFFILE $$PELICANOPTS & pelican_pid=$$! echo $$pelican_pid > $$PELICAN_PID mkdir -p $$OUTPUTDIR && cd $$OUTPUTDIR $PY -m pelican.server $$port & srv_pid=$$! echo $$srv_pid > $$SRV_PID cd $$BASEDIR sleep 1 if ! alive $$pelican_pid ; then echo "Pelican didn't start. Is the Pelican package installed?" return 1 elif ! alive $$srv_pid ; then echo "The HTTP server didn't start. Is there another service using port" $$port "?" return 1 fi echo 'Pelican and HTTP server processes now running in background.' } ### # MAIN ### [[ ($$# -eq 0) || ($$# -gt 2) ]] && usage port='' [[ $$# -eq 2 ]] && port=$$2 if [[ $$1 == "stop" ]]; then shut_down elif [[ $$1 == "restart" ]]; then shut_down start_up $$port elif [[ $$1 == "start" ]]; then if ! start_up $$port; then shut_down fi else usage fi pelican-3.7.1/pelican/tools/templates/fabfile.py.in000066400000000000000000000046421303525152100222600ustar00rootroot00000000000000from fabric.api import * import fabric.contrib.project as project import os import shutil import sys import SocketServer from pelican.server import ComplexHTTPRequestHandler # Local path configuration (can be absolute or relative to fabfile) env.deploy_path = 'output' DEPLOY_PATH = env.deploy_path # Remote server configuration production = '$ssh_user@$ssh_host:$ssh_port' dest_path = '$ssh_target_dir' # Rackspace Cloud Files configuration settings env.cloudfiles_username = '$cloudfiles_username' env.cloudfiles_api_key = '$cloudfiles_api_key' env.cloudfiles_container = '$cloudfiles_container' # Github Pages configuration env.github_pages_branch = "$github_pages_branch" # Port for `serve` PORT = 8000 def clean(): """Remove generated files""" if os.path.isdir(DEPLOY_PATH): shutil.rmtree(DEPLOY_PATH) os.makedirs(DEPLOY_PATH) def build(): """Build local version of site""" local('pelican -s pelicanconf.py') def rebuild(): """`build` with the delete switch""" local('pelican -d -s pelicanconf.py') def regenerate(): """Automatically regenerate site upon file modification""" local('pelican -r -s pelicanconf.py') def serve(): """Serve site at http://localhost:8000/""" os.chdir(env.deploy_path) class AddressReuseTCPServer(SocketServer.TCPServer): allow_reuse_address = True server = AddressReuseTCPServer(('', PORT), ComplexHTTPRequestHandler) sys.stderr.write('Serving on port {0} ...\n'.format(PORT)) server.serve_forever() def reserve(): """`build`, then `serve`""" build() serve() def preview(): """Build production version of site""" local('pelican -s publishconf.py') def cf_upload(): """Publish to Rackspace Cloud Files""" rebuild() with lcd(DEPLOY_PATH): local('swift -v -A https://auth.api.rackspacecloud.com/v1.0 ' '-U {cloudfiles_username} ' '-K {cloudfiles_api_key} ' 'upload -c {cloudfiles_container} .'.format(**env)) @hosts(production) def publish(): """Publish to production via rsync""" local('pelican -s publishconf.py') project.rsync_project( remote_dir=dest_path, exclude=".DS_Store", local_dir=DEPLOY_PATH.rstrip('/') + '/', delete=True, extra_opts='-c', ) def gh_pages(): """Publish to GitHub Pages""" rebuild() local("ghp-import -b {github_pages_branch} {deploy_path} -p".format(**env)) pelican-3.7.1/pelican/tools/templates/pelicanconf.py.in000066400000000000000000000015401303525152100231430ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # from __future__ import unicode_literals AUTHOR = $author SITENAME = $sitename SITEURL = '' PATH = 'content' TIMEZONE = $timezone DEFAULT_LANG = $lang # Feed generation is usually not desired when developing FEED_ALL_ATOM = None CATEGORY_FEED_ATOM = None TRANSLATION_FEED_ATOM = None AUTHOR_FEED_ATOM = None AUTHOR_FEED_RSS = None # Blogroll LINKS = (('Pelican', 'http://getpelican.com/'), ('Python.org', 'http://python.org/'), ('Jinja2', 'http://jinja.pocoo.org/'), ('You can modify those links in your config file', '#'),) # Social widget SOCIAL = (('You can add links in your config file', '#'), ('Another social link', '#'),) DEFAULT_PAGINATION = $default_pagination # Uncomment following line if you want document-relative URLs when developing #RELATIVE_URLS = True pelican-3.7.1/pelican/tools/templates/publishconf.py.in000077500000000000000000000010041303525152100231740ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # from __future__ import unicode_literals # This file is only used if you use `make publish` or # explicitly specify it as your config file. import os import sys sys.path.append(os.curdir) from pelicanconf import * SITEURL = '$siteurl' RELATIVE_URLS = False FEED_ALL_ATOM = 'feeds/all.atom.xml' CATEGORY_FEED_ATOM = 'feeds/%s.atom.xml' DELETE_OUTPUT_DIRECTORY = True # Following items are often useful when publishing #DISQUS_SITENAME = "" #GOOGLE_ANALYTICS = "" pelican-3.7.1/pelican/urlwrappers.py000066400000000000000000000105721303525152100175120ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import functools import logging import os import six from pelican.utils import python_2_unicode_compatible, slugify logger = logging.getLogger(__name__) @python_2_unicode_compatible @functools.total_ordering class URLWrapper(object): def __init__(self, name, settings): self.settings = settings self._name = name self._slug = None self._slug_from_name = True @property def name(self): return self._name @name.setter def name(self, name): self._name = name # if slug wasn't explicitly set, it needs to be regenerated from name # so, changing name should reset slug for slugification if self._slug_from_name: self._slug = None @property def slug(self): if self._slug is None: self._slug = slugify(self.name, self.settings.get('SLUG_SUBSTITUTIONS', ())) return self._slug @slug.setter def slug(self, slug): # if slug is expliticly set, changing name won't alter slug self._slug_from_name = False self._slug = slug def as_dict(self): d = self.__dict__ d['name'] = self.name d['slug'] = self.slug return d def __hash__(self): return hash(self.slug) def _normalize_key(self, key): subs = self.settings.get('SLUG_SUBSTITUTIONS', ()) return six.text_type(slugify(key, subs)) def __eq__(self, other): if isinstance(other, self.__class__): return self.slug == other.slug if isinstance(other, six.text_type): return self.slug == self._normalize_key(other) return False def __ne__(self, other): if isinstance(other, self.__class__): return self.slug != other.slug if isinstance(other, six.text_type): return self.slug != self._normalize_key(other) return True def __lt__(self, other): if isinstance(other, self.__class__): return self.slug < other.slug if isinstance(other, six.text_type): return self.slug < self._normalize_key(other) return False def __str__(self): return self.name def __repr__(self): return '<{} {}>'.format(type(self).__name__, repr(self._name)) def _from_settings(self, key, get_page_name=False): """Returns URL information as defined in settings. When get_page_name=True returns URL without anything after {slug} e.g. if in settings: CATEGORY_URL="cat/{slug}.html" this returns "cat/{slug}" Useful for pagination. """ setting = "%s_%s" % (self.__class__.__name__.upper(), key) value = self.settings[setting] if not isinstance(value, six.string_types): logger.warning('%s is set to %s', setting, value) return value else: if get_page_name: return os.path.splitext(value)[0].format(**self.as_dict()) else: return value.format(**self.as_dict()) page_name = property(functools.partial(_from_settings, key='URL', get_page_name=True)) url = property(functools.partial(_from_settings, key='URL')) save_as = property(functools.partial(_from_settings, key='SAVE_AS')) class Category(URLWrapper): @property def slug(self): if self._slug is None: substitutions = self.settings.get('SLUG_SUBSTITUTIONS', ()) substitutions += tuple(self.settings.get('CATEGORY_SUBSTITUTIONS', ())) self._slug = slugify(self.name, substitutions) return self._slug class Tag(URLWrapper): def __init__(self, name, *args, **kwargs): super(Tag, self).__init__(name.strip(), *args, **kwargs) @property def slug(self): if self._slug is None: substitutions = self.settings.get('SLUG_SUBSTITUTIONS', ()) substitutions += tuple(self.settings.get('TAG_SUBSTITUTIONS', ())) self._slug = slugify(self.name, substitutions) return self._slug class Author(URLWrapper): @property def slug(self): if self._slug is None: self._slug = slugify(self.name, self.settings.get('AUTHOR_SUBSTITUTIONS', ())) return self._slug pelican-3.7.1/pelican/utils.py000066400000000000000000000657211303525152100162720ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals import codecs import datetime import errno import fnmatch import locale import logging import os import re import shutil import sys import traceback from collections import Hashable from contextlib import contextmanager from functools import partial from itertools import groupby from operator import attrgetter import dateutil.parser from jinja2 import Markup import pytz import six from six.moves import html_entities from six.moves.html_parser import HTMLParser try: from html import escape except ImportError: from cgi import escape logger = logging.getLogger(__name__) def strftime(date, date_format): ''' Replacement for built-in strftime This is necessary because of the way Py2 handles date format strings. Specifically, Py2 strftime takes a bytestring. In the case of text output (e.g. %b, %a, etc), the output is encoded with an encoding defined by locale.LC_TIME. Things get messy if the formatting string has chars that are not valid in LC_TIME defined encoding. This works by 'grabbing' possible format strings (those starting with %), formatting them with the date, (if necessary) decoding the output and replacing formatted output back. ''' def strip_zeros(x): return x.lstrip('0') or '0' c89_directives = 'aAbBcdfHIjmMpSUwWxXyYzZ%' # grab candidate format options format_options = '%[-]?.' candidates = re.findall(format_options, date_format) # replace candidates with placeholders for later % formatting template = re.sub(format_options, '%s', date_format) # we need to convert formatted dates back to unicode in Py2 # LC_TIME determines the encoding for built-in strftime outputs lang_code, enc = locale.getlocale(locale.LC_TIME) formatted_candidates = [] for candidate in candidates: # test for valid C89 directives only if candidate[-1] in c89_directives: # check for '-' prefix if len(candidate) == 3: # '-' prefix candidate = '%{}'.format(candidate[-1]) conversion = strip_zeros else: conversion = None # format date if isinstance(date, SafeDatetime): formatted = date.strftime(candidate, safe=False) else: formatted = date.strftime(candidate) # convert Py2 result to unicode if not six.PY3 and enc is not None: formatted = formatted.decode(enc) # strip zeros if '-' prefix is used if conversion: formatted = conversion(formatted) else: formatted = candidate formatted_candidates.append(formatted) # put formatted candidates back and return return template % tuple(formatted_candidates) class SafeDatetime(datetime.datetime): '''Subclass of datetime that works with utf-8 format strings on PY2''' def strftime(self, fmt, safe=True): '''Uses our custom strftime if supposed to be *safe*''' if safe: return strftime(self, fmt) else: return super(SafeDatetime, self).strftime(fmt) class DateFormatter(object): '''A date formatter object used as a jinja filter Uses the `strftime` implementation and makes sure jinja uses the locale defined in LOCALE setting ''' def __init__(self): self.locale = locale.setlocale(locale.LC_TIME) def __call__(self, date, date_format): old_lc_time = locale.setlocale(locale.LC_TIME) old_lc_ctype = locale.setlocale(locale.LC_CTYPE) locale.setlocale(locale.LC_TIME, self.locale) # on OSX, encoding from LC_CTYPE determines the unicode output in PY3 # make sure it's same as LC_TIME locale.setlocale(locale.LC_CTYPE, self.locale) formatted = strftime(date, date_format) locale.setlocale(locale.LC_TIME, old_lc_time) locale.setlocale(locale.LC_CTYPE, old_lc_ctype) return formatted def python_2_unicode_compatible(klass): """ A decorator that defines __unicode__ and __str__ methods under Python 2. Under Python 3 it does nothing. To support Python 2 and 3 with a single code base, define a __str__ method returning text and apply this decorator to the class. From django.utils.encoding. """ if not six.PY3: klass.__unicode__ = klass.__str__ klass.__str__ = lambda self: self.__unicode__().encode('utf-8') return klass class memoized(object): """Function decorator to cache return values. If called later with the same arguments, the cached value is returned (not reevaluated). """ def __init__(self, func): self.func = func self.cache = {} def __call__(self, *args): if not isinstance(args, Hashable): # uncacheable. a list, for instance. # better to not cache than blow up. return self.func(*args) if args in self.cache: return self.cache[args] else: value = self.func(*args) self.cache[args] = value return value def __repr__(self): return self.func.__doc__ def __get__(self, obj, objtype): '''Support instance methods.''' return partial(self.__call__, obj) def deprecated_attribute(old, new, since=None, remove=None, doc=None): """Attribute deprecation decorator for gentle upgrades For example: class MyClass (object): @deprecated_attribute( old='abc', new='xyz', since=(3, 2, 0), remove=(4, 1, 3)) def abc(): return None def __init__(self): xyz = 5 Note that the decorator needs a dummy method to attach to, but the content of the dummy method is ignored. """ def _warn(): version = '.'.join(six.text_type(x) for x in since) message = ['{} has been deprecated since {}'.format(old, version)] if remove: version = '.'.join(six.text_type(x) for x in remove) message.append( ' and will be removed by version {}'.format(version)) message.append('. Use {} instead.'.format(new)) logger.warning(''.join(message)) logger.debug(''.join(six.text_type(x) for x in traceback.format_stack())) def fget(self): _warn() return getattr(self, new) def fset(self, value): _warn() setattr(self, new, value) def decorator(dummy): return property(fget=fget, fset=fset, doc=doc) return decorator def get_date(string): """Return a datetime object from a string. If no format matches the given date, raise a ValueError. """ string = re.sub(' +', ' ', string) default = SafeDatetime.now().replace(hour=0, minute=0, second=0, microsecond=0) try: return dateutil.parser.parse(string, default=default) except (TypeError, ValueError): raise ValueError('{0!r} is not a valid date'.format(string)) @contextmanager def pelican_open(filename, mode='rb', strip_crs=(sys.platform == 'win32')): """Open a file and return its content""" with codecs.open(filename, mode, encoding='utf-8') as infile: content = infile.read() if content[:1] == codecs.BOM_UTF8.decode('utf8'): content = content[1:] if strip_crs: content = content.replace('\r\n', '\n') yield content def slugify(value, substitutions=()): """ Normalizes string, converts to lowercase, removes non-alpha characters, and converts spaces to hyphens. Took from Django sources. """ # TODO Maybe steal again from current Django 1.5dev value = Markup(value).striptags() # value must be unicode per se import unicodedata from unidecode import unidecode # unidecode returns str in Py2 and 3, so in Py2 we have to make # it unicode again value = unidecode(value) if isinstance(value, six.binary_type): value = value.decode('ascii') # still unicode value = unicodedata.normalize('NFKD', value).lower() # backward compatible covert from 2-tuples to 3-tuples new_subs = [] for tpl in substitutions: try: src, dst, skip = tpl except ValueError: src, dst = tpl skip = False new_subs.append((src, dst, skip)) substitutions = tuple(new_subs) # by default will replace non-alphanum characters replace = True for src, dst, skip in substitutions: orig_value = value value = value.replace(src.lower(), dst.lower()) # if replacement was made then skip non-alphanum # replacement if instructed to do so if value != orig_value: replace = replace and not skip if replace: value = re.sub('[^\w\s-]', '', value).strip() value = re.sub('[-\s]+', '-', value) else: value = value.strip() # we want only ASCII chars value = value.encode('ascii', 'ignore') # but Pelican should generally use only unicode return value.decode('ascii') def copy(source, destination, ignores=None): """Recursively copy source into destination. If source is a file, destination has to be a file as well. The function is able to copy either files or directories. :param source: the source file or directory :param destination: the destination file or directory :param ignores: either None, or a list of glob patterns; files matching those patterns will _not_ be copied. """ def walk_error(err): logger.warning("While copying %s: %s: %s", source_, err.filename, err.strerror) source_ = os.path.abspath(os.path.expanduser(source)) destination_ = os.path.abspath(os.path.expanduser(destination)) if ignores is None: ignores = [] if any(fnmatch.fnmatch(os.path.basename(source), ignore) for ignore in ignores): logger.info('Not copying %s due to ignores', source_) return if os.path.isfile(source_): dst_dir = os.path.dirname(destination_) if not os.path.exists(dst_dir): logger.info('Creating directory %s', dst_dir) os.makedirs(dst_dir) logger.info('Copying %s to %s', source_, destination_) copy_file_metadata(source_, destination_) elif os.path.isdir(source_): if not os.path.exists(destination_): logger.info('Creating directory %s', destination_) os.makedirs(destination_) if not os.path.isdir(destination_): logger.warning('Cannot copy %s (a directory) to %s (a file)', source_, destination_) return for src_dir, subdirs, others in os.walk(source_): dst_dir = os.path.join(destination_, os.path.relpath(src_dir, source_)) subdirs[:] = (s for s in subdirs if not any(fnmatch.fnmatch(s, i) for i in ignores)) others[:] = (o for o in others if not any(fnmatch.fnmatch(o, i) for i in ignores)) if not os.path.isdir(dst_dir): logger.info('Creating directory %s', dst_dir) # Parent directories are known to exist, so 'mkdir' suffices. os.mkdir(dst_dir) for o in others: src_path = os.path.join(src_dir, o) dst_path = os.path.join(dst_dir, o) if os.path.isfile(src_path): logger.info('Copying %s to %s', src_path, dst_path) copy_file_metadata(src_path, dst_path) else: logger.warning('Skipped copy %s (not a file or ' 'directory) to %s', src_path, dst_path) def copy_file_metadata(source, destination): '''Copy a file and its metadata (perm bits, access times, ...)''' # This function is a workaround for Android python copystat # bug ([issue28141]) https://bugs.python.org/issue28141 try: shutil.copy2(source, destination) except OSError as e: logger.warning("A problem occurred copying file %s to %s; %s", source, destination, e) def clean_output_dir(path, retention): """Remove all files from output directory except those in retention list""" if not os.path.exists(path): logger.debug("Directory already removed: %s", path) return if not os.path.isdir(path): try: os.remove(path) except Exception as e: logger.error("Unable to delete file %s; %s", path, e) return # remove existing content from output folder unless in retention list for filename in os.listdir(path): file = os.path.join(path, filename) if any(filename == retain for retain in retention): logger.debug("Skipping deletion; %s is on retention list: %s", filename, file) elif os.path.isdir(file): try: shutil.rmtree(file) logger.debug("Deleted directory %s", file) except Exception as e: logger.error("Unable to delete directory %s; %s", file, e) elif os.path.isfile(file) or os.path.islink(file): try: os.remove(file) logger.debug("Deleted file/link %s", file) except Exception as e: logger.error("Unable to delete file %s; %s", file, e) else: logger.error("Unable to delete %s, file type unknown", file) def get_relative_path(path): """Return the relative path from the given path to the root path.""" components = split_all(path) if len(components) <= 1: return os.curdir else: parents = [os.pardir] * (len(components) - 1) return os.path.join(*parents) def path_to_url(path): """Return the URL corresponding to a given path.""" if os.sep == '/': return path else: return '/'.join(split_all(path)) def posixize_path(rel_path): """Use '/' as path separator, so that source references, like '{filename}/foo/bar.jpg' or 'extras/favicon.ico', will work on Windows as well as on Mac and Linux.""" return rel_path.replace(os.sep, '/') class _HTMLWordTruncator(HTMLParser): _word_regex = re.compile(r"\w[\w'-]*", re.U) _word_prefix_regex = re.compile(r'\w', re.U) _singlets = ('br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input') class TruncationCompleted(Exception): def __init__(self, truncate_at): super(_HTMLWordTruncator.TruncationCompleted, self).__init__( truncate_at) self.truncate_at = truncate_at def __init__(self, max_words): # In Python 2, HTMLParser is not a new-style class, # hence super() cannot be used. try: HTMLParser.__init__(self, convert_charrefs=False) except TypeError: # pre Python 3.3 HTMLParser.__init__(self) self.max_words = max_words self.words_found = 0 self.open_tags = [] self.last_word_end = None self.truncate_at = None def feed(self, *args, **kwargs): try: # With Python 2, super() cannot be used. # See the comment for __init__(). HTMLParser.feed(self, *args, **kwargs) except self.TruncationCompleted as exc: self.truncate_at = exc.truncate_at else: self.truncate_at = None def getoffset(self): line_start = 0 lineno, line_offset = self.getpos() for i in range(lineno - 1): line_start = self.rawdata.index('\n', line_start) + 1 return line_start + line_offset def add_word(self, word_end): self.words_found += 1 self.last_word_end = None if self.words_found == self.max_words: raise self.TruncationCompleted(word_end) def add_last_word(self): if self.last_word_end is not None: self.add_word(self.last_word_end) def handle_starttag(self, tag, attrs): self.add_last_word() if tag not in self._singlets: self.open_tags.insert(0, tag) def handle_endtag(self, tag): self.add_last_word() try: i = self.open_tags.index(tag) except ValueError: pass else: # SGML: An end tag closes, back to the matching start tag, # all unclosed intervening start tags with omitted end tags del self.open_tags[:i + 1] def handle_data(self, data): word_end = 0 offset = self.getoffset() while self.words_found < self.max_words: match = self._word_regex.search(data, word_end) if not match: break if match.start(0) > 0: self.add_last_word() word_end = match.end(0) self.last_word_end = offset + word_end if word_end < len(data): self.add_last_word() def handle_ref(self, char): offset = self.getoffset() ref_end = self.rawdata.index(';', offset) + 1 if self.last_word_end is None: if self._word_prefix_regex.match(char): self.last_word_end = ref_end else: if self._word_regex.match(char): self.last_word_end = ref_end else: self.add_last_word() def handle_entityref(self, name): try: codepoint = html_entities.name2codepoint[name] except KeyError: self.handle_ref('') else: self.handle_ref(six.unichr(codepoint)) def handle_charref(self, name): if name.startswith('x'): codepoint = int(name[1:], 16) else: codepoint = int(name) self.handle_ref(six.unichr(codepoint)) def truncate_html_words(s, num, end_text='…'): """Truncates HTML to a certain number of words. (not counting tags and comments). Closes opened tags if they were correctly closed in the given html. Takes an optional argument of what should be used to notify that the string has been truncated, defaulting to ellipsis (…). Newlines in the HTML are preserved. (From the django framework). """ length = int(num) if length <= 0: return '' truncator = _HTMLWordTruncator(length) truncator.feed(s) if truncator.truncate_at is None: return s out = s[:truncator.truncate_at] if end_text: out += ' ' + end_text # Close any tags still open for tag in truncator.open_tags: out += '' % tag # Return string return out def escape_html(text, quote=True): """Escape '&', '<' and '>' to HTML-safe sequences. In Python 2 this uses cgi.escape and in Python 3 this uses html.escape. We wrap here to ensure the quote argument has an identical default.""" return escape(text, quote=quote) def process_translations(content_list, order_by=None): """ Finds translation and returns them. Returns a tuple with two lists (index, translations). Index list includes items in default language or items which have no variant in default language. Items with the `translation` metadata set to something else than `False` or `false` will be used as translations, unless all the items with the same slug have that metadata. For each content_list item, sets the 'translations' attribute. order_by can be a string of an attribute or sorting function. If order_by is defined, content will be ordered by that attribute or sorting function. By default, content is ordered by slug. Different content types can have default order_by attributes defined in settings, e.g. PAGES_ORDER_BY='sort-order', in which case `sort-order` should be a defined metadata attribute in each page. """ content_list.sort(key=attrgetter('slug')) grouped_by_slugs = groupby(content_list, attrgetter('slug')) index = [] translations = [] def _warn_source_paths(msg, items, *extra): args = [len(items)] args.extend(extra) args.extend((x.source_path for x in items)) logger.warning('{}: {}'.format(msg, '\n%s' * len(items)), *args) for slug, items in grouped_by_slugs: items = list(items) # display warnings if slug is empty if not slug: _warn_source_paths('There are %s items with empty slug', items) # display warnings if several items have the same lang for lang, lang_items in groupby(items, attrgetter('lang')): lang_items = list(lang_items) if len(lang_items) > 1: _warn_source_paths( 'There are %s items with slug "%s" with lang %s', lang_items, slug, lang) # items with `translation` metadata will be used as translations... candidate_items = list(filter( lambda i: i.metadata.get('translation', 'false').lower() == 'false', items)) # ...unless all items with that slug are translations if not candidate_items: logger.warning('All items with slug "%s" are translations', slug) candidate_items = items # find items with default language original_items = list(filter( attrgetter('in_default_lang'), candidate_items)) # if there is no article with default language, go back one step if not original_items: original_items = candidate_items # display warning if there are several original items if len(original_items) > 1: _warn_source_paths( 'There are %s original (not translated) items with slug "%s"', original_items, slug) index.extend(original_items) translations.extend([x for x in items if x not in original_items]) for a in items: a.translations = [x for x in items if x != a] if order_by: if callable(order_by): try: index.sort(key=order_by) except Exception: logger.error('Error sorting with function %s', order_by) elif isinstance(order_by, six.string_types): if order_by.startswith('reversed-'): order_reversed = True order_by = order_by.replace('reversed-', '', 1) else: order_reversed = False if order_by == 'basename': index.sort(key=lambda x: os.path.basename(x.source_path or ''), reverse=order_reversed) # already sorted by slug, no need to sort again elif not (order_by == 'slug' and not order_reversed): try: index.sort(key=attrgetter(order_by), reverse=order_reversed) except AttributeError: logger.warning( 'There is no "%s" attribute in the item ' 'metadata. Defaulting to slug order.', order_by) else: logger.warning( 'Invalid *_ORDER_BY setting (%s).' 'Valid options are strings and functions.', order_by) return index, translations def folder_watcher(path, extensions, ignores=[]): '''Generator for monitoring a folder for modifications. Returns a boolean indicating if files are changed since last check. Returns None if there are no matching files in the folder''' def file_times(path): '''Return `mtime` for each file in path''' for root, dirs, files in os.walk(path, followlinks=True): dirs[:] = [x for x in dirs if not x.startswith(os.curdir)] for f in files: if f.endswith(tuple(extensions)) and \ not any(fnmatch.fnmatch(f, ignore) for ignore in ignores): try: yield os.stat(os.path.join(root, f)).st_mtime except OSError as e: logger.warning('Caught Exception: %s', e) LAST_MTIME = 0 while True: try: mtime = max(file_times(path)) if mtime > LAST_MTIME: LAST_MTIME = mtime yield True except ValueError: yield None else: yield False def file_watcher(path): '''Generator for monitoring a file for modifications''' LAST_MTIME = 0 while True: if path: try: mtime = os.stat(path).st_mtime except OSError as e: logger.warning('Caught Exception: %s', e) continue if mtime > LAST_MTIME: LAST_MTIME = mtime yield True else: yield False else: yield None def set_date_tzinfo(d, tz_name=None): """Set the timezone for dates that don't have tzinfo""" if tz_name and not d.tzinfo: tz = pytz.timezone(tz_name) d = tz.localize(d) return SafeDatetime(d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, d.tzinfo) return d def mkdir_p(path): try: os.makedirs(path) except OSError as e: if e.errno != errno.EEXIST or not os.path.isdir(path): raise def split_all(path): """Split a path into a list of components While os.path.split() splits a single component off the back of `path`, this function splits all components: >>> split_all(os.path.join('a', 'b', 'c')) ['a', 'b', 'c'] """ components = [] path = path.lstrip('/') while path: head, tail = os.path.split(path) if tail: components.insert(0, tail) elif head == path: components.insert(0, head) break path = head return components def is_selected_for_writing(settings, path): '''Check whether path is selected for writing according to the WRITE_SELECTED list If WRITE_SELECTED is an empty list (default), any path is selected for writing. ''' if settings['WRITE_SELECTED']: return path in settings['WRITE_SELECTED'] else: return True def path_to_file_url(path): '''Convert file-system path to file:// URL''' return six.moves.urllib_parse.urljoin( "file://", six.moves.urllib.request.pathname2url(path)) def maybe_pluralize(count, singular, plural): ''' Returns a formatted string containing count and plural if count is not 1 Returns count and singular if count is 1 maybe_pluralize(0, 'Article', 'Articles') -> '0 Articles' maybe_pluralize(1, 'Article', 'Articles') -> '1 Article' maybe_pluralize(2, 'Article', 'Articles') -> '2 Articles' ''' selection = plural if count == 1: selection = singular return '{} {}'.format(count, selection) pelican-3.7.1/pelican/writers.py000066400000000000000000000221571303525152100166250ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals, with_statement import logging import os from feedgenerator import Atom1Feed, Rss201rev2Feed, get_tag_uri from jinja2 import Markup import six from pelican import signals from pelican.paginator import Paginator from pelican.utils import (get_relative_path, is_selected_for_writing, path_to_url, set_date_tzinfo) if not six.PY3: from codecs import open logger = logging.getLogger(__name__) class Writer(object): def __init__(self, output_path, settings=None): self.output_path = output_path self.reminder = dict() self.settings = settings or {} self._written_files = set() self._overridden_files = set() def _create_new_feed(self, feed_type, feed_title, context): feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed if feed_title: feed_title = context['SITENAME'] + ' - ' + feed_title else: feed_title = context['SITENAME'] feed = feed_class( title=Markup(feed_title).striptags(), link=(self.site_url + '/'), feed_url=self.feed_url, description=context.get('SITESUBTITLE', '')) return feed def _add_item_to_the_feed(self, feed, item): title = Markup(item.title).striptags() link = '%s/%s' % (self.site_url, item.url) is_rss = isinstance(feed, Rss201rev2Feed) if not is_rss or self.settings.get('RSS_FEED_SUMMARY_ONLY'): description = item.summary else: description = item.get_content(self.site_url) feed.add_item( title=title, link=link, unique_id=get_tag_uri(link, item.date), description=description, content=item.get_content(self.site_url), categories=item.tags if hasattr(item, 'tags') else None, author_name=getattr(item, 'author', ''), pubdate=set_date_tzinfo( item.date, self.settings.get('TIMEZONE', None)), updateddate=set_date_tzinfo( item.modified, self.settings.get('TIMEZONE', None) ) if hasattr(item, 'modified') else None) def _open_w(self, filename, encoding, override=False): """Open a file to write some content to it. Exit if we have already written to that file, unless one (and no more than one) of the writes has the override parameter set to True. """ if filename in self._overridden_files: if override: raise RuntimeError('File %s is set to be overridden twice' % filename) else: logger.info('Skipping %s', filename) filename = os.devnull elif filename in self._written_files: if override: logger.info('Overwriting %s', filename) else: raise RuntimeError('File %s is to be overwritten' % filename) if override: self._overridden_files.add(filename) self._written_files.add(filename) return open(filename, 'w', encoding=encoding) def write_feed(self, elements, context, path=None, feed_type='atom', override_output=False, feed_title=None): """Generate a feed with the list of articles provided Return the feed. If no path or output_path is specified, just return the feed object. :param elements: the articles to put on the feed. :param context: the context to get the feed metadata. :param path: the path to output. :param feed_type: the feed type to use (atom or rss) :param override_output: boolean telling if we can override previous output with the same name (and if next files written with the same name should be skipped to keep that one) :param feed_title: the title of the feed.o """ if not is_selected_for_writing(self.settings, path): return self.site_url = context.get( 'SITEURL', path_to_url(get_relative_path(path))) self.feed_domain = context.get('FEED_DOMAIN') self.feed_url = '{}/{}'.format(self.feed_domain, path) feed = self._create_new_feed(feed_type, feed_title, context) max_items = len(elements) if self.settings['FEED_MAX_ITEMS']: max_items = min(self.settings['FEED_MAX_ITEMS'], max_items) for i in range(max_items): self._add_item_to_the_feed(feed, elements[i]) if path: complete_path = os.path.join(self.output_path, path) try: os.makedirs(os.path.dirname(complete_path)) except Exception: pass encoding = 'utf-8' if six.PY3 else None with self._open_w(complete_path, encoding, override_output) as fp: feed.write(fp, 'utf-8') logger.info('Writing %s', complete_path) signals.feed_written.send( complete_path, context=context, feed=feed) return feed def write_file(self, name, template, context, relative_urls=False, paginated=None, override_output=False, **kwargs): """Render the template and write the file. :param name: name of the file to output :param template: template to use to generate the content :param context: dict to pass to the templates. :param relative_urls: use relative urls or absolutes ones :param paginated: dict of article list to paginate - must have the same length (same list in different orders) :param override_output: boolean telling if we can override previous output with the same name (and if next files written with the same name should be skipped to keep that one) :param **kwargs: additional variables to pass to the templates """ if name is False or \ name == "" or \ not is_selected_for_writing(self.settings, os.path.join(self.output_path, name)): return elif not name: # other stuff, just return for now return def _write_file(template, localcontext, output_path, name, override): """Render the template write the file.""" # set localsiteurl for context so that Contents can adjust links if localcontext['localsiteurl']: context['localsiteurl'] = localcontext['localsiteurl'] output = template.render(localcontext) path = os.path.join(output_path, name) try: os.makedirs(os.path.dirname(path)) except Exception: pass with self._open_w(path, 'utf-8', override=override) as f: f.write(output) logger.info('Writing %s', path) # Send a signal to say we're writing a file with some specific # local context. signals.content_written.send(path, context=localcontext) def _get_localcontext(context, name, kwargs, relative_urls): localcontext = context.copy() localcontext['localsiteurl'] = localcontext.get( 'localsiteurl', None) if relative_urls: relative_url = path_to_url(get_relative_path(name)) localcontext['SITEURL'] = relative_url localcontext['localsiteurl'] = relative_url localcontext['output_file'] = name localcontext.update(kwargs) return localcontext # pagination if paginated: # pagination needed, init paginators paginators = {key: Paginator(name, val, self.settings) for key, val in paginated.items()} # generated pages, and write for page_num in range(list(paginators.values())[0].num_pages): paginated_kwargs = kwargs.copy() for key in paginators.keys(): paginator = paginators[key] previous_page = paginator.page(page_num) \ if page_num > 0 else None page = paginator.page(page_num + 1) next_page = paginator.page(page_num + 2) \ if page_num + 1 < paginator.num_pages else None paginated_kwargs.update( {'%s_paginator' % key: paginator, '%s_page' % key: page, '%s_previous_page' % key: previous_page, '%s_next_page' % key: next_page}) localcontext = _get_localcontext( context, page.save_as, paginated_kwargs, relative_urls) _write_file(template, localcontext, self.output_path, page.save_as, override_output) else: # no pagination localcontext = _get_localcontext( context, name, kwargs, relative_urls) _write_file(template, localcontext, self.output_path, name, override_output) pelican-3.7.1/requirements/000077500000000000000000000000001303525152100156555ustar00rootroot00000000000000pelican-3.7.1/requirements/developer.pip000066400000000000000000000001041303525152100203470ustar00rootroot00000000000000-r test.pip # Development flake8 flake8-import-order sphinx==1.4.9 pelican-3.7.1/requirements/owner.pip000066400000000000000000000000741303525152100175220ustar00rootroot00000000000000-r developer.pip # Release issuance tox bumpr==0.2.0 wheel pelican-3.7.1/requirements/test.pip000066400000000000000000000001111303525152100173370ustar00rootroot00000000000000# Tests mock # Optional Packages Markdown BeautifulSoup4 lxml typogrify pelican-3.7.1/samples/000077500000000000000000000000001303525152100145765ustar00rootroot00000000000000pelican-3.7.1/samples/content/000077500000000000000000000000001303525152100162505ustar00rootroot00000000000000pelican-3.7.1/samples/content/2012-11-30_filename-metadata.rst000066400000000000000000000001061303525152100234400ustar00rootroot00000000000000FILENAME_METADATA example ######################### Some cool stuff! pelican-3.7.1/samples/content/another_super_article-fr.rst000066400000000000000000000001241303525152100237650ustar00rootroot00000000000000Trop bien ! ########### :lang: fr :slug: oh-yeah Et voila du contenu en français pelican-3.7.1/samples/content/another_super_article.rst000066400000000000000000000005651303525152100233710ustar00rootroot00000000000000Oh yeah ! ######### :tags: oh, bar, yeah :date: 2010-10-20 10:14 :category: bar :author: Alexis Métaireau :slug: oh-yeah :license: WTFPL Why not ? ========= After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH ! .. image:: |filename|/pictures/Sushi.jpg :height: 450 px :width: 600 px :alt: alternate text pelican-3.7.1/samples/content/article2-fr.rst000066400000000000000000000002171303525152100211140ustar00rootroot00000000000000Deuxième article ################ :tags: foo, bar, baz :date: 2012-02-29 :lang: fr :slug: second-article Ceci est un article, en français. pelican-3.7.1/samples/content/article2.rst000066400000000000000000000002101303525152100205000ustar00rootroot00000000000000Second article ############## :tags: foo, bar, baz :date: 2012-02-29 :lang: en :slug: second-article This is some article, in english pelican-3.7.1/samples/content/article_tag_baz.rst000066400000000000000000000002401303525152100221100ustar00rootroot00000000000000The baz tag ########### :date: 2010-03-14 :url: tag/baz.html :save_as: tag/baz.html This article overrides the listening of the articles under the *baz* tag. pelican-3.7.1/samples/content/cat1/000077500000000000000000000000001303525152100171005ustar00rootroot00000000000000pelican-3.7.1/samples/content/cat1/article1.rst000066400000000000000000000001031303525152100213300ustar00rootroot00000000000000Article 1 ######### :date: 2011-02-17 :yeah: oh yeah ! Article 1 pelican-3.7.1/samples/content/cat1/article2.rst000066400000000000000000000000621303525152100213350ustar00rootroot00000000000000Article 2 ######### :date: 2011-02-17 Article 2 pelican-3.7.1/samples/content/cat1/article3.rst000066400000000000000000000000621303525152100213360ustar00rootroot00000000000000Article 3 ######### :date: 2011-02-17 Article 3 pelican-3.7.1/samples/content/cat1/markdown-article.md000066400000000000000000000003321303525152100226630ustar00rootroot00000000000000Title: A markdown powered article Date: 2011-04-20 You're mutually oblivious. [a root-relative link to unbelievable](|filename|/unbelievable.rst) [a file-relative link to unbelievable](|filename|../unbelievable.rst) pelican-3.7.1/samples/content/draft_article.rst000066400000000000000000000002241303525152100216030ustar00rootroot00000000000000A draft article ############### :status: draft This is a draft article, it should live under the /drafts/ folder and not be listed anywhere else. pelican-3.7.1/samples/content/extra/000077500000000000000000000000001303525152100173735ustar00rootroot00000000000000pelican-3.7.1/samples/content/extra/robots.txt000066400000000000000000000000421303525152100214400ustar00rootroot00000000000000User-agent: * Disallow: /pictures pelican-3.7.1/samples/content/pages/000077500000000000000000000000001303525152100173475ustar00rootroot00000000000000pelican-3.7.1/samples/content/pages/hidden_page.rst000066400000000000000000000003021303525152100223230ustar00rootroot00000000000000This is a test hidden page ########################## :category: test :status: hidden This is great for things like error(404) pages Anyone can see this page but it's not linked to anywhere! pelican-3.7.1/samples/content/pages/jinja2_template.html000066400000000000000000000001111303525152100232760ustar00rootroot00000000000000{% extends "base.html" %} {% block content %} Some text {% endblock %} pelican-3.7.1/samples/content/pages/override_tag_oh.rst000066400000000000000000000002241303525152100232370ustar00rootroot00000000000000Oh Oh Oh ######## :date: 2010-03-14 :url: tag/oh.html :save_as: tag/oh.html This page overrides the listening of the articles under the *oh* tag. pelican-3.7.1/samples/content/pages/override_url_saveas.rst000066400000000000000000000003201303525152100241370ustar00rootroot00000000000000Override url/save_as #################### :date: 2012-12-07 :url: override/ :save_as: override/index.html Test page which overrides save_as and url so that this page will be generated at a custom location. pelican-3.7.1/samples/content/pages/test_page.rst000066400000000000000000000002631303525152100220550ustar00rootroot00000000000000This is a test page ################### :category: test Just an image. .. image:: |filename|/pictures/Fat_Cat.jpg :height: 450 px :width: 600 px :alt: alternate text pelican-3.7.1/samples/content/pictures/000077500000000000000000000000001303525152100201065ustar00rootroot00000000000000pelican-3.7.1/samples/content/pictures/Fat_Cat.jpg000066400000000000000000001723231303525152100221210ustar00rootroot00000000000000JFIFHHOExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:31:29 PrintIM0250$"'@0220    I &|z.0100,   Dd2010:01:09 14:55:402010:01:09 14:55:40 Ndd%ddFddFUJIFILM 0130Jj r !"#012S100 S100 A592D34383231100603D7050TR73277NORMAL d^^R980100<D(LHHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?6LOn7SoCW,6tĠ>*IwrJp@]~&hFx应FNsSX$4:02~lnOp~\Қ2pR%HQL`tiͅ?r j\n+.AvLpG 9PXtMKL x9 *%T0h$H9??E(A81.cʰ;pDnXRC+F;֠Vx _zIo?́8ֆ\IN!"%T=2"$֎O 攜 B.8Jb"\ɹ`RGZ[;F!Kq}(M~l֔_ 9}ji2sv)Kހ OHԕA1ɖҁꭆݑh2l=r3(X_hRR)Ҡ0{Rc>EP‡"1b[硦/ݷ$*nAp{@;if I':Rݸ=N=i8A=+a*pcTЕ;PWV} ?漺ھOxc;Efn5jr= ;+!jnt\L~\\!_Ą=/ҵ 26v?+ώdz4r=mܾ67 ҷS37VRU]nCNa!D>Rz{.#s֑{p知fh%u-̠d{VAP8 9CE 'U$d*G]オO&BLň ?VFi XOC؋7N}N#Gpbp׵DmAnwcSYXg$6MyQWǽG#Q+)`@dž2 :əFǓȥ9Է;<*2T4Qj@g $f`hD+⢝_3MXx|5)+e= 1]0Xٽw?%W#v\Nj5!on.zw4 ;O$ pNYg͹;*;}X"$`҂۹Jl"}pF=iF3Xɤi oq9曚z.rzUv23WWn{g4ˉ|zk+اyWaEF#aG^^Tu" ($yhU >F9.;K;Tt#0)rLOovJ1+Y-3fWi;0ҹGC9Y"ǣ}* ''TzV`cmޒEl8( N}м_C2ntURXkIr\OJMXW ~vIG˟Zs:,@&F$Rfd5GҐ HLEW4TOcןE^ivaZH%wkIHćS~nZxRI>ILj.bϩEuI'JQ}>f˜Cʫiq\0OLSzdyiIT6uJC>f\}}BA{p@H:uSXc+&h@c f'= qJ7(,FUv$ = P`F =)J8jr>.TyՔ~}҈nW|@1cmrp+"$4=qZb71/`8ϭ7y-m^G]*yK.T]yqܲ)8k#A]J𝸻 Uqj.$rƊ<4?oƾdp'[-"gԛmR#qֹh%u=M р7׊z.t qm, xkt Y\[rḲ-8{=.V%e돧^6,1oZJQ'K0{bgGԮ8OSj*XqWEd8 u>Rܵu7FӌHQֲ|x]z+48ۓҢxAhW* ~EDLR1UN@doW/hjM'BN[HW>S;oO;YanUsB |߅hM#S, &UHdI^'iچ7ZJN8F *C""P5Ic{-d$4ȱtV@46C>m"[u] FᎢdb{qszy3ՑMUWfB#@Nl1Ou. q)d8ʝՖՆbr 7C`=hzX@mM,s %Ipǰ- bܢҲQ7mF7E<)NcE#ieA؂B g-WRTRRAC&xm@ 9u(ձW, Qs7D䠐2FبFG~ Vz,DaA4QJ.@}*t~@[GTTuSȩ  h,lH8W.S;MQ<ҿʄBGQlnq.4B# ($l#p)‰O]5*ƱL`p7g`ŚjU5BFgx+)*~mq2.0rN؝ * s42T>vji6P_g׷!}=54Mh]^%K.4> x}9ռt֮4gCCrdNݻ`mk3-\h'֥d֪ 8f=xQ|K,QPڥʨBG>n?a }-Lk׫G ױ RA;G߫ޫx$gd:(.*w's gbQԜk*BV)%He )99䡧K:UT7Yj$AvM"i:F~`m'8MM=55E0EIvtg'-QyU' FdG;/PpoV`}5-ʞ8xv=Mbu01dVx9lza\Ji>uI#Tr/T$M,ȑHd(2k}1sۆ9,R\&q]::A4T=N891 kJ15U"Fj&]1kgbr[ n<9çHl7rKԎ* ]bDBA՝)r"ϢJzVfX%hDzRz/HKY'`̬ʺ|20; cpmKJr5]ٚdC2 {\c$@?).w&枔 C+yYrs6A;-jZR‘I#i$ֲarA/YmցN1ަثH\f7+H,u,2MIrIH;1Y&%P|P|( FGN c1 M(^6ZbHKrq~~]k4RJ`*?Bvlt-fJ:e"j9]{$ؚ|+ ix~;8O lM?+s];KE*@+3,c꽻 mǵvVGPM&T6R6%-9?I#з b&Gu"jJ@" *p9=Ǿ1{=u-4"zr<ͤX6|!̐Ʊ=-5XQ)rL#" 8ReB0#`0Fޜ`JɋS^zd|+$7Ս2dIRH [r(Q{Q`2٠\vQ vB٭b)fՐN|Һ7m=$9`q/1J`ؖܖ۹>$M4G3T*aX i=<әT M׸6qFzy)by)TOdHUvR@ )y`J5h Ab1r5mi"{!jI6$%B0[l ce.,T+MtY`) }8*Պ2Fj]C '}d_^2S,sK$ÍXa#Lyv4DRB$h,]2X;'z9!f3(+$O aF>^T3T뒑r:UePIl Rt؝;x)l)V\^x%dxԹsf!q A8qWIWC ku {y|lGہkDCױ-E,늳[L>5܁'t&Q(%q؁뇈5 ssWA, #Ï./ԢkXh\dc'|lr\x{`s=Rَ߰|r_ARֶvP^{wӌ.+&SCӌe.DZZCcGgP ԈbH N |qB >U v:9%ȵª\eAOӍG`qW r+,=^@ C m.iSҕe뢡U %YJ7/Y-]B *q_^ &KdQ%5%ae!DB)6w]#gH#Hs* Z@ƮqmE=tBzP ~e j,NV)SC,фM.cM Q;cmMk#y(jMR9ܕFOm7&-7V*$"yΘt @ eOSOSVy%OD!oΕ=p: g#,**n1[β@WT(p~/Y FezyJk|¿~trrX(g)C4}1'PC&vmƱ\h)gHG U@%4w%N7#2t0[TLi#U-*W`c$v` ʙEGU5yDŃĽ5g T:5w:*{|F ST6 9$d03 QEUT¢%.R<*pO~[V5:_2TKA2G<3YũD.1'.FANN M+;ȏ*N>XvSܗLs*\ qjw6Z^QS+*, %\n.(SFfjEcG`No =QU ȵz]##$7ǣf:I::S WsvF%Y ZV1t0V\ [60}dbGJDQLjeEIfl #s8 TRܨ0)=m?I cըRrb}8o }M%LeGs i ۊi$TYm!E0/!XcnI:$[O[Jid! َ?1<#x-6[^u!Y$\'a07'\9o \=tQ ?1UV_RF}#I~EJAJ>;5 ,6#9`^ُr Sa4cELIիP*.G2)s3STuqYj) CN@2{nK-'ڷZz9F[*\MƬnN8J(*nvB2^̯I\vI=25%XS"q#)Qΐ8i.G^ ١Zp*dy v{i؟~R[hy%X~qׅ$wEuHӍazRK@6 'ԦL~=[SOU:Tav#HܑOrqvvhtXds(.ñ@A#|qlUQOye,z!tҬO0vCTubZDe>m {Qz'VUH Yf %W;0r r~nFs[I3dv6")n6yDi[RƯ0PՋAVX*DŖXŽ3AӰ%z<5Қ\VպTNCI5a70T ةxޮ:Ί5,Jls&sX g_GQQFRW0),aFvsK|[h!H<8wr#f\nRdOY6k,Z&g8 UjuLf*24{'ok>c xH &bJm ~f6C~ڸoAfz\cj1P$(Q$?V@ gOrX)Nu.#"AW@%}lA μg\N̕idZa JuzNOlm=Kд_Ω ;3dۀ ^ԼH,0bޞHNHՐ*%˵:T+Z1uw}oX\+TF$sG0p:`3ܩaevK|P"RuF3$;?n%ؠP^Y9zl428]W *$U"%Umi}Mv%hj֥UZws3Gm̖ieq3ըzV;ar3hlek'DJш8X@Q;6#.28:{\'jx#fAL3+!й8n/ZBdft@~Y.Z,KH"ȳ6@9Q&lgxt.K:S3"H͆ʔ;`bu<>^==)AP0PX_A_&DyʳǔT}Ďn. zQJ{@RF #IZӴSMbWdv#)錏0[ Xg.&A}yǶcwe`&z^fFpq$R)yb\*uEYP9vZ_N S]]e#e$Nv'H5AO _UD꘦(Nlq`mxoq4x6=҂iޟLDW1Vh6;sj =VRCJUlNA jR@N@0LUl -Tȸe8탿O흸 5ӣ4H@9m#auی=,UBP!ETn`1a-zkE%hf3n!Iv"j =]U5S/Q l0 lL2S*Q$# 6c=eƑFHbΈ9}3I\LM!=6m0pj~"۫bDuelH;9 (5y Z@Ә2v9+k<Lx 7pOiZfzxLSc?H l\VV{Q]^SW!zWf `201-W[.J q":`'q*Lky办:LH4UQ ƜwZ"H$Z cpPM QB6֧LdigtfVu6̧|8|vCrL 庤noBp_o^$mt$ #:UP`sRב,< Qr$3DyFFs;q$Z-UtR,TnO@ m-HSz;^)9L+"B9: v~b.ecKUy:"B%+Ldum +^JP2emI6>wG=١ʺIVEG%S;@)8'pp3iuri$g%9]AI8cNl3y o*BP4 ye 27wlr14 ey%edhT is%)7zlPƢJ D]3t ^X/ 2l1W߭j/Xѻ?1)rF M;:u1@(3"iܗj)sTub2T9aP3،PwI'b5UAF3 e(G.=PZijzY0Ơ}x9УQ9oz٩y f&),l9bNJGJiB0F78p6BTOO-2s]JZzr"NČyHT-m_LdQM# 9=~GH)nQ6MZ]{$t0H騍STQuH¡I!۸'h{ ع_5=M- 7S$:@Ab+KId(˩!Sl8z`p/DyoEA$#x 4 ye$6DwDLӤq:UK a$;nRÎ0ꑰ'Nވ8WGgL 5} \axVUtIK Y5T% ۩##9jϔZQ#\~^ emz@P6$>#)y{NU[KBSNᖼ 6 3"y/Co-Ti32N'FY;.u.·I<5yiPU C- YИNi*b&*zC8;,mƎH.L@F}Hx3gᐒKn팏sCeic_|Q7`MNĔf25 H3gڝ0㨆E'NF5~gm*Aԑâ~C)tC&,]2ZP@'.!K_M%n% bɝ nu @5B 0XGc$ "G!iT::\ǿ*(^Ǿxlf(1lOۏ>]$'Vqۂ-nC.1∧%|Jf\F@3L~ ǯIM4).YC0 (|zʆQ4 O֕VD}'x-r#w83GY\W G:~N+udS_j'/..8GSA շ5YHm敜ySO,-N,1 ' 4E* ah@4A VʺyHJA:N7+qɏ?;xGP.T~sM/XZ^\@y::1 6VϦ|KC :wvuhs@0RAzytq7"%rJAKmJ@8ܮ}fC]h.si.mSd`9j85dQGOMFx؉F|n{^r4qQOѢыTS87]v[QHt@,2GBR"ՊZp@ TGZ.96Ⱦwʋ4BfO(|OxrO*%3:$EePXt./9S\',tR8$1{7$xy t:z̪A ylμ5V# Jp3wرU7-:: P6݆GDde* NHLi#iRN;j=gfv#`ldy;Kd -ec?NMA#vn#H ]]ۦHSwp6˗I硯e0"A؍8pr924jZT\c, `ocm|US :2H''#ntn(h"$\eJNIՌ3@F$ SU B%H|O|*zW+43u`$KA PcBH*䧐nv`pW m9p\i*rgQJ/۝?ڊ+)ɅT$ I&Wv^ۓn۫Rq2Je {NH(N] B`}aq6 0?5?W%]%UIBP ˰`(%}>%~(y[ồ~HjDIj'C!ϓ$|g:]m9¹X Dq䞜`)tgϖ۫GH-6ey ߑx/Q"FM*wl{q6[xCyq>8YE! ;9Y51\(hL$8C* $d}Ś )Tly2OxѴX1\[ r! V8e `|r㐖b e0= ~ ,"}9} Bi]И d߷C,Ta ?]ĉ!8s۾?t$1ó1 7w~#6ZE_HJw9g{I1 K"H䃝ĝ7!B&~.];ln܍Dڷʟ{~\TYܴѶCn7Rvu5bfVӑ^,Er{B] q2L:]Cf?}c1eSE$lP9Fc  8tc/#X֙d9Ks8~Wpab!,I ߊ.0*eݖWW $' i獁P|9aˌ%+/iPw{uODs?p2?~/r3uޖJJ)h&de %u/̮: 9< _W:##mnӍ14ugGX gG--%+ZwWIQ`dn5HeCK4I-<$eBKV8DA_.Uu-$ R9S"W_n5KY@"<S%FVRr g0pYLUutUVS"w(!2Cd|cՂ+6/ hz-%QIx{Q# 5ltW\Kf[*UDc;)bXce< .hIuS)3ȚdfLww ̶bGG⩋C5$u1rt`l+.bh+MeBC;SL :6Lef >~aIbog7Cx\lA̎w:C}G1-]3,1T -^I a$ 1gH>*ս嬚{ETϟ#3CSiZ=O@ROW;a2G?)/wTRi3Xb)Ol~A[+m5WCXqRg%rHw?0U\uKTTC<ñUʜ,h"u`Pb csr 2m vRY+@KDFWJI=VÃIvAⒺ 0aoAHg$3~ZhV4RpP3 $wj4ZTb S1Gu[]u5-&  2urU:O}~%XtꠍTC/P4 )b ʐtoyUG]piɊD^[*mGAҚ9%סKd6 'mEBnȟeA3)qNc N !`J"bpb~翧-a@i@Q)0N9 ;ߑij&jQEsB1Iv9< L쮞5*2̡BVg͆0>y .pK*ERqty\m"+XXq14ŋo9y`(m29y9#H>9YIKъv'}+MIN7u1Y%J"|rN/gOjُ5rH[M.*++ce9cfy0sn+0R{joۿ@Rj:u$y2\ @{L_8Fc ;r{zkj`θ$~\,5* 1b L۶ |.zK{qi '?޼\QIneUf]*V}0wu'*L:tăwG37m1* JFΘm}غtsD?n < ƧVŽ}dJO1߶='5IGeu*Hg66ʜU*T A'ޥJy|>ۊLi:#T79oPYI2TJL>*`v6TfΜ x67dq(N `Ԝpknnk=4ST,sB$pA~6/|aEEtUdx$m=ԕmGcR2IR=8 w:c@#Qrq/|o{ɗZ;3,u[!S02YwpbTrqcѥ"'_:r墮ZkaOC4*#tǕt)H'r*9;j$5`VpNIo̓;xH$P f8 UNˬi;|A)*" \"V:@*8.Y7φǶkg /(X€6OSs&rYm,0u2lѨ]MN3xW21t&# r;~@wKB*lx!)t`E! qfOOy#k5nr(iD朂AHBz빅REM * pGprzp{U]%m2EԮV6Rce +(㊦*B H-*ap}TT1U4 $vg9O~#G6ARO|嶶zeMAd:Jc`4$%rw F~ dTF& 4_Sj685,<%&һ32Nܓoi9Xjе`FtzvSrNGscL| 8=2Jݠ-mjR,Jw[Y? "ڕP߶UIv=P?∩E=IE;OvtbUtz~lۿsRۂ|Η{tjڊBŋ= ~`e`ѱ`Tv=͑(*67Om&%5\:M B2lQTg*(\1l?kR/b\4%!i]Yp;nus$dƥ̘`Cq [=|W Yt:ib[љlkpj`ÒI9nZZ]IkYհs(=;pJu{E}}BH6 ϯo^5ۑ|,V*r; QLz~d_u8꫕8u8MNs΄%zaRuI@W#2T7mAk-=ʉ&zE%1|En5o&t'`!߯|uNc0<];3lv;QETV%3 k$h .Cߴ.Gr$ctfQOqj 4P e`;n%b(s7S教ʪ)Lgn+)U hJ7X {xsH%P"7A R*+v66 c!=ꡩ- 3RHS@U1Bb| Jj{Ⲇ#%NNi  4^BM z~Y$әחʐCM )A,q;{Ċ[5cY8Z3"VDAm9 <^-MR믎K,Lnb=P1QdH]!#7hWPncb0xMF4βڨ)eԘ`BĐDzU,E@Cber2FGs`q?5U=(ڐyֱ֌ru*ccgǷL+g.nUϜtC<7*IY|ؽCtNnk ¡G؞݉ny8ҖCPe)?n:5mʈ唸ƈ|Vf18xM}b3.+SH CFH*3Y;`KU1n#bO[p*`l*p}9GV2C 7Ʀ@9߿2 @ebTs>p"! C guH@ ԍ!׀9#nG8rN#==E&BdbsrxO^b${`p|&,] U'$=lTVFrHɬ#Y9=yРe* -~]xYq4tx؏HQ97.1/I[/s)ߋy1N!Q{NnN&2}%ʹr;ct9qEbbT|{ot7 {qXF5cǴUUu>e*37f7.f{]Y32T$>`{jS)"*`gV0duIgc'>| oG}ĿҴeE|8#o\ovl6rQQ 213〴Va:Q%\䗔,I!lؗe򒛗o-H(=!!;psէ)kj:y$ɼ)Rw*T6Oߊe7"ND~J$,KPtΕ~rebF ؜yG vxf&xS!+ap>ns{o|)ynJEt.u>-a/?>*Aɒ:xmˉK{H$|&`[`0=ۇ{#[y^1z+dMt+ض5wH*b )tЦ?8ggL7t?~&IZ$3p~R[bIYb*Z7]w#;3AGA4 Q YLnj,G#f?9SK)3N<[:x\#R.P[2V^ cGC=GQ n6⒰[(*Y^FJy(#nkre}-$MlRSHNfɻi8i.^UҍWQRSTľ@#%Ce2`?N+i ۓ#P[gZGDXN5:I>n ]T< ZOMS[GS2Gb`U%.rC<ɂ$ہxYs9v'`LNkzX  '#gؑz:iKJI}$iqg OJ9E΢+tqbêQnкYe3M iX'Yfm NSQ$k7W X( 82qucI Ushi*Z9SeE`Q=]@:K2m,M`~[**`h*%մ6HI>q%q:YW>\6H=A'5rWiCb zŋb3ۧZge1O2#͐2=56uQ"R4l)SC`ዀ8߶Okwg-1;2RPVG]Frt2jO7B"T>QNue5F8be*t G9W͓~ZJB0L8clWlm]ޢ32ž8 | ֘G!!57}'| Ht֢2R$n=6 mҹ^U zیgb/E&I,%e%{zgn AgDI[$>TqXT@v]4@|_AŵrU=qvz3qqk8R1) 26s]4EQ?/ZV`W;gnz#捔O|QRYw%lҫ,r8PNB6= /w F [Iij9QOy[ P42}őcHT:nDXd*}N).7yR#) :vzpa$ BHˋY&7 !vÇcHRm[]c}])y%EA[<+) !\g<ZY< ^։f9#A9STg"cV\` ^vNpȎ?O 4#@Eǀ VA_JV.b}.P{uWhLP:eU:# K72n{O3±FTTCNtp FC #; g% vzybus@ %^HN[, ۾= S +9njQ5H#p}x?>[+O*#iMPNpϯĂɫzhYM$Fx Ȝ VBue >bG}ǿxF1Z|6#'f{q +%Tm SQHcFc8 cn4ƚb]/d)ɧ-3T p#Iz4`cKƮ81Ԫ]_ v`^u钴b3(8;04hXtDl_~m^x_Eɩ*.'4ZR ʬꥦ aU݆NQt.@[A:aQˊ|,S K+LLX#c~:Kݿ ZKaԣ.Đ41m7յ ;̕lߎxcJjh>J)"r!IN#ӆC!ZoWkh9j,z,If',|.<QnQGQH渼2 8P6r;; )/\(JFiDW=0zpBr֙eg 24S|=r6Z[/tLFV IlI{M˴5+WշӺS:F-C';椪Zi$ IeU$ AǮ h.I_Dh))cTJ` (0bw{dpp--@bʙh.uPyrۅVdha*fU`ucf_7j^)z  raCH`7pOg-kU Y9S"udf)W'Wie,>F/݅ ,]bhD4 jU2 0$0H7ཞUO3Jƒ$ &7!QwGO9=;q_j `1.1w ?/SR:M&d>7y8/njHgT$jgң8BVrU5Q?le˕V/(`ǧ”1 S@cy 7iqfP&R22N$omQ ,LkEuAoa,JYtV7:;woTW, MP}㣏% rZ$n2p4|GX wvo)i%r}BCj$d\)~ff'u-2 A)]8̱?c1m5El07qM_uy:dfNW‘Rj`*OۊsQ]alKlN !Tܨ}B4H)ӍC?q͜uzڛK.s+bZOA[QK)Z3oT?ˍXfilջBV]hk#|[w;jLv*b*$zekʖ65=vl]H0>~Al^%-3Do#"2,锅IjLRDt*qӎ`c qZG)D,pq$ӌ n'ٞFh4i*2oƸG`@qgV]k9e\mJ c'$aHV$GTh2\)iY Td7';gZJ[mrK^0+qn˟}imoHUMw嫓`i阸VHːF- d s=Yzt*bHi&B 6N6ᛞu7":Etɑpd)BDzhNbQq8*Uɕ Tb7uhI2+d'e3㥵UiX#i#YF6c R[Se]JBRܒw:P1.KBb3M~a,&`IϮ8ПI/DzJR'K$QFRY[0I- A4#QӮ g*5>q w{yx15*eHEo+;@>V~<= Z2EdFM;6*rrp}=8VlTTհ% ⚥iҧJJqrK:TSHجaT~a3sV//[FPQD`cbNw\2sq~s99W)zj$fܱK>\8e$ =8vW+&i(%e;8*Jca ջlL?n6Obxz&|@JjH@f'Rwu3W$t h9s 4vOlے!j]N}ۊ$d`۳!χX|YW:ȣF&p6oӍK[䀮SNgY˾+AAE ˣceWW++dv+Eؕt* DK㽎 KD:jݲ ӍexidR}Gi߉xڭSݭ5 y5h2Nr0q!ek5EAn X}L9D}/_QrkPF(H0w`?9n*P 49;aOazG:;fs%UXmi. ( w 1&O -nO=:|1[n-(KIju cߍZ֔|D*S~&٢/U6EKEmpb=/jb@K22۹"@Mٔn=xĻa|y,T1WZ8*]DQʿǯn,w+a˗\cу?_U+-W,r1J=,:=}oͼS͗ډGvv;_`>afFGqv$G'<Hem#:w?F ;eoz~zFc}8q:]I=0a߅Sa cN<˜;W2vlg4^)ӕo^覒-Rn#2dp{°9q/?77ެJxLJ_O5 +kdf#~;oj<6^2ƓetP AJf(^ӈg۶8N^[Ġ9g0|*cxá98p!|#}Ha?~)3`[덗TOzz>9ھAUnHDۍд[>H:}=xv nw¼1oŖIRf8xweMhGh؎?yn-%<2q۱.seZԠn[Σq#928!Q`{}` ƉaU܂v,146F0slCsh1ČIڶ~{=yImB RHT@FDeL9 B8?vUH:S#/ d|,SA m҆iupPea>lw6(8_#{I|PPE3f&h.FU%T\曥0g IW;E]R:> Rǰ'8sfm0V`cd'2qH=6]i}ڦ]EP LsNX F|c=MASI,$$%J6lsċSۄVqFe3,D%MCV p`6#n&i2@ FWH8SH|g{읡vhx]٤A|tĶOU[=t1sVʄ'cěMvj9Ldvu8oȻٶV~b$j>j9ؿ;9^dX>A 9QOU)KF$E?ś1cF7Z*,06$c$cc}5g秷XuW > UQ`Y+*^"R5kdhUns664$5Q].Z=^fl*=xyTZ[oZ b^BuaO{n7mUir.Щ"Yl8W9=;d%x uzv+SGMCNPjdgnr8a4=zpR`>;g/xEYwjv26pFv?~qc`X %dE@=ƮXd~vxXҟ m#oT>Xn,}h#z*WE[EWK4xd1ΣIo.OOIE4 T C9 1uaD"cu*jpJ7#A*DF",2aةd/Ce*"ROK$7'wY.#`-:CN`~sO-6~Qp#?1$rUA.DjX '̓5G|ܾ$2X2^,H2w_.'$lЏ2)H;`靇sUt5]Zv]/R؂vsn171RU:SƥZ(Hq*ϮA{W٧lP$pbU[[PKG.t GPˌ`nEnە5vhDB2F `#mg帡W.qH#Q|Us'P`Ī^ezY/U5K7^G;AWɐ;͎`+ᩪ #3%<хE#%W lch#8E1t@3GL2FN9%NJCO;gIX}>|璖RiV+!`ԙ!RI.WFH;z}xqXn@uDsh(U@s3ێ0bi$6 H+&p`ڊuij!`8Q,w?HdV#=25m}=CqrԲuU&Se.0 osſd)Zoh5I8 ӋEYմbĩL ]I;g45R8d0nH]o +"2c)*jḃ;0RB۾]RPOotz!CE 9ܟ*))ӎx%Ļ}-}ZTr4dvv>m󃃿!^챗b ,J`uFǦpOJA@u8* `Vc8ǯ#Q]Y]qkY$Q[L1]C;*\ lT0ApOuO#?̫IUXGVmAǔC}A8#~aW%Ne:ŎoTmM0Pqb|P}kVyRVC #'7 9z^Uqv;bL=pJkফN .eMXs߇[]}gK $I0Hp@0si~eE t*),EKXUEZzB8ii2+jRWIbm}ZCR}$jz [@K'CQWfD/t=$;*I;RVjI! AW p+_5uUDumz"$_Isp\] ) h&T&hd2ɠCVwc`@Jz# )ҮO !IB0 Guc%'W; B`B2p{l} Ye;oSpJc7?9+m5-ڟML *ߘ$~6/9LYga(sqnڻݢh`$IH'GCt??|r_y*LUT:nē^+ogdgu@5FX,KWI1ώ,r_o4<-\/n㫹SssIn4s~4="{G8}I-q޺ 7%D8$|Om\V\i(L3c w#˼$6WUEt=U|[@ sW(J!-AS$yu  $r2!R3FO~ɮNacbF ˆ6ijmYJ#z"H9:@~を ;zb0K7 UI %'w#wH2m;e-(I"PTIҧpfUt$P0IdP9w]灩9M!I3HAWuzt#K']RU }HZr%- vOC%*Z-:;A4yH0#}/si]:Hazy'`~lg6Y\ҢIZݔGl7Hv~bW5iqR;V֙>3n/SIY؆ǖ#qװ +znT# zEA&&a;LGFp1\UGwdhVCD 8Pn4錴VUQU !#MWGc"۶v@8ū- 29g #-K6N}SƵm*G +G.Qi7A@]9*wtZL4EVض/^:̶ihe;(#0 2_*t@ ᗃrk=$\-q 3*gw-nT y"C3"e< 311>Pّ>bxϑZGL T+TżR¬N@qAxZx6$O[3=;OXcV]8lt)={eEMXKJm,1FNxj˜1WMи;jٛm"fvi*DWH(UR5sӜqShw5޺%sQUJ @"Sjӻ.Q870^ڜ4C34CdLH;.sm=9 2GOTe#1&l |ZT%+ rC8]69c:EzV T,`P:F`e ;Y SG3P/V.6aՎ/QZjP$1*hW(I#EEך꧖Y4dI#qjc|p=%,uj^je6:G~fzK\\褑,W5>c$dl,X;0d/tUQ5]G L">V:|:p-G.a\^u+b p\N̤-0yJj[+]*MU'"+(,@WX9`@+K-Ҽa;#Z'|IuMtOo''^(tIp:p v>ZVV+uE3QZ>zV@TN`؂H9&*z,M4:]QʔQM"ޟ榏Kaԑrc½蜻t_J'bKuVT.$(<<._J I $!PHـ Kk庚4+QE4z8\c Ԫ H-k5ǝ3Ha$Y0\38P}xQU꩕:JXnqsEo1rقh^UeMGNPӒ A$q;n6jd^TI&#J\CpuO{b{& (CN2vǿ ^ܢ#q폷 KJ2H^=%>ȷ"b b6=ҟÔ|m4G 4C)#sH1V@R?ʯ9ڧH$icW*:! # o.*؉[~#W\D,!#OHxLYp[QaW IUpp26c8b Cɺ;D+LC c]=l־`UVuɂAv*5 zG3lJc|EtZƬ9:69=A:]uwǎZ(m' ӎ/KW4-r;t2FM#N0[zjUFY^3Ӳ`F5NV*GxIRP+#HYwf H{mTՑ=L0X+6JcbJoZ`DQIwHl{O%(j5DT*!ĚJ^mJ5*+az c' Mdi<-o[rEsSr*#oMGj+tG'\ ҳp@e*Om1۟+|OY 5RA$ԉҏ9>`Iq%y -Q$[F4QRK )\~~tv|*0W^pPP^IAbW  0b3qCM dr*wI$w}2) [voԊ[<1 , $~9%-T2DG3ui 5mveyRV*eO3 EK;(9@=U-s_`237P66W9hG\Q)|] ;0tjV;J{%$un̈́e* 8d\mS$Rxi9&o#wl8a/YtZRпTy*:*˔wJKB xVc/o{\LE|,*5$؜q|9i;UmZUI"PDr +%Nq|0P~ 9C??J(9gI$R:'pnb1Z䋼YjkUnAHhKI|sy a c4 (:u$ Ƭ۳V?mEGTTU҈O,sÓXlǞH7R#=,lHwe㖡TuI*jɪ)Jad,rAT8__ qEtڪyv#J)5l s N/?Aω$jtB[={B5O흲mِĚ`?ύ܌Lu%78ZxEPH9)%PVy%Ck08mL2)C=p=8(T|MEe=XIy e8;8Ƿ>rsTVSMY*e w`mm7RTXZ:Yo ~w,Zn6DEuezCONKZj)9$ϊVUN5?r; 3H.YMrCNNBwevqϷf$pZ+jtH ˜c{z,[9|ԗMl J$M??0T#3`!Lvcc q.GbdybtPWKJ"6w* Ҽ"C,5 Qqk** 4.MM{q5Wj6z)4$>`UAp=v 2Cr ԙ\1U6bE7\g#n'X5WK=¤U:%"j>2ʠ2αAϔb{੫& RI)VSK2]@sJی)'xkBI ZePcNw9 tþ.TP%m35DR,L.NیbMi޹_)JU X@Hg UY^u#aJ0H΃K;w.GhhᒑNJFf3u QߍxsiW zZhݣ QGmmK ԎTŁӬl9' g7מdj.]9^f)LST.WI' .{Rd*&a5qK!A#'RG.1*j,"VP$ZYZ, #Y ! 8zxA[Rs FsѽM2*λڊ{Ég-TQ))gugED͌eƜa}Xy&,tMS-MEE<$Q Tϥ[RV=p ՒH;:J+n q \2ǾsjCm/1RMD<2RGP#h˳56,T{ bf Կ+D;eAA*@ {6hgJIC"BH6A#Q|wݲxdıٞ"i"0UԘ˫$ 8l-2\S+,+E$) $ ' IzXVS֤e*ƃÓBT\Mx<4{}DEXٔ"QWN}~u-@#SI IME)mabadQOSʴ.h؜{FcԍOsv[|$0XN!+#eǨ@C0OG0GK'y⊢P F7ع9Ӿ=GQ٨Lt5%̦֭ J#dQeZT;Mt`51_(J#aT=[#C ž2Dtba;DsJ8V}Wvϟ~HqACM3ZF a\n54]Fᫎ~cqj)؟N:SSJ( PN <մgit&tVi;CzԦYX$ Հ `pϒ8 ,1dZx4m$\ ]]}MKP*%)Tw+YR۝'<}U2@dP̄5w=5؆yZ>CMFVYN[vntmz_ rz~ s +r1ljX !A<ʪ(ƒˀ31 3Zy#jCjW| . v9vWr6j9B-6;($T3N70r}\7T^K,̚T0j8c4 WJh #C %g8CO%#,/50C* daldَܩx)H-g 7ƒ6$}8<5*Դ7&FU8v,a?neOf1O0QQθ1  7ӶNG;.\rچ8kQ)e@ Xݗ9O9|n`}\ND5" I,c9o7xtiu\B+t8DZf#GPֺc=4m>V!}HFC! QA8,btl79ڲg)rG4]Yk,;W9 sZ>G$Ue51Ă~ՐtΏ @K-4ti=5[ -W 8thHԪ HeV풙چB2m8=9ܬ×]G\@OJǦ0 Aq|i'XPa^5*j`k*%TXb3bs;aAVIY)K=\ȫQW p1 nbp=`O/](R|IP;24QPm4^REx$ƉeoApi5ei t# 2F`8O[3_f:d-'SN#m 8845vjUTjV==ϩ9ǧ ƕjh m%yi]^Rjcm:I5dK7P+j)zѢӥfƭxb1Jْ&IQ+7ApX r8w8yRLadGˣ ,sJDuxLIE\0^t _ANS> CtCn:& AMH0(?9ZJHK(I3ϺJ$bABqW8[motN"ʝhC`a[/LOC=AoYkmqӞPaA&N{pzWSKnK4 >IbK :AR  ==5"ҬTJinH#@`2)}Q9wᬤW^͗JOV;" {Em:KEV$JREZLؑlI~3+Cq\X)ZHH"]~WՏ`}G:dD9b=̖Ȫ@žW8/Pdk/DgC In>5jJd; a! )^&Ys#; *vAoI9IK;N#0*bmG?lp|DYT3RUKF >pAƓ;}q K,6zC% 4lcԦc\btDViQ.Q*H˥5{cKw 暞%-T9U|`WeMJGRm2̵adUSS0 #8RI&J[]ts^IDzW,2ܐ_a_됃v-4pVT5rt)RHme5{z).}Lڎv~;Q5((Fa*#9(-#Qr?r)x )[c'NN@ܝx3ۉʎר' cLVj*2\z~|j!uW;cPR]u_%LR78_]ۍcz~aZ rMG!SݘlˎK> lwyO '92#[^0¦=x=UΦ/WhAI)$ >ur+u"oKOR(X6Wqū%M%"2 3`Fˎ$tg+uMtSҍzyW\2c\?75eLPԈ$`ʤlRls2Q\.4vM8t$eu) w0ؑePRG6:$p.>Ǯxo$HSRm-5+KK#4uoO7N}H iՁ,=~~)MXpT's63U,ѴlZHv]MPp7u@I|EYRAOS8h†sg>pMWSTKYo _0sQ$,MϜ)N$aZng{J KRҝIo; #ϨpeiitV%@ŝ;/lIS?Q*1R `Œ`o+þQ7A[ s;9R-XɼRF4v 88 X5NNy*GӜ xU]%3ԄS8Duc V&E/;H4 8$2w'mV|u|Z Zii$WBips`g:MiEACo9"J. ډGa8FOx[me-QVG<cOQ!GRi W}yJUqY*i@DkF!xz)t8"?Ð?M'Te@X;xZSMRDL8s8ۧ_|A]$ DA@#nۉ/ {WS9& acHW󖦄'KċI=9OZ$yFmMh+ٽ&W${hGѩXZ9u9S]N)ZBZVpB R6F1wYT0L^O(1Xor7۷[X^WI[dBxvLc8'mTTMR0KzTTlUE\V2"˜,[ެۖnzi IǎHg.Y#a %C'do +9Xm%9~e"EX$RR9$}rx4/P6?1FIXwepve_(9s#MMDII<*)@#ca?7ܪ5ĵ%=hAW9-caG1d?䚡^ JM$3(@^18ϧXp K`{$P2/.])"ju0MatmQT ULkmm4+fN:vBRrH8G`8.ZT/?MJiA9qg<jV$iC0BHէV 'pb*-ڹƓJOF>\[TRrddl8 W1sjKc)e-Ӱ*sr4 ih*ՑA#nAF=0pJΡթ2SKy;,oAW9udzҝWr5o9P@ w$xTIFxȉ#Ɛ;đx zUmBWgV)gPn ڎHM\-aHs% KD*@$.6=nMPmB bF$H:E'N㎪FsP:pw(j JH*| 1 Q~eVW0hrDm7}C9#8zMzIYB1v(*O'>̓zhd{+H]h֣ѨzrކpKLi.!=Ex FHerp ѯ7VIj 8;dǷ3wĹ#{sHXIL4'U$ig]gQ_G_qh_ioѥ542;&#$6HWg?Q~/5-F|u4)c2N%Y @aܜ<73Smjhi!q1!#PTv{UEdAAKN**dR,`H:/rd+`1SfI#_LU'! \8'g X>?4TW5@-M1S39xrѴQ tfC H_Lw؍r]CS2ڨ6'ƬwM:>e_5ein3IES, ղ*&!B\q{Nj2n)[5,#ԫHa- ><~qj;m=jHCS稣IJd@8֪TIXFJ&rќ)AA9:-YluԦ{3TOSCHЀlA;@8?Ĺ=S=~u|M$UCWR{M:#y9FBL`0'K8 ~2X熚چ@RCR zJPm˜I=x33t:R7e]';pkZKm*b!槤u55QNd3i"==b=MH،|sӝ^"װK=}zCpx%g֒%$@1Zn/[\_.ĂAþ]~Q[40:SHcИ >N;%%×kR9bb適2F0qId5{+,5|SL˦&_Al;UźI)n7E9oR5g^|R'1V|%J1 J;|2K=4YUN&q(VPUq/lk^bI hB4S{)0Ż^WT[kc(p!d+ɐ]@A+RO,]iq,0:ܞzi櫩I`sۇIި;— ~r6h`Kz*v= RKK0Ya_u9ݸqs9`,)2l@*1;PCsBCQA\c!bKN0r1@=r Xh_4 J\88g0>Jue:`h+avһ9 ך)Qz\Fac` Cy;c>ċiZ9VW2y8qH&.zH$`zcHժas@0![)%9>`[9FSru\w_I# 28\;lJ'*niSQr8* }8)gs~-vU\EE/M0wde$g#ҢfTZkGGI3Ϳ17rv e$7$z*3͸$vᛕjOsP%Zѫ `0I߶#5wI) "ʁc=8-qT)xeJ^\ۭD"4&unA`6n._:s)Cg-\>E‚; V)TR1 $c8Vep3q>tnNB*:hiD( 6b1K?|{ѫ'=~䜫m QrZk4ULZyI-,%Pa[H~Qxw+IEh<@rglĪNHOj"8j82 #p͕XL臫Na`HaF=J8rQ1Ji+2,[3DBSeyv9$j"jվc9q2v͍Y'cs S=lK.ȫU 9 WOp4O?8]JixGX.!r p3s,yx7tt?UӭT]'EB1JrG9REpG$t*bDPUS;;0x :[M؎jI[ ζ] wk_%3W#ѕ|or>!6Rٮ"´0K'"0r9''߂6u(MU*=¢ƢPt u LO-S|#G'!p8u`I8$ ï7yȶ EhDS#Owi5rh7U]E-~1N+1:9NAPI##'!xsh9.a:h "ʁ#=¼uӤu!ian E_%=sWxXr?`IM5=ޭ6QK4a>C`Ɲ܂aYp#'П+\hhaD$ J"1| ڣO+4MdFp'mrU\IL@'mqV Bsm|"UtZIQY /g=#9 Ρ[| , sv:H/s/rh@ĭb.%7'cS DIScnt"\9)nRѹ]a@}FpmRYNbF eR46w#툼JV80RXs=lE G;D9rxWpelican-3.7.1/samples/content/pictures/Sushi.jpg000066400000000000000000000705001303525152100217050ustar00rootroot00000000000000JFIFHHExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:31:09 PrintIM0250$"' 0220     &|n.0100,   L&d2010:01:09 14:09:082010:01:09 14:09:08 ddqddFddFUJIFILM 0130>^ f !"#012S100 S100 %A592D34383231100603D7050TR73277NORMAL d^^R98010008(@`HHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?'X|z?kݟmV__:T{hd ($Ojr)@檌} Pּ)ggj һ1i2*Ji% ˡ?hlyWfVjB}y[G~ οζRgu oƦ:,yFڐJ2}5F>4RtȬ}8ttvcZekEҴ@YJziR>( /^E2* 3~j*Yc5!΃).%$v9г:\&1E#Y'+h.Ϲ+/aUL dݞMiiХy\T0H_)0Os @w??[~+:q>foTOs5|a 6'5{'ziN~+4MS% G9edLgY2XoVp#SQԧroIAE"=c_ߛeb`qW6d<ϩ5a\1PUx/Ҧ@LkM^!VC͵ ӊԃF IK@j7!4Ơ IQL MQ@Kuyi|Otc5AB,c~5˹>"ԼWoG}mfSvb WeE#~{7Ʊ|nUt(`+`YZx֤\sE)Zi IPH>iJy[?Z>h%}gV֧C& >nc:~ [qwöZ]̫hAþyYb 9?mEyWC #[szVG~T Jk;Ry:i:kJ/b|i'YAVAٸ>j]#L]jIS&9xCWCN}CN̬}77վz`?ƺ1iO,;xb9Zݟ, tdmn-mC°j>eK#5]hWKr#^ 5iI$qXS'.թqa MI0ga"brGM[50$:T6yO4ots6E9k0(@sf *iR曚3@5$l!P7|MEUMEMxn]2h]#W\5'4uݎ@F̨߾>⯈:Ɣ֖}*346=m6yf1)]iC76A`1/!w)95*lxaaZ2_#"kǥqS|4Ax䚕#GRMTݦP?:owA)<(=~$PjW"X:(OrZ]045{Llm?,_M8P34 v |˭vV$M <¼ u,'daЩ xޣ}׎i30Aƶ7R`sN.9&5Š0Njcj#oRyz#S P=3sNbѾL7Q {QXqw-k) :T~uޗ]>jsJ@>Ĝ&ơw@޸m~nˈ G.vө W`[$PB_:Dv/]bqA=t$LU4OX=4qRwٮ:TfoX]EXѴZrU~e$hrH0 [!DTmSK BFG u9>6M Ӿ(`HR_1V  V~ʧҧO ;n(a)Cu?"ao fi5ı*Cii @ (4S㈏EXU}xqҥ@B>ԦqV!^*@We42w~ U䉱̭"{U )ugP9qYznjƯhae ׭>b+}Fhoun@U'hO}e+鱼˳(~Q5qXx}TS68R5] : HGw=qF dzVq4 k&|T-9ff8Z qֵ$BNW1m;*:*ݸQl} p;SmbhS9_t,T=N{RC?FZ?S[R;TlE+z}iCAՅL  2zus[Y7(%WZǏcPdE;ŜEtXۻh)}ާZ(vEYӎh+!5P2xȼ62XČ$ܠQEHx瘬QEKB.~袊cE㊜*P!GHj(Ҋ(QڪG(@V~(C        C  ,"  O!1A"Qa2q #B$R 4Cbr%3c5S&DTd/!1AQ"2aq#3RBC ?RK*RB9$풄$iUc7hܸ)f`xZݍI$҇X\ O4idTRFk Il~K=ؿ#]!Oꘪѷ-kv5kb=f;k[ckC,6lZzLRSLӇ [دHKqI&-f- FQ\}߁Z!85  WM:Kmn jǗWOPt}vǶX_҆s~bT8wJ QL5fY0.#ܐJm.;=R>$.+\1uAIǝMrZOT2̂LLq]KE IJ@@#-RNEWM>2jL(*U uۼs5*G@;)IsNuʍ;q![ˊ=3 {$lDHM3)@aǥcQ^t#"Rƽ& l$’`Uئ:@n,wmo-%1KAz^ _Á̆+2(1cHm_EFTe<*yo4@ K,"ΒH XUT޴;Wxok--y+&P%ޥl!m6RZN&i5#?W8Y|} Ŗ7-z<[]v-aq +շ2 (~D@+c!6l"? oq{MI6ܝN[gp|F VR-³r4GM8UG}L٘ř1풻 .!q-7%Cf؃@2vcO\I 3J('kknf1yʍGDG%;1n9IbJTʹIlИ0{|Aմk$ZL5D@+ʛӨRW&f@R1HmS&|""\BHwVLR 'ΑNtPSA£Y0vfiߨ.{<ጃƁYrx[  P'h@J-se%;7>ad1Wy%cI'cmg4BR7Ջv9I:ެ\Mi^Iv#c}Qujn3TcHVsg d%bim・*R7#\/hU}0:_ whnTzvڢwLi3)fk{63ew)$<5zM<2r{3u9HXǷWeHзyA )R+8ڙO,%| `]kQPbz!ӠPbRze$5Lwڥyy1ԓ\zGr?.dc<)2XLD^@W"k0IZ-u#sk!?Z^tC%%Php?ZK4Sl>z?JFYy>)O2X*plyC"M Y0ِkŃh qiBwQ>݂cx^"E >5`I%i(uD!#DDcw>W$OA۞j8U-ԗ-9BkB;A4遷R!3؎i;rBW3ȓeK$y ¾1 7ӀO@iXu)eV  6: /!Q+o oDӛyH,Gc-ߎ(ѷ@ mӴDdIُQ>/ 9L+־V@3޽@DfLH |?&$)[HEtvISc Nj\qQ۶qgR*HtGO7CzUf7 h=f4SӅbD_=$=n?MA='2>Llֽ6[8* xߝ[(tW))ROjQVΒ)8)Ĥ]7˃3b-Cg߬$0vHv2v#C*?Bop!eKRk_wqzTiE٥mɠV,x v IvN}~W/u4ӄu"zcs$ _-Y(U,@[ƚ]#?qLy FH1ϕ>/,#sǕzFS8ns'H0u)e>cRXߧF1ԧВWܠoz? ?n}®:7qSAܑ.$eR~kW]kFG1$8hÔF JgNxOd$$IR@\$F}t >i@|GjyXfmJv{x Z`uvz ^$BUGsb 6.K RxHc}r\?EŬ@n屰W?ΧQx1Y'ƕk-Km=i8ى~2)iK[W~4h:1՞^X- \j`ch 'Oz-= O#p[6R }$(YRJ%J@Nf5{q+K]kKk$w&׼Վ8 \}ݎ5p?*r]VmXB)Rǝd25L+4qk~Y`>ӄRAnաvv#z_JHzԒ=䄂w˵^&S#M+ =Χ.HQF6Űɏ81޸emJ(DΏa[i1$ANmJzvlA v22|)&Iz׊0mdTh~]贲bLV." Dw.T-NOpIVBD 3R  1mO]lt9&қ{"3O: P).$γ_s7LSܽ"+ '>y!m<*٢mVn3e8`6KRStտZV[Ob2>$LrK(@;W&Gmqx|-F -O}k{IMR\Կ*.woha ]g,e?#>~@^hk$MC = Uz$蒜 V#ﴚs'+-ͻC.+GS= "yG~ڕ#*&  LRȑyoI-ς4|"CSuo%"uU'n M[5LV-Y2:AS.XILDENBBD ʟG10a?ؓve^q/f#(qa? 1F#΀nI= R(iE &Ihd7b1;M &h@(܎7Qa@*xۊ)d(Fd4&FLnP~( =CΦWXp@!3@ix {Ri0DsADɐo{]Oqz>FFP蒦$?r?$C7oyr Nιիluj:mMt+v1ppUtI#yt{O`oXW B}Tuzv'}_'.ݒ?},һ_Wƺuf.+%g{{MHlZ^&~_#a3RlЗFfݻ$R)#4h}M?W,Rr > Wn!)JEj$ ,μpd A2NՙБC{ObHJ.8[(m2zFy$-͸>P*E׬kR>v(Kh-mB06U&]xF=TZ[;*b Vbw JȑƧ9[G>(Wlaiz՟>5ԽD0c*tyVRp _zsT>[7&3Fss uA%@ '&7y,4[z*B<|=+TdZdF֔!! v\F",&Ugԁ*VJZEXIDGTz' &[[1g`ݛfIAc2*M*oy@jJƸ4buܺ2MJ|Wˆ X8jaa%5o=av/;[CtH.1zIq GnϾ ْmX_:[)`i]HmA)m %~ILO#[y0P< Arh?)D )&? >|edMs_+eA#m3QjPyhyvP0'IEV`r-@e`򪗬MJ$Ӟ^[2ۈwܩHRRfcҙ/M)'OW{68]&ŦQQ@|dfؾ[\cXV#t-Qnw>.j(Xmݕ d%v%1&k~^Ŷ-__`wiĐ[A'K&cm+{Ŗqj,[2K QkghQze,Ǚm#Z6 J؟g/}sn +mIdj'Mkt ˙iAe*Af{X{(}iM}jGcrL?4cVxZպVm6g0,Ʉ%\NZS)wN_uGZ $JLb6ELrԾSٟc9wn\?5JhG"QMjj>_XE$8d!Q7n˖̙aG}*=rChP ?o O0&Evaᬍ#<9N,󟐚ط &MI!ISZDFȝo(:w`2ew' R~{ӻj%Sk̔wcЮ"N6ǁ"=i܅w$SJDҺcD&$jBʭ4~5Vd@W(>QZaD,$N0^PH <5+DhI(>;$S~N>YH}3c1i΍I0wI;yW+)j,AH'B'x|0biځI'y߶by۽vI܈ނn|Ccڼ㝉@fy^[M߆yi 3RfsgA" \eǕQftx|vބ,߸`,pneszZNռ5sC˷O1[f KY) GyO3OA6$zWΠq3XVۯXf%v'גZy[D~ Gta[%ZDlLW2}c! ?qePr6P#K돖Ⱦ=Yv0#kiP_POʽAřʉ?h4.|Icg8:ǖ椕ʐ{S]Pm*u{$S˙|6]7$ZNLq (עf'RJJʌ4򕚚umE^T l9no{S@jq([^^{\KG u௬qxHe'{Ueu MJAjW^P .+q}+T6OP=0% FgRcT@b˒j:;b#^ϽFb)KIIq qWN-0l&Bw^ge'8mɑXL8/KV`-^fo4S(;(sl?RHALӹK̘WmNl D: -mҷmPm0%;D $; ?ae| [x$(H+˽,y8n!v]2۶3=j m12/Xġ{SA[ipa-D$v[Hbw=Qo,e ;AOk#YYEI:F ;NH5E̺GMѰs_*±w4NRk<&`o3ޜ&DG4f: RM ޡ]؋3%ډS)p njɋJw Lի ֬dH2:oMp&7ޡ8;F)=  E`{ic146&&0|3{Pp7ξ8+'EDھ"UǔPTa1x~tY_1H,lw.M^qr!'FOttPԤj־t6̿mhIq+SNG#6xRQJ0ՅI^H-qzp?e=fҤAT G%Y{ҍ)Z]Sl}"ُ3ߗC,8ts_ C_fuPُ=/zXaJ!k&'W~m=dvV~+^H/:1D#H@;VuG4^FIWhȑ54V#x& <մ@OD@ZJ&ciʂw1 ;Vi[ipRw +CuҜ1_f+QR?:FtQ=aHAK.nҋ6\:NX6tɩ1{0mPjDj'AT*#VUG*1\l g0amreAIu"HfėsTAM~c%eZWu Opp< (bx`_JU;x1`y dW qR{,weŊoܰ Y_Mg̣ZvPz&.uj;np+(O_RsIM$觱M/.[w!W"$~utWoMV#&70VLǐ8 l֤ FR}Xa(qQ b̠KA3ю%}6&B+ }y'o'[L_ m֮o] IiQ31^*јscڷ ?rD=ԗq;7.}fmsBi'QR JI>%\.*/-z`Ű8` ; \ôTI*R6^[!KvB ?^U.eKiW=%ut; 'jOh5[YH>U\RIBIZdˊM祰E%gU@-i b|/lMیIyP%^+D d02;|J:I?4ƔغIZ q1+| P.*qBA4hܧھ#> b|"0ukHpS)XR'Ęyh[[y^Uil Q}X 0ObRt<\޷sir&PN(B7}o??uyŲ%͜GW) yikƈ@(GA2.8-Wwʁ~GߌVj-ˁI#kCVqyTۦ6\DZ 3IM![_R cVN0O@7ul냦UбGʶwCzsM#VXE}~46]k󥭺*N⩼1 KR+BҐV'Ν2x;LׁP=ǝ2X\(94ᵫe J{0JI普j'I!-J0G_I%DQOlQ۲Hj1:Ҝ:&xT ~jWEg OjOW-x[}a k*Q!x-KZu($7\$%H(_\PIH>:~A'$pjp*ޓXnCF#iJ`nCq Ӿ8w)ni&#qTmGr{zM<R!#jqˆ6ʇʊ b)CYp#<`*"S"J@$G6U~t{J'ϊv?jUczSfmŶ*R="O_*5& xڗEh>dǙeix̓1v Cl lmu.Ip#+(Q& ɣN#r{sSځ/Na^%hFapG4  ) zιft`??WoUnFU ;8&k>F'eejR-ݤCI*ZH3DkDv%E$m-a0ND.Р(r@4C΀$y~xYgYڟ0A?O:,L(N|TA*RE H$ X*vZdv#s)jLsP9k~=Ήtt-J^q!;IүGa4#ʈu ia4'~tCNxL:ni#!BފMSt!@Iߵi3;[RV[1$V`9Z}1S2۹h#SscSE)&usE"FHGJ zfL~t@PX*hr ɥXkK@hޟ fS j@)D qIoR`FE`(ē";zP &HQ́;D6|`>Q'I$2(䄄I'z$ ;AB9%\Q{ bR;oVwIs# _oo]ywB*ovFjSQ'AZ7F}նlî0 >|IQ۩8duX }LnԻ,b" Fw >w3̀i>rjQu.\?~qed1,)>aCcA q4Ø{Ր>z7 OIY5FMvj&arD)7Tcu+!I2q# p}+2 n3 ?YQ&FxZH$ԕy ˮfg:|źJD wI׆$\I^e~0{?Z'>Q PV6#mPw"s6 (گm]>ֆy LoU“f[6]H>oj^j3 LɈ|,ff;[,:B4S VdQx@|Аk&'D-!Bvj^-` X=*Z.8$ڤJ:-%)KɒLN" v ϠN]^S,($8eEw]aRK [H"ƒ{dt9\]c>Fc}w +_3UU=d爟!ZbYwreXo u̎Ԭ[mv[ گ--YZťtWԐI;9H[=AT 4cL,yn.Jd87zoHNǥj=YȯuP )i*) X[[): T/С D7\B EylA);=K "G~ņ))V4x BL T4$z:uaGh@(XQޘ DlG:A|0R$̐GNdӺgHBL*v-V r)*W5jBQpH#OaN~";RpN=*(Warho)0~h;ұDo 3h>I'֔ „KAv8zccT61?)4*ȏ lkL'5wS\ց$$|ALH1IAEXY(Cv=;[ •y@y*7M⵴Gcbb>ٵ)6"5ܒ|(sq<߉ڟT_RuUA7D FG<[ GrNT@ 7 VQa)|P)6 D-'xFZAq>T[ :gS;>RHJEz-.GuGm{TEvp%$ڂ'IsޛSN:@2Lq^y_ yDsVBݱsoQ?.#iO]*ٍ@ALmU Uj1ԩ?Edj~;97 e {ũP7*ڬN%Z[ưPuT6~|oy}Na#iSX6/,wPTI>uqH:RBɔqYwnӨnv/&,Q C1U[{V:wtMdl|Fm6Q<'VF?\6xp$Y0?i4TvUM&\n.%M5\%H)$I/'Lv&{քn(zP4ΨBm> ^| *IRG]O 1E)d 擻YiC*֞ґAyD1:jwfۤ5IRmgΎH@h"#hhHǠGпȤ۸ "A3?ƏmA(%; H7$D70j}@Hpyo>ce$#ʄ -8ITڌB'`͙& 44+lBTNW@dDWs\\$mҐÒA D%#1(@UI:gqڀ[|L<'a$*T* ;PTuH$fTiyVCqg'ݐb'MlLnR&Ѹ$ 8;i=/rf,c&݃ - ;Vc+$psG7R R F+GOV-֠v2)=3sUu*J`g-G3 QJDϙڒf+ɷ-{f ;kA)鋮!*J #?Z (u'eų+w mùmS;Rp~ۥ һ~&`m"F -x%唇7h{7}Ko  V$WݑrƎՕ8)cN󠜮 ~5CFNOOm̔(p-̄\}b4j(I ߎ);QL '!z2yW1%1FYK HZb)YB\Jé)$XH252NLTʓa-- *NbΡl3+i/j kj@\*.%nPFW5zkQ0+Q>LW{75eT`>vlc֙ A:PzbKIRK,2x6/?`ҢLqsoe8K C.%Dpk+y꧵/1<\C.FGkCl{%6SDNyV mŏlɀ`zLM|YZl)w%+s'VCq4!jdKZCVR4[^[@)64$Ĉ D oRw;!1MӀ h$mjJJ; T=;`SBMAB"I!0#j-FRwzH؀&dj;Dn$T}\ހAĈ6vx@TC7cοvš#jq`~TɊX\O&h Cc p1ێT( $1YpB{wPӲ~f(O|֤goZL=(b6iæv۬L(iKP)zPu+ZRDROz*1?>mpu`$ldQR84jGo^[1o@ bLJmn(Sw,No#ȧD[m@$yw惐'54fn%';_C-.{NԸ\aQ!!1A i֕2854zq=rȸ a.n:]Edʖ#ZȍB+OB+i&70PK 𔈮kf*(Ƶ@_@rp%\m6PQܟ*z09QƔ{rBJ}~9Oʮ>.:dP73t9O +d%upF/oN/['W!z>\hV;rJye }+i lxI jW?<^Ze`$Wsr"`S'F yuI:&ۥ\ )$#L{:).A Wy:I(P7 %Tؓ<ԃ0`)~$OqLaM L+PUk\)y:EsRmP.2N5LON7Q*h#ҿv [FƶAJ,.(Ѕ¼Bg`{P`4kТ]( %Kӿ"[ WiM(+?]jKkd(LbgP @#J;#Zwc`|8a9SBVœ cЈ#($#b&*}eӼbSߏOXwM&=fy܊]F%$RHx0 " 1#C{gKZIR=zwm %=Hښp&x+QU@[k?qK'.դJhR'ҏnS*ʛ/p^:?Kq{YYz'4XLݔ9ړYbnV0'$P&onk.c*vnb`Sb߻R;ȯRKTBv >g_e'Y@u6! 4";#G>lXm{&;aOpOud Uw Yט.?&q ׎IH%ŠX-4Kxa:T|?xW"}J=h~ozBH*3!.lɰQǞYe5)KNpqҧ4$vγfcc_4)dEj,Yq԰ Y{ }Uon/Xiaܒ89ݎ={ dg.ڼU7\Ԍ6+y|!>d* 8Yð뛤2%\ZdMA8.>T<>UJ]џC0ίaH]M;xޭ!D:!oqwՌ隱^VvN(U 8>:j"gqhtUGiU4 Q9ئą'Wz~叉jmTԧ:SL\zE|u!6"fHV~<Oʺwda,Ut~x%XsL >z !I@wT‹vN3B}Lwcב1)e-nx#r*&E*!IVzݣE!RNT/9l)@]oW5e^JS2pNiWh&"x,_YwRqqJFVص*b啰{)+AIIꤘmE (J 4SNDEPQeV VO[ B@ [l$B`w{T[<2tz:;Q0cp' vZSQ.FyagTj2=}Z֕#SB fc; A$xOoFV]MtDn&0iL*Dq%kRLGSuIJNbjWI)  I;ԣ|@ژq$hUƆgVs@.(9{$$zP$"( 938~YƆ Y4%nȝ5zιa8XI:_SE_4]$p8$jXBk#Hs˽iN%]L6gVk\] wROmie>Qܫ̘=Sjm$|e?rkqct/u֮[ҳҴ?|'2,cĭ!8pR!R s/N0mo I)'Ư {^%ְ,Ջ.Fa^%q :/ZP\S/ۀH'aO~j7Xmˎ4XN;bYS[H_ U3.L*)EԅJyTpl]+;|pWN+&*&V{8Uob7܁xM8rdG/Ef_(SdT`4?rI䊻u+Q9JHmwWr*sszӊET"cVeqbnw@+SSD[_ #T 7ؙV&I1{jNn]taB _΅$ցJH?Z!/i jW5;~! "+{$:0*"ͅ^̀;Ҝٳ| +$)wy(oCTQcB&Q>&;R)Rc,x~TՂ!Zp)ySD2{OvXYH ƑNNO&%h +n <'B;*27B\+RV!I$Mȵp?NԽx oEj6/nЗ$G:[ez%ۣJ˱S en4j hP1W+%rVIr5BR n8ډC @hnn(sܫU%}]5XQL*D*5p3e(,Z~8Qȩ 9)偪PyR ?:tI s!T9YpC w^[;nƴ<RJSw\fыT-6Vv-Hm46]htFzZjI|Gw5@q%DsɚmBBN;JTIާG$$5%HП *3 HDRKDp'WΦPbc)ї)iq@RS?*YtPANPІ;ʜ$+6/ґuR+zd `o&N@QUcQjc $K$p V1DIT҇Y@I7{h6 A Wե)"@!*MHfP-7D_:INõGW2f4=o Kd_:IGHP 鳭YGVkN'b‘8T *L$j;؂L`+{±vL.H4แ1GL<5>IqvHn`di؉iaމiϦ{Fe ژVmZ6aͶ^ҙ!PN-Y?rҝ`Uq\%K19qĠQ b/M)D6}kaCݍC BA/^JI,X]6獕|?vXrH6)^))Qw dJ||v/ S.0NQb!?YaħA>RQ 6ݍ?$ڒ6,ک ? 5:v͔8'T|fϹJDӷo]{S!mX@H'ϵ:a A R{&`>tef)HڦQ~F,d#zӭ ;$m?I-lw[ :TÒ%((F (⤈i`;Qݰ|F7ЮrO=j,4*P$ ZB)M6;9)6 AۓF&#`*vm,%P|₶ 'iޫEۥI;|藭N ХF I& Q](RgҰP ԕbwtRƭkDZShBS.J%ˤ)ċTI2|nбJQܓM%DD(K~<2 3]:TwLed˥))PwIʛYm?Bcz?pelican-3.7.1/samples/content/pictures/Sushi_Macro.jpg000066400000000000000000001133021303525152100230240ustar00rootroot00000000000000JFIFHHExifII*  (1 2iFUJIFILMFinePix S1600HHGIMP 2.6.102011:01:05 13:30:38 PrintIM0250$"'@0220    I &|z.0100,   |d2010:01:09 14:10:302010:01:09 14:10:30 :ddddFdzdFUJIFILM 0130Jj r !"#012S100 S100 A592D34383231100603D7050TR73277NORMAL d^^R980100<D(LHHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?qc~tcjSHJy)3ADz{P^+d/RsS&$ś-ЖCֳVF+"?Jk|K9beĈU=9ONj&Zظel̕lTm42-P[CZ8ɧtrFX`#"5\t5"21V" G^ơ#8{NVh~՟$ma+[֜`KEZV*<q+dqLG_UqYxby (hGB: )"%CꢊLwb&+@iR;RHH@:ᳱmdTVngQ~I5-gQJ;k}UE q\wgDWI<@+dJm[H^1X#ظ>7<#Ɓ4Z^;gk;Zٶkl=JxRd*[Eh*٫W6;Eis3;b#nwX#h?h1SH1ڐJ@Gc`)=JEdZ^$%*D`c3tɑwB8RŪ_XVegup\{eOC9E?'޴;eqYoǣoAΝ]g~ec. gyFMlX|rqu1opJ.yj&elqϥvu:B۠ng#5E{O:5JWN=͕XqcH7 g8k|"}F&+H2 wW1qS:SݣDAD\zMa+զeL^9NZd$h–U*+8( 3VsP8w2.eOV5͜\u*qL6(|@)W>BX?2=E+X#SE7#֊b>BSXSJ} g$;R+tx%TH?xǭirؙjb푾Fc{׎R[ZS$P^4/!c;T$>קH_Pk܌U8]$B}1mig~,\1U'iXq¯m<瑎%\W(T3 ae)#ҴU^K ilPʤ3F5kD|nBz?,-͒AC ʽF"(UFYA\+}-mFsRrFo8Չo<s|DeG 8V'**d.*ڠzb+@a꼔Wzҁz] E)E =ΎF3h֭BAqPW+Ib] Bʐ8T'! \J5܃XEf*V#*0RDwP$7b*RZ!isU5b29 gb׼ vai9%j-\_˷+~͏yo-HK`h]W?vUzV%YPIXӖ)1d^k]Ϊ911ZEGV=JXٲ. ZsEJ%N85ׯ1 V߽ـsʚN#%~P=0 zwڠz5asE9ƒ-CWͿʟ 7jԏ}*YD6ɌWhW*xc0{Ԍch)柼*M:Z@U'BYSR@Deq]?is4yԕ.dy~Mn$2I"NJ {l9 p&@ŠApep'u ]C e1 p5;.wbC?Z2AT"'P9@@3@zz'Pv3~ÓV N1"7.Rh"@|,N3fj8mwH F *~qR׊֠CKjB:2>ю %*Cee,MjjWm Q*K_ܼQU$#/-z0U=']«7;J*8tb70SsȨg aEz5mǺ&U=EXs^pYyH]fAFl㪚sP9\P9^j@S9zB"')Z(H?Eh8򤞴QR \RaR@;BIZ(@7 7&)̚{B'R4QL DII U,I 4QHv[\ !r(z=5O!̠Nz(()(C      C  ,"  B!1A"Qaq2B #Rb3$Cr(Sc/!1AQ"a2qB# ?`pTͺzy:"O'q* +>$ c#,7rf+b@Y.WԶJ~#ijzUWaSWw+8qF A+k7RD:\ m O(K}QS{ZW/L%%8!AKz$Z1dc0mKZ@,/M:)$V@X ;1|+  x$]Wmfi Ѹ [?Dַ{zI,$y=14Sqe@1@ ~1[-~zcJmm +<)X 7o'#9AcnĞC(Ak,} Ԙ"T '\~Sf:I-̱ {Q%Tl~cLf ؈7*2&i<6;+o 5 䣾ܲL0SP h:uij99)a1 }ttVA#'QR,T@A$lzL-2 TPxLd2 C:iۡY#+<6Iۮ{S<[tqV-z=v^w0,{О;C޸Ʀڜy0S QOrK(E1Oq̬YM#qtGw {i"ÄћK}/8Q]N/qd`x27|w@*bZ 6~FYFGk)J0!Daס&?Kx\2<;+|P\ ão勮 S2ͲƠxt;{7eVpBf_ ꌆ>K|~exz[ISIc|YEhl$V0,L3$ʪCE![~XFcച' s3,BLn\S),  a3^-`K|ӓ XML-2j,f[ *SMzധTiUn,I&g[hbG^`ʁK# k5 Gdԧ@`l Hr V;HB="3Gf26pzԞYc [zza'"Y ˸/q37*ۑpS)jmG#>0.M%yAEBY43yK7q<~ZI$zxiPߦt6|AR> duI4Gp#錥Sf^8ZUsb=[ju[vlѰ>z%j,Q~Q>[_G|J%po@"q{•;HZTs};-7oĩΪX@"R96 Pkj޿R̺JWGYH#W\)KME>\<`EdסR;"Ƞ6J f5*)0~D%'qTG)xMb>sȲU؋or,DY* R_+0ѧx._?5jN-*0T!d!ߌe.]OzH= E5^9+|0ri SrùZL03Ru C2F_F[ _q$DƊ7b,FoVРZtiř<8=pRT:mLdSUNHU-p?KHJ:Ix*R2*˱t>x]3ht{PM[*6aRBd߶${]6xX\,>N&=0{e[(ڧҨh_t?cS ZʛS;5i\?|Г plGCr ^bZEǡaosr,Ѳl%va1Od8}_ f Bp6a9S}Ɩ.:Qw eu/$lbgi"EL$vl8Ҙ aJi8&H.0GlX[G1;E e;!?S+3#^LZF\n@p@uSs?;Ta#F -ۧ?Հ7Ӫڏ}sc؎񆉒2A)υYC*17:z"-fv=?})  2,R!A_킵}$'jYX=`0-%.HqJ ) ɿKcH,z=tU^ *# uSWju2T0>}l؆ctSPc|5MYYR:zDvf=H|cI}@esZnXcU @ @G 6=qF|ps(^no59hd2ibߡ7܁`~XxGN$I'ῖLq$ ۩$oGPӏðPLdfʨmyD/Lj A׹ۭ Y}W. .WEgѲF[c`G]7%R a.o:c`Āǧ8||vG}Z1m鹷s8N#e޾?["Ӆ-xƻ@~΀*\?;z OsƧb$ΠmfoLs%P`_T=خ8!~G4Saj/;KzᏋ.M:"gÄQBuKcXKS}= 2eG\KI6A 5'I` *o3$ {ៈ8S.j2*飔-bH?UQmהe>/>$fFwOL;g>yDQ cq=z Y&m@نckoyRlenYTpI ѹ>w3)dřXu7̎WÓ=U*cӺ|ǒgQa+VvlhR*C78% kuũج;%ozbOI#qxr:pX n+.+iB",Kjecƒw YK$dy[}z~>rC{$cSN/,*4N"Cc/ nMz2Umv8n e>`V8c_2vN%D" F;3(doc>cꎗp Dv7N8BIK $hbWWs:c7kav@`6ٮ7O\|0rĒmkC[^Zphy-e* f=YT(1#LF c/f9Lلæ*O5eI0z,oyskJ#6!CR=~>$x~)2hv{"F5$˛F\xO#*q5Tg{$ڔ ?t;u= "7*/3*-E4e,*Le_OLz'ʎ!2Ĥ/tM.vQ v1T4dhl$hF]o| V_+I;`MnaŸ#h I(e=cJ;~[}`ًV7eH'AyIH%IFn-qX8%"{`*Tu,AsyͲ, o%jp29dDWD%cAdP,0mܵ4 +xNqQ]v8t -k,V؋mS` ü/ U]lTS u=qh6O3V1cA nL\,N~Z8MvcE#v(`T JwDB#bmo#R|Mk|/7T|~+"yYW{to`YSk2l'$(7ߋ1;I-N/Dgģ/ Nt҂L[^U{c"u e|)iɖ2Sp;oZj.fpzawÙ:H{[όVڴ[kH;=BI}>)@cՐ56Q _CpZJ 7{rۆʸ(|%6+4nhtLVo<`٢}.%(333[ț|y=By5KX/#f͙xS,BE#z$2gPQMWSU â`sk$ίęW䲵&iXo[DdgSGK[<0*%\;ѢTDسEq=VOLı'qkoD]=ln¥Pcm)dc{|PPgO5@Fǵp@mk?6u+MW4uGt1`` ڊWCY JFy3(, {_ǥϛɇl˾+r~ iAR#uK: },;o0ZLe.!+ T!77 [z193?R%\hM`ooo͔VTG!$Z]i-k ׶߆t`ԙA1Y n`SJ\;Y"ceom>GL5ѤJey_Ed#%vuCA7נ醬xYFڒGusss|6ief}FPJ@/~uGeһllն'lՏSm=='!Z{V(iݝH$[0s{z߉uJ%[I \jB SW0, xfk($3?sWy}Ln"C H; ;&Cfz{_Ϋ]RIV#֫m^ޘuW-ITEUKP. DfgE0`A٤vmqʪ)2ܿ0KBj٢[XX'nۓ)s͆1W%^J <:u?{;;-D.tq/DZ0"DGI6e` n],%Fu^ F(>u1xԵP-תˠ vhX3>Irtt:׃"3TcpE\/dsz0pdy Ga/ '7q~W g btۦt7MGP8); Cum1o :^>h~P[q(ٓ'91V&lMPwuīsa[BarLl=5iq}Kuʘ0Am$xHÈÙ>ux1^O[ '5=q[s+>=u yz=4%Rrkf⼒;6]]:u.htHڅ~0IUH7+cP @uy#F ov?<~ .P FB vOPqG5;C) Y}qÐ+n"mQCx]MmHlGK13Psr=/@VP::z΃Ǎ j_c N%KVc䑃sR?KmB@}=wʁT?fMNmr./܌Dž\ X<d:#xR@+fmL\s拔\d?0=:pUX[шp+ VNėg!jK@-ؐ}\Z'>i8C5GGSE<6߯^qGO M맒er4fI%Lhn,l`R=Um#Lw{1-rU_b;C.3?UgHe)+c:\\yp1AӢH%E؋i=Bw^^,TPDѪ2 8zͿc#q/ÖSjP5Ee ZdpJTW7RC8z^9cqgäfKxƿ4˫rx8ehf,F;&]z58l2 |HA_y>[WLI,5#š)5# }7,$ʑ+dyU_#NYVQr.nǖrJ_OGmJ0\rpiMMR1$u1 v[na2VB(rJ,Eگ)5_ TC*<߾jjkgZrJN_t1%[6/s*5(A;auiWHkl u#YOD~52crUIV]:Cm$a4WqUe xx :|1~Crj܋4rjX$á|Ζ# nE#!y|WfUW8\ڊ}W@GN@:+9Ӧz\xu16,-Eʟi ؎MQ!Um6=ͮOoW F.JllYXfVO`5K-juH5=?.h\Z-&aͬ*cj_G3oj1RxURX3,{uo~>+vs|’xwP9 WoF<35%/xS@bMofYQ,-2C;ۿ]q74; S-5ė#'1r/V1AMh 7Yu|sS}#'%7X:ma=ŴU<t<\RMp_s3iᣎ3U$EdEzcf'Vx;ekURb pG3&3v*$̫'yݏ}1γΜOGRAx#hwgp O}NU52Nni,f[Zm&dg% %M07Yum9eNT$>a 075ĆGrf<A= ҙFj,lyʯPEkQ I))O>ht QQek_(N ;4M.L0̳gZ%42n}X6;uw9sR-%JO")]MU;,n #cs%dvf?fR0ɸ$A w-s̚ϘHiژDenHۍa~)$)T[`'IEVR&Ljw n÷m]Jn{Q@]#%@]B}OAӾ|XڴGj)nvƺx_HH`z{\aƢҥZkKRdCM0*CuP U`I}@6ۥÄ ĂG@oЃ²1a_H<7ߖ#HUDLm=Dy!0z* -r{,@αv#K<8`j~$ {h-stR@ }LF]p/(Ob7}dff#O\8<+,lPyi:PC""4PUG2o:VSAW$FWQbp>dfJc _lUk3YWhw}4L0q@9VQykai{(ƚͺ0ű`g F_DI`=: |fUi0սN {I2($%dT) jj. _E:H5Z(:[\`V!uw ʣ6:{ h*'U7-Ols "r5C20]C1^8)e@\rb@B1&66*j(*"v̦Zey5H|b/Y'~*3 O, ؋5 {XERc%|#=|zs,5h¡w5_GfAî`Z5ԋ[p[lꖉVrXȱqQGK] }԰{k[ӸScF ӌiQ$5Yc2]dҦ"TU,q $ar׸'Mv~e90,2 “t 'o1׾3LX'yG_IH(db/{5MI9Iey9D2PEֹrl- >.LuH YtTBłByuF:wA7N/%T:^KFA>"lAN#fa;ANҊY&iZ5'LàìME^[9e*d`gPAl5lpG sMuuS&$ "ȪCqe+WㅣEKdU]F`zF6˗MfeYcc榆-tjQy9(csIg熞 |"Y(#Hk[5MȺ**a$j]gUu7m{á#eGWY-Ud)'6QbYGB:˸3˹˘d]~\Bl* of [{< >Jͥˣ0-o=xL MYFp_# 5QBng?Gu/.U$|)m+E9A,akgQqj[;ȩk"j@PSXPѳ-sxk1>+e.*P񈦍]j@|_^5e-$NѢxPS, E-eb hJ`bAɊ^`KeveSBd14x:>Ug=C1yaQMĵrVMYUExk*b!OJ\)vٝE'QK 859iB#xm7w>P]ݭq_o|o M_U 1hdib%'Fo]%MHaȒĻv:=ln9enH9U|'F)O`!+8."{w$|c>Id5JɤcS'xPE:QmH#t~?F[_^a{@fl6# $`F6]nŁ aʦ;G_ᨷskc\{tþ{tFI#{ ȴn㯾t16RY؟ŜtMm]/6U7;b uCk\^pXwUHXoA4ؑ 0K(#uV빾,o,r)Wgc"~UB1akHE;بVzKn=o:dSqF8,c#xN7]4Iob m^XȦXqIu :uX;ځD)b`FacKx7޿}iU^zc}Ur _'mWP6[ @DNV"{X.7qe(b*" {x]F&[o# ;xk3E5,o#'dM[4r( ͳ4)a@ Hc"؋xw¹MQ%C$㰂QI_P#k k%Y⭥iq~eKT&SN#KNΞ:1/_%K>I$fY:JC$jڵ+\@ rG! %`T @.=,|MK4g+Ry]&CO1I *ƁUrr(ʤ!wi v}zqy\-ʞCE̺$֘M1/! F,H&OE䦆\`y-d+BtSl|sagUqHycer{{FFoo|O8蹫YeɒpSTC5d64P~"-lFxW9} mM6c*c@ST(@Z1W%\$#{N #p[^v{cDU䈤 [p6<T\ aү/ ; [vm]*Oe:w#ÍT~"0OE&{oda{Q7bv6ÕXTɰ>ownww$۶T )'צn5K1۠N9T Qa $z2(y 7 ^{¡P|BX2MJ E=:iaab06TS~2Ynm~N$‹c4$z^Sө1,\{)s=/0u>70 ߱Ft^l}y\e .ŷzc' o:PUd_>>Hߡ\FII%1mКA+:} Al'REUVz a8"BCװg.O#HIWR?yc,lik}qsCVjdT!4^+guj改nqDA#FI!麒m-^{C=.iSm=$LReF71)moRvq+Qx Fve]o$lqx$h*,֙5eJk Y;*"7&9S*#=շihy^Ur1V#S6lH9ʼlM#22?1jq9`M7~gTM^Sf,kxf Lma8ӈ<F2TV14,YK P-pF`3i%NL @pWeɛd-IUQ +ebHlĵ= j3RDf"/o2iu$` 1KX67P FQ•R sFyGRPɭtZ7V]PüKC-%htxU!¬^ok[kthv%-i2C 8ڶHdGNY@ٙرGђ-W&~~ЦZvh.ch Y!=2(5͢=u>,Rl'CI &Up -isG:3J~*rt7)`V{4rhn8Z΀:VH;$R@Rg6a%Y VfS#↪c`C4; [k.ְ(o'3Z@󶆣 Hď˪/M6,J^Lr(1/8u[6W2$w,.ɹ#NgEļAFki>QzuxKO%a=9eyMSG]I;Iӣ$5QQ"IckZzJwaZ*R+%&[_K *i#G-ɲ-`:[J0!K\JgnUk*n+bܟ(M7:V0Tj\j+WPP1[G*JK 2؍x#{ƵbA ?;}s>̣Ulk؎3\:4@s|Y9EzdqWuYhh&tdo"*/\H`fT43橤jk3,*j7DcdEež},beg;WI, pU^!QrMȳỘKQ|MCMFˣԩ't:T|FA ~ 11Ǥ HL- *SpО RaY%7d6;t=~:UZ8HcH&m*[?M+’Ҭ˷Eߦ,Q*8M*hy&bQvrm"bJR/=-`ՒҒ9^b! I |\_tkU<4eq,}a<ɳ_h:)i-v7v~7%_SJ!Xf^Ť a{3'4k_6V@-a u|RW BI%=lo:7BE*R'Iˏ o.?L<8ϗR\u @~؀'F\^DR2s^g@!-bܛikXi% iJe?<2fj@Z_doϿ0w4ƎFrٍu%-n[Wʃ\ M ]*Mƃpm^e<|59Z,{Yɵc$.K1z9pCx1x}}l1!j Ow&Qk|tv4"//rܦdSJOP@j?\OxBAEFPuQEAoKa8̒2]X4>lwyaB%Rjw]t R]%PO96UH]co#.wf9u62*~`a@l5t?Q-N?uRwZfV6m;`sRʓ\1\C(㈶^Pg>*ʾ;sdH5G5*#(:6Qzr/~ج99giQQFTC4bHV! lQ Gk50,>~pw/.i3z&ԉULK06"b+oːT= |(KCÙm.YI b( (1 ϸ?&`"c^ R}|aHe $mÏ7+#rܖ6TyKYnYD\iZIH.M'v3e͛PdA",/0k\u"ܱ<M-sÇy̼ۇ.c02x C{G}a8Z/$+OQ |0,]5*\ /!̳y(*3]B- c2R (M54c/\Hzk*M&>?zS+~#/5:I?y,eeg(`|:v|Mh&Τ~R>% ]tm9הCNI\N#kT˅8e %PUw>bݷw!QS5lK*nsji#ȬJʲ̒MP/^qڗU[4S=@Y,fZނl#wŚ˾[/T I*Uo"E()WʲȖEd 7=E)I*T(\Qo|;e1%IJ߿n` r ~&ir)\EҲ*{?[W UU4vUHk0}cnUsLQ HTaoc ý~qgнE}g04Ff$ (+}n+(0O=2̎YI}P*\l#(%5 \?TiRRT(cv= #A-jBс(o w6 AQ @.>[N iߨrs~_PsjوٮcZ'v;z[ t 7Sߖ܎6HacsܐU.g}p}`!K_MVV逈RM$-A9 =NB7qcmRMLRl-{g٭|:kӶ[3>mBڻob p'}ӣ 8O #J.-`3YJM_YDCK]wmmI 먞KQoa?LK,o&b;Ls:BxZnǨ%e ]aA:j&d聊>I{~.4e+n5Ǯۛ3&E[U5 7R%7W8Dv !3ᯰAUH)䥖y%fLW9%WGEQ'0) ],>egtZd&4ooyP,!FIdEukP\a_ѹ"{aq2=J@[.&|)G`-G-o`;bX U+"$RH6#bН)S {Ķ,EE-Ѹ%9?vK57k4 `ͭvg&WצcSLM cܝzEtoadʠa/3\GdF -ܓ?C"SQKeAk/bIk_lfO3dGU$5MEBm($MbS\&.eQG> J_`B6ܱQnqc?VQrȪi* Wkȭ#ZCpK{^\+' i1Rөg$SQ Ё{߷λSF ɨtې:8U2(Zt#F㏭˙>cE(/fdq}rZ,,6Y<$շMU.&U]{X]bIƫyTsĩ *;Zn}A?3N,bHַЏKa1gDר͆[.|zꪅZhы.Z@vܑΏZ?2xlC)PȄea/RG7?OC?WMf1,bdu*M+]Ǫŕ-ݞK4nM, DWY$zY$#FJaVFF,1v圾"VHBVq_z ʟUT& 0Pw+kX W#,|QNz ȥo}޿ 噛2 M4QN)'I+f pzXw\yd9Tڥ۳`ceR[{Q+e; 4)v )2X2\&L)!!ʪJzȎSH:{`څ.j<"VNp]1o7,.=nqSrJQFl }8Y&ki[F-E,Bbc,mfĪ[nG\YgUP5 '!6zdD Qm}_<3-H}!TV6`P*T#뀪7KeGUv6 6dB%Y*7; .؛ų{ R M]1~U]_v'W^S> NB ηA _F0 éX jFL8)+rlpRCF CXmT#*cB Ấmm[]z[`1.Z@l|Y+K [%W9V-َ;v' iTq pD;ujXQ/e>qԔ$Uk/=>xi)B؝iڬ'ШFDd*l7&<3BPtrXEŃp$* M6^ߞ%+.u\j*Ac`87\B,A؜g_>$Q-.I cE oqI*'DS ? TE"QO0U^JTY%]z'Y3DU0.F%8o/[CU+ en#r>uNՊ F^Jl(Ά6zaCU*nޞE)ե25VE @e %DzI%ԍSU4 6$ )dL-S 9Tdep=CI0S2!q|E#n(ck؋6Wp&QyC㛋䬼z0T40e,=kXmw_}[)bI&ǰ{~{drvb_/Fd;ڈt9I4_Qwpn[S%%+@fP3uje$2 r?bU(| {G eKD0P[}}qD5%Hzἵs/!{ÒMY= #YڥQshR[J|Tei^bO`6Zibx|l{I`f*@'qka~Jƾ_O|VLx,\M2q6s i(;bkRo} 21})LJ_v=`n&Ϣ6tܜk8m1 o1n 8Q2!E,`v=0@Ih uPt*:x v62SʨU僳*ye+ka[^ذOp}:vttq*[Oq4"" \tq냩OknM_aW">ŭ S( Ǯ - 0PM670i"'s9,"fqˇ ib4k|w%#2{&ᕸv"iam`\&Jcxr|18QHksYA=S5Ni[&y<š5  1 HV/CKpXk|+#VW&@:}qpqi qv/ubԲcw_Eo,x4NWL!9d .OE*v#Ͼ[/38*ئP< f С`!6)7Di%VeR :6g%? ?M6\jId` axj3N1;-qo LS}1=YI56HVǔuHҍoN~:TKYmX[1g$ 1mm&DHfAp>кWq؜kYV3zZ!@퀪#)\zo*:Aa'ֈKӾ5\|7Ԓm;ԒXX\:dSٍPXsͮm J ][s0%Um0GI ll:PCb`S{2ߦ \U甎ְ5o cfbz/,$`*ۘi$5{uZKHGD(3-EL, ?7 aЗUc(Ƒ#2H^ֽAt`GQ877 hvLxw%Vӵ\ _eZpH bk쨍/@ҚGٝ5e4X&zTk c35F;XeN5݉z\EPQp}0J#1,{{a FQP-K];l֫l<"~v´A*\[vÕJdJ^/cױÞ^Α K>CAAN.z[ ,O1tzs-L_LM94  LNV&\tLE$YX]E݊H>PAZۭ`^D~Ȋm1&j ٘jlN@ l MΛl&ҷop&p}Q̵ =mmjjYnЌw[Na-F^ø=1 }:Enen;_Aǥ׶3Kb.!,l8!H3j:,WF_q5j Z&6+n:QG*wPQnwl}03 mWn'{\60̢3=FpkyYvUl],.|QJ)+i` 2bmЂ?ы<x1$:`QqFtn{ nmۦ _[qR˭X7]]z\Grç HWK7 7[Z`MԜ@6 Q!=i}Sjv\`N㵰ě^-;aֿN:I?M6aUwc|D@iIѵ©ڑe$v6܌}. (>2aropV :sA+:ܒ0lH # @ms .NUe"=D o|#4` LmeSIcpma Rʫ!>6qP=y6)r}R$tTPGzoc폕 Lҝq wl1|S!eف6P/}p/o2JھfRE%8Ъs|ٕ2 xSbz*R5̀|k&-ar*蜎NUYlO>7' .An,t3\W0rډ>eU@ܞvv@1lA0I'aHi2P,_Y&oTHͲ^pZvFfA>22 .8h:2cMEтb}0"Y:F pA7=oERgĐ쑛8R(NLJdbؔ"g mѠ,,cL SK:߯% TOᎠv ; z,Kc]XkZ,@P'7`z*ڋlA㻛'<4%b=:R|0fBwlk]LFޘ8`L,FX F3XT?|UC1L % H"AIBi:W-sw3<:t4cE`]UY5 K_T+iYYTKP z8 5\.4YZ*jf0xp=Kcq@4yY|,f[/xij>XPA M{ W9_Y2嚙>27}$ն̦[k?sViha;ٴnl;܅GSF4&:u[#~Ew|sSG d!MDz{bǜtMYj|r0?x^o¬E52*`E,7#lTWezGMR Ql4$%q5r4F˥6*" ߦ67UK,oX,M>P>u ;`ݏU2PK{ lߦ4q6 )$ ܀:7lBL,: "$n~"V lp DF$ -b `*F`;zગ=WG|BUc;V w5. V~$nЍT>a'u^ǥધ%s V04-T5`*b Nĭ[5 C,ucOiI(aj@{㥣FtY-eF[#YaO#; jSGB9[$R;b4۠< fl~Xy™%{f܃D;ᛍj-I+k'`CM#1 ߥ7JzYUQM}X yp9 g01PKXZn3䎑YB .̰duXљEKԴMك7R{3Eh30;퉝 CC [ ?p[@W_^"lM1ʩ9H[[c$y|;($ ; `栍{aVG*aH 큳H Ttd%$â6Ds|\#L),fF7km_ ;cZǶ#~I:8\m۵­p &T06c*U  Rb4 0 e$b/!@a]Dܜq #tu2F"no|Fd #)}7_ n g+=gX$e,;V H\pr̶2R6w; w7Liglchg_ x_{!MBK -6?/F^!hsxRZtU1UYbni187橚JE[ex@Гw#yJ]TV-MAQ#hB$AsMWf|9&dE] jF05n; x⊶>YBSؐI@߄8]]Q+0r ':!AlXZ|I]/ -+Z`9bRK-4bsfҵ5"4pEَ#]MT\AFua;(@"6"xw6nO<"-u7~f|D)#(GHY*T^-Zz*$Jo~v:rڹVUSc}¸rH7,:wV X:)`7%;0ːfV0f4bw#I`/EKd lJaqon5Lh_Yc3}mߕy!XI@o({'SUPLuڷ6F+:LTGŰn͕mvJ=(9ôP< .MV6z$ /6\>> from ipdb import set_trace >>> set_trace() → And now try with some utf8 hell: ééé .. _stuff: http://books.couchdb.org/relax/design-documents/views pelican-3.7.1/samples/content/unbelievable.rst000066400000000000000000000044441303525152100214450ustar00rootroot00000000000000Unbelievable ! ############## :date: 2010-10-15 20:30 Or completely awesome. Depends the needs. `a root-relative link to markdown-article <|filename|/cat1/markdown-article.md>`_ `a file-relative link to markdown-article <|filename|cat1/markdown-article.md>`_ Testing sourcecode directive ---------------------------- .. sourcecode:: python :linenos: formatter = self.options and VARIANTS[self.options.keys()[0]] Testing another case -------------------- This will now have a line number in 'custom' since it's the default in pelican.conf, it will have nothing in default. .. sourcecode:: python formatter = self.options and VARIANTS[self.options.keys()[0]] Lovely. Testing more sourcecode directives ---------------------------------- .. sourcecode:: python :anchorlinenos: :classprefix: testing :hl_lines: 10,11,12 :lineanchors: foo :linenos: inline :linenospecial: 2 :linenostart: 8 :linenostep: 2 :lineseparator:
    :linespans: foo :nobackground: def run(self): self.assert_has_content() try: lexer = get_lexer_by_name(self.arguments[0]) except ValueError: # no lexer found - use the text one instead of an exception lexer = TextLexer() if ('linenos' in self.options and self.options['linenos'] not in ('table', 'inline')): self.options['linenos'] = 'table' for flag in ('nowrap', 'nobackground', 'anchorlinenos'): if flag in self.options: self.options[flag] = True # noclasses should already default to False, but just in case... formatter = HtmlFormatter(noclasses=False, **self.options) parsed = highlight('\n'.join(self.content), lexer, formatter) return [nodes.raw('', parsed, format='html')] Lovely. Testing even more sourcecode directives --------------------------------------- .. sourcecode:: python :linenos: table :nowrap: formatter = self.options and VARIANTS[self.options.keys()[0]] Lovely. Testing overriding config defaults ---------------------------------- Even if the default is line numbers, we can override it here .. sourcecode:: python :linenos: none formatter = self.options and VARIANTS[self.options.keys()[0]] Lovely. pelican-3.7.1/samples/content/unwanted_file000066400000000000000000000000211303525152100210100ustar00rootroot00000000000000not to be parsed pelican-3.7.1/samples/kinda/000077500000000000000000000000001303525152100156645ustar00rootroot00000000000000pelican-3.7.1/samples/kinda/exciting/000077500000000000000000000000001303525152100174765ustar00rootroot00000000000000pelican-3.7.1/samples/kinda/exciting/new/000077500000000000000000000000001303525152100202675ustar00rootroot00000000000000pelican-3.7.1/samples/kinda/exciting/new/files/000077500000000000000000000000001303525152100213715ustar00rootroot00000000000000pelican-3.7.1/samples/kinda/exciting/new/files/zap!000066400000000000000000000000001303525152100221350ustar00rootroot00000000000000pelican-3.7.1/samples/kinda/exciting/old000066400000000000000000000000001303525152100201650ustar00rootroot00000000000000pelican-3.7.1/samples/pelican.conf.py000077500000000000000000000031461303525152100175160ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals AUTHOR = 'Alexis Métaireau' SITENAME = "Alexis' log" SITEURL = 'http://blog.notmyidea.org' TIMEZONE = "Europe/Paris" # can be useful in development, but set to False when you're ready to publish RELATIVE_URLS = True GITHUB_URL = 'http://github.com/ametaireau/' DISQUS_SITENAME = "blog-notmyidea" REVERSE_CATEGORY_ORDER = True LOCALE = "C" DEFAULT_PAGINATION = 4 DEFAULT_DATE = (2012, 3, 2, 14, 1, 1) FEED_ALL_RSS = 'feeds/all.rss.xml' CATEGORY_FEED_RSS = 'feeds/%s.rss.xml' LINKS = (('Biologeek', 'http://biologeek.org'), ('Filyb', "http://filyb.info/"), ('Libert-fr', "http://www.libert-fr.com"), ('N1k0', "http://prendreuncafe.com/blog/"), ('Tarek Ziadé', "http://ziade.org/blog"), ('Zubin Mithra', "http://zubin71.wordpress.com/"),) SOCIAL = (('twitter', 'http://twitter.com/ametaireau'), ('lastfm', 'http://lastfm.com/user/akounet'), ('github', 'http://github.com/ametaireau'),) # global metadata to all the contents DEFAULT_METADATA = {'yeah': 'it is'} # path-specific metadata EXTRA_PATH_METADATA = { 'extra/robots.txt': {'path': 'robots.txt'}, } # static paths will be copied without parsing their contents STATIC_PATHS = [ 'pictures', 'extra/robots.txt', ] # custom page generated with a jinja2 template TEMPLATE_PAGES = {'pages/jinja2_template.html': 'jinja2_template.html'} # code blocks with line numbers PYGMENTS_RST_OPTIONS = {'linenos': 'table'} # foobar will not be used, because it's not in caps. All configuration keys # have to be in caps foobar = "barbaz" pelican-3.7.1/samples/pelican.conf_FR.py000066400000000000000000000034211303525152100200760ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals AUTHOR = 'Alexis Métaireau' SITENAME = "Alexis' log" SITEURL = 'http://blog.notmyidea.org' TIMEZONE = "Europe/Paris" # can be useful in development, but set to False when you're ready to publish RELATIVE_URLS = True GITHUB_URL = 'http://github.com/ametaireau/' DISQUS_SITENAME = "blog-notmyidea" PDF_GENERATOR = False REVERSE_CATEGORY_ORDER = True LOCALE = "fr_FR.UTF-8" DEFAULT_PAGINATION = 4 DEFAULT_DATE = (2012, 3, 2, 14, 1, 1) DEFAULT_DATE_FORMAT = '%d %B %Y' ARTICLE_URL = 'posts/{date:%Y}/{date:%B}/{date:%d}/{slug}/' ARTICLE_SAVE_AS = ARTICLE_URL + 'index.html' FEED_ALL_RSS = 'feeds/all.rss.xml' CATEGORY_FEED_RSS = 'feeds/%s.rss.xml' LINKS = (('Biologeek', 'http://biologeek.org'), ('Filyb', "http://filyb.info/"), ('Libert-fr', "http://www.libert-fr.com"), ('N1k0', "http://prendreuncafe.com/blog/"), ('Tarek Ziadé', "http://ziade.org/blog"), ('Zubin Mithra', "http://zubin71.wordpress.com/"),) SOCIAL = (('twitter', 'http://twitter.com/ametaireau'), ('lastfm', 'http://lastfm.com/user/akounet'), ('github', 'http://github.com/ametaireau'),) # global metadata to all the contents DEFAULT_METADATA = {'yeah': 'it is'} # path-specific metadata EXTRA_PATH_METADATA = { 'extra/robots.txt': {'path': 'robots.txt'}, } # static paths will be copied without parsing their contents STATIC_PATHS = [ 'pictures', 'extra/robots.txt', ] # custom page generated with a jinja2 template TEMPLATE_PAGES = {'pages/jinja2_template.html': 'jinja2_template.html'} # code blocks with line numbers PYGMENTS_RST_OPTIONS = {'linenos': 'table'} # foobar will not be used, because it's not in caps. All configuration keys # have to be in caps foobar = "barbaz" pelican-3.7.1/samples/theme_standard/000077500000000000000000000000001303525152100175605ustar00rootroot00000000000000pelican-3.7.1/samples/theme_standard/a_stylesheet000066400000000000000000000000001303525152100221620ustar00rootroot00000000000000pelican-3.7.1/samples/theme_standard/a_template000066400000000000000000000000001303525152100216040ustar00rootroot00000000000000pelican-3.7.1/samples/very/000077500000000000000000000000001303525152100155635ustar00rootroot00000000000000pelican-3.7.1/samples/very/exciting/000077500000000000000000000000001303525152100173755ustar00rootroot00000000000000pelican-3.7.1/samples/very/exciting/new/000077500000000000000000000000001303525152100201665ustar00rootroot00000000000000pelican-3.7.1/samples/very/exciting/new/files/000077500000000000000000000000001303525152100212705ustar00rootroot00000000000000pelican-3.7.1/samples/very/exciting/new/files/bap!000066400000000000000000000000001303525152100220040ustar00rootroot00000000000000pelican-3.7.1/samples/very/exciting/new/files/boom!000066400000000000000000000000001303525152100221760ustar00rootroot00000000000000pelican-3.7.1/samples/very/exciting/new/files/wow!000066400000000000000000000000001303525152100220560ustar00rootroot00000000000000pelican-3.7.1/setup.cfg000066400000000000000000000000341303525152100147500ustar00rootroot00000000000000[bdist_wheel] universal = 1 pelican-3.7.1/setup.py000077500000000000000000000052231303525152100146510ustar00rootroot00000000000000#!/usr/bin/env python from io import open from os import walk from os.path import join, relpath import sys from setuptools import setup requires = ['feedgenerator >= 1.9', 'jinja2 >= 2.7', 'pygments', 'docutils', 'pytz >= 0a', 'blinker', 'unidecode', 'six >= 1.4', 'python-dateutil'] entry_points = { 'console_scripts': [ 'pelican = pelican:main', 'pelican-import = pelican.tools.pelican_import:main', 'pelican-quickstart = pelican.tools.pelican_quickstart:main', 'pelican-themes = pelican.tools.pelican_themes:main' ] } README = open('README.rst', encoding='utf-8').read() CHANGELOG = open('docs/changelog.rst', encoding='utf-8').read() description = u'\n'.join([README, CHANGELOG]) if sys.version_info.major < 3: description = description.encode('utf-8') setup( name='pelican', version='3.7.1', url='http://getpelican.com/', author='Alexis Metaireau', maintainer='Justin Mayer', author_email='authors@getpelican.com', description="Static site generator supporting reStructuredText and " "Markdown source content.", long_description=description, packages=['pelican', 'pelican.tools'], package_data={ # we manually collect the package data, as opposed to using, # include_package_data=True because we don't want the tests to be # included automatically as package data (MANIFEST.in is too greedy) 'pelican': [relpath(join(root, name), 'pelican') for root, _, names in walk(join('pelican', 'themes')) for name in names], 'pelican.tools': [relpath(join(root, name), join('pelican', 'tools')) for root, _, names in walk(join('pelican', 'tools', 'templates')) for name in names], }, install_requires=requires, entry_points=entry_points, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'License :: OSI Approved :: GNU Affero General Public License v3', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Software Development :: Libraries :: Python Modules', ], test_suite='pelican.tests', ) pelican-3.7.1/tox.ini000066400000000000000000000015401303525152100144450ustar00rootroot00000000000000[tox] envlist = py{27,33,34,35},docs,flake8 [testenv] basepython = py27: python2.7 py33: python3.3 py34: python3.4 py35: python3.5 passenv = * usedevelop=True deps = -rrequirements/developer.pip nose nose-cov coveralls pygments==2.1.3 commands = {envpython} --version nosetests -sv --with-coverage --cover-package=pelican pelican - coveralls [testenv:docs] basepython = python2.7 deps = sphinx==1.4.9 sphinx_rtd_theme changedir = docs commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . _build/html [flake8] application-import-names = pelican import-order-style = cryptography [testenv:flake8] basepython = python2.7 deps = flake8 <= 2.4.1 git+https://github.com/public/flake8-import-order@2ac7052a4e02b4a8a0125a106d87465a3b9fd688 commands = flake8 --version flake8 pelican