pax_global_header00006660000000000000000000000064127161472420014520gustar00rootroot0000000000000052 comment=465fb06cf35fe1ce26e71b73811fa4149b4a8adc python-darkslide-2.3.3/000077500000000000000000000000001271614724200150065ustar00rootroot00000000000000python-darkslide-2.3.3/.bumpversion.cfg000066400000000000000000000002541271614724200201170ustar00rootroot00000000000000[bumpversion] current_version = 2.3.3 commit = True tag = True [bumpversion:file:setup.py] [bumpversion:file:docs/conf.py] [bumpversion:file:src/darkslide/__init__.py] python-darkslide-2.3.3/.cookiecutterrc000066400000000000000000000020621271614724200200340ustar00rootroot00000000000000# Generated by cookiepatcher, a small shim around cookiecutter (pip install cookiepatcher) cookiecutter: appveyor: 'yes' c_extension_cython: 'no' c_extension_optional: 'no' c_extension_support: 'no' codacy: 'yes' codeclimate: 'yes' codecov: 'yes' command_line_interface: plain command_line_interface_bin_name: darkslide coveralls: 'yes' distribution_name: darkslide email: contact@ionelmc.ro full_name: Ionel Cristian Mărieș github_username: ionelmc landscape: 'yes' package_name: darkslide project_name: Darkslide project_short_description: Lightweight markup language-based html5 slideshow generator. Forked from landslide. release_date: today repo_name: python-darkslide requiresio: 'yes' scrutinizer: 'yes' sphinx_doctest: 'no' sphinx_theme: sphinx-py3doc-enhanced-theme test_matrix_configurator: 'no' test_matrix_separate_coverage: 'no' test_runner: pytest travis: 'yes' version: 2.3.0 website: http://blog.ionelmc.ro year: 2015-2016 python-darkslide-2.3.3/.coveragerc000066400000000000000000000002671271614724200171340ustar00rootroot00000000000000[paths] source = src/darkslide */site-packages/darkslide [run] branch = True source = darkslide parallel = true [report] show_missing = true precision = 2 omit = *migrations* python-darkslide-2.3.3/.editorconfig000066400000000000000000000003271271614724200174650ustar00rootroot00000000000000# see http://editorconfig.org root = true [*] end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 charset = utf-8 [*.{bat,cmd,ps1}] end_of_line = crlf python-darkslide-2.3.3/.gitignore000066400000000000000000000010611271614724200167740ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs .eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 venv*/ pyvenv*/ # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox .coverage.* nosetests.xml coverage.xml htmlcov # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject .idea *.iml *.komodoproject # Complexity output/*.html output/*/index.html # Sphinx docs/_build .DS_Store *~ .*.sw[po] .build .ve .env .cache .pytest .bootstrap .appveyor.token *.bak presentation.htmlpython-darkslide-2.3.3/.travis.yml000066400000000000000000000024201271614724200171150ustar00rootroot00000000000000language: python python: '3.5' sudo: false env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so - SEGFAULT_SIGNALS=all matrix: - TOXENV=check - TOXENV=examples,publish - TOXENV=py27,coveralls,codecov - TOXENV=py33,coveralls,codecov - TOXENV=py34,coveralls,codecov - TOXENV=py35,coveralls,codecov - TOXENV=pypy,coveralls,codecov before_install: - | if [[ "${TOXENV}" =~ "publish" ]]; then openssl aes-256-cbc -K $encrypted_fabbc4622c56_key -iv $encrypted_fabbc4622c56_iv -in publish-key.enc -out ~/.ssh/publish-key -d chmod u=rw,og= ~/.ssh/publish-key echo "Host github.com" >> ~/.ssh/config echo " IdentityFile ~/.ssh/publish-key" >> ~/.ssh/config git --version git remote set-url origin git@github.com:ionelmc/python-darkslide.git git fetch origin -f gh-pages:gh-pages fi - python --version - uname -a - lsb_release -a install: - pip install tox - virtualenv --version - easy_install --version - pip --version - tox --version script: - tox -v after_failure: - more .tox/log/* | cat - more .tox/*/log/* | cat before_cache: - rm -rf $HOME/.cache/pip/log cache: directories: - $HOME/.cache/pip notifications: email: on_success: never on_failure: always python-darkslide-2.3.3/CHANGELOG.rst000066400000000000000000000133121271614724200170270ustar00rootroot00000000000000========= Changelog ========= Darkslide v2.3.3 (2016-05-15) ============================= * Fixed height of QR svg elements. Darkslide v2.3.2 (2016-04-12) ============================= * Fixed underline occlusion shadows in the footer (for links). * Fixed missing `presenter_notes` class not being set when notes mode was on. Darkslide v2.3.1 (2016-02-08) ============================= * MathJax is loaded on HTTPS. Darkslide v2.3.0 (2016-02-07) ============================= * The Darkslide version is shown in the help sidebar. Darkslide v2.2.1 (2015-10-06) ============================= * Fixed config file parsing for math_output. Darkslide v2.2.0 (2015-10-06) ============================= * Now macro failures abort rendering. Previously they would just log a message that you'd probably woulnd't notice. * Fixed broken handling where you have css/js in the cfg file. * Allowed setting the math_output option in the cfg file. * Fixed encoding issues in the QR macro. * Added back the old theme with completely black background (as "void"). * Tweak the faux underlines to look better. Darkslide v2.1.0 (2015-10-05) ============================= * Added demo links. * Fixed options handling. Options from command line now will actually work if a cfg file is used. * Corrected relative paths handling: - paths in sources are now relative to the cfg file (previously they were relative to whatever was cwd). - relative option now correctly works when destination file is not in cwd. * Fixed layout of slides with many headering (no more paddings for headings, all root elements are spread out evenly anyway). * Fixed bad styling of ToC (and probably other things in the sidebar). * Fixed ToC links (contributed by Cyrille Pontvieux). Darkslide v2.0.4 (2015-09-09) ============================= * Improved handling for filenames that have non-ascii characters in them. Darkslide v2.0.3 (2015-09-08) ============================= * Fixed handling for filenames that have non-ascii characters in them. Darkslide v2.0.2 (2015-07-20) ============================= - Added color classes in the abyss theme. - Fixed link underlines in the presenter notes. Darkslide v2.0.1 (2015-07-19) ============================= * Don't use Monaco in the ``base.css`` - it's way bigger than Consolas and the other fonts. And Consolas is nice enough. Darkslide v2.0.0 (2015-07-17) ============================= - Fix display of RST image target links. - Add cmd line option to print version. - Rewrote the default theme (solarized colors) - Overhauled the abyss theme, improved the coloring. - Removed all the other themes (they are ugly and broken anyway) (**backwards incompatible**). - Fixes for print css. - Added support for two new css files: ``base.css`` and ``theme.css``. This makes reusing styles acros themes and kinds of display (print/screen) more easy. - Expanded mode is now activated by default. - Changed macros to use compiled regexes. - Added a footnote macro. - Changed QR macro to use ``qrcode`` library. Now it's rendered to SVG. The size is removed (**backwards incompatible**). Darkslide v1.2.2 (2015-05-22) ============================= - Fix the blank page issue when generating pdfs (via Chrome's pdf printer). Darkslide v1.2.1 (2015-05-21) ============================= - Couple minor improvements to Abyss theme. Darkslide v1.2.0 (2015-05-19) ============================= - Modifier keys flag was not cleared propertly (kb shortcuts were not working anymore after alt-tab etc); now it's cleared on visibility changes and focus loss. - Changed expanded mode to automatically hide the context. - Fixed window resize flickering (for every resize event the expaded flag was toggled). - Disabled context hiding in presenter view. - Other small styling improvements. - Added "abyss" theme. Landslide v1.1.3 ================ - Identify each slide by a numbered class (#171) (dkg) - Fix theme image embedding regex to grab all images (#170) - Fix blockquote font size for rst (#161) - Fix display of RST image target links (#87) - Fix relative path generation (#147) - Add command line option for print version (#135) - Add use of '---' as a slide separator to textile files (#163) - README improvements (#88 and #101) - Improve image path regex and replacement (#177) Landslide v1.1.2 ================ - Add support for Python 3 - Allow support for copy\_theme argument in CFG files (#139) (syscomet) - Improve MathJax rendering for Markdown files - Support math output (#144) (davidedelvento) - Allow presenter notes in slides with no heading in RST files (#141) (regebro) - And more... Landslide v1.1.1 ================ Fixes ----- - Don't accidentally require watchdog (#134) Landslide v1.1.0 ================ Major Enhancements ------------------ - Add CHANGELOG - Add "ribbon" theme from "shower" presentation tool (#129) (durden) - Add ``-w`` flag for watching/auto-regenerating slideshow (#71, #120) (jondkoon) Minor Enhancements ------------------ - Supress ReST rendering errors - CSS pre enhancements (#91) (roktas) - Add an example using presenter notes (#106) (netantho) - Run macros on headers also, to embed images (#74) (godfat) - Allow PHP code snippets to not require `_ please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting. * Detailed steps to reproduce the bug. Documentation improvements ========================== Darkslide could always use more documentation, whether as part of the official Darkslide docs, in docstrings, or even on the web in blog posts, articles, and such. Feature requests and feedback ============================= The best way to send feedback is to file an issue at https://github.com/ionelmc/python-darkslide/issues. If you are proposing a feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that code contributions are welcome :) Development =========== To set up `python-darkslide` for local development: 1. Fork `python-darkslide `_ (look for the "Fork" button). 2. Clone your fork locally:: git clone git@github.com:your_name_here/python-darkslide.git 3. Create a branch for local development:: git checkout -b name-of-your-bugfix-or-feature Now you can make your changes locally. 4. When you're done making changes, run all the checks, doc builder and spell checker with `tox `_ one command:: tox 5. Commit your changes and push your branch to GitHub:: git add . git commit -m "Your detailed description of your changes." git push origin name-of-your-bugfix-or-feature 6. Submit a pull request through the GitHub website. Pull Request Guidelines ----------------------- If you need some code review or feedback while you're developing the code just make the pull request. For merging, you should: 1. Include passing tests (run ``tox``) [1]_. 2. Update documentation when there's new API, functionality etc. 3. Add a note to ``CHANGELOG.rst`` about the changes. 4. Add yourself to ``AUTHORS.rst``. .. [1] If you don't have all the necessary python versions available locally you can rely on Travis - it will `run the tests `_ for each change you add in the pull request. It will be slower though ... Tips ---- To run a subset of tests:: tox -e envname -- py.test -k test_myfeature To run all the test environments in *parallel* (you need to ``pip install detox``):: detox python-darkslide-2.3.3/LICENSE000066400000000000000000000236751271614724200160300ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS python-darkslide-2.3.3/MANIFEST.in000066400000000000000000000006031271614724200165430ustar00rootroot00000000000000graft docs graft examples graft src graft ci graft tests include .bumpversion.cfg include .coveragerc include .cookiecutterrc include .editorconfig include .isort.cfg include AUTHORS.rst include CHANGELOG.rst include CONTRIBUTING.rst include LICENSE include README.rst include tox.ini .travis.yml appveyor.yml exclude publish-key.enc global-exclude *.py[cod] __pycache__ *.so *.dylib python-darkslide-2.3.3/README.rst000066400000000000000000000412241271614724200165000ustar00rootroot00000000000000======== Overview ======== .. start-badges .. list-table:: :stub-columns: 1 * - docs - |docs| * - tests - | |travis| |appveyor| |requires| | |coveralls| |codecov| | |landscape| |scrutinizer| |codacy| |codeclimate| * - package - |version| |downloads| |wheel| |supported-versions| |supported-implementations| .. |docs| image:: https://readthedocs.org/projects/python-darkslide/badge/?style=flat :target: https://readthedocs.org/projects/python-darkslide :alt: Documentation Status .. |travis| image:: https://travis-ci.org/ionelmc/python-darkslide.svg?branch=master :alt: Travis-CI Build Status :target: https://travis-ci.org/ionelmc/python-darkslide .. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/ionelmc/python-darkslide?branch=master&svg=true :alt: AppVeyor Build Status :target: https://ci.appveyor.com/project/ionelmc/python-darkslide .. |requires| image:: https://requires.io/github/ionelmc/python-darkslide/requirements.svg?branch=master :alt: Requirements Status :target: https://requires.io/github/ionelmc/python-darkslide/requirements/?branch=master .. |coveralls| image:: https://coveralls.io/repos/ionelmc/python-darkslide/badge.svg?branch=master&service=github :alt: Coverage Status :target: https://coveralls.io/r/ionelmc/python-darkslide .. |codecov| image:: https://codecov.io/github/ionelmc/python-darkslide/coverage.svg?branch=master :alt: Coverage Status :target: https://codecov.io/github/ionelmc/python-darkslide .. |landscape| image:: https://landscape.io/github/ionelmc/python-darkslide/master/landscape.svg?style=flat :target: https://landscape.io/github/ionelmc/python-darkslide/master :alt: Code Quality Status .. |codacy| image:: https://img.shields.io/codacy/5ee39ea7087c472684feca411080ce10.svg?style=flat :target: https://www.codacy.com/app/ionelmc/python-darkslide :alt: Codacy Code Quality Status .. |codeclimate| image:: https://codeclimate.com/github/ionelmc/python-darkslide/badges/gpa.svg :target: https://codeclimate.com/github/ionelmc/python-darkslide :alt: CodeClimate Quality Status .. |version| image:: https://img.shields.io/pypi/v/darkslide.svg?style=flat :alt: PyPI Package latest release :target: https://pypi.python.org/pypi/darkslide .. |downloads| image:: https://img.shields.io/pypi/dm/darkslide.svg?style=flat :alt: PyPI Package monthly downloads :target: https://pypi.python.org/pypi/darkslide .. |wheel| image:: https://img.shields.io/pypi/wheel/darkslide.svg?style=flat :alt: PyPI Wheel :target: https://pypi.python.org/pypi/darkslide .. |supported-versions| image:: https://img.shields.io/pypi/pyversions/darkslide.svg?style=flat :alt: Supported versions :target: https://pypi.python.org/pypi/darkslide .. |supported-implementations| image:: https://img.shields.io/pypi/implementation/darkslide.svg?style=flat :alt: Supported implementations :target: https://pypi.python.org/pypi/darkslide .. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/python-darkslide/master.svg?style=flat :alt: Scrutinizer Status :target: https://scrutinizer-ci.com/g/ionelmc/python-darkslide/ .. end-badges Lightweight markup language-based html5 slideshow generator. Forked from landslide. Demo: http://ionelmc.github.io/python-darkslide/ Overview ======== Landslide generates a slideshow using from markdown, ReST, or textile. It builds off of Google's `html5slides `__ template. The following markdown produces `this slideshow `__. :: # Landslide --- # Overview Generate HTML5 slideshows from markdown, ReST, or textile. ![python](http://i.imgur.com/bc2xk.png) Landslide is primarily written in Python, but it's themes use: - HTML5 - Javascript - CSS --- # Code Sample Landslide supports code snippets !python def log(self, message, level='notice'): if self.logger and not callable(self.logger): raise ValueError(u"Invalid logger set, must be a callable") if self.verbose and self.logger: self.logger(message, level) Requirements ============ ``python`` and the following modules: - ``jinja2`` - ``pygments`` for code blocks syntax coloration Markup Conversion ----------------- - ``markdown`` for `Markdown `__ - ``docutils`` for `reStructured Text `__ - ``textile`` for `Textile `__ Optional -------- - ``watchdog`` for watching/auto-regeneration with the ``-w`` flag - `PrinceXML `__ for PDF export Installation ============ Install the latest stable version of Landslide with a python package manager like ``pip``: :: $ pip install landslide If you want to stay on the edge: :: $ git clone https://github.com/adamzap/landslide.git $ cd landslide $ python setup.py build $ sudo python setup.py install Formatting ========== Markdown -------- - Your Markdown source files must be suffixed by ``.md``, ``.markdn``, ``.mdwn``, ``.mdown`` or ``.markdown`` - To create a title slide, render a single ``h1`` element (eg. ``# My Title``) - Separate your slides with a horizontal rule (``---`` in markdown) except at the end of md files - Your other slides should have a heading that renders to an ``h1`` element - To highlight blocks of code, put ``!lang`` where ``lang`` is the pygment supported language identifier as the first indented line ReStructuredText ---------------- - Your ReST source files must be suffixed by ``.rst`` or ``.rest`` (**``.txt`` is not supported**) - Use headings for slide titles - Separate your slides using an horizontal rule (``----`` in RST) except at the end of RST files Textile ------- - Separate your slides using ``---``, just like in markdown Rendering ========= - Run ``landslide slides.md`` or ``landslide slides.rst`` - Enjoy your newly generated ``presentation.html`` Or get it as a PDF document if PrinceXML is installed and available on your system: :: $ landslide README.md -d readme.pdf $ open readme.pdf Viewing ======= - Press ``h`` to toggle display of help - Press ``left arrow`` and ``right arrow`` to navigate - Press ``t`` to toggle a table of contents for your presentation. Slide titles are links - Press ``ESC`` to display the presentation overview (Exposé) - Press ``n`` to toggle slide number visibility - Press ``b`` to toggle screen blanking - Press ``c`` to toggle current slide context (previous and next slides) - Press ``e`` to make slides filling the whole available space within the document body - Press ``S`` to toggle display of link to the source file for each slide - Press '2' to toggle notes in your slides (specify with the .notes macro) - Press '3' to toggle pseudo-3D display (experimental) - Browser zooming is supported Commandline Options =================== Several options are available using the command line: :: -h, --help show this help message and exit -c, --copy-theme Copy theme directory into current presentation source directory -b, --debug Will display any exception trace to stdin -d FILE, --destination=FILE The path to the to the destination file: .html or .pdf extensions allowed (default: presentation.html) -e ENCODING, --encoding=ENCODING The encoding of your files (defaults to utf8) -i, --embed Embed stylesheet and javascript contents, base64-encoded images in presentation to make a standalone document -l LINENOS, --linenos=LINENOS How to output linenos in source code. Three options availables: no (no line numbers); inline (inside
                          tag); table (lines numbers in another cell, copy-paste
                          friendly)
    -o, --direct-output    Prints the generated HTML code to stdin; won't work
                          with PDF export
    -q, --quiet           Won't write anything to stdin (silent mode)
    -r, --relative        Make your presentation asset links relative to current
                          pwd; This may be useful if you intend to publish your
                          html presentation online.
    -t THEME, --theme=THEME
                          A theme name, or path to a landlside theme directory
    -v, --verbose         Write informational messages to stdin (enabled by
                          default)
    -w, --watch           Watch the source directory for changes and
                          auto-regenerate the presentation
    -x EXTENSIONS, --extensions=EXTENSIONS
                          Comma-separated list of extensions for Markdown
    -m, --math-output     Enable mathematical output using mathjax

Presentation Configuration
==========================

Landslide allows to configure your presentation using a ``cfg``
configuration file, therefore easing the aggregation of source
directories and the reuse of them across presentations. Landslide
configuration files use the ``cfg`` syntax. If you know ``ini`` files,
you get the picture. Below is a sample configuration file:

::

    [landslide]
    theme  = /path/to/my/beautiful/theme
    source = 0_my_first_slides.md
             a_directory
             another_directory
             now_a_slide.markdown
             another_one.rst
    destination = myWonderfulPresentation.html
    css =    my_first_stylesheet.css
             my_other_stylesheet.css
    js =     jquery.js
             my_fancy_javascript.js
    relative = True
    linenos = inline

Don't forget to declare the ``[landslide]`` section. All configuration
files must end in the .cfg extension.

To generate the presentation as configured, just run:

::

    $ cd /path/to/my/presentation/sources
    $ landslide config.cfg

Macros
======

You can use macros to enhance your presentation:

Notes
-----

Add notes to your slides using the ``.notes:`` keyword, eg.:

::

    # My Slide Title

    .notes: These are my notes, hidden by default

    My visible content goes here

You can toggle display of notes by pressing the ``2`` key.

Some other macros are also available by default: ``.fx: foo bar`` will
add the ``foo`` and ``bar`` classes to the corresponding slide ``
`` element, easing styling of your presentation using CSS. QR Codes -------- Add a QR Code to your presentation by using the ``.qr`` keyword: :: .qr: http://github.com/adamzap/landslide Footnote -------- Add footnote to the current and all the following presentations :: .footnote: Slides available at https://blog.ionelmc.ro/presentations/ Presenter Notes =============== You can also add presenter notes to each slide by following the slide content with a heading entitled "Presenter Notes". Press the 'p' key to open the presenter view. Registering Macros ================== Macros are used to transform the HTML contents of your slide. You can register your own macros by creating ``landslide.macro.Macro`` derived classes, implementing a ``process(content, source=None)`` method and returning a tuple containing the modified contents and some css classes you may be wanting to add to your slide ``
`` element. For example: :: !python import landslide class MyMacro(landslide.Macro): def process(self, content, source=None): return content + '

plop

', ['plopped_slide'] g = landslide.generator.Generator(source='toto.md') g.register_macro(MyMacro) print g.render() This will render any slide as below: :: !html

foo

my slide contents

plop

Advanced Usage ============== Setting Custom Destination File ------------------------------- :: $ landslide slides.md -d ~/MyPresentations/presentation.html Working with Directories ------------------------ :: $ landslide slides/ Working with Direct Output -------------------------- :: $ landslide slides.md -o | tidy Using an Alternate Landslide Theme ---------------------------------- :: $ landslide slides.md -t mytheme $ landslide slides.md -t /path/to/theme/dir Embedding Base-64-Encoded Images -------------------------------- :: $ landslide slides.md -i Exporting to PDF ---------------- :: $ landslide slides.md -d presentation.pdf Enabling mathematical notation ------------------------------ :: Note that this require writing the slides in ReST format as well as using Docutils 0.8 or newer. $ landslide slides.rst -m Enabling Markdown Extensions ---------------------------- See documentation on available Markdown extensions `here `__: :: $ landslide slides.md -x abbr Theming ------- A Landslide theme is a directory following this simple structure: :: mytheme/ |-- base.html |-- css | |-- print.css | `-- screen.css `-- js `-- slides.js If a theme does not provide HTML and JS files, those from the default theme will be used. CSS is not optional. Last, you can also copy the whole theme directory to your presentation one by passing the ``--copy-theme`` option to the ``landslide`` command: :: $ landslide slides.md -t /path/to/some/theme --copy-theme User stylesheets and Javascripts ================================ If you don't want to bother making your own theme, you can include your own user css and js files to the generated presentation. This feature is only available if you use a landslide configuration file, by setting the ``css`` and/or ``js`` flags: :: [landslide] theme = /path/to/my/beautiful/theme source = slides.mdown css = custom.css js = jquery.js powerpoint.js These will link the ``custom.css`` stylesheet and both the ``jquery.js`` and ``powerpoint.js`` files within the ```` section of the presentation html file. **NOTE:** Paths to the css and js files must be relative to the directory you're running the ``landslide`` command from. Publishing your Presentation Online =================================== If you intend to publish your HTML presentation online, you'll have to use the ``--relative`` option, as well as the ``--copy-theme`` one to have all asset links relative to the root of your presentation; :: $ landslide slides.md --relative --copy-theme That way, you'll just have to host the whole presentation directory to a webserver. Of course, no Python nor PHP nor anything else than a HTTP webserver (like Apache) is required to host a landslide presentation. `Here's an example `__. Theme Variables =============== The ``base.html`` must be a `Jinja2 template file `__ where you can harness the following template variables: - ``css``: the stylesheet contents, available via two keys, ``print`` and ``screen``, both having: - a ``path_url`` key storing the url to the asset file path - a ``contents`` key storing the asset contents - ``js``: the javascript contents, having: - a ``path_url`` key storing the url to the asset file path - a ``contents`` key storing the asset contents - ``slides``: the slides list, each one having these properties: - ``header``: the slide title - ``content``: the slide contents - ``number``: the slide number - ``embed``: is the current document a standalone one? - ``num_slides``: the number of slides in current presentation - ``toc``: the Table of Contents, listing sections of the document. Each section has these properties available: - ``title``: the section title - ``number``: the slide number of the section - ``sub``: subsections, if any Styles Scope ============ - To change HTML5 presentation styles, tweak the ``css/screen.css`` stylesheet bundled with the theme you are using - For PDF, modify the ``css/print.css`` Authors ======= Original Author and Development Lead ------------------------------------ - Adam Zapletal (adamzap@gmail.com) Co-Author --------- - Nicolas Perriault (nperriault@gmail.com) Contributors ------------ See https://github.com/ionelmc/python-darkslide/contributors Base Template Authors and Contributors (html5-slides) ----------------------------------------------------- - Marcin Wichary (mwichary@google.com) - Ernest Delgado (ernestd@google.com) - Alex Russell (slightlyoff@chromium.org) python-darkslide-2.3.3/appveyor.yml000066400000000000000000000037411271614724200174030ustar00rootroot00000000000000version: '{branch}-{build}' build: off cache: - '%LOCALAPPDATA%\pip\Cache' environment: global: WITH_COMPILER: 'cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd' matrix: - TOXENV: check PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27,codecov' TOXPYTHON: C:\Python27\python.exe PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27,codecov' TOXPYTHON: C:\Python27-x64\python.exe WINDOWS_SDK_VERSION: v7.0 PYTHON_HOME: C:\Python27-x64 PYTHON_VERSION: '2.7' PYTHON_ARCH: '64' - TOXENV: 'py34,codecov' TOXPYTHON: C:\Python34\python.exe PYTHON_HOME: C:\Python34 PYTHON_VERSION: '3.4' PYTHON_ARCH: '32' - TOXENV: 'py34,codecov' TOXPYTHON: C:\Python34-x64\python.exe WINDOWS_SDK_VERSION: v7.1 PYTHON_HOME: C:\Python34-x64 PYTHON_VERSION: '3.4' PYTHON_ARCH: '64' - TOXENV: 'py35,codecov' TOXPYTHON: C:\Python35\python.exe PYTHON_HOME: C:\Python35 PYTHON_VERSION: '3.5' PYTHON_ARCH: '32' - TOXENV: 'py35,codecov' TOXPYTHON: C:\Python35-x64\python.exe PYTHON_HOME: C:\Python35-x64 PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' init: - ps: echo $env:TOXENV - ps: ls C:\Python* install: - python -u ci\appveyor-bootstrap.py - '%PYTHON_HOME%\Scripts\virtualenv --version' - '%PYTHON_HOME%\Scripts\easy_install --version' - '%PYTHON_HOME%\Scripts\pip --version' - '%PYTHON_HOME%\Scripts\tox --version' test_script: - '%WITH_COMPILER% %PYTHON_HOME%\Scripts\tox' on_failure: - ps: dir "env:" - ps: get-content .tox\*\log\* artifacts: - path: dist\* ### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker): # on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) python-darkslide-2.3.3/ci/000077500000000000000000000000001271614724200154015ustar00rootroot00000000000000python-darkslide-2.3.3/ci/appveyor-bootstrap.py000066400000000000000000000100711271614724200216320ustar00rootroot00000000000000""" AppVeyor will at least have few Pythons around so there's no point of implementing a bootstrapper in PowerShell. This is a port of https://github.com/pypa/python-packaging-user-guide/blob/master/source/code/install.ps1 with various fixes and improvements that just weren't feasible to implement in PowerShell. """ from __future__ import print_function from os import environ from os.path import exists from subprocess import check_call try: from urllib.request import urlretrieve except ImportError: from urllib import urlretrieve BASE_URL = "https://www.python.org/ftp/python/" GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" GET_PIP_PATH = "C:\get-pip.py" URLS = { ("2.7", "64"): BASE_URL + "2.7.10/python-2.7.10.amd64.msi", ("2.7", "32"): BASE_URL + "2.7.10/python-2.7.10.msi", # NOTE: no .msi installer for 3.3.6 ("3.3", "64"): BASE_URL + "3.3.3/python-3.3.3.amd64.msi", ("3.3", "32"): BASE_URL + "3.3.3/python-3.3.3.msi", ("3.4", "64"): BASE_URL + "3.4.3/python-3.4.3.amd64.msi", ("3.4", "32"): BASE_URL + "3.4.3/python-3.4.3.msi", ("3.5", "64"): BASE_URL + "3.5.0/python-3.5.0-amd64.exe", ("3.5", "32"): BASE_URL + "3.5.0/python-3.5.0.exe", } INSTALL_CMD = { # Commands are allowed to fail only if they are not the last command. Eg: uninstall (/x) allowed to fail. "2.7": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "3.3": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "3.4": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "3.5": [["{path}", "/quiet", "TargetDir={home}"]], } def download_file(url, path): print("Downloading: {} (into {})".format(url, path)) progress = [0, 0] def report(count, size, total): progress[0] = count * size if progress[0] - progress[1] > 1000000: progress[1] = progress[0] print("Downloaded {:,}/{:,} ...".format(progress[1], total)) dest, _ = urlretrieve(url, path, reporthook=report) return dest def install_python(version, arch, home): print("Installing Python", version, "for", arch, "bit architecture to", home) if exists(home): return path = download_python(version, arch) print("Installing", path, "to", home) success = False for cmd in INSTALL_CMD[version]: cmd = [part.format(home=home, path=path) for part in cmd] print("Running:", " ".join(cmd)) try: check_call(cmd) except Exception as exc: print("Failed command", cmd, "with:", exc) if exists("install.log"): with open("install.log") as fh: print(fh.read()) else: success = True if success: print("Installation complete!") else: print("Installation failed") def download_python(version, arch): for _ in range(3): try: return download_file(URLS[version, arch], "installer.exe") except Exception as exc: print("Failed to download:", exc) print("Retrying ...") def install_pip(home): pip_path = home + "/Scripts/pip.exe" python_path = home + "/python.exe" if exists(pip_path): print("pip already installed.") else: print("Installing pip...") download_file(GET_PIP_URL, GET_PIP_PATH) print("Executing:", python_path, GET_PIP_PATH) check_call([python_path, GET_PIP_PATH]) def install_packages(home, *packages): cmd = [home + "/Scripts/pip.exe", "install"] cmd.extend(packages) check_call(cmd) if __name__ == "__main__": install_python(environ['PYTHON_VERSION'], environ['PYTHON_ARCH'], environ['PYTHON_HOME']) install_pip(environ['PYTHON_HOME']) install_packages(environ['PYTHON_HOME'], "setuptools>=18.0.1", "wheel", "tox", "virtualenv>=13.1.0") python-darkslide-2.3.3/ci/appveyor-with-compiler.cmd000066400000000000000000000030761271614724200225220ustar00rootroot00000000000000:: To build extensions for 64 bit Python 3, we need to configure environment :: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) :: :: To build extensions for 64 bit Python 2, we need to configure environment :: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) :: :: 32 bit builds do not require specific environment configurations. :: :: Note: this script needs to be run with the /E:ON and /V:ON flags for the :: cmd interpreter, at least for (SDK v7.0) :: :: More details at: :: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows :: http://stackoverflow.com/a/13751649/163740 :: :: Author: Olivier Grisel :: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ SET COMMAND_TO_RUN=%* SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows SET WIN_WDK="c:\Program Files (x86)\Windows Kits\10\Include\wdf" ECHO SDK: %WINDOWS_SDK_VERSION% ARCH: %PYTHON_ARCH% IF "%PYTHON_VERSION%"=="3.5" ( IF EXIST %WIN_WDK% ( REM See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ REN %WIN_WDK% 0wdf ) GOTO main ) IF "%PYTHON_ARCH%"=="32" ( GOTO main ) SET DISTUTILS_USE_SDK=1 SET MSSdk=1 "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% CALL "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release :main ECHO Executing: %COMMAND_TO_RUN% CALL %COMMAND_TO_RUN% || EXIT 1 python-darkslide-2.3.3/docs/000077500000000000000000000000001271614724200157365ustar00rootroot00000000000000python-darkslide-2.3.3/docs/changelog.rst000066400000000000000000000000361271614724200204160ustar00rootroot00000000000000.. include:: ../CHANGELOG.rst python-darkslide-2.3.3/docs/conf.py000066400000000000000000000026161271614724200172420ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import os extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.coverage', 'sphinx.ext.doctest', 'sphinx.ext.extlinks', 'sphinx.ext.ifconfig', 'sphinx.ext.napoleon', 'sphinx.ext.todo', 'sphinx.ext.viewcode', ] if os.getenv('SPELLCHECK'): extensions += 'sphinxcontrib.spelling', spelling_show_suggestions = True spelling_lang = 'en_US' source_suffix = '.rst' master_doc = 'index' project = 'Darkslide' year = '2015-2016' author = 'Ionel Cristian Mărieș' copyright = '{0}, {1}'.format(year, author) version = release = '2.3.3' pygments_style = 'trac' templates_path = ['.'] extlinks = { 'issue': ('https://github.com/ionelmc/python-darkslide/issues/%s', '#'), 'pr': ('https://github.com/ionelmc/python-darkslide/pull/%s', 'PR #'), } import sphinx_py3doc_enhanced_theme html_theme = "sphinx_py3doc_enhanced_theme" html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()] html_theme_options = { 'githuburl': 'https://github.com/ionelmc/python-darkslide/' } html_use_smartypants = True html_last_updated_fmt = '%b %d, %Y' html_split_index = True html_sidebars = { '**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'], } html_short_title = '%s-%s' % (project, version) napoleon_use_ivar = True napoleon_use_rtype = False napoleon_use_param = False python-darkslide-2.3.3/docs/contributing.rst000066400000000000000000000000411271614724200211720ustar00rootroot00000000000000.. include:: ../CONTRIBUTING.rst python-darkslide-2.3.3/docs/index.rst000066400000000000000000000003651271614724200176030ustar00rootroot00000000000000======== Contents ======== .. toctree:: :maxdepth: 2 readme installation usage reference/index contributing authors changelog Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` python-darkslide-2.3.3/docs/installation.rst000066400000000000000000000001311271614724200211640ustar00rootroot00000000000000============ Installation ============ At the command line:: pip install darkslide python-darkslide-2.3.3/docs/readme.rst000066400000000000000000000000331271614724200177210ustar00rootroot00000000000000.. include:: ../README.rst python-darkslide-2.3.3/docs/reference/000077500000000000000000000000001271614724200176745ustar00rootroot00000000000000python-darkslide-2.3.3/docs/reference/darkslide.rst000066400000000000000000000001521271614724200223660ustar00rootroot00000000000000darkslide ========= .. testsetup:: from darkslide import * .. automodule:: darkslide :members: python-darkslide-2.3.3/docs/reference/index.rst000066400000000000000000000000751271614724200215370ustar00rootroot00000000000000Reference ========= .. toctree:: :glob: darkslide* python-darkslide-2.3.3/docs/requirements.txt000066400000000000000000000000561271614724200212230ustar00rootroot00000000000000sphinx>=1.3 sphinx-py3doc-enhanced-theme -e . python-darkslide-2.3.3/docs/spelling_wordlist.txt000066400000000000000000000001551271614724200222440ustar00rootroot00000000000000builtin builtins classmethod staticmethod classmethods staticmethods args kwargs callstack Changelog Indices python-darkslide-2.3.3/docs/usage.rst000066400000000000000000000001061271614724200175710ustar00rootroot00000000000000===== Usage ===== To use Darkslide in a project:: import darkslide python-darkslide-2.3.3/examples/000077500000000000000000000000001271614724200166245ustar00rootroot00000000000000python-darkslide-2.3.3/examples/_assets/000077500000000000000000000000001271614724200202655ustar00rootroot00000000000000python-darkslide-2.3.3/examples/_assets/landscape.jpg000066400000000000000000001454101271614724200227260ustar00rootroot00000000000000JFIFxPhotoshop 3.08BIM?Z%G>20101214?090740720101214<0907408BIM%JRgJ1ɾ XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmExifMM* z(1*2ЇiCanonCanon EOS 5D Mark IIAdobe Photoshop Lightroom 5.0 (Macintosh)2014:02:23 12:53:34:B"'@0230J^ rz   2121X242010:12:14 09:07:402010:12:14 09:07:40d2=0! >BF24-70mm,http://ns.adobe.com/xap/1.0/ 134217728 25 +25 -5 +20 +40 30 1 100 75 0 0.575884 False 0 -90 As Shot 10 0 0 100 0 0.5 0 25 -15 0.0 0 -5 +70 LensDefaults 0 0 Canon (Sigma_24-70mm_F2.8_EX_DG_MACRO ) - RAW.lcp Kodak Portra 160 v2C -10 50 0 +5 0 0, 3 55, 52 125, 125 255, 255 -10 +1.0 0 100 0 True 0 Custom 0, 4 255, 255 0 70 1 0 0 5400 0 +10 0 0 +10 0 0 -5 -1.05 50 0 -20 -5 0.989261 +20 0 0 -5 0 0 0 0.5 20 35 1 0 6.7 6DFB20602C65436FA1DC9D2F0F2A6934 +5 True False Adobe (SIGMA 24-70mm F2.8 EX DG MACRO, Canon) -35 +6 100 -15 25 0 +20 30 True -10 +8 -10 0 0 0.010715 30 60 -30 -20 -15 8.1 40 0, 4 56, 57 126, 128 202, 199 255, 255 0 1 0, 0 126, 124 205, 202 255, 255 +10 0 0/1 161 24/1 70/1 0/0 0/0 830501070 2.0.7 0 24-70mm 2014-02-23T12:53:34Z 2014-02-23T12:53:34Z 2010-12-14T09:07:40.21 Adobe Photoshop Lightroom 5.0 (Macintosh) 5 xmp.did:00d30d39-6ccf-4b50-b2e9-2457edc6a416 6A4E5EF91BC8EE91D159036500E79817 xmp.iid:00d30d39-6ccf-4b50-b2e9-2457edc6a416 xmp.iid:9c1a20ab-f1fe-45c9-b51f-0dbef4c759ea xmp.did:9c1a20ab-f1fe-45c9-b51f-0dbef4c759ea derived converted from image/x-canon-cr2 to image/dng, saved to new location Adobe Photoshop Lightroom 5.0 (Macintosh) / 2013-11-01T18:36:27Z xmp.iid:00d30d39-6ccf-4b50-b2e9-2457edc6a416 saved derived converted from image/dng to image/jpeg, saved to new location Adobe Photoshop Lightroom 5.0 (Macintosh) / 2014-02-23T12:53:34Z xmp.iid:9c1a20ab-f1fe-45c9-b51f-0dbef4c759ea saved 6A4E5EF91BC8EE91D159036500E79817 image/jpeg 2010-12-14T09:07:40.21 C  $ """%(%!(!"!C !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!X" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?uw)!jCӊ泱eCr*f|ܚ_OVP)8,*wMº9Q"s2}i@U<Ւ f CׁHfU ݱPJϕ,G~ sЗfAG)4bCXK%(,-ZD <965 Uէ1qmm{ȩQ<U!ɁXV}wa3hI6 /V#rF16L#` VٰAҴPQ%$nH '5@iF9шGn4SY֣b#Ba ANH#Lk7$Tns0fGġUlPk]'xo(#s[zv @w"̥4ҀQVDž½-#GVsNuLp}hadp }XUmU,8ϵuISÞǡZnڎf;#Kq~䱃͌s+z=5\n$c`}m9''=khϿRk_(:U&&JF#gw $cMf molsahfs 앃g*H*|K,zW9ך#j+U3DR=k#S> Ĩ\ddBD?*Y'ەRqz⦵8|9 x|Yk 47+٠!vB(#^ $3/SȝZE+3ld=+W,@5_Q2Aq◶mRè)tC,8CDb#uctܼq;Ӗ%mqMԸ*V"M=b"I)Y.%MSa?\2`GJϩIM E'o/ڎ ( ~$wB r75ҒBr9A;0>4F1Y31ޭři B I#ߟP4H?! v[$С{jݝ@, LmR0#ҥϡqՓ[ |r:U;#Q%#8MWZZ˃ Y=[/?A-Vfv9{`y G85Me3ϩZD!=ȮUQ㫇sY0S+Nqlˢ*J}.e9PZG*;`Ib*.z8R >%*3ޔƷvm',iSMh<ʨ7݊cJTLukAQL &CҠe "6N:z&_&}c#jy8Feoǥ+4U(Ct' r[b g[Kg=`zDR6x>.Is+w"1A9Dn8kK+U @@ 1TW| NIkn1qs\ScNsje\g(iٝD4/$#b(8/KݞԷeجm~9Zf$'#jϝ p2*Tt5hͳ*:j-_n?w[˳"FsN+ [W)$ۣ't78M'n@ѐ{ >tʲ+G1+ֈ9 xmQcpP 5چ$ ?Jjj#:FQC I 0:kr6Ŗ<sb;.tQ4* n=yP"ҼMruԐ{⏫K)fw #'p>cBxW?ZkQ,~=]R&c| b3Xżj`Y;dljvrW⑷sGzF}MJWNՍrt?x5NMnqb)Irb6y02OɢM.>p[1u bKs#P:H&~Ud,H^-r\y% E<ʬ}kw2=U#US$@95b7W*7/Z}j+Br;oL~Uo~*GP6)HbwrwUy{9|3vPyd޳fb}j- <wVS{JHmҢYwVi`Y/j_1 (mKjnJinm ];&.0Z'_F<4ᮆ='I y^!%G!;Ӧ,4Bç1M[;Yc qUtBN*b:-g[}+4װ)QmμraI{5&5U=N-dI%I#j;{Y pﰞjn$X8g}u$wR[C%˘#LUŹ5޼ş̉c>qVه$ 2S%nmqfb y ;V|pQv\dz[w$esWfx{i,;Cx۱{1@ 4ԶTTv#mbX_1oN+zt䭈ԧ7 `=Bw:54'4(UI;훝1Rr׊Wl^ҤVݬF}3Ud zօ*n=W5`ȯqO+B=Iт_4Ȯt]I9R%G,4d'#5*-r<Ǧ)Ħ7 Q"WTef3i$M[/P*xSW?ZQ4Xx(ǥLw=+niav⫬'YI U'JۚX|U^$[ךĔX zB1N:UVYc$N=Fk+bT$t*cuW%?xw fy5$. V&KdoߐbTOmDֹƜp=jQATSr%NWٕH;QdMƣֳ0S@r1"P&ً&{ ұnuy+CUNřNثJγ|_!`1S&[n}57U lW B1HbCF6ɏ!qVm(5Ďh۴}sR ֫OEm摃X7B>O҈Ǜaj Si!aO7V0J>&\6}j)/d#3Z xu5VcCU ?ԨtCҏK`*F8<ժ,clW eƴ]e$ePq\#M1#Mu&?ƧjTw\VK_<=EsE|3Ƞb犓Qa{E^Hj i{͝q \̐[L g9 0>h"ߩ<]DF4wk֥)=6g u2>+?)qQ4DVz\x#tIr&29pZBY+z0 ~عwS 8'Wwd|\syyYfbOǬ2FHxQY^}>TvO&\[؎*=g?)8\\̊y '?y~5K>KIos;ej/&N>*c~&CzSa~Ƨr~CN=#~*z>~uAcWOxzQ[AtHeyjFg~@ 98 ?zO쳲+xnU2mV$ 7@mi (N=7GD"|;gLk%5lO:H Rt;~{9.ҷȒ{>U#8uVvdTPUvGHRn:rg(3pHՅG O>RcZ++ u x)5}l5$#`؄g>>WsZ{kVLґ0H7]Q5IL%-b) ݞtT!aЩQ-)$Zh/9i>g}YY@ytѣC;7m3?d5bwU"5P?opڵZXeq13ey*ܜ)4Uo,vR|(Ԭs,~ ?G5vp2TimHˣ*4wHw#TrZ۞Ǻտ"H8he8phVJH!cȣ-`2)Dgp>azkO}NM)27ty)Z~e6iY[1Hf?f8zm81X}5:=踚fQJt0}GZsc3.!O˜VyٟqNğ}=M#~fӺ 266S5]$|FQR@y֌zwD"# M\Gmv>V?VSS`Ep Ayz;!BM1h&ÇLO}Pym` 335%G;mz"ℲQ(t Co{戁0:ըnj}+TgqG/m~,=r09#5ܼLܐZ-N&*udvR[~uI3[jkiK+e\xki5>^}Ph;W˥F=>}.=5q SxVC՛>m_IV@?T2@U9H綺aUep,~ҝ *ODtÓ=ER%BZGWd~Hdt d]*7W푓ϣ9pc@)BFO]Rq2MO~HAX*EU?m aHOTCR/+z;eDA7mzs# QV,O4_nNX$n*Eqsښ4r_jO%*}NӃ]zsW€JKEG.yz<㞵q<3p5G`ѫ1Eҳx[3›$*n5 k`_hݑTyO]'*ȿAQ1:{3]|o(4* t9T2Ċq[Yp`55R^϶+hJ`!AW_'Q~ӿO7iʍbպq%RF[qTinfI;p}SM$fP??*iCoҴ|2#`z4 TG33 Q<Ҝ͞E= S(}߭PJmʟF; - UqM%GC1EO h>f}sӅyoB_n~ǷNC9ƾ,0J.1R-P3IPԅZ73hwG˃%1j<iu$ڢ!kE'9opK&IU$L8t ѐ~4LƱ'A&v֒6ԁպ`yOcNY)}L_X$? /FQ͟q)e wגOF~#cœGHFd8;*X*:?CQF9sL l<*@2u*ɷ#-c?#U1dϾqQ=5vd][5|na횊H-վVU}NqY7BۜR*Ȕw5$"QnȓŸSWQJwTue ge9 ֪1X!:JOXyNuԱM>[n}e}C1 4yT4d4y텦߱76WJWmA`i]vt9隳u3ǣU{u"ĠtCLrynGf4l(=L!.~bsNȅPÎk[֪HB;g5 "4ع)-ts$1SGbvmN3UWEBxދW&m,1鶐sLJWхB F!ñig gA[/I?i:82ݿ@*)"F{ V*]ݯ;V.p:F{%)U qp}:TRCQ`;TR%(N9C&i^ڬ.IT~5=('`cMuxFyAve9 >ơ~@$]}0e'F)6qU~CmJsN(]}Zn8vV;\H$xhj+j9=zq D3Bi0bֹwSLU{}rTvBN$٭ G;Q?oaw~hkFP oK)F ֫GyP|RQZƽ&삣ڧ_J=/ϸ}~X<ʀT%>rVCjg>廈 JKs9bKd6͒@#^ք)*O"ZYyQhCbSUءzQZАHZ(||L1*_*Lp_~!fn)w4f9TM~N?ԊQI9#ܚ 0@Y?瘣E0hoΘbp(>y\Tlќ=٠dVC drS[0xF>š]IMH (?2ʡIf?S@!#0Ì5[c<sM% H eAiJqM349 Ɯ[ƨg"Ͻ0%bs?tgpy'89 d4:PJMM=mvNcV*Շ$c]rTQ|cN U;b.$`vS]%=E51~JD&pa;OWn$1ÞM@Q{5K"}*6XXD?f4Q`>V]8HEتU_VCD[XzF?fx;wT h6rE/#'afUTg*U>˱㍣lze+SL[+’s^G Hd{ WɓN[H6Zq{; 4c ?Ƨ5F _ං2x VFxBwyn':(5A Q¯@1/LRxCYe%< ?R ?j#j 6WwDxaR3?©c$ϝ5kp DsDM} #ۜl=9tU{S'@d_Ċ P{ilmExOE=IkOtȖTr(h3DGw/k_uZT&"?M_ivfu[{5i-RF_'#R.>(Ŋ!LzTlzG,ݣ%0 S"pW=e0&']q?mbX{BdL~k‡u{i$$LGn* dkL;QԻy[&#򉾬p+> hІ 7|$fH$V2N S(#|?5EK{V>ÊY<5:yX?Q֭y55G(DӢס?u)3·@R+Ur-'ugdu$}jt m5-^<԰56h$ /Eu/">r$K?~*OK-וĺD0@MW?J崹HNE,Bq۷ h;K G&49D$zՄ?3]lqJ͏(v\H,#Cav .=HSsxus1I?; v'Rx?7>}A噌P.Dg9WA)(sUyɣcBݸؘܿ֯{G@+V{EYkZ82?f9dBR2C.1ya-^r?JjK<ŇT->"L`k{>wlt{0=`&>O+0;?rWn5w?54sCC'%$|'mrB.:; ((NF3,fv♺[Nv d!?JyIR<4Oi"0`T$Z4Q3]qi_ ~g([{'amC0D5Q܊i(:^-L7Q i"ZkG3*X4ԫlК#tLi=һ(cM1U_9K΍@## gsၠ EWژQ}*;O*iyk)6)zE`?hHvzSwc!qE?LSJa~~A04—xq sHJ0#\sIz.v$ #U|$>S !OQOȈڳ1%G4 |dtgSRywad1e8T 1­rj_ j^BjL{oRM}/"pݮp̤rbT]2WRX! 4$-aZ"HϮR tBQ}Y$z_Ʋ@:W`dVQyU*Lu9Ht--gjPvntBTқ!,~ïB~jˣW-~bl1dk kj;Ǻԫx4j Sp#ҨpA?\:M5PsR~lLjA\j5 _aOKi }k.]|i/O4jՉg__)E;yE( n1?J_Yo T?H7:OYu)@ \tyJ?al}iM&G֝m U?*Ff#a SNTs?Z.;`k+5Fn:ʗ9cʇCv;bPyZK'x}(Ak=J_y3LR}eMR1na@f35n\2/;.ix^9P?_Ѩ]ywSO7|ӱ?+*܁NrsFsUԝoړ=YݘO)5J.8qOQhIc4`4}WA6>j=?(@oW?zݧf+DaF6>M5_?ptdDNCXL:7YM+tJ.*Y<8?8}7GJ.׻7N9qe9k%T_ilZDk<9fVdwdS@~t4 HSYX vY[Gǩ5RwZa>h;׽Vrԋx:ViAi1irߟ)@9a .Țv Eu  QMzF6iA]U$A\}c_sE5IO GV+ E'CPvE*ݝ ǧ ui-EcKa\˟OʢmZCEA_}@)C\w:h=UW 5) NҷY1I%33!=Gҝs7c"QM|!qsC W`룼ӌt R Yy뛗oΣtO٪Xe܇}G:CL:g\ Yb,5st}^=Ʊ2S:_֙¸5qP6?}ME5KD7Q[u8@+9T$I\B!#V-9UX>-EnhhGI)%=4ҧg劔Ym'FإFV٢?xӄ?:~=L睤~klnַ|E4*){E~1 X)؛#t a پf9"e֫Z[?SOH|?h-* SEV=E^e=77 XBz/)D;-=dcRx@{)gd(A1oxzԢ쏙p)MesKھ*KtǓ.ҥ]>`y~U{PeSSd5N%a)?ID?({?EOO@A#uϰL|OTnnu))LsH-} ֕s\ D>nja'?L2\cVTn g|#MRo.݉Ŵ M0B==Ys]JKfkZE#֊-:Ftftc`5y2=L{(ϒGqUٛI?#vZMBeR! ڷDjS9bറմ6͜ +dҊ9݂桠6?={] WIm;xL3k톜סJTԏ*\4Dk{Y>ncN,<嘮eEt,*H>?Mz"}Nx| wcԚmV*)^Q{^G4ã\bR/aښ"U&ϠU?ҦXYW$Tqf==5%Oʼbw'i_[)_TX.lOժi:ISM=x/!Z4ߊm"j]Y]:-xaRTJjGU<{yD~}Jy#I>\}7?,4~,[$>M\hԒFU+Qw)Dy",x\}I{3b#-bBrjQ<„v{ZjO1 jTo||Oy_[S˥J㧙ӓ)$LR 3ɀ54+|V[ס~>H^U;MfMj)8q1slj%/lGBO_Ү^ 6̢;5y[g +n$ t}^ck-yׯ u !OF FYe1*O\אqgI,=6cjEԙ֗>7)휎e>-謧r}3+'V Gթ/땺3Ӧ;_![P2I!22G;_~D[}Fwcr*4zc!V quc@nf 3}5Wc,vwpGQ?& +^>dc=+5ն·oK$zşŽ/cnTEy{J ~,i61kJ(jŃqOf5V{=}Ypz执1[r^ ;ğ&m/g,GJ֯D^ٞy#?bҧ鳪5om^;`R4;ˊj5%9=Vpo-n"E?u^3ҵEUrz)+'\2BW֟xٟ]JP̤C_+kڮ_\£&I|whUcK_Yw%.ă׎Iu#̹RZז>|W0NK)_?@9cK_2]N(ho0kgH[ɷUHb'7U/29uG>|Dp٨^!uzčV60pďZV.T,aO2Y#Fhҹ?nDZ|_^io[Hi^i0>FG|OTyJst-bF3Iy^j1EӥQ yW"ps 5Q¹nLj;;L%L_5h^44]I,$ ]OW͠8IuayVPĎ>0®iK NǢ%YǞXYcolMxƭI#)i+kv۱UR_~,1BԗON:^ҿ's_6[T\+=SyIm]ؼ#ɸO*e*8RC?:@zּOٖ;왎7ʁ}Jq [f3 Ѩiީ?xtּݾ-xXmQn>#|T?n$[G֏aS{z}C1Yifb .EAƹ %rO\p_B%g5V5(>`k'9\%OMg?įeu2 `*a0&G%kGG#J~$AƱ)ϬhZ|UFx0Q{b()@ӭ"}}S>T1}\^$Ly=V>6#i1HaXo@[?v}(&ㄞk]|nN (Tj(j_+p(sʡ_4P~_Ln+рj}5N=-pʹ .}i}KFGjp*}3x cƜm)!AGT`3W#|ZH<(t>G=_=dջBfGa;)PqPY."V<0?֭ ;¿%gUiðL(}FWlAUGpAJ6M H&Q,M#J5$̮ g _)*]Y p!U97-B92W0dʛGU*[2]r+6FvTʧzS?dxy?"^D1CSi4[x>.'9;Vd/ 탡NCġג?@^sT4 #*BSuqO6G(*Xj>S"C_pԧR?H5Li9jc)\Ap*ŗ4TVv4}bi]Ho MA0L\5!2r>x-mSoH߭g4GQxZ]"h W)4MG_|;,La5I!qM~VzM9/HG| `M<*7a 旷/غTǥ< d1cYQH‘K퐕6^S?yAiv06 G223){}}IZtUd>2FER$G?R>ՉQp89lUw~pOz<#ӥ/n.m0i`B!=`@$ hLBa#bcTWpG"xwG֢V#h'y,@ TٹU wun*S^H  }-JP4홥.}Ia;=ZO,=u2!I5' jf} P'иqdQϚ$ Dxmqes(?:r\?2VPc朳>5KK#idԄ?yy*1֢,2yZĐk3JơiK+8i \qNcXdrǭ'7*̽ t`} ◶`˫1Pcƒ9.KӼNqRec R: g5UZrr4 J^ܥ-y#4qVTsSKg?(|TvWZk\JuLIДj˞=3M.XzҏlcB9u*ޅjbI閬\+3eϮiyw'Gdt!J⊡> >{O wC&}v6}go]<`Ahdz (D2Hq_REp7.Vm쑅<>SGU2Y]F-Ў^$4;d3rXMBUqn32E7Q$Vcjٯ5"n+Vatp`$pyJSDW-'D P5%eGU6wٸ;Vp2v֟;;QJ쑗"$9" 7/ִRAjOBXQ)[x$vHI )lV<>"<]8> eWUƭ>GJiFқ)Q|td$ srazIBO5mߴ*@30#c@\sѹ'=1"y&ӷr6Aǧ K"Oa.30'N=h+'ef~@3LG52U<6? x ҡki>S&M&Ib*Шn?RZ_s){t545̓qO:Tt4>t`7 YnV2Gf\!e)a8Xr+G#uS#'k{r9i`ZKf8nz)1ǘrwc0fK^=4p Ԗ $.áSUš,@1~5fCxe] 'iR 0GV4sЦŐ}TɎ:U'sR:*I>Žt+`cFQ3iVr:SA BWaԁҥF1B}; AVvVF҉4طnd.w14YyZE}`zVhM[#''"+yA8PLsUd̹%,7(drwzA3h4ОU`G4.p zj hn]bU$2x9"$<7vFޕ;g2ndhA5nPF%~~)ܞ6 ⒲ ,^%KshEG1=;CϔzLdTqܜz`@vvfl.;HFiOG<|ݺS4 gO%>c<EbylҜF9iʇN{ ޘUP}ig8@ r)3y\ñWn{bWnIެKQr± 0#4,N8^ԥ t@|Ӹ ,đڣb\kKƮr(L PѼY4PEgo+oֲ-Dݺly~Q1Yy-YBbYQ W=蹉 +)&Tյr|G r{U_(#*!5r7YY .Y2=956s#Χ8W6xsRS/[f\[R&G<3u+3A?ʡ-1|㴀9MtkBzf2i'Ѕ3ˎ*>E&8WC8O,8ǐHz5ލq=̟)HCk Spd{pZ|N!q'Nv7*뼓BU'$؜V=׆&r6r?c%v.ĖKw0Ƅ t:z{~\eԀ 8 <`U[XVZ_.cP]3psT>=s55s6c*xkv;?Zb՜jH]./gRЛ#@|fc[*ڤToss]r?Ƥѯ/Ly$Bǹnj䔔8f/}@{_Qyde2&ұ?XH%nDPfݟtSː`+agtE#"ͽ;c=鈝$>֣67*FAF~*?BlyF69+vcG-ͪH#DY$$cыyGݸs?Ҕ (X| 8([fS2+М:)8$`SUؓE} ENi)?J@ĄvTFӐ>YPPY.%SUޏlg"PmOL ʞ?$}JR!@H1|⑳=85Y>F8c(hv##8 ޵bCTΣqCַ| $9^Ml" l`(\pp3"?+_cSueU/p0%'?Ҧ)$m_9G $5\夰UT[ fG8r@{‘#>bT8q]ci! m.NoшV.=S /8<:SPPlcځg԰d \̂EHp賩En|ߒպ\烞}3n=GsTGosQ h\֥u[?J&B>h#߂3w2f)Aۚ>աw k5VcFjFU=5dyfvL:sR1wc4 6$w6C)pMÎ1Qy `SDHz,yh&й^SZ)y,RH qtMk~: DEP.>z/ ]5ɮ _ ͜m,+YW8VsS1@g* F Om*Z&RSvH$pFϥUvE> i0>Q\9lOLu$nQwz+<'U|]pbK&>$SzdU t+v ~2? AaնYUp4[nJstW6p?qT}4.!V? 8S@=ƱLb=4LzF8=zq;Y歰*g)v)WHT(n2iLw`Gp{JIv~GF`֟~n=)TAXxu>QQ1-~i&Wߎ(Q}@p(NI`G"U3O3O>VPzRKab$aw7usKq|6<=jEswqA N޹u3qR +ibd<#QTȎÇBC?%d(-re?2FP4#J p>W}EGnJ0mA 0={RlR>Qfja#M^z2׭J@?yS4n>iLA {Np[47t~Rp=T>b"eMh9%E_ vN%|^AUWX=eݹ̐zU&lFPo j8"T*sU g%xe%JkBƪkYپ Nj1ڻKz6Eo#%`I*` N~j6IzIUҵHr'%ŢA94ܰCY{ȒG_8^ŭin<`Ԟ`@#ۭeA]~RW7{vM@R;Npdg6{cp#tV< *?rwsqv%Ѥ83XVbj6}ծ ɽr3&uù$i^\(Y=|2rxr Ji} (;QgL"T1AiYb*2rZXTv䵅g 8+*Uj! fz=ytFJV()S#fw\`;Z%mh$zSM\Ye ɖ948l3T6;p!fTY+u"V"}+3/S9b]w1RGNԙ8â RaOu#-u2mv+H($pE$6UOSk2=TmwpaW{' F8 dZ'ۥ|¤ 4X C̣i84IF㎴olZI{bJ ¦3&Fj*T?<5p.ٗ8#қ+oPuاR0T"d3&qNݔ ߡHD<8gz\H8Q'r֫ylp,ʹ9(eFRrHC |Hw#E l9ֻ! ʌ{䁐X98VpFsO3( Q Asrba$iye֫ydi$lSVg8&ȀM\g*`HTc;MV\n)KO91!R?44y=HBg&Mb)SF*2=Hª B_Z6dzQvE>`;h#v>.=j-SFXƩ6c,ۘ iiM/U0$1NWUf3%ۦIxiiӟu*4w_V˰f&Sg~B߃UB}ezJh03y ,M)PQ[KJ)G"ڟNCDo<^~Me))8.$B1I>Vr9v3G{H/ⰚQ%R9DOl}) 櫴(ĕIQyM^\۷qQ]ʃG!v\4"m:&?g?c9 G} Mk k@?FާrʗF=꽥M +q*ULn9d?4mW4HNީWFйwBBPXl2 q1|+L4c#hx NQ9cDA' G9ׁq[I\bcC1U+ItV[O?J+EY ˹;j ɜvZ[pS# 1(.O3{f˩XnOqJJ1;v}O4r<Bv A/F4[A+Q } n 63pj/-V=M5vVpC#=8iNQM_PXfg#Q#F2 3ˑNTʡ O:V 7cMR7EaB $5gS3Ԏ %8S`Y-jb~aA 8Oj\d@*?0;4^9fEaQfB#JMBTgߊib UiL\6J O1A݂.V"3HYsUXɟϱ89فS W`9 pd1D{=fQ;T>~Sɧ2gOC-%1VQl C\Fɂ@Tq9M{R$6L=TZuU R2҅*1hI-Q5*Aa(PYjidSQ\vk$c5 kT:_{a늅O㊔LRA*jiZu9΄rF}kH^ҤB0 )Õ=^\lǵj&PGAgQO^jEP KJtt}+_ex5:L4OAҦ(T/8^ICNBqsEĶPnqʕ^tVe).1&d $SV΂ao*'$QU.bЩ"-#4(\3L,@cdI=. cHz>}&Bs.xBHeGr7u,jPb @'4NO9/U{`T}E'LaM+5LÎ4x%YA&Lvf RjCki*Kdiʤ/b ۛvȦpԭ+n%EEvzT4#0wqP`uS@y2}ӷ8)}>P,ywSU;W֣ T.vi2A)ApSR1Q㌀=i`]&%Xw)2=s֫#;TܴD`@i #ĂNqJ0G_֎[u +.hǨCQnsopiمL q߽7~;=vRR HihR:✲sO!!g>;OҘda׊`F!aOXX•[qϵL/D?Pi91\OA?BTlGq-HsN 8('.@UrjqQ Rq+0_l;*i8/tF;M;z#ʓ˅?9QHp7d{Q!z^}}E0!'ߝ;I~ҋWDCj?-pHR]*ޒ~EIʩE`H;vx[)[vPp=(F[h9ˍN1L\hUd.e͹$=X{UZx ,l{WFH6r@olFBݼynJ0vH[42H$p5ɣ2pTM*vHYʒc}nm¼![%v<aM4!-EHo8 5%vfd|%OlSN-s$1 @ c{ܾ/dP,qִe;I2ORA楸]Eۨ63hhf.VF?2jje:Ҭ1tz# F9D2c{ Ȼ$9KkQ4x֘`?Mwe#Fc5)Wsj_3aB~5G9] E7vI]3, jg 9T'~8pB I`2OqR0Cg_8k9 Ztz4C ٓ;w=1bJ<+sqJJ$uPxIqL@ʌnH< B`YY9+}O@T' 95r\gJFI?1'9b?NsOB~"dҗyU?Z9@dT~nn\S˧#󣕡;yPJӡ".:z9cL9i:}  ?}I1Q׃Li[n9)RN~REUFs)l2ir5*16=0 @ ӄR~r׌>@c-H%QcҗrTـneǧj(8E=3%-;  ) ,zc S9SЇb-agڦK !89f7>٤b*,*3>0=qBH#^iX Y  '+3F?s9ߩmcv)fr3۲U`r=. ,^4WjI{<ȲF3* QI q?:[K6(' wF힜g4ۈe )ˉV&YDeж2H}}kb$MU[;WRR}o@$Qœ\x9ߊG KpVDJɴm] zՄ.H؀Or@)0GW;"DBqZ{ Uq&hʞӸv1h}!jnV)ہ`Ǧ9q{ǒX24J A YB.eHҞ$e8O,U8?h`q\NSǸU n]gSc1vǸ.G^9Āsޑ$p  ݗn0N,Bܠ;9J);K;*BaTB`2 XF%3g?JF ^6ppOo"μe਩ ҞlI?ÇU򦌨cpBkE! thrNGR|Fzv #ع$bOJQ2SPB 023O0:0:R;匏v&`1M7Ym/jEݑJ8:JUpN:g ׽7c9FE)i8GE #65n]޸⟴2`nzFQK!2O!aFSJv¸zS'+<12ݣ9=9&ǧ)G+{bV}sKT#=m22O~ *e;sސ ?1J3RspsS+`@R(:{t& zZJX IZ8H9PH8*NX F31rM"O9)A lzB#;9P=j|#}+ӧJ:۱Ҧ$!ՂJ))@N7sҖJ6m_VaIJ0 #AN(L,sN=j*>QNp^402Vs~렒 yYe9svknpۇbhI8FA'-[ɫovJ*We@XPZIcS>8H61K#<3\U(6]wWCFrA=j]Ҷڬ433 % :Қ=  sDrKpB|T̉*̯+t'RHG4wۃ/\Ҕ1 ?:jfMlf[9>e`z>pLNyvI8*y|1=.*Utzž., J>4R 2=4&W>5[cKT1 9S{M J1,w8>Ƕi݀\ǥ.ӀiنK+^ƕsS[v19p)T䝣8)h-~r;)|3E``gQEDPVސOZOOVJ*:^<QIBVFsӚzɆ2'TY<3\[']YxeHnzU*_8 `"EM .<2 dܑl$ι|1#j m*)vV^ʚ4* e 5(Fh%&-!7V,7'{q? WehTeTݺI ",cVqr:Y6zTs]D,4¢Ӿ*t$$ǻ=}O~*wX.&ggӊD+Hn+2l4Uq=U˹Q`?רخ]I/yfp6d+SRȣfj]Jl8`*v٭ dgj>P|*zަY#r+L4w03'2o71Q)qK&plŽZB\3ЏMYyJzǠ9g8$BtCE,`x<>[B' V,i\*퇪4tu#4^2P+t)psqRɐ*?:­o`#q APv?}`~枪a6m NjyT*98d 8Pp2zǥ;s3 pݪ\dv=*M';X23M$RICNjFXQKsI=q/-@iP78v9&@q:ᩛc۔ޠ3B *aÁg\^[p;N8ERK  HԹ!o wcF~x-& R,>$ƀ݉  V`)ctf0S6s?*6t 6 Nkax9M$qJ:ts8v1JQLnJ(⭻zR*9iefnGb) 3H8f*ݘ1L0C hY0y\El:vSG iO~  i i~s旙JfpJw`ڗpxYI2B1ޑܧQGoAȥf'N_{L PKgӠ6B Nv Tlq )7}zLE+6q8 2Rs{Tvܢ J ۯ7<ZJy96Q@%. )ʌ ջbhRA3!Bzo隃W3X<+JeЎ@qPRDLH$}~t[KwFI18Asr'w$jOʈNCV3Zb7SG*ܤsN;F =fY d> Wk|\mfe\+ryj'dwy''1y2֡JC&C #98O!>fc߁\\^A")ف"KcH)֐brNqM@ei$iz@#IX~Gtq` (3Y"ws\SDv8?=ASmij^pJɦ FOWR2vš)9 I,|Gozyr;柨 (1}dp(D2fN 2> 5^(hʱ7jR# !'WNUP?)X8`+I3nQ:O/AKc:.:Fd + Day=3֣hx]JrpUB󒹨b,eqW  Q3pz RfpJȦy׵Lp͓qItU\S~C;w3.0z݅@9oJ*|qGOn3IAs3ǭHH$ҏl |ᏽB+{uq@}&J_8POJ{,pZ%9}S9#+yPzP ''ckOP`9N ?/HC,8/p֜N?J׿KJ[!A (n0*=p}߼Wyn}z4P$g`?python-darkslide-2.3.3/examples/config-file/000077500000000000000000000000001271614724200210065ustar00rootroot00000000000000python-darkslide-2.3.3/examples/config-file/presentation.cfg000066400000000000000000000002331271614724200242000ustar00rootroot00000000000000[landslide] source = ../markdown ../restructuredtext ../textile ../multiple-files ../other-features math_output = true python-darkslide-2.3.3/examples/markdown/000077500000000000000000000000001271614724200204465ustar00rootroot00000000000000python-darkslide-2.3.3/examples/markdown/slides.md000066400000000000000000000034371271614724200222620ustar00rootroot00000000000000# Title Slide .footer: [default theme](.) | [abyss theme](abyss.html) | [void theme](void.html) | [github](https://github.com/ionelmc/python-darkslide) --- # Paragraphs Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc elit, vel iaculis lorem facilisis non. Vivamus ante mauris, pellentesque et rhoncus ut, condimentum sed ipsum. Nullam eu molestie sapien. Curabitur imperdiet, ligula id blandit sagittis, libero quam consectetur felis, ac pharetra metus lectus vitae leo. Mauris lacinia fermentum augue. --- # Blockquotes > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies > tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus > scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc > elit, vel iaculis lorem facilisis non. --- # Subheadings and Emphasis ## Italic *Lorem ipsum dolor sit amet* ## Bold **Lorem ipsum dolor sit amet** --- # Lists ## Unordered List - Markdown - ReStructured Text - Textile ## Ordered List 1. Python 2. JavaScript 3. HTML5 --- # Second Title Slide --- # Code ## Single Word Hello `World` ## Python !python def multiply (x, y): return x * y ## JavaScript !javascript multiply: function (x, y) { return x * y; } ## HTML !html --- # Images ![Landscape](../_assets/landscape.jpg) --- # View Presenter Notes This slide has presenter notes. Press `p` to view them. # Presenter Notes Hello from presenter notes --- # Other features View other features in the help sidebar by pressing `h` python-darkslide-2.3.3/examples/multiple-files/000077500000000000000000000000001271614724200215575ustar00rootroot00000000000000python-darkslide-2.3.3/examples/multiple-files/1.md000066400000000000000000000016751271614724200222520ustar00rootroot00000000000000# Title Slide --- # Paragraphs Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc elit, vel iaculis lorem facilisis non. Vivamus ante mauris, pellentesque et rhoncus ut, condimentum sed ipsum. Nullam eu molestie sapien. Curabitur imperdiet, ligula id blandit sagittis, libero quam consectetur felis, ac pharetra metus lectus vitae leo. Mauris lacinia fermentum augue. --- # Blockquotes > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies > tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus > scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc > elit, vel iaculis lorem facilisis non. --- # Subheadings and Emphasis ## Italic *Lorem ipsum dolor sit amet* ## Bold **Lorem ipsum dolor sit amet** python-darkslide-2.3.3/examples/multiple-files/2.rst000066400000000000000000000010641271614724200224530ustar00rootroot00000000000000Lists ===== Unordered List -------------- - Markdown - ReStructured Text - Textile Ordered List ------------ 1. Python 2. JavaScript 3. HTML5 ---- Second Title Slide ================== ---- Code ==== Single Word ----------- Hello ``World`` Python ------ .. code-block:: python def multiply (x, y): return x * y JavaScript ---------- .. code-block:: javascript multiply: function (x, y) { return x * y; } HTML ---- .. code-block:: html python-darkslide-2.3.3/examples/multiple-files/3.textile000066400000000000000000000004241271614724200233210ustar00rootroot00000000000000h1. Images !.../_assets/landscape.jpg(Landscape)!
h1. View Presenter Notes This slide has presenter notes. Press `p` to view them. h1. Presenter Notes Hello from presenter notes
h1. Other features View other features in the help sidebar by pressing `h` python-darkslide-2.3.3/examples/other-features/000077500000000000000000000000001271614724200215615ustar00rootroot00000000000000python-darkslide-2.3.3/examples/other-features/slides.md000066400000000000000000000003351271614724200233670ustar00rootroot00000000000000# Other Features --- # Math MathJax rendering is available for presentations compiled with the `-m` flag \\[ \\left( \\sum_{k=1}^n a_k b_k \\right)^2 \\] --- # QR Codes .qr: 450|http://github.com/adamzap/landslide python-darkslide-2.3.3/examples/restructuredtext/000077500000000000000000000000001271614724200222645ustar00rootroot00000000000000python-darkslide-2.3.3/examples/restructuredtext/slides.rst000066400000000000000000000035761271614724200243140ustar00rootroot00000000000000Title Slide =========== ---- Paragraphs ========== Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc elit, vel iaculis lorem facilisis non. Vivamus ante mauris, pellentesque et rhoncus ut, condimentum sed ipsum. Nullam eu molestie sapien. Curabitur imperdiet, ligula id blandit sagittis, libero quam consectetur felis, ac pharetra metus lectus vitae leo. Mauris lacinia fermentum augue. ---- Blockquotes =========== Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc elit, vel iaculis lorem facilisis non. ---- Subheadings and Emphasis ======================== Italic ------ *Lorem ipsum dolor sit amet* Bold ---- **Lorem ipsum dolor sit amet** ---- Lists ===== Unordered List -------------- - Markdown - ReStructured Text - Textile Ordered List ------------ 1. Python 2. JavaScript 3. HTML5 ---- Second Title Slide ================== ---- Code ==== Single Word ----------- Hello ``World`` Python ------ .. code-block:: python def multiply (x, y): return x * y JavaScript ---------- .. code-block:: javascript multiply: function (x, y) { return x * y; } HTML ---- .. code-block:: html ---- Images ====== .. image:: ../_assets/landscape.jpg ---- View Presenter Notes ==================== This slide has presenter notes. Press ``p`` to view them. Presenter Notes =============== Hello from presenter notes ---- Other features ============== View other features in the help sidebar by pressing ``h`` python-darkslide-2.3.3/examples/textile/000077500000000000000000000000001271614724200203025ustar00rootroot00000000000000python-darkslide-2.3.3/examples/textile/slides.textile000066400000000000000000000032031271614724200231630ustar00rootroot00000000000000h1. Title Slide --- h1. Paragraphs Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc elit, vel iaculis lorem facilisis non. Vivamus ante mauris, pellentesque et rhoncus ut, condimentum sed ipsum. Nullam eu molestie sapien. Curabitur imperdiet, ligula id blandit sagittis, libero quam consectetur felis, ac pharetra metus lectus vitae leo. Mauris lacinia fermentum augue. --- h1. Blockquotes bq. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc elit, vel iaculis lorem facilisis non. --- h1. Subheadings and Emphasis h2. Italic _Lorem ipsum dolor sit amet_ h2. Bold *Lorem ipsum dolor sit amet* --- h1. Lists h2. Unordered List * Markdown * ReStructured Text * Textile h2. Ordered List # Python # JavaScript # HTML5 --- h1. Second Title Slide --- h1. Code h2. Single Word Hello @World@ h2. Python bc. def multiply (x, y): return x * y h2. JavaScript bc. multiply: function (x, y) { return x * y; } h2. HTML bc. --- h1. Images !.../_assets/landscape.jpg(Landscape)! --- h1. View Presenter Notes This slide has presenter notes. Press `p` to view them. h1. Presenter Notes Hello from presenter notes --- h1. Other features View other features in the help sidebar by pressing `h` python-darkslide-2.3.3/publish-key.enc000066400000000000000000000032201271614724200177260ustar00rootroot00000000000000~kØ^RNT(3uò5M0i3HEgdmvǗ?a{TZg>9ߡ>r'6Mʏ`Dҍ^g([7!7|q,%<ї̀n@~R^.$dK>b6i-{`yd9k)){:VЩj.FjZA_ v$gtLz%+ ׵v 8?6Yf_{ aT}cRVB3ݪ0Sk-o o$Hl;JkhyI6JOR }V.\=:zǘ7eL*!`OFn1}$fUGns 97h$xa<ť QA' ZF Y]Re:P":6DK{ ౞6_l#0as ~B쬰1]8$wRc(r!ko8=[o;>=.| gU{f!1);SyBǚ6k=BW TP(~w- |Kd_k)+轮Oqf!C?6%rm*j45iی垡yiCAob؊_9QLD9?Xċ895f6,c"{ë_@R su5@[U1/[P8daMeQiT|. h*+o%*fѵΐAS`p.'E wS rȲNh5t۲=>(ӚblNɁA'4〶 ȟlcLxX&^qTXq'vzm2#x8!H[FGP&mzWZLo%2m ?{'PQ"N^ҒH8)b^a:)9r3_W `1ċ"{՞D KLb\M[Tq*%.YX{OJ= 8|q#1r?,բTPWvѡNW9)}Zf *Yh.:`/~ fU Wc{ovҍvۂ0~T6' r o`nklCC nowFk9-}Q\ fwސ8nDcEWq%*ewElgjܗ]%vOŅr7~\Eqͮ7Zbnb5,3j?,|cUJfE|Fo” =0.11'], }, entry_points={ 'console_scripts': [ 'darkslide = darkslide.cli:main', ] }, ) python-darkslide-2.3.3/src/000077500000000000000000000000001271614724200155755ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/000077500000000000000000000000001271614724200175375ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/__init__.py000066400000000000000000000000261271614724200216460ustar00rootroot00000000000000__version__ = "2.3.3" python-darkslide-2.3.3/src/darkslide/__main__.py000066400000000000000000000001071271614724200216270ustar00rootroot00000000000000from darkslide.cli import main if __name__ == "__main__": main() python-darkslide-2.3.3/src/darkslide/cli.py000077500000000000000000000112351271614724200206650ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import sys from optparse import OptionParser from . import generator from . import __version__ def _parse_options(): """Parses landslide's command line options""" parser = OptionParser( usage="%prog [options] input.md ...", description="Generates an HTML5 or PDF " "slideshow from Markdown or other formats", epilog="Note: PDF export requires the `prince` program: " "http://princexml.com/", version="%prog " + __version__) parser.add_option( "-c", "--copy-theme", action="store_true", dest="copy_theme", help="Copy theme directory into current presentation source directory", default=False) parser.add_option( "-b", "--debug", action="store_true", dest="debug", help="Will display any exception trace to stdout", default=False) parser.add_option( "-d", "--destination", dest="destination_file", help="The path to the to the destination file: .html or " ".pdf extensions allowed (default: presentation.html)", metavar="FILE", default="presentation.html") parser.add_option( "-e", "--encoding", dest="encoding", help="The encoding of your files (defaults to utf8)", metavar="ENCODING", default="utf8") parser.add_option( "-i", "--embed", action="store_true", dest="embed", help="Embed stylesheet and javascript contents, " "base64-encoded images in presentation to make a " "standalone document", default=False) parser.add_option( "-l", "--linenos", type="choice", choices=generator.VALID_LINENOS, dest="linenos", help="How to output linenos in source code. Three options availables: " "no (no line numbers); " "inline (inside
 tag); "
        "table (lines numbers in another cell, copy-paste friendly)",
        default="inline",
    )

    parser.add_option(
        "-o", "--direct-output",
        action="store_true",
        dest="direct",
        help="Prints the generated HTML code to stdout; won't work with PDF "
             "export",
        default=False)

    parser.add_option(
        "-P", "--no-presenter-notes",
        action="store_false",
        dest="presenter_notes",
        help="Don't include presenter notes in the output",
        default=True)

    parser.add_option(
        "-q", "--quiet",
        action="store_false",
        dest="verbose",
        help="Won't write anything to stdout (silent mode)",
        default=False)

    parser.add_option(
        "-r", "--relative",
        action="store_true",
        dest="relative",
        help="Make your presentation asset links relative to current working dir; "
             "This may be useful if you intend to publish your html "
             "presentation online.",
        default=False,
    )

    parser.add_option(
        "-t", "--theme",
        dest="theme",
        help="A theme name, or path to a landlside theme directory",
        default='default')

    parser.add_option(
        "-v", "--verbose",
        action="store_true",
        dest="verbose",
        help="Write informational messages to stdout (enabled by default)",
        default=True)

    parser.add_option(
        "-x", "--extensions",
        dest="extensions",
        help="Comma-separated list of extensions for Markdown",
        default='',
    )

    parser.add_option(
        "-w", "--watch",
        action="store_true",
        dest="watch",
        help="Watch source directory for changes and regenerate slides",
        default=False
    )

    parser.add_option(
        "-m", "--math-output",
        action="store_true",
        dest="math_output",
        help="Enable mathematical output using MathJax",
        default=False
    )

    (options, args) = parser.parse_args()

    if not args:
        parser.print_help()
        sys.exit(1)

    return options, args[0]


def log(message, type):
    """Log notices to stdout and errors to stderr"""

    (sys.stdout if type == 'notice' else sys.stderr).write(message + "\n")


def run(input_file, options):
    """Runs the Generator using parsed options."""

    options.logger = log
    generator.Generator(input_file, **options.__dict__).execute()


def main():
    """Main program entry point"""

    options, input_file = _parse_options()

    if (options.debug):
        run(input_file, options)
    else:
        try:
            run(input_file, options)
        except Exception as e:
            sys.stderr.write("Error: %s\n" % e)
            sys.exit(1)
python-darkslide-2.3.3/src/darkslide/generator.py000066400000000000000000000612461271614724200221100ustar00rootroot00000000000000# -*- coding: utf-8 -*-
import codecs
import inspect
import os
import re
import shutil
import sys
import tempfile
from subprocess import Popen

import jinja2

from six import string_types, binary_type

from six.moves import configparser
from . import macro as macro_module
from . import utils
from .parser import Parser
from . import __version__

BASE_DIR = os.path.dirname(__file__)
THEMES_DIR = os.path.join(BASE_DIR, 'themes')
TOC_MAX_LEVEL = 2
VALID_LINENOS = ('no', 'inline', 'table')


class Generator(object):
    """The Generator class takes and processes presentation source as a file, a
       folder or a configuration file and provides methods to render them as a
       presentation.
    """
    default_macros = (
        macro_module.CodeHighlightingMacro,
        macro_module.EmbedImagesMacro,
        macro_module.FixImagePathsMacro,
        macro_module.FxMacro,
        macro_module.NotesMacro,
        macro_module.QRMacro,
        macro_module.FooterMacro,
    )

    def __init__(self, source, **kwargs):
        """ Configures this generator. Available ``args`` are:
            - ``source``: source file or directory path
            Available ``kwargs`` are:
            - ``copy_theme``: copy theme directory and files into presentation
                              one
            - ``destination_file``: path to html or PDF destination file
            - ``direct``: enables direct rendering presentation to stdout
            - ``debug``: enables debug mode
            - ``embed``: generates a standalone document, with embedded assets
            - ``encoding``: the encoding to use for this presentation
            - ``extensions``: Comma separated list of markdown extensions
            - ``logger``: a logger lambda to use for logging
            - ``presenter_notes``: enable presenter notes
            - ``relative``: enable relative asset urls
            - ``theme``: path to the theme to use for this presentation
            - ``verbose``: enables verbose output
        """
        self.user_css = []
        self.user_js = []
        self.copy_theme = kwargs.get('copy_theme', False)
        self.debug = kwargs.get('debug', False)
        self.destination_file = kwargs.get('destination_file',
                                           'presentation.html')
        self.direct = kwargs.get('direct', False)
        self.embed = kwargs.get('embed', False)
        self.encoding = kwargs.get('encoding', 'utf8')
        self.extensions = kwargs.get('extensions', None)
        self.logger = kwargs.get('logger', None)
        self.presenter_notes = kwargs.get('presenter_notes', True)
        self.relative = kwargs.get('relative', False)
        self.theme = kwargs.get('theme', 'default')
        self.verbose = kwargs.get('verbose', False)
        self.linenos = self.linenos_check(kwargs.get('linenos'))
        self.watch = kwargs.get('watch', False)
        self.math_output = kwargs.get('math_output', False)
        self.num_slides = 0
        self.__toc = []

        if self.direct:
            # Only output html in direct output mode, not log messages
            self.verbose = False

        if not source or not os.path.exists(source):
            raise IOError("Source file/directory %s does not exist" % source)

        if source.endswith('.cfg'):
            self.work_dir = os.path.dirname(source)
            config = self.parse_config(source)
            self.source = config.get('source')
            if not self.source:
                raise IOError('unable to fetch a valid source from config')
            source_abspath = os.path.abspath(self.source[0])
            self.destination_file = config.get('destination', self.destination_file)
            self.embed = config.get('embed', self.embed)
            self.relative = config.get('relative', self.relative)
            self.copy_theme = config.get('copy_theme', self.copy_theme)
            self.extensions = config.get('extensions', self.extensions)
            self.theme = config.get('theme', self.theme)
            self.destination_dir = os.path.dirname(self.destination_file)
            self.add_user_css(config.get('css', []))
            self.add_user_js(config.get('js', []))
            self.linenos = self.linenos_check(config.get('linenos', self.linenos))
            self.math_output = config.get('math_output', self.math_output)
        else:
            self.source = source
            self.work_dir = '.'
            self.destination_dir = os.path.dirname(self.destination_file)

            source_abspath = os.path.abspath(source)

        if not os.path.isdir(source_abspath):
            source_abspath = os.path.dirname(source_abspath)

        self.watch_dir = source_abspath

        if os.path.exists(self.destination_file) and not os.path.isfile(self.destination_file):
            raise IOError("Destination %s exists and is not a file" % self.destination_file)

        if self.destination_file.endswith('.html'):
            self.file_type = 'html'
        elif self.destination_file.endswith('.pdf'):
            self.file_type = 'pdf'
            self.embed = True
        else:
            raise IOError("This program can only write html or pdf files. "
                          "Please use one of these file extensions in the "
                          "destination")

        self.theme_dir = self.find_theme_dir(self.theme, self.copy_theme)
        self.template_file = self.get_template_file()

        # macros registering
        self.macros = []
        self.register_macro(*self.default_macros)

    def add_user_css(self, css_list):
        """ Adds supplementary user css files to the presentation. The
            ``css_list`` arg can be either a ``list`` or a string.
        """
        if isinstance(css_list, string_types):
            css_list = [css_list]

        for css_path in css_list:
            if css_path and css_path not in self.user_css:
                if not os.path.exists(css_path):
                    raise IOError('%s user css file not found' % (css_path,))
                with codecs.open(css_path, encoding=self.encoding) as css_file:
                    self.user_css.append({
                        'path_url': utils.get_path_url(css_path,
                                                       self.relative and self.destination_dir),
                        'contents': css_file.read(),
                    })

    def add_user_js(self, js_list):
        """ Adds supplementary user javascript files to the presentation. The
            ``js_list`` arg can be either a ``list`` or a string.
        """
        if isinstance(js_list, string_types):
            js_list = [js_list]
        for js_path in js_list:
            if js_path and js_path not in self.user_js:
                if js_path.startswith("http:"):
                    self.user_js.append({
                        'path_url': js_path,
                        'contents': '',
                    })
                elif not os.path.exists(js_path):
                    raise IOError('%s user js file not found' % (js_path,))
                else:
                    with codecs.open(js_path,
                                     encoding=self.encoding) as js_file:
                        self.user_js.append({
                            'path_url': utils.get_path_url(js_path,
                                                           self.relative and self.destination_dir),
                            'contents': js_file.read(),
                        })

    def add_toc_entry(self, title, level, slide_number):
        """ Adds a new entry to current presentation Table of Contents.
        """
        self.__toc.append({'title': title, 'number': slide_number,
                           'level': level})

    @property
    def toc(self):
        """ Smart getter for Table of Content list.
        """
        toc = []
        stack = [toc]
        for entry in self.__toc:
            entry['sub'] = []
            while entry['level'] < len(stack):
                stack.pop()
            while entry['level'] > len(stack):
                stack.append(stack[-1][-1]['sub'])
            stack[-1].append(entry)
        return toc

    def execute(self):
        """ Execute this generator regarding its current configuration.
        """
        if self.direct:
            if self.file_type == 'pdf':
                raise IOError("Direct output mode is not available for PDF "
                              "export")
            else:
                print(self.render().encode(self.encoding))
        else:
            self.write_and_log()

            if self.watch:
                from .watcher import watch

                self.log(u"Watching %s\n" % self.watch_dir)

                watch(self.watch_dir, self.write_and_log)

    def write_and_log(self):
        self.watch_files = []
        self.num_slides = 0
        self.__toc = []
        self.write()
        self.log(u"Generated file: %s" % self.destination_file)

    def get_template_file(self):
        """ Retrieves Jinja2 template file path.
        """
        if os.path.exists(os.path.join(self.theme_dir, 'base.html')):
            return os.path.join(self.theme_dir, 'base.html')
        default_dir = os.path.join(THEMES_DIR, 'default')
        if not os.path.exists(os.path.join(default_dir, 'base.html')):
            raise IOError("Cannot find base.html in default theme")
        return os.path.join(default_dir, 'base.html')

    def fetch_contents(self, source, work_dir):
        """ Recursively fetches Markdown contents from a single file or
            directory containing itself Markdown/RST files.
        """
        slides = []

        if type(source) is list:
            for entry in source:
                slides.extend(self.fetch_contents(entry, work_dir))
        else:
            source = os.path.normpath(os.path.join(work_dir, source))
            if os.path.isdir(source):
                self.log(u"Entering %r" % source)
                entries = os.listdir(source)
                entries.sort()
                for entry in entries:
                    slides.extend(self.fetch_contents(entry, source))
            else:
                try:
                    parser = Parser(os.path.splitext(source)[1], self.encoding, self.extensions)
                except NotImplementedError as exc:
                    self.log(u"Failed   %r: %r" % (source, exc))
                    return slides

                self.log(u"Adding   %r (%s)" % (source, parser.format))

                try:
                    with codecs.open(source, encoding=self.encoding) as file:
                        file_contents = file.read()
                except UnicodeDecodeError:
                    self.log(u"Unable to decode source %r: skipping" % source,
                             'warning')
                else:
                    inner_slides = re.split(r'', parser.parse(file_contents))
                    for inner_slide in inner_slides:
                        slides.append(self.get_slide_vars(inner_slide, source))

        if not slides:
            self.log(u"Exiting  %r: no contents found" % source, 'notice')

        return slides

    def find_theme_dir(self, theme, copy_theme=False):
        """ Finds them dir path from its name.
        """
        if os.path.exists(theme):
            self.theme_dir = theme
        elif os.path.exists(os.path.join(THEMES_DIR, theme)):
            self.theme_dir = os.path.join(THEMES_DIR, theme)
        else:
            raise IOError("Theme %s not found or invalid" % theme)
        target_theme_dir = os.path.join(os.getcwd(), 'theme')
        if copy_theme or os.path.exists(target_theme_dir):
            self.log(u'Copying %s theme directory to %s'
                     % (theme, target_theme_dir))
            if not os.path.exists(target_theme_dir):
                try:
                    shutil.copytree(self.theme_dir, target_theme_dir)
                except Exception as e:
                    self.log(u"Skipped copy of theme folder: %s" % e)
                    pass
            self.theme_dir = target_theme_dir
        return self.theme_dir

    def get_css(self):
        """ Fetches and returns stylesheet file path or contents, for both
            print and screen contexts, depending if we want a standalone
            presentation or not.
        """
        css = {}

        base_css = os.path.join(self.theme_dir, 'css', 'base.css')
        if not os.path.exists(base_css):
            base_css = os.path.join(THEMES_DIR, 'default', 'css', 'base.css')
            if not os.path.exists(base_css):
                raise IOError(u"Cannot find base.css in default theme")
        with codecs.open(base_css, encoding=self.encoding) as css_file:
            css['base'] = {
                'path_url': utils.get_path_url(base_css, self.relative and self.destination_dir),
                'contents': css_file.read(),
            }

        print_css = os.path.join(self.theme_dir, 'css', 'print.css')
        if not os.path.exists(print_css):
            print_css = os.path.join(THEMES_DIR, 'default', 'css', 'print.css')
            if not os.path.exists(print_css):
                raise IOError(u"Cannot find print.css in default theme")
        with codecs.open(print_css, encoding=self.encoding) as css_file:
            css['print'] = {
                'path_url': utils.get_path_url(print_css, self.relative and self.destination_dir),
                'contents': css_file.read(),
            }

        screen_css = os.path.join(self.theme_dir, 'css', 'screen.css')
        if not os.path.exists(screen_css):
            screen_css = os.path.join(THEMES_DIR, 'default', 'css', 'screen.css')
            if not os.path.exists(screen_css):
                raise IOError(u"Cannot find screen.css in default theme")
        with codecs.open(screen_css, encoding=self.encoding) as css_file:
            css['screen'] = {
                'path_url': utils.get_path_url(screen_css, self.relative and self.destination_dir),
                'contents': css_file.read(),
            }

        theme_css = os.path.join(self.theme_dir, 'css', 'theme.css')
        if not os.path.exists(theme_css):
            theme_css = os.path.join(THEMES_DIR, 'default', 'css', 'theme.css')
            if not os.path.exists(theme_css):
                raise IOError(u"Cannot find theme.css in default theme")
        with codecs.open(theme_css, encoding=self.encoding) as css_file:
            css['theme'] = {
                'path_url': utils.get_path_url(theme_css, self.relative and self.destination_dir),
                'contents': css_file.read(),
            }

        return css

    def get_js(self):
        """ Fetches and returns javascript file path or contents, depending if
            we want a standalone presentation or not.
        """
        js_file = os.path.join(self.theme_dir, 'js', 'slides.js')

        if not os.path.exists(js_file):
            js_file = os.path.join(THEMES_DIR, 'default', 'js', 'slides.js')

            if not os.path.exists(js_file):
                raise IOError(u"Cannot find slides.js in default theme")
        with codecs.open(js_file, encoding=self.encoding) as js_file_obj:
            return {
                'path_url': utils.get_path_url(js_file, self.relative and self.destination_dir),
                'contents': js_file_obj.read(),
            }

    def get_slide_vars(self, slide_src, source,
                       _presenter_notes_re=re.compile(r']*>presenter notes',
                                                      re.DOTALL | re.UNICODE | re.IGNORECASE),
                       _slide_title_re=re.compile(r'((.+?))\s?(.+)?', re.DOTALL | re.UNICODE)):
        """ Computes a single slide template vars from its html source code.
            Also extracts slide information for the table of contents.
        """
        presenter_notes = None

        find = _presenter_notes_re.search(slide_src)

        if find:
            if self.presenter_notes:
                presenter_notes = slide_src[find.end():].strip()

            slide_src = slide_src[:find.start()]

        find = _slide_title_re.search(slide_src)

        if not find:
            header = level = title = None
            content = slide_src.strip()
        else:
            header = find.group(1)
            level = int(find.group(2))
            title = find.group(3)
            content = find.group(4).strip() if find.group(4) else find.group(4)

        slide_classes = []
        context = {}

        if header:
            header, _ = self.process_macros(header, source, context)

        if content:
            content, slide_classes = self.process_macros(content, source, context)

        source_dict = {}

        if source:
            source_dict = {
                'rel_path': source.decode(sys.getfilesystemencoding(), 'ignore') if isinstance(source,
                                                                                               binary_type) else source,
                'abs_path': os.path.abspath(source)
            }

        if header or content:
            context.update(
                content=content,
                classes=slide_classes,
                header=header,
                level=level,
                math_output=self.math_output,
                presenter_notes=presenter_notes,
                source=source_dict,
                title=title,
            )
            return context

    def get_template_vars(self, slides):
        """ Computes template vars from slides html source code.
        """
        try:
            head_title = slides[0]['title']
        except (IndexError, TypeError):
            head_title = "Untitled Presentation"

        for slide_index, slide_vars in enumerate(slides):
            if not slide_vars:
                continue
            self.num_slides += 1
            slide_number = slide_vars['number'] = self.num_slides
            if slide_vars['level'] and slide_vars['level'] <= TOC_MAX_LEVEL:
                self.add_toc_entry(slide_vars['title'], slide_vars['level'],
                                   slide_number)
            else:
                # Put something in the TOC even if it doesn't have a title or level
                self.add_toc_entry(u"-", 1, slide_number)

        return {'head_title': head_title, 'num_slides': str(self.num_slides),
                'slides': slides, 'toc': self.toc, 'embed': self.embed,
                'css': self.get_css(), 'js': self.get_js(),
                'user_css': self.user_css, 'user_js': self.user_js,
                'math_output': self.math_output, 'version': __version__}

    def linenos_check(self, value):
        """ Checks and returns a valid value for the ``linenos`` option.
        """
        return value if value in VALID_LINENOS else 'inline'

    def log(self, message, type='notice'):
        """ Logs a message (eventually, override to do something more clever).
        """
        if self.logger and not callable(self.logger):
            raise ValueError(u"Invalid logger set, must be a callable")
        if self.verbose and self.logger:
            self.logger(message, type)

    def parse_config(self, config_source):
        """ Parses a landslide configuration file and returns a normalized
            python dict.
        """
        self.log(u"Config   %s" % config_source)
        try:
            raw_config = configparser.RawConfigParser()
            raw_config.read(config_source)
        except Exception as e:
            raise RuntimeError(u"Invalid configuration file: %s" % e)
        config = {}
        config['source'] = raw_config.get('landslide', 'source') \
            .replace('\r', '').split('\n')
        if raw_config.has_option('landslide', 'theme'):
            config['theme'] = raw_config.get('landslide', 'theme')
            self.log(u"Using    configured theme %s" % config['theme'])
        if raw_config.has_option('landslide', 'destination'):
            config['destination'] = raw_config.get('landslide', 'destination')
        if raw_config.has_option('landslide', 'linenos'):
            config['linenos'] = raw_config.get('landslide', 'linenos')
        for boolopt in ('embed', 'relative', 'copy_theme', 'math_output'):
            if raw_config.has_option('landslide', boolopt):
                config[boolopt] = raw_config.getboolean('landslide', boolopt)
        if raw_config.has_option('landslide', 'extensions'):
            config['extensions'] = ",".join(raw_config.get('landslide', 'extensions').replace('\r', '').split('\n'))
        if raw_config.has_option('landslide', 'css'):
            config['css'] = raw_config.get('landslide', 'css').replace('\r', '').split('\n')
        if raw_config.has_option('landslide', 'js'):
            config['js'] = raw_config.get('landslide', 'js').replace('\r', '').split('\n')
        return config

    def process_macros(self, content, source, context):
        """ Processed all macros.
        """
        classes = []
        for macro in self.macros:
            content, add_classes = macro.process(content, source, context)
            if add_classes:
                classes += add_classes
        return content, classes

    def register_macro(self, *macros):
        """ Registers macro classes passed a method arguments.
        """
        macro_options = {'relative': self.relative, 'linenos': self.linenos, 'destination_dir': self.destination_dir}
        for m in macros:
            if inspect.isclass(m) and issubclass(m, macro_module.Macro):
                self.macros.append(m(logger=self.logger, embed=self.embed, options=macro_options))
            else:
                raise TypeError("Couldn't register macro; a macro must inherit"
                                " from macro.Macro")

    def render(self):
        """ Returns generated html code.
        """
        with codecs.open(self.template_file, encoding=self.encoding) as template_src:
            template = jinja2.Template(template_src.read())
        slides = self.fetch_contents(self.source, self.work_dir)
        context = self.get_template_vars(slides)

        html = template.render(context)

        if self.embed:
            images = re.findall(r'url\(["\']?(.*?\.(?:jpe?g|gif|png|svg)[\'"]?)\)', html, re.DOTALL | re.UNICODE)

            for img_url in images:
                img_url = img_url.replace('"', '').replace("'", '')
                if self.theme_dir:
                    source = os.path.join(self.theme_dir, 'css')
                else:
                    source = os.path.join(THEMES_DIR, self.theme, 'css')

                encoded_url = utils.encode_image_from_url(img_url, source)
                if encoded_url:
                    html = html.replace(img_url, encoded_url, 1)
                    self.log("Embedded theme image %s from theme directory %s" % (img_url, source))
                else:
                    # Missing file in theme directory. Try user_css folders
                    found = False
                    for css_entry in context['user_css']:
                        directory = os.path.dirname(css_entry['path_url'])
                        if not directory:
                            directory = "."

                        encoded_url = utils.encode_image_from_url(img_url, directory)

                        if encoded_url:
                            found = True
                            html = html.replace(img_url, encoded_url, 1)
                            self.log("Embedded theme image %s from directory %s" % (img_url, directory))

                    if not found:
                        # Missing image file, etc...
                        self.log(u"Failed to embed theme image %s" % img_url)

        return html

    def write(self):
        """ Writes generated presentation code into the destination file.
        """
        html = self.render()

        if self.file_type == 'pdf':
            self.write_pdf(html)
        else:
            dirname = os.path.dirname(self.destination_file)
            if dirname and not os.path.exists(dirname):
                os.makedirs(dirname)
            with codecs.open(self.destination_file, 'w',
                             encoding='utf_8') as outfile:
                outfile.write(html)

    def write_pdf(self, html):
        """ Tries to write a PDF export from the command line using PrinceXML
            if available.
        """
        try:
            f = tempfile.NamedTemporaryFile(delete=False, suffix='.html')
            f.write(html.encode('utf_8', 'xmlcharrefreplace'))
            f.close()
        except Exception:
            raise IOError("Unable to create temporary file, aborting")

        dummy_fh = open(os.path.devnull, 'w')

        try:
            command = ["prince", f.name, self.destination_file]

            Popen(command, stderr=dummy_fh).communicate()
        except Exception:
            raise EnvironmentError("Unable to generate PDF file using "
                                   "prince. Is it installed and available?")
        finally:
            dummy_fh.close()
python-darkslide-2.3.3/src/darkslide/macro.py000066400000000000000000000153341271614724200212200ustar00rootroot00000000000000# -*- coding: utf-8 -*-
import os
import re
import sys
try:
    from io import BytesIO as StringIO
except ImportError:
    from StringIO import StringIO

import pygments
import qrcode
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_by_name
from qrcode.image.svg import SvgPathImage
from six.moves import html_entities

from . import utils


class Macro(object):
    """Base class for altering slide HTML during presentation generation"""

    def __init__(self, logger=sys.stdout, embed=False, options=None):
        self.logger = logger
        self.embed = embed
        if options:
            if not isinstance(options, dict):
                raise ValueError(u'Macro options must be a dict instance')
            self.options = options
        else:
            self.options = {}

    def process(self, content, source=None, context=None):
        """Generic processor (does actually nothing)"""
        return content, []


class CodeHighlightingMacro(Macro):
    """Performs syntax coloration in slide code blocks using Pygments"""

    macro_re = re.compile(
        r'(()?\s?!(\S+?)\n(.*?)()?
)', re.UNICODE | re.MULTILINE | re.DOTALL) html_entity_re = re.compile('&(\w+?);') def descape(self, string, defs=None): """Decodes html entities from a given string""" if defs is None: defs = html_entities.entitydefs def replacer(m): if len(m.groups()) > 0: return defs[m.group(1)] else: return m.group(0) return self.html_entity_re.sub(replacer, string) def process(self, content, source=None, context=None): code_blocks = self.macro_re.findall(content) if not code_blocks: return content, [] classes = [] for block, void1, lang, code, void2 in code_blocks: try: lexer = get_lexer_by_name(lang, startinline=True) except Exception: self.logger(u"Unknown pygment lexer \"%s\", skipping" % lang, 'warning') return content, classes if 'linenos' not in self.options or self.options['linenos'] == 'no': self.options['linenos'] = False formatter = HtmlFormatter(linenos=self.options['linenos'], nobackground=True) pretty_code = pygments.highlight(self.descape(code), lexer, formatter) content = content.replace(block, pretty_code, 1) return content, [u'has_code'] class EmbedImagesMacro(Macro): """Encodes images in base64 for embedding in image:data""" macro_re = re.compile( r'|]+?data="(.*?)"[^<>]+?type="image/svg\+xml"', re.DOTALL | re.UNICODE) def process(self, content, source=None, context=None): classes = [] if not self.embed: return content, classes images = self.macro_re.findall(content) source_dir = os.path.dirname(source) for image_url, data_url in images: encoded_url = utils.encode_image_from_url(image_url or data_url, source_dir) if not encoded_url: self.logger(u"Failed to embed image \"%s\"" % image_url, 'warning') return content, classes if image_url: content = content.replace(u"src=\"" + image_url, u"src=\"" + encoded_url, 1) else: content = content.replace(u"data=\"" + data_url, u"data=\"" + encoded_url, 1) self.logger(u"Embedded image %s" % (image_url or data_url), 'notice') return content, classes class FixImagePathsMacro(Macro): """Replaces html image paths with fully qualified absolute urls""" macro_re = re.compile( r']+?data="(?!http://)(.*?)"[^<>]+?type="image/svg\+xml"', re.DOTALL | re.UNICODE ) def process(self, content, source=None, context=None): classes = [] if self.embed: return content, classes base_path = utils.get_path_url(source, self.options['relative'] and self.options['destination_dir']) base_url = os.path.split(base_path)[0] images = self.macro_re.findall(content) for matches in images: for image in matches: if image: full_path = '"%s"' % os.path.join(base_url, image) image = '"%s"' % image content = content.replace(image, full_path) return content, classes class FxMacro(Macro): """Adds custom CSS class to slides""" macro_re = re.compile(r'(

\.fx:\s?(.*?)

\n?)', re.DOTALL | re.UNICODE) def process(self, content, source=None, context=None): classes = [] fx_match = self.macro_re.search(content) if fx_match: classes = fx_match.group(2).split(u' ') content = content.replace(fx_match.group(1), '', 1) return content, classes class NotesMacro(Macro): """Adds toggleable notes to slides""" macro_re = re.compile(r'

\.notes:\s?(.*?)

') def process(self, content, source=None, context=None): classes = [] new_content = self.macro_re.sub(r'

\1

', content) if content != new_content: classes.append(u'has_notes') return new_content, classes class QRMacro(Macro): """Generates a QR code in a slide""" macro_re = re.compile(r'

\.qr:\s?(.*?)

') def process(self, content, source=None, context=None): classes = [] def encoder(match): qr = qrcode.QRCode(1, error_correction=qrcode.ERROR_CORRECT_L, box_size=40) qr.add_data(match.group(1)) buff = StringIO() qr.make_image(image_factory=SvgPathImage).save(buff) return '

%s

' % buff.getvalue().decode('utf-8') new_content = self.macro_re.sub(encoder, content) if content != new_content: classes.append(u'has_qr') return new_content, classes class FooterMacro(Macro): """Add footer in slides""" footer = '' macro_re = re.compile(r'

\.footer:\s?(.*?)

') def process(self, content, source=None, context=None): classes = [] def save(match): self.footer = match.group(1) return '' content = self.macro_re.sub(save, content) if self.footer: classes.append(u'has_footer') context['footer'] = self.footer return content, classes python-darkslide-2.3.3/src/darkslide/parser.py000066400000000000000000000056461271614724200214200ustar00rootroot00000000000000# -*- coding: utf-8 -*- import re SUPPORTED_FORMATS = { 'markdown': ['.mdown', '.markdown', '.markdn', '.md', '.mdn', '.mdwn'], 'restructuredtext': ['.rst', '.rest'], 'textile': ['.textile'], } class Parser(object): """This class generates the HTML code depending on which syntax is used in the souce document. The Parser currently supports both Markdown and restructuredText syntaxes. """ RST_REPLACEMENTS = [ (r'', r'', re.UNICODE), (r'
', r'', re.UNICODE), (r'

.*?

', r'', re.UNICODE), (r'Document or section may not begin with a transition\.', r'', re.UNICODE), (r'', r'', re.DOTALL | re.UNICODE), (r'\n', r'
\n', re.DOTALL | re.UNICODE), ] md_extensions = '' def __init__(self, extension, encoding='utf8', md_extensions=''): """Configures this parser. """ self.encoding = encoding self.format = None for supp_format, supp_extensions in SUPPORTED_FORMATS.items(): for supp_extension in supp_extensions: if supp_extension == extension: self.format = supp_format if not self.format: raise NotImplementedError(u"Unsupported format %s" % extension) if md_extensions: exts = (value.strip() for value in md_extensions.split(',')) self.md_extensions = filter(None, exts) def parse(self, text): """Parses and renders a text as HTML regarding current format. """ if self.format == 'markdown': try: import markdown except ImportError: raise RuntimeError(u"Looks like markdown is not installed") if text.startswith(u'\ufeff'): # check for unicode BOM text = text[1:] return markdown.markdown(text, self.md_extensions) elif self.format == 'restructuredtext': try: from .rst import html_body except ImportError: raise RuntimeError(u"Looks like docutils are not installed") html = html_body(text, input_encoding=self.encoding) # RST generates pretty much markup to be removed in our case for (pattern, replacement, mode) in self.RST_REPLACEMENTS: html = re.sub(re.compile(pattern, mode), replacement, html, 0) return html.strip() elif self.format == 'textile': try: import textile except ImportError: raise RuntimeError(u"Looks like textile is not installed") text = text.replace('\n---\n', '\n
\n') return textile.textile(text, encoding=self.encoding) else: raise NotImplementedError(u"Unsupported format %s, cannot parse" % self.format) python-darkslide-2.3.3/src/darkslide/rst.py000066400000000000000000000071601271614724200207250ustar00rootroot00000000000000# -*- coding: utf-8 -*- from pygments import highlight from pygments.formatters import HtmlFormatter from pygments.lexers import get_lexer_by_name, TextLexer from docutils import core, nodes from docutils.parsers.rst import directives, Directive class Pygments(Directive): """ Source code syntax hightlighting for ReST syntax.""" required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True option_spec = { 'linenos': directives.flag, 'emphasize-lines': directives.unchanged_required, } 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() args = {'noclasses': False} if 'linenos' in self.options: args['linenos'] = 'table' if 'emphasize-lines' in self.options: args['hl_lines'] = self.options['emphasize-lines'].split(',') formatter = HtmlFormatter(**args) parsed = highlight(u'\n'.join(self.content), lexer, formatter) return [nodes.raw('', parsed, format='html')] directives.register_directive('sourcecode', Pygments) directives.register_directive('code-block', Pygments) def html_parts(input_string, source_path=None, destination_path=None, input_encoding='unicode', doctitle=1, initial_header_level=1): """ Given an input string, returns a dictionary of HTML document parts. Dictionary keys are the names of parts, and values are Unicode strings; encoding is up to the client. Parameters: - `input_string`: A multi-line text string; required. - `source_path`: Path to the source file or object. Optional, but useful for diagnostic output (system messages). - `destination_path`: Path to the file or object which will receive the output; optional. Used for determining relative paths (stylesheets, source links, etc.). - `input_encoding`: The encoding of `input_string`. If it is an encoded 8-bit string, provide the correct encoding. If it is a Unicode string, use "unicode", the default. - `doctitle`: Disable the promotion of a lone top-level section title to document title (and subsequent section title to document subtitle promotion); enabled by default. - `initial_header_level`: The initial level for header elements (e.g. 1 for "

"). """ overrides = { 'input_encoding': input_encoding, 'doctitle_xform': doctitle, 'initial_header_level': initial_header_level, 'report_level': 5 } parts = core.publish_parts( source=input_string, source_path=source_path, destination_path=destination_path, writer_name='html', settings_overrides=overrides) return parts def html_body(input_string, source_path=None, destination_path=None, input_encoding='unicode', doctitle=1, initial_header_level=1): """ Given an input string, returns an HTML fragment as a string. The return value is the contents of the element. Parameters (see `html_parts()` for the remainder): - `output_encoding`: The desired encoding of the output. If a Unicode string is desired, use the default value of "unicode" . """ parts = html_parts( input_string=input_string, source_path=source_path, destination_path=destination_path, input_encoding=input_encoding, doctitle=doctitle, initial_header_level=initial_header_level) fragment = parts['html_body'] return fragment python-darkslide-2.3.3/src/darkslide/themes/000077500000000000000000000000001271614724200210245ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/abyss/000077500000000000000000000000001271614724200221455ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/abyss/css/000077500000000000000000000000001271614724200227355ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/abyss/css/theme.css000066400000000000000000000225461271614724200245620ustar00rootroot00000000000000/* ====================================== FONTS ====================================== */ h1, h2, h3, h4, h5, h6, body, header { font-family: 'Candara', 'Calibri', 'Segoe UI Semilight', 'Corbel', 'Trebuchet Ms', 'Segoe UI', sans-serif; } section { font: 34px 'Palatino', 'Palatino Linotype', 'URW Palladio L', 'Century Schoolbook L', 'Georgia', serif; } /* ====================================== COLORS ====================================== */ .yellow { color: #b58900; } .orange { color: #cb4b16; } .red { color: #dc322f; } .magenta { color: #d33682; } .violet { color: #6c71c4; } .blue { color: #268bd2; } .cyan { color: #2aa198; } .green { color: #859900; } body { background: black; color: #eee; } footer { color: #aaa; } a, a:hover { color: #268bd2; padding: 0; text-decoration: none; background-color: transparent; background-image: linear-gradient(#268bd2, #268bd2); background-size: 1px 1px; background-repeat: repeat-x; background-position: 0% 95%; text-shadow: -0.06em -0.03ex #222,-0.06em -0.06ex #222,-0.06em -0.09ex #222,0.12em 0ex #222,-0.09em -0.09ex #222,-0.09em -0.06ex #222,-0.09em -0.03ex #222,0.12em -0.21ex #222,0.12em -0.27ex #222,0.12em -0.24ex #222,0em 0.08ex #222,0em -0.18ex #222,0em -0.15ex #222,0em 0.02ex #222,-0.06em 0ex #222,-0.03em 0ex #222,0em 0.06ex #222,0em -0.12ex #222,-0.12em -0.06ex #222,-0.12em -0.03ex #222,0.15em 0ex #222,-0.12em -0.09ex #222,0.03em -0.21ex #222,-0.09em -0.18ex #222,0.03em -0.24ex #222,0.03em -0.27ex #222,-0.09em -0.12ex #222,-0.09em -0.15ex #222,0.09em -0.27ex #222,0.09em -0.24ex #222,0.09em -0.21ex #222,0em 0ex #222,-0.15em 0.08ex #222,0.06em 0ex #222,0.12em -0.12ex #222,-0.15em 0.02ex #222,-0.15em 0.06ex #222,-0.15em 0.04ex #222,-0.15em -0.15ex #222,-0.09em -0.21ex #222,-0.09em -0.27ex #222,-0.09em -0.24ex #222,0.06em 0.08ex #222,-0.06em -0.21ex #222,0.06em 0.06ex #222,0.06em 0.04ex #222,-0.15em -0.18ex #222,-0.06em -0.24ex #222,-0.06em -0.27ex #222,0.15em 0.08ex #222,0.12em -0.09ex #222,0.03em 0.02ex #222,0.03em 0.04ex #222,0.03em 0.06ex #222,0.09em -0.18ex #222,0.03em 0.08ex #222,0.09em -0.15ex #222,0.12em -0.03ex #222,0.09em -0.12ex #222,0.12em -0.06ex #222,0.15em 0.02ex #222,-0.15em -0.03ex #222,-0.06em -0.15ex #222,-0.15em -0.06ex #222,-0.06em -0.12ex #222,-0.15em -0.09ex #222,-0.12em -0.21ex #222,-0.06em -0.18ex #222,-0.12em -0.27ex #222,-0.12em -0.24ex #222,-0.03em 0.04ex #222,-0.03em 0.06ex #222,0.09em -0.09ex #222,-0.03em 0.02ex #222,0.09em -0.06ex #222,-0.03em 0.08ex #222,0.09em -0.03ex #222,0.09em 0ex #222,0em -0.09ex #222,0em -0.06ex #222,-0.15em 0ex #222,0em -0.03ex #222,-0.12em 0.02ex #222,0.12em 0.06ex #222,-0.12em 0.06ex #222,-0.12em 0.04ex #222,-0.12em -0.12ex #222,-0.12em 0.08ex #222,0.15em -0.15ex #222,0.15em -0.12ex #222,-0.03em -0.24ex #222,0em -0.24ex #222,-0.03em -0.27ex #222,0.15em -0.18ex #222,-0.03em -0.21ex #222,0.06em -0.24ex #222,0.06em -0.27ex #222,-0.09em 0ex #222,0.06em -0.21ex #222,-0.15em -0.12ex #222,-0.06em 0.08ex #222,-0.06em 0.02ex #222,-0.06em 0.06ex #222,-0.06em 0.04ex #222,-0.12em -0.18ex #222,-0.15em -0.21ex #222,-0.15em -0.24ex #222,-0.15em -0.27ex #222,0.06em 0.02ex #222,0.15em -0.21ex #222,0.03em 0ex #222,0.15em -0.27ex #222,0.09em 0.02ex #222,0.12em -0.18ex #222,0.09em 0.06ex #222,0.09em 0.04ex #222,0em 0.04ex #222,0.09em 0.08ex #222,0.12em -0.15ex #222,-0.03em -0.03ex #222,-0.03em -0.06ex #222,-0.12em -0.15ex #222,0em -0.27ex #222,0em -0.21ex #222,-0.03em -0.09ex #222,0.06em -0.09ex #222,0.03em -0.18ex #222,0.12em 0.08ex #222,0.03em -0.15ex #222,0.12em 0.04ex #222,0.12em 0.02ex #222,0.06em -0.06ex #222,0.03em -0.12ex #222,-0.03em -0.12ex #222,-0.03em -0.15ex #222,-0.03em -0.18ex #222,0.15em 0.06ex #222,0.15em 0.04ex #222,0.15em -0.06ex #222,0.15em -0.03ex #222,0.15em -0.09ex #222,0.06em -0.18ex #222,0.03em -0.09ex #222,0.03em -0.03ex #222,0.06em -0.12ex #222,0.03em -0.06ex #222,0.06em -0.15ex #222,0.06em -0.03ex #222,-0.09em 0.08ex #222,-0.09em 0.02ex #222,-0.12em 0ex #222,-0.09em 0.06ex #222,-0.09em 0.04ex #222,0.15em -0.24ex #222; } a:hover { color: #2aa198; background-image: linear-gradient(#2aa198, #2aa198), linear-gradient(#2aa198, #2aa198), linear-gradient(#2aa198, #2aa198); } .presenter_notes a, .presenter_notes a:hover, div#current_presenter_notes a, div#current_presenter_notes a:hover { text-shadow: -0.06em -0.03ex #eee,-0.06em -0.06ex #eee,-0.06em -0.09ex #eee,0.12em 0ex #eee,-0.09em -0.09ex #eee,-0.09em -0.06ex #eee,-0.09em -0.03ex #eee,0.12em -0.21ex #eee,0.12em -0.27ex #eee,0.12em -0.24ex #eee,0em 0.08ex #eee,0em -0.18ex #eee,0em -0.15ex #eee,0em 0.02ex #eee,-0.06em 0ex #eee,-0.03em 0ex #eee,0em 0.06ex #eee,0em -0.12ex #eee,-0.12em -0.06ex #eee,-0.12em -0.03ex #eee,0.15em 0ex #eee,-0.12em -0.09ex #eee,0.03em -0.21ex #eee,-0.09em -0.18ex #eee,0.03em -0.24ex #eee,0.03em -0.27ex #eee,-0.09em -0.12ex #eee,-0.09em -0.15ex #eee,0.09em -0.27ex #eee,0.09em -0.24ex #eee,0.09em -0.21ex #eee,0em 0ex #eee,-0.15em 0.08ex #eee,0.06em 0ex #eee,0.12em -0.12ex #eee,-0.15em 0.02ex #eee,-0.15em 0.06ex #eee,-0.15em 0.04ex #eee,-0.15em -0.15ex #eee,-0.09em -0.21ex #eee,-0.09em -0.27ex #eee,-0.09em -0.24ex #eee,0.06em 0.08ex #eee,-0.06em -0.21ex #eee,0.06em 0.06ex #eee,0.06em 0.04ex #eee,-0.15em -0.18ex #eee,-0.06em -0.24ex #eee,-0.06em -0.27ex #eee,0.15em 0.08ex #eee,0.12em -0.09ex #eee,0.03em 0.02ex #eee,0.03em 0.04ex #eee,0.03em 0.06ex #eee,0.09em -0.18ex #eee,0.03em 0.08ex #eee,0.09em -0.15ex #eee,0.12em -0.03ex #eee,0.09em -0.12ex #eee,0.12em -0.06ex #eee,0.15em 0.02ex #eee,-0.15em -0.03ex #eee,-0.06em -0.15ex #eee,-0.15em -0.06ex #eee,-0.06em -0.12ex #eee,-0.15em -0.09ex #eee,-0.12em -0.21ex #eee,-0.06em -0.18ex #eee,-0.12em -0.27ex #eee,-0.12em -0.24ex #eee,-0.03em 0.04ex #eee,-0.03em 0.06ex #eee,0.09em -0.09ex #eee,-0.03em 0.02ex #eee,0.09em -0.06ex #eee,-0.03em 0.08ex #eee,0.09em -0.03ex #eee,0.09em 0ex #eee,0em -0.09ex #eee,0em -0.06ex #eee,-0.15em 0ex #eee,0em -0.03ex #eee,-0.12em 0.02ex #eee,0.12em 0.06ex #eee,-0.12em 0.06ex #eee,-0.12em 0.04ex #eee,-0.12em -0.12ex #eee,-0.12em 0.08ex #eee,0.15em -0.15ex #eee,0.15em -0.12ex #eee,-0.03em -0.24ex #eee,0em -0.24ex #eee,-0.03em -0.27ex #eee,0.15em -0.18ex #eee,-0.03em -0.21ex #eee,0.06em -0.24ex #eee,0.06em -0.27ex #eee,-0.09em 0ex #eee,0.06em -0.21ex #eee,-0.15em -0.12ex #eee,-0.06em 0.08ex #eee,-0.06em 0.02ex #eee,-0.06em 0.06ex #eee,-0.06em 0.04ex #eee,-0.12em -0.18ex #eee,-0.15em -0.21ex #eee,-0.15em -0.24ex #eee,-0.15em -0.27ex #eee,0.06em 0.02ex #eee,0.15em -0.21ex #eee,0.03em 0ex #eee,0.15em -0.27ex #eee,0.09em 0.02ex #eee,0.12em -0.18ex #eee,0.09em 0.06ex #eee,0.09em 0.04ex #eee,0em 0.04ex #eee,0.09em 0.08ex #eee,0.12em -0.15ex #eee,-0.03em -0.03ex #eee,-0.03em -0.06ex #eee,-0.12em -0.15ex #eee,0em -0.27ex #eee,0em -0.21ex #eee,-0.03em -0.09ex #eee,0.06em -0.09ex #eee,0.03em -0.18ex #eee,0.12em 0.08ex #eee,0.03em -0.15ex #eee,0.12em 0.04ex #eee,0.12em 0.02ex #eee,0.06em -0.06ex #eee,0.03em -0.12ex #eee,-0.03em -0.12ex #eee,-0.03em -0.15ex #eee,-0.03em -0.18ex #eee,0.15em 0.06ex #eee,0.15em 0.04ex #eee,0.15em -0.06ex #eee,0.15em -0.03ex #eee,0.15em -0.09ex #eee,0.06em -0.18ex #eee,0.03em -0.09ex #eee,0.03em -0.03ex #eee,0.06em -0.12ex #eee,0.03em -0.06ex #eee,0.06em -0.15ex #eee,0.06em -0.03ex #eee,-0.09em 0.08ex #eee,-0.09em 0.02ex #eee,-0.12em 0ex #eee,-0.09em 0.06ex #eee,-0.09em 0.04ex #eee,0.15em -0.24ex #eee; } code, tt.docutils.literal { color: #6c71c4; } div.slide { background-color: #222; color: #eee; } body.expose div.slide:hover { box-shadow: 0 0 0 15px #268bd2; } body.expose .slide.current { box-shadow: 0 0 0 30px #b58900; } body.expose .slide.current:hover { box-shadow: 0 0 0 15px #268bd2, 0 0 0 30px #b58900; } .presenter_notes { background: #eee; color: #222; } ::-webkit-scrollbar-thumb { background: #222; border-color: #444; } ::-webkit-scrollbar { background: #444; border-color: #444; } ::-webkit-scrollbar-corner { background: #222; } .qr svg { box-shadow: inset 0 0 10px #eee8d5; } div.slides, body.expose div.slides.nocontext, body.expose .slide.current, body.expose .slide.current .inner { /*background: #000;*/ } /* See: http://stylishthemes.github.io/GitHub-Dark/ */ /* Synic syntax highlighting */ pre pre:not(.diff-line-pre),pre table{background:#000!important;color:#fffff0!important;} pre .hll{background-color:#ffc!important;} pre .cp{color:#ffa0a0!important;} pre .gd{color:#add8e6!important;background-color:#e0ffff!important;} pre .ge{color:#fffff0!important;text-decoration:underline!important;} pre .gi{color:#00f!important;background-color:#e0ffff!important;} pre .go{color:#008b8b!important;} pre .ni{color:#daa520!important;} pre .ow{color:#8673e8!important;} pre .c,pre .cm,pre .c1,pre .cs{color:#708090!important;} pre .err,pre .g,pre .l,pre .n,pre .o,pre .x,pre .p,pre .gp, pre .gs,pre .ld,pre .nb,pre .nc,pre .nd,pre .nn,pre .nx,pre .py, pre .w,pre .bp{color:#fffff0!important;} pre .k,pre .kc,pre .kd,pre .kn,pre .kp,pre .kr, pre .nt{color:#f0e68c!important;} pre .gr,pre .gt{color:red!important;background-color:#faf0e6!important;border-radius:2px;} pre .gh,pre .gu{color:#ee0!important;} pre .kt,pre .ne,pre .nl{color:#ffdead!important;} pre .m,pre .no,pre .mf,pre .mh,pre .mi,pre .mo, pre .il{color:#cdb7b5!important;} pre .s,pre .sb,pre .sc,pre .sd,pre .s2,pre .se,pre .sh,pre .si, pre .sx,pre .sr,pre .s1,pre .ss{color:#9ac0cd!important;} pre .na,pre .nf,pre .nv,pre .vc,pre .vg, pre .vi{color:#68838b!important;font-weight:700!important;} .white { background: white; } python-darkslide-2.3.3/src/darkslide/themes/default/000077500000000000000000000000001271614724200224505ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/default/base.html000066400000000000000000000141241271614724200242520ustar00rootroot00000000000000 {{ head_title }} {% if embed %} {% else %} {% endif %} {% for css in user_css %} {% if embed %} {% else %} {% endif %} {% endfor %} {% if embed %} {% else %} {% endif %} {% for js in user_js %} {% if embed %} {% else %} {% endif %} {% endfor %} {% if math_output %} {% endif %}
{% for slide in slides %}
{% if slide.header %}
{{ slide.header }}
{% endif %} {% if slide.content %}
{{ slide.content }}
{% endif %}

Presenter Notes

{% if slide.presenter_notes %} {{ slide.presenter_notes }} {% endif %}
{% if slide.footer %} {{ slide.footer }} {% endif %} {% if slide.source %} {% endif %}
{% endfor %}
{% if toc %} {% endif %} python-darkslide-2.3.3/src/darkslide/themes/default/css/000077500000000000000000000000001271614724200232405ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/default/css/base.css000066400000000000000000000051751271614724200246740ustar00rootroot00000000000000h1, h2, h3, h4, h5, h6, p, body, header { padding: 0; margin: 0; } div.slide { position: absolute; overflow: hidden; width: 1024px; height: 768px; border-radius: 20px; -moz-border-radius: 20px; -webkit-border-radius: 20px; } p.hr { height: 0px; font-size: 0px !important; display: block; border-bottom: 1px solid #fdf6e3; } header:not(:only-child) { font-size: 60px; position: absolute; left: 30px; top: 25px; margin: 0; padding: 0; } header h1, header h2, header h3, header h4, header h5, header h6 { display: inline; font-size: 110%; font-weight: bold; padding: 0; margin: 0; } header h2:first-child { margin-top: 0; } footer { position: absolute; bottom: 0; left: 0; right: 0; padding: 5px; text-align: center; } section, .slide header:only-child h1 { margin-left: 30px; margin-right: 30px; margin-top: 100px; display: block; overflow: hidden; } section { position: absolute; margin: 0; left: 30px; right: 30px; top: 135px; bottom: 30px; overflow: auto; display: flex; flex-direction: column; justify-content: space-around; } section > * { overflow: hidden; } section img.align-center { display: block; margin-left: auto; margin-right: auto; } section img.align-right { display: block; margin-left: auto; margin-right: 0; } section img.align-left { display: block; margin-right: auto; margin-left: 0; } a { text-decoration: none; line-height: 110%; } ul { margin: 0; } pre, code, tt { font-family: Consolas, 'Bitstream Vera Sans Mono', 'Lucida Console', FreeMono, Courier, monospace; } pre, .gist .gist-file .gist-data { font-size: 24px; max-height: 485px; padding: 0 0.5em !important; margin: 0; overflow: auto; } li { padding: 10px 0; } li pre { margin: 0; } .slide header:only-child h1 { line-height: 180%; text-align: center; display: table-cell; vertical-align: middle; height: 768px; width: 1024px; font-size: 68px; margin-top: 100px; margin-bottom: 100px; } aside { display: none; } aside.source { position: absolute; bottom: 6px; left: 10px; } aside.page_number { position: absolute; bottom: 6px; right: 10px; text-indent: 10px; } div.slide p.notes { font-size: 90%; } img { display: block; margin: 0 auto; } .center { align-self: center; display: inline-block; } .large { font-size: 120%; } .huge { font-size: 150%; } .qr svg { background: white; max-height: 100%; } .qr { text-align: center; } python-darkslide-2.3.3/src/darkslide/themes/default/css/print.css000066400000000000000000000011141271614724200251030ustar00rootroot00000000000000#toc, #help, .slide aside, .slide .notes, .presenter_notes, #current_presenter_notes, #presenter_note { display: none; } @page { size: landscape; margin: 0; size: 1124px 852px; } @page:last { display: none; } div.slide-wrapper { padding: 15px; } div.slide, div.slide.current, div.slides, body, div.presentation { position: relative !important; margin: 0 !important; } div.inner { position: absolute !important; top: 0; left: 0; right: 0; bottom: 0; } div.slide { page-break-after: avoid; } div.slide-wrapper:last-of-type .slide { page-break-after: auto; } python-darkslide-2.3.3/src/darkslide/themes/default/css/screen.css000066400000000000000000000133001271614724200252260ustar00rootroot00000000000000html, body { overflow: hidden; position: relative; width: 100%; height: 100%; } div.presentation, body.presenter_view div#current_presenter_notes section, div.slides, body.expose div.slides.nocontext, .presenter_notes { top: 0; left: 0; right: 0; bottom: 0; position: absolute; display: block; background: inherit; } div.slides.nocontext .slide { opacity: 0; } div.slides.nocontext .slide.future { } body.expose div.slides.nocontext .slide, div.slides.nocontext .slide.current { opacity: 1; } div.slide { display: none; left: 50%; top: 50%; margin-top: -384px; -webkit-transition: margin 0.3s ease-in, opacity 0.3s ease-in; -moz-transition: margin 0.3s ease-in, opacity 0.3s ease-in; -o-transition: margin 0.3s ease-in, opacity 0.3s ease-in; } .slide.far-past { display: block; margin-left: -2660px; } .slide.past { display: block; margin-left: -1586px; } .slide.current { display: block; margin-left: -512px; } .slide.future { display: block; margin-left: 562px; } .slide.far-future { display: block; margin-left: 1636px; } /* Content */ /* render a nice scrollbar in overflowed pre area's */ ::-webkit-scrollbar-thumb { background: -webkit-gradient(linear, left bottom, left top, from(#eee), to(#fefefe)); border: 1px solid #888; -webkit-border-radius: 1ex; } ::-webkit-scrollbar-corner { background: #dedede; } ::-webkit-scrollbar { height: 8px; width: 8px; background: #888; border-radius: 5px; } .sidebar { background: white; color: black; border-right: 5px solid #ccc; z-index: 9999999; height: 100%; overflow: hidden; top: 0; position: absolute; display: block; margin: 0; margin-left: -400px; padding: 10px 16px; overflow: auto; -webkit-transition: margin 0.2s ease-in; -moz-transition: margin 0.2s ease-in; -o-transition: margin 0.2s ease-in; } .sidebar h2 { text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px; margin: 0 0 16px; padding: 0; } .sidebar table { width: 100%; margin: 0; padding: 0; border-collapse: collapse; } .sidebar table caption { display: none; } .sidebar tr { margin: 2px 0; border-bottom: 1px solid #ccc; } .sidebar tr:last-of-type { border-bottom: none; } .sidebar th { text-align: left; font-weight: normal; max-width: 300px; overflow: hidden; } .sidebar tr.sub th { text-indent: 20px; } .sidebar td { text-align: right; min-width: 20px; } .sidebar a, .sidebar a:hover { display: block; text-decoration: none !important; text-shadow: none !important; background: none !important; border-bottom: none; padding: 4px 0; } .sidebar tr.active { background: #ff0; } .notes { display: none; padding: 10px; background: #ccc; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } /* Expose */ body.expose div.slides { float: left; position: relative; overflow: auto; margin-bottom: 10px; } body.expose div.slide { display: block; float: left; position: relative; left: auto !important; top: auto !important; margin: 10px !important; -webkit-transition: none; -moz-transition: none; -o-transition: none; -moz-transform: scale(.30, .30); -moz-transform-origin: 0 0; -webkit-transform: scale(.30, .30); -webkit-transform-origin: 0 0; -o-transform: scale(.30, .30); -o-transform-origin: 0 0; -webkit-transition: none; -moz-transition: none; -o-transition: none; cursor: pointer; } body.expose .slide-wrapper { float: left; position: relative; margin: 2%; width: 300px; height: 233px; } body.expose .slide footer { } body.expose .slide .inner { } body.expose .slide.far-past, body.expose .slide.past, body.expose .slide.future, body.expose .slide.far-future { margin-left: 0; } /* Presenter Mode */ body.presenter_view div.slide { display: inline; position: absolute; overflow: hidden; -moz-transform: scale(.5, .5); -moz-transform-origin: 0 0; -webkit-transform: scale(.5, .5); -webkit-transform-origin: 0 0; -o-transform: scale(.5, .5); -o-transform-origin: 0 0; margin-top: -384px; } body.presenter_view .slide.far-past { display: block; margin-left: -1594px; } body.presenter_view .slide.past { display: block; margin-left: -1049px; } body.presenter_view .slide.current { display: block; margin-left: -512px; xborder: 8px solid maroon; box-shadow: 0 0 0 15px #dc322f; z-index: 2; } body.presenter_view .slide.future { display: block; margin-left: 25px; z-index: 1; } body.presenter_view .slide.far-future { display: block; margin-left: 562px; } body.presenter_view .slide.none { display: none; } body.presenter_view div#current_presenter_notes { visibility: visible; display: block; position: fixed; overflow: auto; vertical-align: middle; left: 50%; top: 50%; bottom: 0; margin-left: -475px; margin-top: 20px; z-index: 2; width: 950px; border-radius: 10px; margin-bottom: 20px; } body.presenter_view div#current_presenter_notes section { display: block; overflow: visible; margin: 60px 30px 0 30px; font-size: 24px; } body.presenter_view div#current_presenter_notes section p { margin: 0; } body.presenter_view div#current_presenter_notes h1 { font-size: 50%; display: block; } div#current_presenter_notes { display: none; } div.slide div.presenter_notes { display: none; } #blank { position: absolute; top: 0; left: 0; background-color: black; width: 100%; height: 100%; z-index: 64; display: none; } python-darkslide-2.3.3/src/darkslide/themes/default/css/theme.css000066400000000000000000000300321271614724200250520ustar00rootroot00000000000000/* ====================================== FONTS ====================================== */ h1, h2, h3, h4, h5, h6, body, header { font-family: 'Candara', 'Calibri', 'Segoe UI Semilight', 'Corbel', 'Trebuchet Ms', 'Segoe UI', sans-serif; } section { font: 34px 'Palatino', 'Palatino Linotype', 'URW Palladio L', 'Century Schoolbook L', 'Georgia', serif; } /* ====================================== COLORS ====================================== */ /* $base03: #002b36; $base02: #073642; $base01: #586e75; $base00: #657b83; $base0: #839496; $base1: #93a1a1; $base2: #eee8d5; $base3: #fdf6e3; $yellow: #b58900; $orange: #cb4b16; $red: #dc322f; $magenta: #d33682; $violet: #6c71c4; $blue: #268bd2; $cyan: #2aa198; $green: #859900; @mixin rebase($rebase03,$rebase02,$rebase01,$rebase00,$rebase0,$rebase1,$rebase2,$rebase3) { background-color:$rebase03; color:$rebase0; * { color:$rebase0; } h1,h2,h3,h4,h5,h6 { color:$rebase1; border-color: $rebase0; } a, a:active, a:visited { color: $rebase1; } } @mixin accentize($accent) { a, a:active, a:visited, code.url { color: $accent; } h1,h2,h3,h4,h5,h6 {color:$accent} } / * light is default mode, so pair with general html definition * / html, .light { @include rebase($base3,$base2,$base1,$base0,$base00,$base01,$base02,$base03)} .dark { @include rebase($base03,$base02,$base01,$base00,$base0,$base1,$base2,$base3)} html * { color-profile: sRGB; rendering-intent: auto; } */ .base03 { color: #002b36; } .base02 { color: #073642; } .base01 { color: #586e75; } .base00 { color: #657b83; } .base0 { color: #839496; } .base1 { color: #93a1a1; } .base2 { color: #eee8d5; } .base3 { color: #fdf6e3; } .yellow { color: #b58900; } .orange { color: #cb4b16; } .red { color: #dc322f; } .magenta { color: #d33682; } .violet { color: #6c71c4; } .blue { color: #268bd2; } .cyan { color: #2aa198; } .green { color: #859900; } body { background: #073642; color: #93a1a1; } footer { color: #93a1a1; } a, a:hover { color: #268bd2; padding: 0; text-decoration: none; background-color: transparent; background-image: linear-gradient(#268bd2, #268bd2); background-size: 1px 1px; background-repeat: repeat-x; background-position: 0% 95%; text-shadow: -0.06em -0.03ex #fdf6e3,-0.06em -0.06ex #fdf6e3,-0.06em -0.09ex #fdf6e3,0.12em 0ex #fdf6e3,-0.09em -0.09ex #fdf6e3,-0.09em -0.06ex #fdf6e3,-0.09em -0.03ex #fdf6e3,0.12em -0.21ex #fdf6e3,0.12em -0.27ex #fdf6e3,0.12em -0.24ex #fdf6e3,0em 0.08ex #fdf6e3,0em -0.18ex #fdf6e3,0em -0.15ex #fdf6e3,0em 0.02ex #fdf6e3,-0.06em 0ex #fdf6e3,-0.03em 0ex #fdf6e3,0em 0.06ex #fdf6e3,0em -0.12ex #fdf6e3,-0.12em -0.06ex #fdf6e3,-0.12em -0.03ex #fdf6e3,0.15em 0ex #fdf6e3,-0.12em -0.09ex #fdf6e3,0.03em -0.21ex #fdf6e3,-0.09em -0.18ex #fdf6e3,0.03em -0.24ex #fdf6e3,0.03em -0.27ex #fdf6e3,-0.09em -0.12ex #fdf6e3,-0.09em -0.15ex #fdf6e3,0.09em -0.27ex #fdf6e3,0.09em -0.24ex #fdf6e3,0.09em -0.21ex #fdf6e3,0em 0ex #fdf6e3,-0.15em 0.08ex #fdf6e3,0.06em 0ex #fdf6e3,0.12em -0.12ex #fdf6e3,-0.15em 0.02ex #fdf6e3,-0.15em 0.06ex #fdf6e3,-0.15em 0.04ex #fdf6e3,-0.15em -0.15ex #fdf6e3,-0.09em -0.21ex #fdf6e3,-0.09em -0.27ex #fdf6e3,-0.09em -0.24ex #fdf6e3,0.06em 0.08ex #fdf6e3,-0.06em -0.21ex #fdf6e3,0.06em 0.06ex #fdf6e3,0.06em 0.04ex #fdf6e3,-0.15em -0.18ex #fdf6e3,-0.06em -0.24ex #fdf6e3,-0.06em -0.27ex #fdf6e3,0.15em 0.08ex #fdf6e3,0.12em -0.09ex #fdf6e3,0.03em 0.02ex #fdf6e3,0.03em 0.04ex #fdf6e3,0.03em 0.06ex #fdf6e3,0.09em -0.18ex #fdf6e3,0.03em 0.08ex #fdf6e3,0.09em -0.15ex #fdf6e3,0.12em -0.03ex #fdf6e3,0.09em -0.12ex #fdf6e3,0.12em -0.06ex #fdf6e3,0.15em 0.02ex #fdf6e3,-0.15em -0.03ex #fdf6e3,-0.06em -0.15ex #fdf6e3,-0.15em -0.06ex #fdf6e3,-0.06em -0.12ex #fdf6e3,-0.15em -0.09ex #fdf6e3,-0.12em -0.21ex #fdf6e3,-0.06em -0.18ex #fdf6e3,-0.12em -0.27ex #fdf6e3,-0.12em -0.24ex #fdf6e3,-0.03em 0.04ex #fdf6e3,-0.03em 0.06ex #fdf6e3,0.09em -0.09ex #fdf6e3,-0.03em 0.02ex #fdf6e3,0.09em -0.06ex #fdf6e3,-0.03em 0.08ex #fdf6e3,0.09em -0.03ex #fdf6e3,0.09em 0ex #fdf6e3,0em -0.09ex #fdf6e3,0em -0.06ex #fdf6e3,-0.15em 0ex #fdf6e3,0em -0.03ex #fdf6e3,-0.12em 0.02ex #fdf6e3,0.12em 0.06ex #fdf6e3,-0.12em 0.06ex #fdf6e3,-0.12em 0.04ex #fdf6e3,-0.12em -0.12ex #fdf6e3,-0.12em 0.08ex #fdf6e3,0.15em -0.15ex #fdf6e3,0.15em -0.12ex #fdf6e3,-0.03em -0.24ex #fdf6e3,0em -0.24ex #fdf6e3,-0.03em -0.27ex #fdf6e3,0.15em -0.18ex #fdf6e3,-0.03em -0.21ex #fdf6e3,0.06em -0.24ex #fdf6e3,0.06em -0.27ex #fdf6e3,-0.09em 0ex #fdf6e3,0.06em -0.21ex #fdf6e3,-0.15em -0.12ex #fdf6e3,-0.06em 0.08ex #fdf6e3,-0.06em 0.02ex #fdf6e3,-0.06em 0.06ex #fdf6e3,-0.06em 0.04ex #fdf6e3,-0.12em -0.18ex #fdf6e3,-0.15em -0.21ex #fdf6e3,-0.15em -0.24ex #fdf6e3,-0.15em -0.27ex #fdf6e3,0.06em 0.02ex #fdf6e3,0.15em -0.21ex #fdf6e3,0.03em 0ex #fdf6e3,0.15em -0.27ex #fdf6e3,0.09em 0.02ex #fdf6e3,0.12em -0.18ex #fdf6e3,0.09em 0.06ex #fdf6e3,0.09em 0.04ex #fdf6e3,0em 0.04ex #fdf6e3,0.09em 0.08ex #fdf6e3,0.12em -0.15ex #fdf6e3,-0.03em -0.03ex #fdf6e3,-0.03em -0.06ex #fdf6e3,-0.12em -0.15ex #fdf6e3,0em -0.27ex #fdf6e3,0em -0.21ex #fdf6e3,-0.03em -0.09ex #fdf6e3,0.06em -0.09ex #fdf6e3,0.03em -0.18ex #fdf6e3,0.12em 0.08ex #fdf6e3,0.03em -0.15ex #fdf6e3,0.12em 0.04ex #fdf6e3,0.12em 0.02ex #fdf6e3,0.06em -0.06ex #fdf6e3,0.03em -0.12ex #fdf6e3,-0.03em -0.12ex #fdf6e3,-0.03em -0.15ex #fdf6e3,-0.03em -0.18ex #fdf6e3,0.15em 0.06ex #fdf6e3,0.15em 0.04ex #fdf6e3,0.15em -0.06ex #fdf6e3,0.15em -0.03ex #fdf6e3,0.15em -0.09ex #fdf6e3,0.06em -0.18ex #fdf6e3,0.03em -0.09ex #fdf6e3,0.03em -0.03ex #fdf6e3,0.06em -0.12ex #fdf6e3,0.03em -0.06ex #fdf6e3,0.06em -0.15ex #fdf6e3,0.06em -0.03ex #fdf6e3,-0.09em 0.08ex #fdf6e3,-0.09em 0.02ex #fdf6e3,-0.12em 0ex #fdf6e3,-0.09em 0.06ex #fdf6e3,-0.09em 0.04ex #fdf6e3,0.15em -0.24ex #fdf6e3; } a:hover { color: #2aa198; background-image: linear-gradient(#2aa198, #2aa198); } .presenter_notes a, .presenter_notes a:hover, div#current_presenter_notes a, div#current_presenter_notes a:hover { text-shadow: -0.06em -0.03ex #002b36,-0.06em -0.06ex #002b36,-0.06em -0.09ex #002b36,0.12em 0ex #002b36,-0.09em -0.09ex #002b36,-0.09em -0.06ex #002b36,-0.09em -0.03ex #002b36,0.12em -0.21ex #002b36,0.12em -0.27ex #002b36,0.12em -0.24ex #002b36,0em 0.08ex #002b36,0em -0.18ex #002b36,0em -0.15ex #002b36,0em 0.02ex #002b36,-0.06em 0ex #002b36,-0.03em 0ex #002b36,0em 0.06ex #002b36,0em -0.12ex #002b36,-0.12em -0.06ex #002b36,-0.12em -0.03ex #002b36,0.15em 0ex #002b36,-0.12em -0.09ex #002b36,0.03em -0.21ex #002b36,-0.09em -0.18ex #002b36,0.03em -0.24ex #002b36,0.03em -0.27ex #002b36,-0.09em -0.12ex #002b36,-0.09em -0.15ex #002b36,0.09em -0.27ex #002b36,0.09em -0.24ex #002b36,0.09em -0.21ex #002b36,0em 0ex #002b36,-0.15em 0.08ex #002b36,0.06em 0ex #002b36,0.12em -0.12ex #002b36,-0.15em 0.02ex #002b36,-0.15em 0.06ex #002b36,-0.15em 0.04ex #002b36,-0.15em -0.15ex #002b36,-0.09em -0.21ex #002b36,-0.09em -0.27ex #002b36,-0.09em -0.24ex #002b36,0.06em 0.08ex #002b36,-0.06em -0.21ex #002b36,0.06em 0.06ex #002b36,0.06em 0.04ex #002b36,-0.15em -0.18ex #002b36,-0.06em -0.24ex #002b36,-0.06em -0.27ex #002b36,0.15em 0.08ex #002b36,0.12em -0.09ex #002b36,0.03em 0.02ex #002b36,0.03em 0.04ex #002b36,0.03em 0.06ex #002b36,0.09em -0.18ex #002b36,0.03em 0.08ex #002b36,0.09em -0.15ex #002b36,0.12em -0.03ex #002b36,0.09em -0.12ex #002b36,0.12em -0.06ex #002b36,0.15em 0.02ex #002b36,-0.15em -0.03ex #002b36,-0.06em -0.15ex #002b36,-0.15em -0.06ex #002b36,-0.06em -0.12ex #002b36,-0.15em -0.09ex #002b36,-0.12em -0.21ex #002b36,-0.06em -0.18ex #002b36,-0.12em -0.27ex #002b36,-0.12em -0.24ex #002b36,-0.03em 0.04ex #002b36,-0.03em 0.06ex #002b36,0.09em -0.09ex #002b36,-0.03em 0.02ex #002b36,0.09em -0.06ex #002b36,-0.03em 0.08ex #002b36,0.09em -0.03ex #002b36,0.09em 0ex #002b36,0em -0.09ex #002b36,0em -0.06ex #002b36,-0.15em 0ex #002b36,0em -0.03ex #002b36,-0.12em 0.02ex #002b36,0.12em 0.06ex #002b36,-0.12em 0.06ex #002b36,-0.12em 0.04ex #002b36,-0.12em -0.12ex #002b36,-0.12em 0.08ex #002b36,0.15em -0.15ex #002b36,0.15em -0.12ex #002b36,-0.03em -0.24ex #002b36,0em -0.24ex #002b36,-0.03em -0.27ex #002b36,0.15em -0.18ex #002b36,-0.03em -0.21ex #002b36,0.06em -0.24ex #002b36,0.06em -0.27ex #002b36,-0.09em 0ex #002b36,0.06em -0.21ex #002b36,-0.15em -0.12ex #002b36,-0.06em 0.08ex #002b36,-0.06em 0.02ex #002b36,-0.06em 0.06ex #002b36,-0.06em 0.04ex #002b36,-0.12em -0.18ex #002b36,-0.15em -0.21ex #002b36,-0.15em -0.24ex #002b36,-0.15em -0.27ex #002b36,0.06em 0.02ex #002b36,0.15em -0.21ex #002b36,0.03em 0ex #002b36,0.15em -0.27ex #002b36,0.09em 0.02ex #002b36,0.12em -0.18ex #002b36,0.09em 0.06ex #002b36,0.09em 0.04ex #002b36,0em 0.04ex #002b36,0.09em 0.08ex #002b36,0.12em -0.15ex #002b36,-0.03em -0.03ex #002b36,-0.03em -0.06ex #002b36,-0.12em -0.15ex #002b36,0em -0.27ex #002b36,0em -0.21ex #002b36,-0.03em -0.09ex #002b36,0.06em -0.09ex #002b36,0.03em -0.18ex #002b36,0.12em 0.08ex #002b36,0.03em -0.15ex #002b36,0.12em 0.04ex #002b36,0.12em 0.02ex #002b36,0.06em -0.06ex #002b36,0.03em -0.12ex #002b36,-0.03em -0.12ex #002b36,-0.03em -0.15ex #002b36,-0.03em -0.18ex #002b36,0.15em 0.06ex #002b36,0.15em 0.04ex #002b36,0.15em -0.06ex #002b36,0.15em -0.03ex #002b36,0.15em -0.09ex #002b36,0.06em -0.18ex #002b36,0.03em -0.09ex #002b36,0.03em -0.03ex #002b36,0.06em -0.12ex #002b36,0.03em -0.06ex #002b36,0.06em -0.15ex #002b36,0.06em -0.03ex #002b36,-0.09em 0.08ex #002b36,-0.09em 0.02ex #002b36,-0.12em 0ex #002b36,-0.09em 0.06ex #002b36,-0.09em 0.04ex #002b36,0.15em -0.24ex #002b36; } code, tt.docutils.literal { color: #6c71c4; } div.slide { background-color: #fdf6e3; color: #586e75; } body.expose div.slide:hover { box-shadow: 0 0 0 15px #268bd2; } body.expose .slide.current { box-shadow: 0 0 0 30px #b58900; } body.expose .slide.current:hover { box-shadow: 0 0 0 15px #268bd2, 0 0 0 30px #b58900; } .presenter_notes { background: #002b36; } @media screen, projection { ::-webkit-scrollbar-thumb { background: #fdf6e3; border-color: #eee8d5; } ::-webkit-scrollbar { background: #eee8d5; } ::-webkit-scrollbar-corner { background: #fdf6e3; } } .qr svg { box-shadow: inset 0 0 10px #eee8d5; } div.slides, body.expose div.slides.nocontext, body.expose .slide.current, body.expose .slide.current .inner { /*background: #000;*/ } /* See: https://gist.github.com/nicolashery/5765395 */ /* Synic syntax highlighting */ /*pre pre:not(.diff-line-pre),pre table{background:#000!important;color:#fdf6e3ff0!important;}*/ pre { background: #fdf6e3; color: #586e75; } .linenos pre { background: #eee8d5;} .c { color: #93a1a1; } .err { color: #586e75; } .g { color: #586e75; } .k { color: #859900; } .l { color: #586e75; } .n { color: #586e75; } .o { color: #859900; } .x { color: #cb4b16; } .p { color: #586e75; } .cm { color: #93a1a1; } .cp { color: #859900; } .c1 { color: #93a1a1; } .cs { color: #859900; } .gd { color: #2aa198; } .ge { color: #586e75; font-style: italic; } .gr { color: #dc322f; } .gh { color: #cb4b16; } .gi { color: #859900; } .go { color: #586e75; } .gp { color: #586e75; } .gs { color: #586e75; font-weight: bold; } .gu { color: #cb4b16; } .gt { color: #586e75; } .kc { color: #cb4b16; } .kd { color: #268bd2; } .kn { color: #859900; } .kp { color: #859900; } .kr { color: #268bd2; } .kt { color: #dc322f; } .ld { color: #586e75; } .m { color: #2aa198; } .s { color: #2aa198; } .na { color: #586e75; } .nb { color: #b58900; } .nc { color: #268bd2; } .no { color: #cb4b16; } .nd { color: #268bd2; } .ni { color: #cb4b16; } .ne { color: #cb4b16; } .nf { color: #268bd2; } .nl { color: #586e75; } .nn { color: #586e75; } .nx { color: #586e75; } .py { color: #586e75; } .nt { color: #268bd2; } .nv { color: #268bd2; } .ow { color: #859900; } .w { color: #586e75; } .mf { color: #2aa198; } .mh { color: #2aa198; } .mi { color: #2aa198; } .mo { color: #2aa198; } .sb { color: #93a1a1; } .sc { color: #2aa198; } .sd { color: #586e75; } .s2 { color: #2aa198; } .se { color: #cb4b16; } .sh { color: #586e75; } .si { color: #2aa198; } .sx { color: #2aa198; } .sr { color: #dc322f; } .s1 { color: #2aa198; } .ss { color: #2aa198; } .bp { color: #268bd2; } .vc { color: #268bd2; } .vg { color: #268bd2; } .vi { color: #268bd2; } .il { color: #2aa198; } python-darkslide-2.3.3/src/darkslide/themes/default/js/000077500000000000000000000000001271614724200230645ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/default/js/slides.js000066400000000000000000000423521271614724200247130ustar00rootroot00000000000000function main() { // Since we don't have the fallback of attachEvent and // other IE only stuff we won't try to run JS for IE. // It will run though when using Google Chrome Frame if (document.all) { return; } var currentSlideNo; var notesOn = false; var expanded = false; var hiddenContext = false; var blanked = false; var slides = document.getElementsByClassName('slide'); var touchStartX = 0; var spaces = /\s+/, a1 = ['']; var tocOpened = false; var helpOpened = false; var overviewActive = false; var modifierKeyDown = false; var scale = 1; var showingPresenterView = false; var presenterViewWin = null; var isPresenterView = false; var str2array = function(s) { if (typeof s == 'string' || s instanceof String) { if (s.indexOf(' ') < 0) { a1[0] = s; return a1; } else { return s.split(spaces); } } return s; }; var trim = function(str) { return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; var addClass = function(node, classStr) { classStr = str2array(classStr); var cls = ' ' + node.className + ' '; for (var i = 0, len = classStr.length, c; i < len; ++i) { c = classStr[i]; if (c && cls.indexOf(' ' + c + ' ') < 0) { cls += c + ' '; } } node.className = trim(cls); }; var removeClass = function(node, classStr) { var cls; if (!node) { throw 'no node provided'; } if (classStr !== undefined) { classStr = str2array(classStr); cls = ' ' + node.className + ' '; for (var i = 0, len = classStr.length; i < len; ++i) { cls = cls.replace(' ' + classStr[i] + ' ', ' '); } cls = trim(cls); } else { cls = ''; } if (node.className != cls) { node.className = cls; } }; var getSlideEl = function(slideNo) { if (slideNo > 0) { return slides[slideNo - 1]; } else { return null; } }; var getSlideTitle = function(slideNo) { var el = getSlideEl(slideNo); if (el) { var headers = el.getElementsByTagName('header'); if (headers.length > 0) { return el.getElementsByTagName('header')[0].innerText; } } return null; }; var getSlidePresenterNote = function(slideNo) { var el = getSlideEl(slideNo); if (el) { var n = el.getElementsByClassName('presenter_notes'); if (n.length > 0) { return n[0]; } } return null; }; var changeSlideElClass = function(slideNo, className) { var el = getSlideEl(slideNo); if (el) { removeClass(el, 'far-past past current future far-future none'); addClass(el, className); } }; var updateSlideClasses = function(updateOther) { window.location.hash = (isPresenterView ? "presenter:" : "slide:") + currentSlideNo; for (var i=1; i 1) { currentSlideNo--; } updateSlideClasses(true); }; var showNotes = function() { var slide = getSlideEl(currentSlideNo), notes = slide.getElementsByClassName('presenter_notes'); for (var i = 0, len = notes.length; i < len; i++) { notes.item(i).style.display = (notesOn) ? 'none':'block'; } notesOn = !notesOn; if (notesOn) { addClass(slide, 'presenter_notes'); } else { removeClass(slide, 'presenter_notes'); } }; var showSlideNumbers = function() { var asides = document.getElementsByClassName('page_number'); var hidden = asides[0].style.display != 'block'; for (var i = 0; i < asides.length; i++) { asides.item(i).style.display = hidden ? 'block' : 'none'; } }; var showSlideSources = function() { var asides = document.getElementsByClassName('source'); var hidden = asides[0].style.display != 'block'; for (var i = 0; i < asides.length; i++) { asides.item(i).style.display = hidden ? 'block' : 'none'; } }; var showToc = function() { if (helpOpened) { showHelp(); } var toc = document.getElementById('toc'); if (toc) { toc.style.marginLeft = tocOpened ? '-' + (toc.clientWidth + 20) + 'px' : '0px'; tocOpened = !tocOpened; } updateOverview(); }; var showHelp = function() { if (tocOpened) { showToc(); } var help = document.getElementById('help'); if (help) { help.style.marginLeft = helpOpened ? '-' + (help.clientWidth + 20) + 'px' : '0px'; helpOpened = !helpOpened; } }; var showPresenterView = function() { if (isPresenterView) { return; } if (showingPresenterView) { if (presenterViewWin) presenterViewWin.close(); presenterViewWin = null; showingPresenterView = false; } else { presenterViewWin = open(window.location.pathname + "#presenter:" + currentSlideNo, 'presenter_notes', 'directories=no,location=no,toolbar=no,menubar=no,copyhistory=no'); showingPresenterView = true; } }; var toggleOverview = function() { if (!overviewActive) { addClass(document.body, 'expose'); overviewActive = true; setScale(1); } else { removeClass(document.body, 'expose'); overviewActive = false; if (expanded) { setScale(scale); // restore scale } } updateOverview(); }; var updateOverview = function() { try { var presentation = document.getElementsByClassName('presentation')[0]; } catch (e) { return; } if (isPresenterView) { var action = overviewActive ? removeClass : addClass; action(document.body, 'presenter_view'); } var toc = document.getElementById('toc'); if (!toc) { return; } if (!tocOpened || !overviewActive) { presentation.style.marginLeft = '0px'; presentation.style.width = '100%'; } else { presentation.style.marginLeft = toc.clientWidth + 'px'; presentation.style.width = (presentation.clientWidth - toc.clientWidth) + 'px'; } }; var computeScale = function() { var cSlide = document.getElementsByClassName('current')[0]; var sx = (cSlide.clientWidth + 20) / window.innerWidth; var sy = (cSlide.clientHeight + 20) / window.innerHeight; return 1 / Math.max(sy, sx); }; var setScale = function(scale) { var presentation = document.getElementsByClassName('slides')[0]; var transform = 'scale(' + scale + ')'; presentation.style.MozTransform = transform; presentation.style.WebkitTransform = transform; presentation.style.OTransform = transform; presentation.style.msTransform = transform; presentation.style.transform = transform; }; var expandSlides = function() { if (overviewActive) { return; } if (expanded) { setScale(1); showContext(); expanded = false; } else { setExpanded(); } }; var setExpanded = function() { scale = computeScale(); setScale(scale); expanded = true; hideContext(); }; var showContext = function() { var presentation = document.getElementsByClassName('slides')[0]; removeClass(presentation, 'nocontext'); hiddenContext = true; }; var hideContext = function() { if (isPresenterView) { return; } var presentation = document.getElementsByClassName('slides')[0]; addClass(presentation, 'nocontext'); hiddenContext = false; }; var toggleContext = function() { if (hiddenContext) { hideContext(); } else { showContext(); } }; var toggleBlank = function() { blank_elem = document.getElementById('blank'); blank_elem.style.display = blanked ? 'none' : 'block'; blanked = !blanked; }; var isModifierKey = function(keyCode) { switch (keyCode) { case 16: // shift case 17: // ctrl case 18: // alt case 91: // command return true; break; default: return false; break; } }; var checkModifierKeyUp = function(event) { if (isModifierKey(event.keyCode)) { modifierKeyDown = false; } }; var checkModifierKeyDown = function(event) { if (isModifierKey(event.keyCode)) { modifierKeyDown = true; } }; var handleBodyKeyDown = function(event) { if (modifierKeyDown && event.keyCode == 80) { setScale(1); showContext(); expanded = false; } if (modifierKeyDown) { return } switch (event.keyCode) { case 13: // Enter if (overviewActive) { toggleOverview(); } break; case 27: // ESC toggleOverview(); break; case 37: // left arrow case 33: // page up event.preventDefault(); prevSlide(); break; case 39: // right arrow case 32: // space case 34: // page down event.preventDefault(); nextSlide(); break; case 50: // 2 showNotes(); break; case 190: // . case 48: // 0 case 66: // b if (!overviewActive) { toggleBlank(); } break; case 67: // c if (!overviewActive) { toggleContext(); } break; case 69: // e if (!overviewActive) { expandSlides(); } break; case 72: // h showHelp(); break; case 78: // n if (!overviewActive) { showSlideNumbers(); } break; case 80: // p if (!overviewActive) { showPresenterView(); } break; case 83: // s if (!overviewActive) { showSlideSources(); } break; case 84: // t showToc(); break; } }; var handleWheel = function(event) { if (tocOpened || helpOpened || overviewActive) { return; } var delta = 0; if (!event) { event = window.event; } if (event.wheelDelta) { delta = event.wheelDelta/120; if (window.opera) delta = -delta; } else if (event.detail) { delta = -event.detail/3; } if (delta && delta <0) { nextSlide(); } else if (delta) { prevSlide(); } }; var addSlideClickListeners = function() { for (var i=0; i < slides.length; i++) { var slide = slides.item(i); slide.num = i + 1; slide.addEventListener('click', function(e) { if (overviewActive) { currentSlideNo = this.num; toggleOverview(); updateSlideClasses(true); e.preventDefault(); } return false; }, true); } }; var addRemoteWindowControls = function() { window.addEventListener("message", function(e) { if (e.data.indexOf("slide#") != -1) { currentSlideNo = Number(e.data.replace('slide#', '')); updateSlideClasses(false); } }, false); }; var addTouchListeners = function() { document.addEventListener('touchstart', function(e) { touchStartX = e.touches[0].pageX; }, false); document.addEventListener('touchend', function(e) { var pixelsMoved = touchStartX - e.changedTouches[0].pageX; var SWIPE_SIZE = 150; if (pixelsMoved > SWIPE_SIZE) { nextSlide(); } else if (pixelsMoved < -SWIPE_SIZE) { prevSlide(); } }, false); }; var addTocLinksListeners = function() { var toc = document.getElementById('toc'); if (toc) { var tocLinks = toc.getElementsByTagName('a'); for (var i=0; i < tocLinks.length; i++) { tocLinks.item(i).addEventListener('click', function(e) { currentSlideNo = Number(this.attributes['href'].value.replace('#slide:', '')); updateSlideClasses(true); e.preventDefault(); }, true); } } }; // initialize (function() { if (window.location.hash == "") { currentSlideNo = 1; } else if (window.location.hash.indexOf("#presenter:") != -1) { currentSlideNo = Number(window.location.hash.replace('#presenter:', '')); isPresenterView = true; showingPresenterView = true; presenterViewWin = window; addClass(document.body, 'presenter_view'); } else { currentSlideNo = Number(window.location.hash.replace('#slide:', '')) || 1; } document.addEventListener('keyup', checkModifierKeyUp); document.addEventListener('keydown', handleBodyKeyDown); document.addEventListener('keydown', checkModifierKeyDown); document.addEventListener('visibilitychange', function(event) { if (document.hidden) { modifierKeyDown = false; } }, false); setInterval(function() { if (!document.hasFocus()) { modifierKeyDown = false; } }, 100); window.addEventListener("mousewheel", handleWheel); window.addEventListener("DOMMouseScroll", handleWheel); window.addEventListener("DOMContentLoaded", expandSlides); window.onresize = function(){ setScale(!overviewActive && expanded ? scale = computeScale() : 1); } for (var i = 0, el; el = slides[i]; i++) { addClass(el, 'slide far-future'); } updateSlideClasses(false); // add support for finger events (filter it by property detection?) addTouchListeners(); addTocLinksListeners(); addSlideClickListeners(); addRemoteWindowControls(); })(); } python-darkslide-2.3.3/src/darkslide/themes/void/000077500000000000000000000000001271614724200217655ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/void/css/000077500000000000000000000000001271614724200225555ustar00rootroot00000000000000python-darkslide-2.3.3/src/darkslide/themes/void/css/theme.css000066400000000000000000000056311271614724200243760ustar00rootroot00000000000000/* ====================================== FONTS ====================================== */ h1, h2, h3, h4, h5, h6, body, header { font-family: 'Segoe UI', 'Verdana', sans-serif; } header h1, header h2, header h3, header h4, header h5, header h6 { font-size: 90%; } section { font: 28px 'Palatino', 'Palatino Linotype', 'URW Palladio L', 'Century Schoolbook L', 'Georgia', serif; } /* ====================================== COLORS ====================================== */ .yellow { color: #b58900; } .orange { color: #cb4b16; } .red { color: #dc322f; } .magenta { color: #d33682; } .violet { color: #6c71c4; } .blue { color: #268bd2; } .cyan { color: #2aa198; } .green { color: #859900; } body { background: black; color: #eee; } blockquote { padding: 1ex; margin-left: 0px; border-left: 1em solid #333; } footer { color: #aaa; } a, a:hover { color: #268bd2; padding: 0; } a:hover { color: #2aa198; } code, tt.docutils.literal { color: #6c71c4; } div.slide { border-radius: 20px; border: 2px solid #aaa; } body.expose div.slide:hover { box-shadow: 0 0 0 15px #268bd2; } body.expose .slide.current { box-shadow: 0 0 0 30px #b58900; } body.expose .slide.current:hover { box-shadow: 0 0 0 15px #268bd2, 0 0 0 30px #b58900; } .presenter_notes { background: #eee; color: #222; } ::-webkit-scrollbar-thumb { background: #222; border-color: #444; } ::-webkit-scrollbar { background: #444; border-color: #444; } ::-webkit-scrollbar-corner { background: #222; } /* See: http://stylishthemes.github.io/GitHub-Dark/ */ /* Synic syntax highlighting */ pre pre:not(.diff-line-pre),pre table{background:#000!important;color:#fffff0!important;} pre .hll{background-color:#ffc!important;} pre .cp{color:#ffa0a0!important;} pre .gd{color:#add8e6!important;background-color:#e0ffff!important;} pre .ge{color:#fffff0!important;text-decoration:underline!important;} pre .gi{color:#00f!important;background-color:#e0ffff!important;} pre .go{color:#008b8b!important;} pre .ni{color:#daa520!important;} pre .ow{color:#8673e8!important;} pre .c,pre .cm,pre .c1,pre .cs{color:#708090!important;} pre .err,pre .g,pre .l,pre .n,pre .o,pre .x,pre .p,pre .gp, pre .gs,pre .ld,pre .nb,pre .nc,pre .nd,pre .nn,pre .nx,pre .py, pre .w,pre .bp{color:#fffff0!important;} pre .k,pre .kc,pre .kd,pre .kn,pre .kp,pre .kr, pre .nt{color:#f0e68c!important;} pre .gr,pre .gt{color:red!important;background-color:#faf0e6!important;border-radius:2px;} pre .gh,pre .gu{color:#ee0!important;} pre .kt,pre .ne,pre .nl{color:#ffdead!important;} pre .m,pre .no,pre .mf,pre .mh,pre .mi,pre .mo, pre .il{color:#cdb7b5!important;} pre .s,pre .sb,pre .sc,pre .sd,pre .s2,pre .se,pre .sh,pre .si, pre .sx,pre .sr,pre .s1,pre .ss{color:#9ac0cd!important;} pre .na,pre .nf,pre .nv,pre .vc,pre .vg, pre .vi{color:#68838b!important;font-weight:700!important;} .white { background: white; } python-darkslide-2.3.3/src/darkslide/utils.py000066400000000000000000000022311271614724200212470ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os import base64 import mimetypes def get_path_url(path, relative=False): """ Returns an absolute or relative path url given a path """ if relative is False: return 'file://%s' % os.path.abspath(path) else: return os.path.relpath(path, relative) def encode_image_from_url(url, source_path): if not url or url.startswith('data:') or url.startswith('file://'): return False if (url.startswith('http://') or url.startswith('https://')): return False real_path = url if os.path.isabs(url) else os.path.join(source_path, url) if not os.path.exists(real_path): print('%s was not found, skipping' % url) return False mime_type, encoding = mimetypes.guess_type(real_path) if not mime_type: print('Unrecognized mime type for %s, skipping' % url) return False try: with open(real_path, 'rb') as image_file: image_contents = image_file.read() encoded_image = base64.b64encode(image_contents) except IOError: return False return u"data:%s;base64,%s" % (mime_type, encoded_image.decode()) python-darkslide-2.3.3/src/darkslide/watcher.py000066400000000000000000000016511271614724200215510ustar00rootroot00000000000000import sys import time try: from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler, DirModifiedEvent except ImportError: print('Error: The watchdog module must be installed to use the -w option') print('Exiting...') sys.exit(1) def watch(watch_dir, generate_func): event_handler = LandslideEventHandler(generate_func) observer = Observer() observer.schedule(event_handler, path=watch_dir, recursive=True) observer.start() try: while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join() class LandslideEventHandler(FileSystemEventHandler): def __init__(self, generate_func): super(LandslideEventHandler, self).__init__() self.generate_func = generate_func def on_modified(self, event): if isinstance(event, DirModifiedEvent): self.generate_func() python-darkslide-2.3.3/tests/000077500000000000000000000000001271614724200161505ustar00rootroot00000000000000python-darkslide-2.3.3/tests/test-data/000077500000000000000000000000001271614724200200365ustar00rootroot00000000000000python-darkslide-2.3.3/tests/test-data/căcăneață.rst000066400000000000000000000000461271614724200243310ustar00rootroot00000000000000La țară mere ============ Pam pam. python-darkslide-2.3.3/tests/test-data/encoding.rst000066400000000000000000000001021271614724200223470ustar00rootroot00000000000000Encoding Test ============= ---- koi8_r ====== . python-darkslide-2.3.3/tests/test-data/img.png000066400000000000000000000071251271614724200213250ustar00rootroot00000000000000PNG  IHDR:~U 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  iTXtXML:com.adobe.xmp 2014-04-26T13:04:56 Pixelmator 3.1 1 5 1 72 72 1 1 1 Љ IDATc`5IENDB`python-darkslide-2.3.3/tests/test-data/test.css000066400000000000000000000000171271614724200215250ustar00rootroot00000000000000* {color: red;}python-darkslide-2.3.3/tests/test-data/test.js000066400000000000000000000000151271614724200213470ustar00rootroot00000000000000alert('foo');python-darkslide-2.3.3/tests/test-data/test.md000066400000000000000000000032421271614724200213400ustar00rootroot00000000000000# Title Slide --- # Paragraphs Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc elit, vel iaculis lorem facilisis non. Vivamus ante mauris, pellentesque et rhoncus ut, condimentum sed ipsum. Nullam eu molestie sapien. Curabitur imperdiet, ligula id blandit sagittis, libero quam consectetur felis, ac pharetra metus lectus vitae leo. Mauris lacinia fermentum augue. --- # Blockquotes > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies > tempus ultricies. Ut porta scelerisque viverra. Pellentesque aliquam metus > scelerisque dui ultricies, auctor dictum erat aliquet. Integer vehicula nunc > elit, vel iaculis lorem facilisis non. --- # Subheadings and Emphasis ## Italic *Lorem ipsum dolor sit amet* ## Bold **Lorem ipsum dolor sit amet** --- # Lists ## Unordered List - Markdown - ReStructured Text - Textile ## Ordered List 1. Python 2. JavaScript 3. HTML5 --- # Second Title Slide --- # Code ## Single Word Hello `World` ## Python !python def multiply (x, y): return x * y ## JavaScript !javascript multiply: function (x, y) { return x * y; } ## HTML !html --- # Images ![img](img.png) --- # View Presenter Notes This slide has presenter notes. Press `p` to view them. # Presenter Notes Hello from presenter notes --- # Other features View other features in the help sidebar by pressing `h` --- # Unicode This is ünicô∂e python-darkslide-2.3.3/tests/test_landslide.py000066400000000000000000000204721271614724200215250ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os import re import codecs import base64 from pytest import raises from darkslide import macro from darkslide.generator import Generator from darkslide.parser import Parser DATA_DIR = os.path.join(os.path.dirname(__file__), 'test-data') if not os.path.exists(DATA_DIR): raise IOError('Test data not found, cannot run tests') def logtest(message, type='notice'): if type == 'warning': raise WarningMessage(message) elif type == 'error': raise ErrorMessage(message) def test_generator__init__(): raises(IOError, Generator, None) raises(IOError, Generator, 'foo.md') def test_add_user_assets(): base_dir = os.path.join(DATA_DIR, 'test.md') g = Generator(base_dir, logger=logtest) g.add_user_css(os.path.join(DATA_DIR, 'test.css')) g.add_user_js(os.path.join(DATA_DIR, 'test.js')) assert g.user_css[0]['contents'] == '* {color: red;}' assert g.user_js[0]['contents'] == "alert('foo');" def test_get_toc(): base_dir = os.path.join(DATA_DIR, 'test.md') g = Generator(base_dir, logger=logtest) g.add_toc_entry('Section 1', 1, 1) g.add_toc_entry('Section 1.1', 2, 2) g.add_toc_entry('Section 1.2', 2, 3) g.add_toc_entry('Section 2', 1, 4) g.add_toc_entry('Section 2.1', 2, 5) g.add_toc_entry('Section 3', 1, 6) toc = g.toc assert len(toc) == 3 assert toc[0]['title'] == 'Section 1' assert len(toc[0]['sub']) == 2 assert toc[0]['sub'][1]['title'] == 'Section 1.2' assert toc[1]['title'] == 'Section 2' assert len(toc[1]['sub']) == 1 assert toc[2]['title'] == 'Section 3' assert len(toc[2]['sub']) == 0 def test_get_slide_vars(): g = Generator(os.path.join(DATA_DIR, 'test.md')) svars = g.get_slide_vars("

heading

\n

foo

\n

bar

\n", '') assert svars['title'] == 'heading' assert svars['level'] == 1 assert svars['header'] == '

heading

' assert svars['content'] == '

foo

\n

bar

' assert svars['source'] == {} assert svars['classes'] == [] def test_unicode(): g = Generator(os.path.join(DATA_DIR, 'test.md')) g.execute() s = g.render() assert s.find('
') != -1
    assert len(re.findall('
foo

\n

.notes: bar

\n

baz

', '', {}) assert r[0].find('

bar

') == 11 assert r[1] == [u'has_notes'] # FXs content = '

foo

\n

.fx: blah blob

\n

baz

' r = g.process_macros(content, '', {}) assert r[0] == '

foo

\n

baz

' assert r[1][0] == 'blah' assert r[1][1] == 'blob' def test_register_macro(): g = Generator(os.path.join(DATA_DIR, 'test.md')) class SampleMacro(macro.Macro): pass g.register_macro(SampleMacro) assert any(isinstance(i, SampleMacro) for i in g.macros) def plop(foo): pass raises(TypeError, g.register_macro, plop) def test_presenter_notes(): g = Generator(os.path.join(DATA_DIR, 'test.md')) svars = g.get_slide_vars("

heading

\n

foo

\n" "

Presenter Notes

\n

bar

\n", '') assert svars['presenter_notes'] == "

bar

" # Check that presenter notes work even if the slide has no heading. # For example, if it is only an image: g = Generator(os.path.join(DATA_DIR, 'test.md')) svars = g.get_slide_vars("

foo

\n" "

Presenter Notes

\n

bar

\n", '') def test_skip_presenter_notes(): g = Generator(os.path.join(DATA_DIR, 'test.md'), presenter_notes=False) svars = g.get_slide_vars("

heading

\n

foo

\n" "

Presenter Notes

\n

bar

\n", '') assert svars['presenter_notes'] == None SAMPLE_HTML = '''

Let me give you this snippet:

!python
def foo():
    "just a test"
    print bar

Then this one:

!php

Then this other one:

!xml

    baz

End here.

''' def test_macro_parsing_code_blocks(): m = macro.CodeHighlightingMacro(logtest) blocks = m.macro_re.findall(SAMPLE_HTML) assert len(blocks) == 3 assert blocks[0][2] == 'python' assert blocks[0][3].startswith('def foo():') assert blocks[1][2] == 'php' assert blocks[1][3].startswith('') def test_macro_descape(): m = macro.CodeHighlightingMacro(logtest) assert m.descape('foo') == 'foo' assert m.descape('>') == '>' assert m.descape('<') == '<' assert m.descape('&lt;') == '<' assert m.descape('<span>') == '' assert m.descape('<spam&eggs>') == '' def test_macro_process(): m = macro.CodeHighlightingMacro(logtest) hl = m.process("
!php\n$foo;
") assert hl[0].startswith('
Let me give you this') assert hl[0].find('

Then this one') > 0 assert hl[0].find('

Then this other one') > 0 assert hl[0].find('

0 assert hl[1][0] == u'has_code' def test_embed_images_macro_process(): base_dir = os.path.join(DATA_DIR, 'test.md') m = macro.EmbedImagesMacro(logtest, True) raises(WarningMessage, m.process, '', '.') content, classes = m.process('', base_dir) match = re.search(r'', content) assert base64.b64decode(match.group(1)) def test_fix_image_paths_macro_process(): base_dir = os.path.join(DATA_DIR, 'test.md') m = macro.FixImagePathsMacro(logtest, False, options={"relative": False}) content, classes = m.process('', base_dir) assert re.match(r'', content), content def test_fx_macro_process(): m = macro.FxMacro(logtest) content = '

foo

\n

.fx: blah blob

\n

baz

' r = m.process(content) assert r[0] == '

foo

\n

baz

' assert r[1][0] == 'blah' assert r[1][1] == 'blob' def test_notes_macro_process(): m = macro.NotesMacro(logtest) r = m.process('

foo

\n

.notes: bar

\n

baz

') assert r[0].find('

bar

') == 11 assert r[1] == [u'has_notes'] def test_parser__init__(): assert Parser('.md').format == 'markdown' assert Parser('.markdown').format == 'markdown' assert Parser('.rst').format == 'restructuredtext' raises(NotImplementedError, Parser, '.txt') class WarningMessage(Exception): pass class ErrorMessage(Exception): pass python-darkslide-2.3.3/tox.ini000066400000000000000000000052601271614724200163240ustar00rootroot00000000000000; a generative tox configuration, see: https://testrun.org/tox/latest/config.html#generative-envlist [tox] envlist = clean, check, examples, {py27,py33,py34,py35,pypy}, report, docs [testenv] basepython = pypy: {env:TOXPYTHON:pypy} {py27,docs,spell}: {env:TOXPYTHON:python2.7} py33: {env:TOXPYTHON:python3.3} py34: {env:TOXPYTHON:python3.4} py35: {env:TOXPYTHON:python3.5} {clean,check,report,examples,extension-coveralls,coveralls,codecov,publish}: python3.5 bootstrap: python setenv = PYTHONPATH={toxinidir}/tests PYTHONUNBUFFERED=yes passenv = * usedevelop = false deps = pytest pytest-cov Jinja2==2.8 Markdown==2.6.5 Pygments==2.1 docutils==0.12 textile==2.2.2 six==1.10.0 qrcode==5.2.2 watchdog==0.8.3 commands = {posargs:py.test --cov=darkslide --cov-report=term-missing -vv tests} examples: darkslide --verbose --debug {posargs:--embed} examples/config-file/presentation.cfg --destination=dist/examples/index.html examples: darkslide --verbose --debug {posargs:--embed} --theme=void examples/config-file/presentation.cfg --destination=dist/examples/void.html examples: darkslide --verbose --debug {posargs:--embed} --theme=abyss examples/config-file/presentation.cfg --destination=dist/examples/abyss.html [testenv:publish] deps = ghp-import2 skip_install = true commands = ghp-import -n -p -m "Update gh-pages." dist/examples passenv = * [testenv:bootstrap] deps = jinja2 matrix skip_install = true commands = python ci/bootstrap.py passenv = * [testenv:spell] setenv = SPELLCHECK=1 commands = sphinx-build -b spelling docs dist/docs skip_install = true deps = -r{toxinidir}/docs/requirements.txt sphinxcontrib-spelling pyenchant [testenv:docs] deps = -r{toxinidir}/docs/requirements.txt commands = sphinx-build {posargs:-E} -b html docs dist/docs sphinx-build -b linkcheck docs dist/docs [testenv:check] deps = docutils check-manifest flake8 readme-renderer pygments skip_install = true commands = python setup.py check --strict --metadata --restructuredtext check-manifest {toxinidir} flake8 src tests setup.py [testenv:coveralls] deps = coveralls skip_install = true commands = coverage combine coverage report coveralls [] [testenv:codecov] deps = codecov skip_install = true commands = coverage combine coverage report coverage xml --ignore-errors codecov [] [testenv:report] deps = coverage skip_install = true commands = coverage combine coverage report coverage html [testenv:clean] commands = coverage erase skip_install = true deps = coverage