Kajiki-0.5.3/0000755000076500000240000000000012651435631013002 5ustar amolstaff00000000000000Kajiki-0.5.3/CHANGES.rst0000644000076500000240000000515112651435003014577 0ustar amolstaff00000000000000CHANGES ======= 0.5.3 (2016-01-25) ------------------ * ``py:with`` statement now keeps order of variables, so that variables can depend from each other. * Babel is no longer a dependency unless you want to use the message extractor. 0.5.2 (2015-10-13) ------------------ * TranslatableTextNodes are now only generated for non-empty strings * ``py:with`` statement now accepts multiple variables separated by semicolon * Babel message extractor fixed on Python2 0.5.1 (2015-07-26) ------------------ * Fix crash on PyPy 0.5.0 (2015-07-25) ------------------ * CDATA sections created by the user are now properly preserved * ``cdata_scripts=False`` option in ``XMLTemplate`` allows disabling automatic CDATA for script and style tags. * Autoblocks experimental feature automatically creates blocks from specified tag names. 0.4.4 (2013-09-07) ------------------ * Also accept "$." without erroring out. In fact, accept anything. * Add integration plugin for TurboGears 1 0.4.3 (2013-08-12) ------------------ * Accept "$(" without erroring out. Easier to write jQuery stuff. 0.4.2 (2013-08-01) ------------------ * There was a showstopper regression in FileLoader. Fixes #1 0.4.0 (2013-07-29) ------------------ * Support Python versions 2.6, 2.7, 3.2, 3.3 in a single codebase using the *nine* library. * Support HTML entities as well as XML entities in input templates. * py:include fixed, can see global variables. * Genshi compatibility: support built-in functions: defined(), value_of() and Markup(). * ``py:def``: Do not crash if a function has no content. * ``py:strip=''`` is the same as ``py:strip='True'``. * Correctness: escape HTML attribute values. * Correctness: Always close script tags, even in XML mode. * Add integration module for the Pyramid web framework. * Give the FileLoader a *path*, not just a base *directory*. * Documentation improvements, including the need to write CDATA sections. * Move from Sourceforge to Github. * Use Travis for continuous integration. * The whole codebase is formatted according to PEP8. 0.3.5 (2012-05-07) ------------------ * Several bugfixes * Output HTML attributes in alphabetical order (for testability) 0.3.4 (2011-06-01) ------------------ * Make Kajiki work on Python 2.4 0.3.2 (2010-11-26) ------------------ * Fix Python 2.5 syntax error 0.3.1 (2010-11-24) ------------------ * Add support for py:with * Remove unused babel import that was breaking pip/easy_install * Python 2.5 fixes * Correctly strip None attributes and expressions * Turn off autoescaping in text templates 0.3 (2010-10-10) ---------------- * Adds i18n support * Fixes several bugs: [#7], [#9], [#10] Kajiki-0.5.3/docs/0000755000076500000240000000000012651435631013732 5ustar amolstaff00000000000000Kajiki-0.5.3/docs/_static/0000755000076500000240000000000012651435631015360 5ustar amolstaff00000000000000Kajiki-0.5.3/docs/_static/favicon.ico0000644000076500000240000001027612554436352017512 0ustar amolstaff00000000000000  ( @ 4W cw%#3r ^#k Lg+Sf+|l.TF᫱~nk^OjtK;(3 V?!KK255*ᳵ$ *ۭox))0չ'("' 33  :&S+n ?8p12^+"C3n03X& 0Q ;޳V'0#$C( )5ɧ?'hg_컶ךipRE2 :!,A3y1xx$^[,+???????Kajiki-0.5.3/docs/conf.py0000644000076500000240000001575112554436352015245 0ustar amolstaff00000000000000# -*- coding: utf-8 -*- # # Kajiki documentation build configuration file, created by # sphinx-quickstart on Wed Jul 7 22:31:03 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os from kajiki import version as _version # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.append(os.path.abspath('..')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Kajiki' copyright = u'2010-2013, Rick Copeland' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = _version.__version__ # The full version, including alpha/beta/rc tags. release = _version.__release__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = 'favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'Kajikidoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Kajiki.tex', u'Kajiki Documentation', u'Rick Copeland', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'kajiki', u'Kajiki Documentation', [u'Rick Copeland'], 1) ] Kajiki-0.5.3/docs/i18n.rst0000644000076500000240000000353512554436352015254 0ustar amolstaff00000000000000==================== Internationalization ==================== Kajiki provides supporting infrastructure for internationalizing and localizing templates. This includes functionality for extracing localizable strings from templates, as well as translation of localizable strings. Basics ======= To internationalize and translate templates, other templating solutions require that you wrap all localizable strings in a `gettext()` function call (usually aliased to `_()` for brevity). In this case, you would write your templates similar to the following: .. code-block:: xml

${_('Hello, world!')}

This approach, however, adds lots of noise to your templates. Kajiki does not require that you wrap localizable strings since it automatically finds all "translatable text" in XML templates (any text outside of an XML tag). In order to actually use translation, you must replace the placeholder function in `kajiki.i18n.gettext` with the actual gettext function. For instance, you might place the following in your top-level script to enable the Python gettext module:: from gettext import gettext from kajiki import i18n i18n.gettext = gettext Extraction ===================== Kajiki also provides support for extracing all localizable strings found in a template. This functionality is integrated with the excellent message extraction framework provided by the Babel_ project. Typically, you would notify Babel of the location of your templates before running the extraction routine: .. code-block:: none # Python source [python:**.py] # Kajiki Templates [kajiki:**/templates/**.html] Please consult the Babel documentation for further details. If all goes well, the extraction process should create a POT file containing the strings from your Kajiki templates and your Python source files. .. _Babel: http://babel.pocoo.org/ Kajiki-0.5.3/docs/include/0000755000076500000240000000000012651435631015355 5ustar amolstaff00000000000000Kajiki-0.5.3/docs/include/index.html0000644000076500000240000000267412554436352017366 0ustar amolstaff00000000000000 Welcome to TurboGears 2.0, standing on the shoulders of giants, since 2007 ${sidebar_top()}

Presentation

TurboGears 2 is rapid web application development toolkit designed to make your life easier.

  1. Code your data model

    Design your data model, Create the database, and Add some bootstrap data.

  2. Design your URL architecture

    Decide your URLs, Program your controller methods, Design your templates, and place some static files (CSS and/or JavaScript).

  3. Distribute your app

    Test your source, Generate project documents, Build a distribution.

Thank you for choosing TurboGears.
Kajiki-0.5.3/docs/include/index_kajiki.html0000644000076500000240000000274612554436352020710 0ustar amolstaff00000000000000 Welcome to TurboGears 2.0, standing on the shoulders of giants, since 2007 ${parent_block()}

Some extra header data

${sidebar_top()}

Presentation

TurboGears 2 is rapid web application development toolkit designed to make your life easier.

  1. Code your data model

    Design your data model, Create the database, and Add some bootstrap data.

  2. Design your URL architecture

    Decide your URLs, Program your controller methods, Design your templates, and place some static files (CSS and/or JavaScript).

  3. Distribute your app

    Test your source, Generate project documents, Build a distribution.

Thank you for choosing TurboGears.
Kajiki-0.5.3/docs/include/layout.html0000644000076500000240000000341212554436352017563 0ustar amolstaff00000000000000 Your title goes here

My Header

Now Viewing:
Your body text goes here ${footer()}
Kajiki-0.5.3/docs/include/master.html0000644000076500000240000000451512554436352017546 0ustar amolstaff00000000000000 Your title goes here ${header()}
Now Viewing:
${footer()}
Kajiki-0.5.3/docs/index.rst0000644000076500000240000000117412554436352015601 0ustar amolstaff00000000000000.. Kajiki documentation master file, created by sphinx-quickstart on Wed Jul 7 22:31:03 2010. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. .. image:: media/Logo.png Welcome to Kajiki's documentation! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. include:: ../README.rst Documentation contents ~~~~~~~~~~~~~~~~~~~~~~ .. toctree:: :maxdepth: 2 templating-basics.rst xml-templates.rst text-templates.rst migrating_from_genshi.rst i18n.rst runtime.rst Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` Kajiki-0.5.3/docs/Makefile0000644000076500000240000001110112554436352015367 0ustar amolstaff00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" upload: html rsync -cavz _build/html/* rick446,kajiki@web.sourceforge.net:htdocs clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Kajiki.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Kajiki.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Kajiki" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Kajiki" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." Kajiki-0.5.3/docs/media/0000755000076500000240000000000012651435631015011 5ustar amolstaff00000000000000Kajiki-0.5.3/docs/media/favicon.ico0000644000076500000240000002056612554436352017146 0ustar amolstaff00000000000000  &  ( @ i\V RcWw%5n,r Y!3k K(g+2Sf}l.TFGȒ|lk^OjtK# kkN00#.(8"3 V?!QQ7p++$ *>{|kϒx}++M/)*$' <3  _ & fSCS 58p12^+"A3n03X& Q ;޳V'C( Oɧ?fe]ǻYiqSF2!5:!,N=v)^[Me7@?( @ 4g k|'3t o*vn Si/Ug+|m/THՋiŐ~k^OlvQ;s+8 YG%fCC-FF=<=6 > *бŨ/0- '&'JJGe`Y0OOE,wNPH##G  3o,0/S)':.075s;3+% 8II-40~KBI2NP065xF< 0fDqt066vG>0FH8557272bH7 )5,+%^=5'ywnȾ?DCpZ, סnoRD?k;" -3( y1xx he",}+????O??Kajiki-0.5.3/docs/media/icon.png0000644000076500000240000001425212554436352016456 0ustar amolstaff00000000000000PNG  IHDR,,N~GsRGB{PLTEf33f3ff33f3f33fff333fffff33f3333ffff33ffff3ffff3f333Ֆ_tRNS@fbKGDH pHYs  tIME  RIDATx],7r"YY]=Ʈa/tFu# E꽹$@f0[;N;N;N;N;S?Ajhf];blhxK5_hh ?\%Z?K6WSzd'jrl'QuCC~('[RDDZ'O]+jQvRJ>T"" TI1yt;PF^*\VF:w"xUJ8~`wBKAe'Fbv:a HD(`bۉk7,2B+rƠTPS0:n""In7Yq:$;`,A'0.K_oOV'ɴ&`jSɇE#t!,}=0T3^ɶd݄uN\!kA$t6͌QYAu<10mZBȦFHDRJ-mdYz" r^DWl+5M>P= ^{3">;$?,-d "9cRŀ|J.4DGzF2! O^'$:]2z%B:VFO[/[r1$q0Hc?{t܄J% k@f^ U>Z;2넬Vv75 @KA?o_=?NOgJiIݘҷH}+Ii(Eɂ`ET-nlk0vˇ>}G2xŔ,GptY^F%oIX D,đb+ R8=}E 1D[x R~}BSO ŋb]/IOle?eIqwr5>nC1yLOf PjvDzU#q)E8M `qkX"S}7J>+Ehچ}1$ߣ0ZCF0||ibȑ()\͉րG ^t=%Ks`-uqF;S@~p =rfy &v 1k n7+x|TNqq(;(~@qZ+S? &4i""8QmtԖ݁#CPN;V"Uh.DY\*;Ð a"fZDȱxhs2HzAKKk]mJ0oa.^QES檥J |pXalgXIpҡa,BacNCbݴC[~=$P".-l0蒯+Oqsp)aUM9P*s=` C*F7-f h]/%Vn0gffhAކ=clrdݤ0ל65{f0$Aɜ\Q\<]H1d2f0bW+8CQ+Qd=y|YCP}z\A)k}6AWa7C91?ըb|oߝ7n+r8wNiYʮܪ;bnӊg 6]:S .inTh?NUgG\z1 __'?Tn%A*SŞpz\`[p̍hR2pŢ2_=o8fm:K,]p>ӻ"vKR˝*eZe5Qqj"Gqdo~|~==N-65KRaqaMb eq7zkA^7#z<+suݚcoIu04,V5hHklV^$ r<%YgZv4C4g$K^kZ%!1~gֆBڻ*" y1j_/Z<%)KtnBE bt#ꝗ5 %9'Dk5#ۊajwZRg:ܶQzG F.ΛGQdYl[Cs å"7B({%.PKj^E.q5ɨaT:}9i][H:/(Y,Ϡ p}|+ΕKpU6.Z%*,vߒ~1c)B>;bQ¯O%?<0UvuKCF:0N7$]NW?8%MO0YqP%>Zk_K^@kx4.řeN"ÁNV:{d\KX]3f.`^CCW L5XFʫp Qj>w=(+'U}| J)w#^5ډt%%ͱꭀ2XMk;1|fdNVoy58LtB]g&g!H6^%),J[)kW.GkD(xZj--"~_ɭoS]{ g"~[_Jk-6bWwdU@"$<7eP1VVI?<}wC%yZ>' '[&uX>beHh h>OU%}$[V7T]h0[1z&6ԧt֗>em!U$׹},gݷ~&*F}ж:@uWKlWcN-cyWs߉]m|us[A2s![-mW%θVg#j> -qQu] o&O&X[qߞT @^c$;U ?>VbZ(~XsWWνXѿWfZ<ZZ^iKit_6m{6g#L4Xk FpVM{Pd6u\~E?WeE5و{+ 8~2mz`6,VQCڞ<\ X3*?Z-{mb !&x*6b3AAʾGIQUVDsK | qf#c>2UZvb t5[ OÚʑĉ9LTW;O*ɖ~7Rݕnu⬮sscl6OT9joΰWߍk1f~&W6=9Zu7}s'O["yjk7EqߘX,M]AK\lͪ!b4d<̷xbXbznEܻu9& ^Sc waEaufOܑm]ccPֺ=5lv!,M˴^|"Usxsd/Ķ91;H;yu1i(y,+'@$83kk1wX-~^2Xl}sy"vwX`vacf1 ­8w\sIA񀿻`Fxxݱ#ìU>\,"͋(li(`1#NjF3/}{q̏b35Qs׈h_{!xGo4jTƐ׍<+NUMWѱ^c,/Fi}IH|ݿtζT^2e%{gC&?Ȳ<"9GIpqnOϗM3vQu1|yB+Zxc zy;k\9a3vI }XsNT'{#=~eh턑( GIX``fcɸ[F6Ŵhz(O |F^SjC7Ov!2YmZS8|}d'B=#]b^9a{iR7f ȸqk60X"R!J]7b@6‚9{zu&K4ȳI?0/ckD~}p߅p34v;uJrn͔)مr)*4jxkKj&fgxw5?;}#OѢ0!b* tН?l"L<˃@ gL}rـ$zn<2AC˛=Ev 6߃*U.R~wWTt(~ 0^g,KRcIܛ͐:I^I:1&t]$qaΦ}4)sJAIi7X-e,QTC5h>{$WmG\e4ͱ @V֗eas. }[\n4 IT tc_-΄=o>\CiW78)5HM uuhXYӚĔ]s %nG696 r@[>TtC|kj+[{ "yT,AO ozʎΈSWaP6@ r="BXs 7*QTqBSWX>&  U}bۊڣHMJ'KrkJ}jϊv ӍgtEU^̓|B9'?U,2w2jFke\N4v E=;')Z5_m ]IJ}4˵#[( `xR࠱]Cf)arP!L[a$MAZto+55"}E #X^Z|g`)~O" dVޟTRz Aֵ2XܧX/3sK2,wLXV'`W G'#ZeQ()eR nteh D/`gnh3l'~BZ3|yjԲt6lg`ilu;@ ` g'ıaə,g~hͲ^;m 9ZV"oh+ 'U 'iOwX&e$'k'j=c,( ,'8 ÇLg"c x;  n/QM ddT~c ]XBvۘ.Y-E- u,/50`0 .T +3 T(%} р3Rw93 !诃p  \G5 ( b!_ #"Mp ^/" $\$ 8q97#87U<::::hyK_YF5*'21 41 1W2Ⳍg=3ʋN @ VW2E+ )  8Ugʱ`Y35|5 Z8ViC  @$* p+B '. /y2]5\e7|T ] @5<7'77^676i6F67o78 :   8?RKajiki      Ggimp-text-layer+(text "Kajiki") (font "UnBatang Bold") (font-size 58.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode fixed) (box-width 186.000000) (box-height 82.000000) (box-unit pixels) &R'55R'>,25r5z5B"$$$ $    I(Nw  : B") U#(0 $(%(&(((  (Qw"(`E (L"{Wn(?2(4 ()\<( 4(nO( (@;(1 \(s( `k(P' r+( lt(X\(U] (- X'((<9t(zee(goz(J_**51&*=?/5EDk]_ /gL$4   ; aP&! !6BJR Uat?6:]8; Tw O#bz24EJ$lg-`QwR(M`D %V]1 66 Elk*Pw$et,t ,,Ktm,&t,|8t,%tq,N$tp,$tp,$tp,o$tp,'$tp,g$tp,x!$tp,$tp,$tp,u$tp,$tp,D$tp,$tp,$tp,I$tp,$tp, $tp,R$ty79%$tmVɹu$t0sX$ @+%sp , s)op , |Q-h58X5F@5]56*Tw 1#b/2.E.l.g.-//(2%V]1 !-ell *Pw$ ,}  ,m,,> , q, p,p,/p,/p,/p,/p,p,pp,1 p, p, p,m p,B p," p,p, p,p, y7mfH0sX$>{p ,Kp ,w V5p4a4 4!2(Z3T5c2]).o. Background     6o.6ԡԭԹo.789&@J1JJJJJKK*R`tlyB{ /ôü&ŦϠϨϰϸb  7 43 0..-,+ ' (,0/  2   7 430..-,+'(,003 =:3 ( ! "     =:3(!% <:9  8 8 6 5 4  32 20  / / .  - ,  + * *   )   ( '   ' & %   %    %   #   "   " !        !                                                                                    <;:98765 4 3 2 1 00/.-,++*)(('&&&$##"!!!!#%&(*-/0 2 568:;>H;   2  0     - , ,   ,   ,  , ,   -   - -  - .  - ---  . ..  -..- - -   -,  ,  , +  *  * )   '     $                                                                                                                       H;3 1.------..../....///.//....---,++*(%! !!$$(,-/1 3 78;>? :64 2 1  /  + *;7 5 3 20,+  7 :7;                                                                                       '    !        %       (                                       "    #    &   &   '      (    (   )   *    )    *   *    +   -   -   .   .   2   3   3   5 6  7 9 9 :  ; = =;97 3/+''$ "      "$&'())***++,--//1 3 4 6779:;<>=                                                                                          !    $   !            #                                                                                                                               ===;976 5 2/                                                                                                                                               4+   =.,   '  %     !             &                                                                                                                                                                                                              (%"!"#&**-1 2 5 8:< @= 8 7 4 1  0  -   ,)   &  %   "   !                                        "                                                                                                                          @=98 5 2 1.-*'&#"!"%&)+,/02 3 669::<= @=;:8632 /-!                      @=<:86 3 2/-!   : 9  7   5 3  31    0    /   -  ,   ,   *   *   (    '    &    $    $      "     "     "   !                                 ;:864 4 2 1 0.--+*)('%%#""! !"#$#                                                                                               !"#$ % &'& '()* ,,,#  ! " # $%%&''()*+,,,                                  "  "   %   &  )   *  * *  *    *    +  * + +, + +4  43 3 224 22 1 11 1<<==<-,))&&#" "#&'**++++,++,,++4544334332221<<===2( 7 *  "   3  /   .             *                                                                                              $   +  -    ,    ,   + .  +    -   .   -    .    / 0  0  2 1   2   6   9==<$   %,---,.,././0113 2 3 7:     ! 9%. 3 A.$c )#9Z=76  8                    -  3  ; @9 5 -*" - 4 <                                # " #$%($ *E%   D'!&#                                                                    !  $   ==:70 )%$! "%                                                                                                                   +    & 5 &                        $ + , / 1  45 8  :;<<=> =$!%(,01 5 69;@===::   6 5 3     &      &     &  , /- , (%$                                                                                                                  '    ,   /   1  @===;;76 4&&&-0--(%$ "%&).4Q%"#(,0 2                                                                                                                                                                                                                                                                                                                                                  $    &                                          %%%%&&&'&''(((()**)*+*+++,.-,,+++*)))''&%%%%$$$$###""""!!!! !!!!    (   * +   -  .0  /  2   2  4 5  7  8  9  ;  )+,-/003 3 5 689:< < < 5 7 8 9  : ;;==> 689:;<<==>                                                                                                                                                                                                                                                                           !     ! "   #    !    "  #    #    $     $  %   $      $    $     $   %     &     !!!"""####$$##"""!"!!        !!!! !!!!!!!!""##"#$$%%&%%%%&'                      &   &  &   '    '    '   '    (   )    (   )   (  *   *    *   *   +    +   +    -   .   .   /   1   2   3  4  5 6 8 8 :<= '''(((()*)*)++++,,,.//02 3 4 5 6799;== , ++ * * )) (  ( '' ' ' &  %    % &  &' '  ) +,},,,++**))((('&& &''((*+,}7KM%&o.Selection Mask Go.k+o.?CGKOSW[_cgkosw{փև֋֏ֳַֻֿ֛֣֧֓֗֟֫֯             r7KM%&Kajiki-0.5.3/docs/media/Logo.png0000644000076500000240000004243712554436352016434 0ustar amolstaff00000000000000PNG  IHDRo.sRGB~PLTEf33f3ff33f3f33fff333fffff33f3333ffff̙33ffff3ffff3f333@tRNS@fbKGDH pHYs  tIME ./\51 IDATx}cH-n:H"}_WUGIc fc`|jYz֏`=w;m'R]Q~\}VgiKj[eˋQc~ YmJN;q)AMa}+ֳImEv֭z"7μ8;m=˜Vn=u@V}vD/}S1^"YƘZp TgM֫9]2pӇvG%Sګτ8ެ݊JIumMg vӘj 3u\z뇳}7 ݤ|s8F\~k&Ӄt1b2@n=sЛAeL05`SAq 35%BsS[t{ kVgb.4Аo2@ۈ+u7 Nuh&~UGy{ӝ |1V&߰H9A4Ĺp)-_G<5S+87,Gu=t^ I^q0zS#ZHg ~ dWn7cBW2p'Q`vr.b5U ٿ#ϹV{;bO(* oY]0 YEWּ8ngPk{F[#WҽO>[xgsWiiLKR}'Mdmn8 QSg 4Es0:M؊Z}`o\S8)lV9}|1dp+N|[?%p?g4&IE >ߎ6/&eg£γw@ q9  ;_h{tI#Aj:-K~} pw'9{ CD)rFX)º@BJC<~xÁ 񝴏?嶈aSɣۻh6$Ěu sB3/9ܹ;$<aڵtF"Uh@ {x32Dv!"uDfALJbhQ>lHd0p?Nٰo߅D+YzMZ[JcQlw-\c%HPo4dL~yw\fzV?{1 j9I2 $5zw U+w_={| {U,7.k{>)p_У:(3iJZ7sk!'M(:(+_qoלYٷHНޒU 46.yC*ShÒ1C2%Wg\cUiZ*7GRrC[0_6LbyJb!* С5𻐞VzUQcͽ0TR"uAni0zzrjP EEr8&M2z/r.)śr s`;Opտ1"|P~0Y*&W[0:D~=4 >>3xVtj&|#:b 8UwBQ_cV-j,pL˜;&/Ǩrg} (D.9*[(8~dc@JyK-UPipRh]_:L ׶eAѢ7,\/s߽)Q{3Jwit__R[1:g%B7R֡~'Dt05[zV<h["RB$ڷwɽ$?5 ?RF.@j|sRC'j:F :yXOY8dIq7`_*Omw|AlОi27܇=C%Isw[kļng MH& yQ: 0dG$(Cc3Uw~f+NW`29mJ&]lOfCOeا ٨݈ 5PEwVGrsr|ˉnа?7Y%msv\fm\lKs),V),}@=GNe y}̘P/אb]Ʊ?N+ $){fi=6z*7aɴڂ ɷF Z<%G15?iM&.<)t.4*Dj $`C1E pB\PC%`ER id|2.T|o]<7$IVnm+uP:&u] s5Hݝ0p&+jf@Co_|A2dʱy1m/b8 !(tqQ&Գ\ qUxMpnT9AUg!DdEP 2j ܱ? d,[zu4٫vd1^:`g =nZ@Ñ Am{ڶӪi(ުU!cTB+zVk!I@k.I N`M_QPHR{gH{m۰ ub[|)}'|wq2yruRkAQsM141- \J$AB伤3F3O7qza@:Vk50blak;0[?ohq:'xXz_њb]CDF;Ѡ 7hmf:FF=@inXW_m?׶[RCd>G=TofwpYgߨ;ؚXGj`hӇ627dOf[Is _.Aՠ)뚨8llX= q4W[(֦桁PӔ~Mb(ms}Y\";é xZMU.~<"Ӫf6{{+3A8}S Du\@A)e}!D]^y:ovk2fҰOjm^p OJ}1S;3:~!`thXŪWÂE!D^BQSsZ\y] &Ílqlj/-plr瓦|րҘpAxUA , .@`v6tD82ė{}'S2& _ol"OO}20;2SjТovrCW}tpcpB-d#Eâ~Gˬp%-B+}ɡz29C/LX?|hϿL~JjP7 2BJbN5qF}Ϗu\V9 d,ucYl1)'o΁҃˶T"7ʼL݋grT&4-s pX@ 7dn­CϬwZwP̪^M޷hi;6,F=v;Oiɉxų%&-F=Vݒ%538]-Dҏ]a" =H8\pnWwN'k . '%sv4 t'_,=;ހЪtPwGnq x!pS\V} vvɊF]`UQ yvThuEC4n" #"IJ{t؞g?oii[?Ҫ{~H9JovYE1d6vjem*'>!y`Q AAd-H@"qGr`]gLf5h9qB]QxD9yo2HC4adm9_xսlCZ00YzJؔ9I.-A- n6 hsNX:ChǾ%=)L~.n +zE؄ ׺r$$քLpwQھOq%gUl{gG[An};~c6Gtx.jEK]Ob;0Xy6i 8}нhYW06rq,dkP;C{.h }t!xG7^l֐tI:G(6!,ii}7#Cշ>@,_FWo04})Z @U(b %UQmHD5wSum"z0H8~|{e: %k, qFk dL=Tcc,Ka%kXj,/yvS&p ~yB4V$66Cy)N>6H}PKnƵ P IGwϐH.pv st8kRVV,IJEVԇKc=,650&쳡,pc__OƵ{t*w׷AC Lnwy&liD\?.XUX>^K"6Q݇3$ ziuy`  ԅS:ٖ#E >ONA}/!v+ 2g>B?dԌ$U6惊sĄ-4۽C%ߴB%Ai$NR0!I8C-w_Vx7|]6.0o6A:$LL,aSZ5d+6r?.G 6a5l876M qۻ(UJjrnT!f,7~8'V+XJ}\ɺFrX+S&XMj_FkR.C`Nb?~JcЃp  $)8$>&̪]4MNdj1 b9L]5R)EV/lt5ӕ˳~Kr%|moE2)#PjLv9H*&J͇þlib'p _ ۺmiAV9vL?SZʻEUezVA۞ :A:Ls LpcLVDƦ`i|HiT̤:=:fT4C4]QNVߴ}瓂hb>:8!C Z|кH%G$gH_B6ZT4A]%( 6Ӯ/(D< ؇ՒqȻ'cds=զ 0M!G˼Ӡ&r~pzۂ6VlLh" *&tS  &#GoXRL[>0Ҝ"jWY*ы0Gd+;D\$ +1Ԇ)cb0SFRqon@p,k{V@ K¸V%V{6-2m4Ɂ,W*异=W, S6qHv8v!+oݐkeѩ "SwM:3 IDAT;Vv[KATe~. JbehY I0Gi (k9sDHtPv֣INi ƶk.}u\ac]EUUZ]ٺ aaZWQX9sbǁ6MSS؁T3-'ZRirʠ 's6WΨ::"y΢A)ypOrxM`d;/jE[zPܐޚOxx<>WA(n`HpӝŭNB&łʆlf.ybo l!By 9Of[12j)R lW= "IlZvw؝o(6U*~Gu$&eIx%v+aL3(yY2\dW@n)*S w4ug{|J0=C2QliJO;o~\fYS²}U5f"&$fk@(j Ͻ݈hh7#s6Yڛ2mKP4QFTI^(-!A(tn T*GW:3k5>H] Dk~”1v<>kw8Jeq{|",?v.o2-\Lu#^!b[3[^ڻx9nnT{B`S*0C;ݴ 8@W R T*dryIrO;nM®k֐ZKMu&aJ=໡QTXfZn8O8nW}-~>j kAʺ`Y[n# h^5-#e`"0jx_p{J>K!nN۰f -YJ$')]]es0:.3$A%M5um’. UǵhOk:E`OP&D^yC~c BЉ$ ,4 ٰʧa6.^)#Fm(Sƃ0?޽gā1E:)xD?N21l'gn^15Ѧ^cK\"k'a^)]/m%kQVbNka䑆LVZvK!7?d]7qW_c%JXj άvʽ K! sibyY ̧{}A;#E^ C;cL[r,0k%LV^]p!z.GQ!rǁ+77P&q3 J?Uro{? +&βoٌaX2겑\8}c^aB8Dɑ]:O3wl\Ӑ8O:-P5&-\UG"|".0ݶZ _3Y.$;|}Ue # Hv_x@ßv>bF!,JLPkQ\SԕnmjblNڍ HUj=./49r5*SΗse)np}ӧh"Zpl/WaU9ZS(ncRI9 X!47OMCG'ZXU@oz|C$%"n.z߮,960];+Ŗh_ ZhCmNT6N2.H3rζJmk!u{KD::c GN1f[Y)|h  j ;_hIggs.I d@Pu. ձG+KcyCk*&,f~<\"N@J2{IMjtNWٙO|zMݠ3t-ssDx#r;nR 7Oy@R,*7dOmmplJ*emq>U(h; *o%C0 96tI9_D_)id7Aвbiܤ|~v_ymU[a`ZmgmN,RWWO?ROߋ7?.p$ټ(6]L{AdyaOg>&!M.aR .zp)! \nXMwJM}x#Ҽg8-`KJ-k-X{IZSd3AWmڢn5*e:c?>e+UO*! &56}ޞVe\>ZS´zsZR gnp=T`Tl~7m}:MhD li\;T?({t*CģpZVi22Yff^S>z/]$ lf=;YXQJS>j`-dR"%a |pmd:_@! x+Ty8P'1WQv *M\K]l l2a\::SHu+ _xK.>jx3Dqov䲐<=<*ݿO8O Ӡ]n376͜ %;)Th.#~H|ob@z 8*C!ihR_8)߆ y.[69Md;WT=t H=U1jhuP!.@opJ"?~5lBgTO8PܥD:-$pB*6iF.?( ZijDظsœ=MF#!v}]w5cXvyUǩy eQUBpXE?6q}JÙܤ }0;`І=hSDH攼UM R[jaNlm7&А>}CX.ұv,'jZ.;'oij1dzodVRf$Aox,n(?^b(Nց]-&6$Ԉ&njoQ% ՠpv_ZɺtHl\|Qyғ}CꙖy=`ҏeb#g{4θv慨4U|͎AHclr,c ;;Xƪhl\xч@TR3ZlR6qw6rL*_ %a$iXcؔf89auܨW]7|CwA =H߹KcekIՔ#6z7S19m₂Ġ%D f^!h]8t(験uC3eSvd`]ȸx<4+5b~Y΢,<Şuv5 1Rvn77 ;o鑷oXQƼDʪr> ,e蜭d;VhPe"$v5^qnkݍ=2C\ao3|Qcj2aЁ1d+$b Yig,HKHq·Ӡ*dR3B,:'@KCC 6~;ۮIbhёGA 4;$Fք 6^%a#!̚2#pf,®vmTBe=CBwԉl8ٳ?G; 7ⰉOwxiXeME Rk #aJX-Z\\CT7} L<破4 #O6WWlB4Lxrt!ff"%CV.QYRq@oorgG-_*j@뇰@$C|5ݡYazg;W;f71DxYӓ&J6 Un?Ϥ vSZgjՙ|BqT&_xgdL;ʥWqEŝ!M@O*wH\$G5rC>ΐ4;.4a !QSA9>yhf[<`8*z@! n[ %T:d}eY mዅ$``W݆BPWh 4>e+^My4g˒7xuHE Ÿǹ8@p%8E %dӊ8TQ_k]oSCM*.xx7.iI /PDʿ^{[B zt&3犧x\RT̆1'c%~Vh{MoT?No}6m {Po/ZGs ΪG{q]IqeB?$Ea*[e\<r?ˍ)Y>[L&=(Dt'G9O os;v=޴F( FP(~6eB}JЎ"Rp)q{^-Ї jxSECĔN-"=AE謑5{!K(K\O|=W'oD/ %ov*1U(~6?*\ A_cbDE.{7ӗ{ oco)l5dnh(Ւe7B^+Qy S%Fv!N*I^,3.d 7 냊V&&qqW#9pqrtq&9O#L8x1FrZ6 {陋}\Gĩ;?Euxs~){QNZ6[,\l$ަ_ytMlpr+yئ\} fۉQ [j nNNr nJpoowQ_K{v6ZVia]usoK k)8?8zu{!1+V]+ޖH‰EP:h0ue?x[\j xw䚪a^xYmi VSp~n]v+ޞp-ώyGnh~ s5rߐaj7 W-x;iQOֿz=->$C<Ѻ]ii7>9!?Lx*R"\nۘwX/D1lи 5mh"K,y baGmm oWesgUd=#8d9OpJto\ʀz TХS߄),,v[~P ɂSAA&GoWa?ķZTqş?3fo˷hP9ZQ }pw#3f[vFۉ*:06o^D|@U{x;7PzB /9#pSG` xȨP+NnZwF>C܎b}v)b=\\},&8>\5wm?9=Euo䫦ͧ6$Po"y?,)l/Y>;z%o xk28m/V_ _/tg=ʯTxS=-].F/zO~ oN ZfU3mz~$MK[aJ:^}Woʧv ZXWj% V׺bc"\o= Ri17ܪv p\+"ء=kYv=T3`Qϳ~ lWo7 Nі)GpR<ͶcTz~+vo_^Eb_9smx܀+QTpG]|yEn['僚2n{a!;|H=ճ.\tҔ63 FxZW}%^(6ٓ0.N՝j;qg_>$8tdǵȢ >oPOal=k3Jԃ(}=S̓t!L-T-}_'>DĠwT+V͍7H¡ڥ'8 NKnnO72xuUGJ"%mC "$SD~{~8I".Vg NjI wWv&n<@N[N6@Y"Y~8XAܔ\ޢq3fIDATz 8A$XBT.٬gakHtg1wJ͔gNY ӡ[Tzp߃O\,WEbcyl] nI^^GnԸo#8U{]Ys߂_\׊ X}WYxL) 6tEk:K5prYb,p8 sJbImw>X~Lyzi46+۴lI-œ1.j{y:<3S"*t!\ mͰx洶Gꃇ^f(VL .vGԓVzk45YwΓS=)89855'1 dk9W2Fk92Oh0]NgL <6| #-  ަ<Ӵ|_g3 ĊϧO[&x xDn O ڮ:<= xMO-P oc:xG" 9}xPn0h֢e;ocK67k{;]-4mBfuYh"!'֜pQːa#mc)a : pƐa1gaxV[r" -8r+gI;r+ֳ 'pkU,xZkɴdzg8ci ŝGkQk=KIKI /V5,JptV4F Y܇#9_u0n=R6YKtZ8[?,Kqkvbm,_Ҁt]zpY;ĚY|8Zud:+:9Mޢr*zAq[[^; q{h3r=?q~z5VŊ q|5 ֝3빛יp#{T(ޯe܍l'un=w Tפzq+soĭzֳz?pDz~O$HIENDB`Kajiki-0.5.3/docs/media/Logo.xcf0000644000076500000240000005341212554436352016423 0ustar amolstaff00000000000000gimp xcf v001,,)f33f3ff33f3f33fff333fffff33f3333ffff̙33ffff3ffff3f333BBgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  ,  Background     , VVV, I $s'03j669-@LKPP PPUV]VeVmVuV>?>=;<;;::::;;:;:99 8899 8 7  67 6 776 4  *   )                          !    !   "   #  ' #   $  $   (!  $    %    %  (  '  $    '  &    )  ' (  *,  )   )*   ) +  *   >?>>;=;<;;;;;<:<:9:99::8878788 6 4 +)  !""$$%%&&%%%&&&'(())***++   1  -   +   ' &   $  $ #   !                                                                                                                                     2.,('%%$" '*))))(())*+,-..//1 2 3 3 5 5 7788:;  *  '  &   $# !                                                                  $   '    (                                                                            #   %   (       %  +   '  '   (  *   +  ,   .  00 0   1  0 1 1 2 2  ++,-..//1 1 2 3 3 4 5 5 67889::;::9999989998988>>                                                                                                                       #                                                      <=>==<<<<;;;;;<>:9/-,,+((' % $  #  "  !     )@=;; :: 8 77 44  3 2  3  1  / .-  -  ,+  * )   (   ' &    $   #    !                                                                         "                                             @=<<;:988 5 5 4 3 3 20/..-,+*)('&%$$#"!   !""#$%&&'(())**++-../01  9 5  3   1  0 /  , *  &     $                                                            %                                                                                                  !  !  "   " 33886 67>                              '    '     '    %%  7  9  ,-.1 2 4 5 78;<===             "   #                        !                                         - 5 21 0 8 9 74 6 6 78 2 3 3 5 5 6688:=======<;;) &!  -./002 4 4 5 6788                                                                                                        !    "   "  "               !   !     !        !              !    "  !        "    !                                                                                                                                       #    "  :7777776666 5 3 3 2 2 1. +00.--,(# $&*0 48]=976 3 1-*)(&#!!## # # $ %%& &  & & ' '(((( ((((((( ''& &&&  %  % % %                                                                                           &)*$  !$%&(     %     &   ' (   )   *    )    +    +     ,   +    ,    ,      ,    ,    ,   -   -     -   .  .  .   .      .   . .   /   0  /  0    0  0 0  1 0 0 0 1   1  1  2  2  2 2  2  2 2 5 336 5  5 4   5    6 7  7    7  8  8 9 :&'()*+*,,-,-----...///////01 01 1 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3 3 5 4 4 65 6 56788899:;  "     ! " # $# % %   &  &'  ( @@@@@@! : ;; ; ; <  <>!;<<<<==>KB%!Kajiki-0.5.3/docs/media/Maind_u0.gif0000644000076500000240000003050612554436352017143 0ustar amolstaff00000000000000GIF87aUUUUUUUUUUUUUUUU 0@@ (@ (P  @u@(P@}̓ ,H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0c<͛8sɳϟ@ JѣH*]ʴӧPJJ՜jʵׯ`ÊKYYϪ]˶۷pʝ5-ݻx˷_v LÈN̸ǐ#],˘3kJyϠCyӨSnZzװcn-۸ͻcwN+_μxУKw|/WνwۿOmӫz~Oߟ>?f_܀&`o.5&afXمva~({H(eb,|.(d0hn<c@ӏB)$F&#J6)#NF"RV)"Vf!Zv !^ b fyj n_r9"vz9~&z&6&F&V:@fv*jƪ֊Jk &6!FV;fvކ ;$궫 oK+nzo ,m;p.̰?,lJqź^o,k rȪL&,j*{r˚ 2,i6;sJ @33A@-D7H'SC7mQ? UVQT\w"aM6fi @Umw3w]uW4pg-l)y ~߆+6a=U7^Q'ڋnyF [U~g擳-ԑs^);ܚK鹿7G4XCҿ|a%?x nK}>c:hxA?V׻9FXfosdcV́VdǺ}u}uЁ 2 EZ9VewaA WBx3? Pa{(y/kYP("у;"<-q#zʘh\#7;͝/mq$qlj#QD}4B3QyTdQhEvbxI;p4ߨ?!f2r yR2l#,JPQ/W!s(L)2(Ó\#wDq c#Y7,Q )i͞`ӑ+CYDShD#*˹=['; TLxS'Oi>E~ev*i A |:s48KE<^L>[7}b@$-͈~)@v!T1"zL1ݩR#tng0IOrttDG ?E5.KJm O[ uYެNɪSbNĜ G U.auQZHqiA+J56OU ;XfU*4:ce KWle%и知lWxWֆP%f K׺ j[ՑԴ6gýj(N"/[Vn~1ԭu{Y~oэ- }"mz۩pKZ~r*cϬʷduҗ߇li.r[^ʵtoWT6ʖ[@֮rr;]NYz4Xb3~d%f%,*_/0ayu2Kl|FXr- j#6 \ UdMshSЄ<ɫN|HТnD0Ɲ0V4Kd%\Eoe )@d-kԚ&?pGY:[eeWٌߞ#Yi=j#m2C?D].GN|HZֳ~wmmxڸA!S׬>~H҂,}\w_`4DPq609(?/KTiZw8lMYSf>q :~wHS#˼VEqH8-7\WβV&TP&a{Cy0s8Ɠ7^xNFluaGqǗVݳ7߉S;G iNŻaPW9xئ>a?}6?.{K ?VlVw=;שE>fs'k@W8xtp{'vvqw~ft 7|oV|t"`ArrQmi_nuz}4ml-H{':yGyk{bߖhpg|D&z]\mu׃sPhShx7Hq7Pp5 |oE!Gb:G}kzȖx۷{O;9~LVx'gx{iXt&`GdJGgbxW2j{DŽw糊l({g8~Gȃ}Yhw؈<~7_K JxWJubpW}HWul֊:hR}y~GDf6TcQGQ|zHaXk\n׸xW8㗍(h8旂\X}jg !_6w0el\|WNJh؍بz{9)i{s蒇uHȓ䷍ Ajqhd`i!rY~kӓGzs{ِGt׋܈ٕkyglhy@&7DQE@G8fWXxhgx19i8 A:yeه⧃7uu⨐W^p{xq\TyLjx]7)t9{i}xdY@Y6i FqVx) A)ytрcFdBx?YZ9}Ygɐ빙;x(Rׇ=Xl`{z)U'T$D3y}ȩǞ)Q4) (*9q5K1:+:{a ZDIA7 ӧh/ZoI)ʒ(yq)8kI)4JkʣJy˅!KcFTיL*o{Ǟ8dy(cYV0o vQ#:کJ=^D& iz,4y`J_W6o9\YVzęǩ$ghĹ Ҧ۹;ʣy9Gwx`i1g}b _zO~HY3)o;)jY}7BԺ U~;6Wjx[țzO}7x%yw2Jk(kk(ӷEP:j<9*Joڟ  Z `|Ac:DZD{G*+9xepز昕f{lliT:7k58+MZZ˰`IKíBjHN)ط˹ j#˪c3dK3d9m;\׶"EвH`ӲW%3Kj ۫v[H;ʦzɣKk ;@#4:ĭOUw[H鈞^j싺I ۺ+;{qAq[PH:ƻڕ ʡ{ :y:Zk[ ;;aHFTшw};@۵2˺:̺8 :A<𫺧˪Il˂Qn8j;Ka{ԋ։]Qof1Rc&Ȭ.L(5>SkÆȏÏ<< ɒ|Ú,<|Hħ{+ʵ cU[nƋ=+|;L+ln|bᠸ䚀Sr$YnIgi44ȉȎɐ|`ɒ<ȝÑ =,oΞLġ<ʨʒ;ō],ͻlpČNZlhQ cWjk@"]΍ ͋,)}'&} K̺1ɘ ?@lϵ7 mķ iI*W L& Ɲ9b*nDvYÆۜғ8Z FzK։qu|,ڔ7<یpm&w-qۼ(|]A\:; ̬ʍ]~ƚ ❍EF}}:ǥZѤ)ڪ`y^[m* z ټ]- >ܿ={ܔ\؄ΚG<ԹeLi'سˡ6i{ڤCAաX@̴)|ZwnM..}IE L~Ӎ,Ά@JC?Yщq8rkݗm_ yYk6NW̸ސEbM6ngb,=CKN^NQ~4=-ɟ,ϪlzzhS'rH 5^}4<;\ }CyNK.R T \<bڅZ̘zË͛:{mLLb1ޚ18,v=om n, ɋGNun}έ|Z^ϑ-*5/7vH}aL=8682ڤcx˖J{m} !^v~̎Tێ-<}Nm$;\2/LaGD}l+ֽ%\*]">=ɘnn/O.^Ͳp/ɧ)^->meoɚa2]<:Juꤎqȏ[;`ˋ=5z嶇^|rj` 1L BͲ@h`cЩ(<θ4m5;h>,54!K{)S.lmFc7Ѹ i1! k,ʒJ+߳2KKO?(ʦ P<"T:2 sKqE7qč,IlMP`mO\L -?'-76 !\1s2,@KWݣ*V#0Ž4KM"DE53 HvʄdSBl[TPP(ʱlU75 %MCuEn7$TM +P݊JY+ּlea*V'≭1zR -ؑ)mL6ÆlM=魐\q'fH74yg>y4$ QT+t^;S7ԀhF=kza’϶50ôb˸058+23}t`zܑv<ΠiI%h<Ҿ5g1MrJ+6]xq{JY-EUQtUNSBu<ݬrm3=x xGx0Ϩ(ؽ2v vALYBIGrq:hmfJJ%( TQmvshyd3~,푨WGD EmbU ymҦz'VWԫQK bԆ&bL}R*nL"YSHB+AYtSL['séY[y|~ծ\hJUJ28iUUbXrLJ9SIOdNI‘2}gVi$\a+u]{wWVȋRv(Y{% Pq $eY+Fl]J#Ui}; vVzk+&}sUɜUQpei`[N?Nı!ǹ .]ܓ[wR6i ݎ9]t%n8XѰ]1O@wtGhݔ?%жϾ|*,WHؼ o}Y^H Ww sQ}<+Xds̷pOUVdu֖bf+XMo(TA+Z3UE =r;6҂Vg(\QnFXvYAyߐ*F$2 o,09&Vr,P$ Շ:nyM7ol(C<zzp-o#Z3g{A%We툋~x+mU_˸/3٘K:XAASUJ<|6o۸wm{e-T:*禟鄏:Y*u\vAKٳ:nȠ9w2{\f`]:N՛^_e|ӻ7.>0^xGcVc*o7HMw{7oz趯%ǹ=,;;_VP:9/M)!S1?s=kys@ӻ4{6JC1`:z?m7?c<⳿(t -!9B2Wb $P "Q; 5?B@! =S%›3!k ? @輨04Azl 6$·+2C,%t?3,S8=Bɿt;yX,Ɉ@reB Tԛ7;82d:Aj.klC>|?) D86sðёLJD_\C7`侟:T.StR,>W|8ml 됗۹+vT6vDcA TFMaF+=U5kd/TF®×lY26tG54x\ d&{ E;TD<i l B$)ǸG' 32ċɟ4' wQ|0.ij~|ʨ<5H F@ ":dz J;˴ KSǨ=p <3TCi`nJ <ȗTA݂ԭπ A4D>!^ /ȣKTB~&k{JӸ˻IY|Iγ!~5ΪAI@ Hl >Ʉ lߔܜ\5KҘKPM6TdS9TZ 䬶=UUd-t>Iu?./m8aù>bĹHUi% MS|VY}SuTV(Jl%08T*-Ȳ$cQDkWQ\ymXA'=eI+בžͻv4# E]J%LWV-ь ВSЩ8Vu(VxҊ|_c]PD2Y]VXY٫ &Vj,[~5YBڅZ˞lZ[/:ʡ;]a|WD[Ӄ8ڰB%cۣ-Y-H:-L|4ݩڌPjèmnr%1HZOqO*6N`He s]L'CFkm75M9hctM\d-JF݉ Pof:3QTUajF6=ִem. Yt6N۵ce֒uצpf&b];j ,֜LdP(HdfamfUIhYv]()Z aV|K[LcܰG+g/Ndi<>hPN,ϚvhT\w֊MIk$| ݨ蔆WF6 Vkxj`^&"!KMWĢ}й٥dU?>gN.A@Ic9>jQLlv쿅ls&3v]ElIUi.縞l#.mUn ѽw6=q賰kĨn!nltgL.i^>uZ`nۖo@nn ~ؓn^==ҧ6oGVo~h^pҶIeg(N^2^&5,cllqJopq_qNj q vVpp"6p#goO38(d)qn srq8d^\'Yե. s {h]q,=s%?_t/t"t_. /WIQG?,tP_f 3l@XlNe&yz{?}! /vExdx_s3sPt/vL?pdx`x=o:Wx?q^Ai*ydJXgf?gwwoywy2Jy펷_(r?xu?%wgi_qzw{Wwhwp{{7wd%R?gǷ|{m|*}Q1W}O:՗Wx}}Zkޅ'~WNo/?{'h4 wM~yE~~|6 7􂙺W~yWLhx ` H!Ĉ'Rh"ƌ7r#Ȑ"G,i$ʔ*I$X%̖6\i&Μ:w'РBSfA42m)ԨRR Q2+ذbǒ-Ѥ m-ܸr,Jڃl/a[UU0Ċ3nQÎ'Sl2ܽ7sM͠G.mڴӪWn7زgӎ 6ܺw7#/n8ھ3oҧS:ګ^;xÓ/o>׳Z=Jo~7?* g 2 9!5jhz!w8"euX")t-h/8#G1x#3#=zdAEHIMjȤQFU*HY]ǥaeGimjǦqNu2Gy}Ƨ*"HfvZF6"ƩEŪZƨbFūņɎ͞ʬѮ վJΊEW~2Eo[Fo\["p 3\ĭR\qc\ڱǝr#\'Gʍr/\3Z}s;\?m]tG#]Kٴ]BuSS]WGMru_]cY=vk}oɭ]ww㍯{۷xN 3xÏCO\cyƛsα"^zɧꫯܺ.{̳Nߜ:{Ͽ]F#|3W?RS_}coݽ^4>>髿>>?????(< 2| ;Kajiki-0.5.3/docs/media/Marlin.png0000644000076500000240000003667312554436352016763 0ustar amolstaff00000000000000PNG  IHDRo.sRGB~PLTEf33f3ff33f3f33fff333fffff33f3333ffff̙33ffff3ffff3f333tRNS@fbKGDH pHYs  tIME 2^ IDATx}bۺ IQ\}}7 ؎-ǘ#'Z^5kڏ٧8]wOٵ=i]٠c4&ڜik7kvEW^75Y npo'MxOٕy6{>  oͮc:?tߚ] nG~Ì|+43 TN]np}G=Q m?fHLkR # 'FmbN'n-uu|4x8$G j4tu]_Oo[Í ni53Ŋ(굧ABK[|d+!?1ہ% !Z d of qb2{)G;mv퀎Wȁƒ삩)KE/07V~kvITBGx8[K:GhtAKʀ_Զ.쒹9Ӊ*j$;Ƞm)>{bK]ě2µ>"q:Pt fW# vc f$e p~۰H= 6Q#ON p~3W4fI?A(!MNgۊVuMWGPB{ +9_m)jߢ7ѣ18B5 2Z &|Ggۖ} X 9n)Fqfvl$cQ)dP ѡۋi 55QU%Dlj3Mn eq乴G|ljV:4=hcf4yyMr6hcĄ=OK.ԶHwX@L)^g ͅ90H7Z4C__^A_m|ވ~tm[26(c>3:a;#, q5{ -ZL0â#Z\nk rC it 6XK &Zc5 `3y(AN6 VH"T9^WX|g4Z޲*f8nr3RF Dn f-yT1$!!,UשCs9SFj3Pk+Dj\핐.?%<^6Xj\\"w[37.'j,zELU; ~5[N j6Aՠ쯍q.cl\ɴ-,oRDm>ՄuHM%:ʿДp0'_ -PeT4x,\)A=s] ڦ#Xѭ$1^4TR֥FzUvxХщ|i0 nFOK5|[5+C}FaHlG3) H h>H..3ȁ,b} 6̤k@3%]C 4A|C0g՘[>TŇ{bȿͲ?ϫ9j @Rȁ`>?=S$_sUz;ލ#\k-b`# v{VR~'S'Ң'h[b|]`\W&L72.ĜIM}Hяb|JHۧ}BQb:E8ĤFK[ocKf 8҈MeO6)"tL".U8/TI "p_jt|A8SE̥  G; Je- !*) DڰAS 0B*):ߙ=oa U|bO'\wa.4S':Hb679IM)+&MwgjK!jx2r"#,OY˶%ۣ8\zqariBlԬrvU!Z"*Qs۪B^Хu+&xѵ61GVi$#*'; +vF*|Z!['I1.udq]HRuxDMW=Txo*QEM(H%I0 Mr7jB ?inN-"aV`A(EWU 6/d JhZ{K{K&7].ݷھ>fq$Vyr?%qܭ>z>⳧ xT/]M(c."WB>iϛ iC#,2$ 11q9O >zj{3oq8gmKs;|ĪX@}4Lɑz{gyDS:C$tI,UW*)TF2i~4-y8t=>` AuCl#X%0Y < Y+Ω`Wa';z+'"OT%?Bix _Kɴ Y4iFAV_Ձos>nxuh2!Fd e˯qfaw_js H4P7 8 pĪɫzc:G\( iO ׃0 nػq?)_&=7o RA q4w?~E`CGS(zkE)`ҚשMQ‰q2c9tްx8A23<$M==_6oʦ|Gď^ߎhamߧlYL9oPxMZ#4J?+rjmk㕮Eߛ9/QP f_.߾gb΀>G'Kzot1ä5F>: 0i}PN$SCv ;Br}$u_P;a 4zD23 !g '$$Eb*]ݯtv{겮vhzi b횎)P_7 vь n*Q݂5` cAҗp\C` Jl_ UWHkU:w ="lqyu n'V?~` ߐU2'J)Cй&Ra+iʌf1e~ƛv')xVv:L_ͳa3NN ig25,-XN%y-0WJR=s=8M]v50eH*=*kx:baGkNJ;M%_qs,G!G J?`8I\[)j`u_Ja M:#Ǒtڷ 8c#sDj)@򌜶>Dp+Tۼtd6U%sCmQp f""m~  aہDl!}k!)O0MAU 7e\UH50u9"r8S!F!L\FQB]B*$(Brui0qmYM:OAܱ8 r2ř.* ˲RB J!!嫹ųǽ s#gʭJߵZ\D ]UZۘܖpg"IyIɼKmz1qA(.Wrʿ&_KyI~[urDUyQ}b L"LwVTI~Oד|>CFp41Я6O?r n9,UMe)b6Ljg8.zx偽GO6Zj~z[H2 O(~xLHk1EZ~6hTs~:98S( ř UNA ?d(_/;XC%LkB5%J+cME{KzK؋)`M{A m]ɨxH?)I/67\1HnFa(1|u[J US%5Z5M.xs'IKh$ WթEpbq8^ԏTꛘ 13)T1M #Լ uMUILѕ3չ2 uYh?j:J_e!7 ZA5@dwn߷_]*>L+k`(O=R4 uo\0vkWF8glHp}%y@UGaJNfy-5oN}SeMtiZ7X@@fHl 4<,aܸfwe(MXV(S[HsbtT:K3M ź? @3}1cqOg I)׻P] s {Z7Q+fVozqND[vZAdC6_mF24Ij+L`v[xq{@#}\Z"`2p.ФR! 8#-wi+71LHR,'`$ 4geygU(-rKyBumԋ֫[ $וt;4"x\q&hvaun1 a巸7E:K8W: 7hN h|C WӦԂep~76w4B"I* |Y:K R !FI< 8"W>2Dl']j}UV=N'D\u_NJg } }u!L ,j>pԒӌܜ k Y Pyq]{Y 93mtUԵJYZwVEk$ EK|㦧JY}>A|x%v#B-NpG˩P1y~!t{)Z;:+X:Y j%s=zwok ic=L[_mkRs:U6ӀM /'5Wu+ꮮm`Dor3tZn\3pj4RqfyK<4\3ԔO\8tc'M/R>SUxqØT!hۉlk4IlF!{C!GkR5fxZ3exATDR{rqYU[Kn3oaye3B'^%B3u8VWn13n)r` ~DfDetţI [~(uR=jڤH2tV$:Tb41ZgM%ȍgn*4,w`'F^TS\c_:/FzoW''jS{]w[DLXx*Gצ:׋(Nȩ?ڏ"71*V`KYT(㸔 DYQ- $u?b-ſ)H--F!zxHIDATq69NKkΡmvo<´&HuΎyUr-ҍ[;^9Uz\f΍BĞcd[]^B<| 6"s~"eI^fBŗ^ugaٍ tr^n8޹SJ-ջ=1ܸ `&$9Ft O4mviͤ?ߗcwx$u~{ORɞ>J_c@5v~i9,PWJr8sK EdF8wAvO0Kx,O R ^O}g[qPoԇ^.z詭29;9ҭB7nꟖ_*lڏFmi6P$Fu _G\pm %ډR `nxfeW!|VW\RnJ $s:Y+V"PF` =+*a3j2IpcȠ]I!ѩk4Vs+,]5w:♆EEb֦4!]eW`77'qH>xsM`Sy9n$(:W;-v8wwcWՋa6}sU%:uHQa-FYuԒ7. !nMOw:=ی;kP=}a]ydsz\%;T$!%\M }ґ.#r}U򧈵|2S`/3\ 1F(orȟ%hqQj$ AxZ::p@CM< vaZ .2v>J>T3l: C+b{ *M0&n5:O"?N꼧 '3e8m!1:}xe3cE5ĭAT$JuzsF]7NW>?yOSV7U].U;ucu^^SnTV18J{Tڼ~Ľ'SK,eY9*+ z|-ۄ2 G}(G +ց.Sx8Q6D W谨^ߘ2/ E!_4;!P)Gȩ ӕ$cc1tjzuWq~>07ׇ"Rw#b8m] Ɋ;s>_`CU_ܻn^)kZl"aj!1t!Z+!mSkIeUN+p:ojwP1u:{]g~^8,鼯9U ~ ̨Qm-( ꝲ6o ώ&'٣ dtO՗WUx5p2hHLLE`[-Ցlj8=R qn[ :zwW1$Or%qx>"Tk TIGZHOHX07yԐLM ަ-լu+&?ǡ>N"xHc ɛ:|I_uQ$<ލaqV&:ilT,*t߆莫 T|}Uwzb'0gP6ju{j?ޚB-{E$oۜt,oI9$ƽ\FtO_8}JzFdŵR_ w]^s6&+ 4h̕w4|N|NZNANy.RXP݉ɨqHT5bǽ}}9i7aw 8k0Hco,T+}#qGNAj5:NGzLoȻ>,^+\BGhe5C*4T W4Z{-}aܷἓ,eUݙ#e[Ֆ_`b4^Z<>KjٽZ;|O>_!~{;R*׮Jp)FGș!N2S&^@0oFooF}JOR:gM}N2~!mϣM,Oj}qKi-l ۧ2R-LIn~;IjZ ה] m \F*tzί dҡ@ 7yFPpFʩ, UId$RP磌W6%{ujTkmhFd`'s1Bx'v /1oByQ~i!}SUҲg0kWԫ%7aL]כ_]Z7`'CQMT9Lx[cڢM3*h2817!I9iP˦Z+C:+)~߾6=zV1,/coY3t\*WLr6}oۭrX ǘ;UVJ)n%Q`EqI!-d7:CS<*9mv^C% I2I{iW/qujԻWLsj K9)Fas2mlaz sNT66MJ]TGT'XLnN!8MH:\^pOC[/4aQ/ ' +'+@~5u"IJs\ԩۢm#6\<@30DU\u}HVyk :6%ű=ϹUNIP}sL.%sg!-ձD~.J'o Nmgr8"Ar0"!;mKTS/,Z3ZJ4Ҹܯ6g*x5NN3pBzcN5`ŝ7|yԉX f(-BcqA}F.$+wa*##Bn3-JU)0oN_+k GC@#|s[](Pۃ%nG7,)|)54Iu2y%mnv pk:q++}gzrѓ8cg~p-⻎+k4//DUqh ͹VG[SV<Ÿ-r f⸁rLi)A`.X@Я%V7qTp,?\O5@:ںCxA=ВfO2\64..TD_޶XEkjsJ0L?_ڢ"N}{?yB--R:2h-n54ݲ70 _:G2ɨҚ)Nȱ^IQ1X\[Bڜ˒[Pgcs:7-m;ZnF}bky9\"3w ?\"voM۳m x<#r{' !X &c֮y5]riy\$R\Qȯ/|Δ,oG;Nn3cĆoIS+淹7o")ԣkx2.56cl%|9I؞/v:*f{I&3%Ac$c"/ݪC%3 \{K)8ZSQŐ8>X :*xlx*YC[ u=F|R2zM0|ᒣ!f8f7t=+ e_n6~:E^@,&Kj7r# ;9øM{'ѩ틕F:ux&ѝ0j>6C/.ja xpi9z^S9Cz<0Ҝhu5Fp.q'r 5l.Xel]6epG) A)i߶gH"y$Jp|cs.M (=ԘɃi\.Mp;^\ o. ݎ QGA#مSo 2zt]أS1DȗO]FDLۈE_Hs*5]"%6nK]lN&i-f&R!(k٥g)͇ yfgEq05kvC$Ikޚ]d^d[mvizr)#6kvqjIu^aJ".Npd~# o.o@URVs ۞"8cIK "$2fv!pހrĶ)jҺ ۶ gR~UMRq M-Ep.7&b7?7%f!87g!|Ӻlvi#Ny]=)-#ܷoC+xJ4H pv)g|ӎnv* H\DXW.** m7#$V뢨5B8I')\Ӻlv b7]D&255YF2$+b\& _ps&rGm?f 8Ë,XRTml4 h4dԴ] o|jZJuʃyз\kWZͷunMɃ]X$e6]x6+$i~2ͮ8] m̷.O@ՓGmvMۤ eͮ2 U NS5dNL[\@ lv5ϥ Mu=j}~.ͮ2xIZSuC8#8ehzͮ 8k"2jͮ28Mޚ]5gؤ M5gEg5 )CkrͮhR 5Q{ ]73o/Zk6b_˖ oͮp!H7ZS5 B8y2 eMSkvU-xQ Ğj]=c90M_27r'w$ 3mٵ C"fWʹHOQms]ߑryZgPѕ{ޚ}а5ޚ} 8ڑf8:ss7ܪixkYõ"\O1͙fM'ζAfRyڨ>dVi~͚5IENDB`Kajiki-0.5.3/docs/migrating_from_genshi.rst0000644000076500000240000001122012554436352021024 0ustar amolstaff00000000000000Migrating from Genshi ====================================== Kajiki uses syntax derived from the syntax of Genshi_. In particular, the following directives are supported, with semantics intended to be nearly identical to those of Genshi_. * ``py:def`` * ``py:choose`` -- renamed ``py:with`` * ``py:when`` -- renamed ``py:case`` * ``py:otherwise`` -- renamed ``py:else`` * ``py:for`` * ``py:if`` * ``py:with`` * ``py:replace`` * ``py:content`` * ``py:attrs`` * ``py:strip`` * ``xi:include`` -- renamed ``py:include`` Note that, in particular, ``py:match`` is not supported. But Kajiki supports the following additional directives: * ``py:extends`` - indicates that this is an extension template. The parent template will be read in and used for layout, with any ``py:block`` directives in the child template overriding the ``py:block`` directives defined in the parent. * ``py:block`` - used to name a replaceable 'slot' in a parent template, or to specify a slot override in a child template. The ``py:block`` semantics are modeled after the ``{% block %}`` semantics of Jinja2_. Generally, migration consists of a few steps that can be simple or quite difficult based on your fondness of the ``py:match`` directive in Genshi. In simple cases where you have one ``master.html`` template with a few ``py:match`` directives that is ``xi:included`` into all your page templates, the following steps should suffice: * Rename tags and attributes as indicated above; e.g. ``xi:include`` becomes ``py:include``. * Rewrite your *include* directives to use Kajiki's module naming system and relative imports. * In a simple case where you have only a few ``py:match`` directives, all of which are in a ``master.html`` template that is being included from child templates, I recommend that you rewrite the ``master.html`` as ``layout.html``, defining named ``py:block`` regions that will be overridden in child templates. * In your child templates, remove the ```` that probably lurks near the top. Then add a ``py:extends`` directive to the top-level tag (usually ````). The tag the parts of the child template that are intended to override parts of the parent template with the ``py:block`` directive. Kajiki also provides some helper functions of Genshi: * ``defined('some_variable')`` (which returns True if 'some_variable' exists in the template context), * ``value_of('name', default_value)``, and * ``Markup(some_string)`` (which marks a string so it won't be escaped in the output), though Kajiki prefers to call this ``literal(some_string)``. Example Migration --------------------------------- Suppose you have a couple of Genshi templates, one of which called ``master.html`` and one of which is ``index.html``. (TurboGears developers may recognize these files as slightly modified versions of the default templates deposited in a TG quickstarted project.) The contents of ``master.html`` are: .. literalinclude:: include/master.html :linenos: :language: html Likewise, the contents of ``index.html`` are as follows: .. literalinclude:: include/index.html :linenos: :language: html In order to perform our kajiki migration, we begin by creating two empty templates. The first one will replace our ``master.html``, and we will call it ``layout.html``: .. literalinclude:: include/layout.html :linenos: :language: html Note the introduction of the ``py:block`` directive, and the disappearance of the ``py:match`` directives from ``master.html``. ``py:block`` mimics the behavior of Jinja2 "blocks", providing a name to a construct in a parent template which can be replaced by the contents of ``py:block`` -named constructs in child templates. For instance, the "title" slot in ``layout.html``: .. literalinclude:: include/layout.html :linenos: :language: html :lines: 8 can be replaced by a similarly-named slot in the child document ``index_kajiki.html``: .. literalinclude:: include/index_kajiki.html :linenos: :language: html :lines: 1-8 We also provide a way of including the contents of the parent template's slot in a child template's slot using ``${parent_block()}``. The following slot in ``layout.html``: .. literalinclude:: include/layout.html :linenos: :language: html :lines: 16 can be replaced in ``include/index_kajiki.html`` with: .. literalinclude:: include/index_kajiki.html :linenos: :language: html :lines: 9-12 Yielding the following html once rendered: .. code-block:: html :linenos:

My Header

Some extra header data

.. _Genshi: http://genshi.edgewall.org/ .. _Jinja2: http://jinja.pocoo.org/2/documentation/ Kajiki-0.5.3/docs/runtime.rst0000644000076500000240000002554412554436352016164 0ustar amolstaff00000000000000================================== Kajiki Runtime Transformations ================================== It's sometimes good to have a mental model of the Python code that Kajiki creates in order to generate your templates. This document uses several examples taken from the text templating language to illustrate the semantics of Kajiki templates. If in doubt, you can always view the Python text generated for a template by examining the py_text attribute of the generated Template class. Basic Expressions ========================= Let's start with a hello world template: .. code-block:: none Hello, World! This converts to the equivalent Python:: @kajiki.expose def __call__(): yield 'Hello, World!\n' Slightly more verbose "hello_name.txt": .. code-block:: none Hello, $name! This converts to the equivalent Python:: @kajiki.expose def __call__(): yield 'Hello, ' yield name yield '!\n' By default, the $-syntax picks up any identifiers following it, as well as any periods. If you want something more explicit, use the extended expression form as in "hello_arithmetic.txt": .. code-block:: none Hello, 2 + 2 is ${2+2}! This converts to:: @kajiki.expose def __call__(): yield 'Hello, 2 + 2 is ' yield 2+2 yield '!' If you wish to include a literal $, simply prefix it with a backslash. Control Flow ============ Kajiki provides several tags that affect the rendering of a template. The following template "control_flow.txt" illustrates: .. code-block:: none A{%for i in range(5)%} {%if i < 2%}Low{%elif i < 4%}Mid{%else%}High{%end%}$i {%switch i % 2%} {%case 0%} even {%default%} odd {%end%}{%end%}{%end%} This yields the following Python:: @kajiki.expose def __call__(): yield 'A\n' # from the {%for... line for i in range(10): yield '\n ' # from the newline and initial indent of next line if i < 2: yield 'Low' elif i < 4: yield 'Mid' else: yield 'High' yield i yield '\n ' # from the {%if... newline and next indent local.__kj__.push_switch(i%2) # whitespace after {%switch is always stripped if local.__kj__.case(0): yield '\n even\n ' else: yield '\n odd\n ' local.__kj__.pop_switch() Which would in turn generate the following text: .. code-block:: none A Low0 even Low1 odd Mid2 even Mid3 odd High4 even If you want to strip whitespace before or after a tag, just replace ``{%`` with ``{%-`` (for stripping leading whitespace) or ``%}`` with ``-%}`` (for stripping trailing whitespace). If you would like to remove newlines, just end a line with a backslash. Here is the equivalent template with whitespace removed, "control_flow_ws.txt": .. code-block:: none A{%-for i in range(5) -%}\ {%-if i < 2%}Low{%elif i < 4%}Mid{%else%}High{%end%}$i {%-switch i % 2%}\ {%-case 0%}\ even {%-default%}\ odd {%-end%}\ {%-end%}\ {%-end%}\ This would generate the following Python:: @kajiki.expose def __call__(): yield 'A' for i in range(10): if i < 2: yield 'Low' elif i < 4: yield 'Mid' else: yield 'High' yield i yield '\n' local.__kj__.push_switch(i % 2) if local.__kj__.case(0): yield 'even\n' else: yield 'odd\n' local.__kj__.pop_switch() Which would generate the following text: .. code-block:: none ALow0 even Low1 odd Mid2 even Mid3 odd High4 even which is probably closer to what you wanted. There is also a shorthand syntax that allows for line-oriented control flow as seen in "control_flow_ws_short.txt": .. code-block:: none A\ %for i in range(5) %if i < 2 Low\ %elif i < 4 Mid\ %else High\ {%-end%}$i %switch i % 2 %case 0 even %default odd %end %end %end This syntax yields exactly the same results as "control_flow_ws.txt" above. Python Blocks ============== You can insert literal Python code into your template using the following syntax in "simple_py_block.txt": .. code-block:: none {%py%}\ yield 'Prefix' {%end%}\ Body or alternatively: .. code-block:: none %py yield 'Prefix' %end Body or even more succinctly: .. code-block:: none %py yield 'Prefix' Body all of which will generate the following Python:: def __call__(): yield 'Prefix' yield 'Body' Note in particular that the Python block can have any indentation, as long as it is consistent (the amount of leading whitespace in the first non-empty line of the block is stripped from all lines within the block). You can insert module-level Python (imports, etc.) by using the %py% directive (or {%py%%} as in "module_py_block.txt": .. code-block:: none %py% import sys import re %end Hello %py% import os %end This yields the following Python:: import sys import re import os @kajiki.expose def __call__(): yield 'Hello' Functions and Imports ==================================== Kajiki provides for code reuse via the %def and %import directives. First, let's see %def in action in "simple_function.txt": .. code-block:: none %def evenness(n) %if n % 2 == 0 even\ %else odd\ %end %end %for i in range(5) $i is ${evenness(i)} %end This compiles to the following Python:: @kajiki.expose def evenness(n): if n % 2: yield 'even' else: yield 'odd' @kajiki.expose def __call__(): for i in range(5): yield i yield ' is ' yield evenness(i) The %import directive allows you to package up your functions for reuse in another template file (or even in a Python package). For instance, consider the following file "import_test.txt": .. code-block:: none %import "simple_function.txt" as simple_function %for i in range(5) $i is ${simple_function.evenness(i)} %end This would then compile to the following Python:: @kajiki.expose def __call__(): simple_function = local.__kj__.import_("simple_function.txt") for i in range(5): yield i yield ' is ' yield simple_function.evenness(i) Note that when using the %import directive, any "body" in the imported template is ignored and only functions are imported. If you actually wanted to insert the body of the imported template, you would simply call the imported template as a function itself (e.g. ${simple_function()}). Sometimes it is convenient to pass the contents of a tag to a function. In this case, you can use the %call directive as shown in "call.txt": .. code-block:: none %def quote(caller, speaker) %for i in range(5) Quoth $speaker, "${caller(i)}." %end %end %call(n) quote('the raven') Nevermore $n\ %end This results in the following Python:: @kajiki.expose def quote(caller, speaker): for i in range(5): yield 'Quoth ' yield speaker yield ', "' yield caller(i) yield '."' @kajiki.expose def __call__(): @kajiki.expose def _fpt_lambda(n): yield 'Nevermore ' yield n yield quote(_fpt_lambda, 'the raven') del _fpt_lambda Which in turn yields the following output: .. code-block:: none Quoth the raven, "Nevermore 0." Quoth the raven, "Nevermore 1." Quoth the raven, "Nevermore 2." Quoth the raven, "Nevermore 3." Quoth the raven, "Nevermore 4." Includes =============== Sometimes you just want to pull the text of another template into your template verbatim. For this, you use the %include directive as in "include_example.txt": .. code-block:: none This is my story: %include "call.txt" Isn't it good? which yields the following Python:: @kajiki.expose def __call__(): yield 'This is my story:\n' yield _fpt.import("simple_function.txt")() yield 'Isn't it good?\n' Which of course yields: .. code-block:: none This is my story: Quoth the raven, "Nevermore 0." Quoth the raven, "Nevermore 1." Quoth the raven, "Nevermore 2." Quoth the raven, "Nevermore 3." Quoth the raven, "Nevermore 4." Isn't it good? Inheritance ============== Kajiki supports a concept of inheritance whereby child templates can extend parent templates, replacing their methods and "blocks" (to be defined below). For instance, consider the following template "parent.txt": .. code-block:: none %def greet(name) Hello, $name!\ %end %def sign(name) Sincerely, $name\ %end ${greet(to)} %block body It was good seeing you last Friday. Thanks for the gift! %end ${sign(from)} This would generate the following Python:: @kajiki.expose def greet(name): yield 'Hello, ' yield name yield '!' @kajiki.expose def sign(name): yield 'Sincerely,\n' yield name @kajiki.expose def _fpt_block_body(): yield 'It was good seeing you last Friday! Thanks for the gift!\n' @kajiki.expose def __call__(): yield greet(to) yield '\n\n' yield self._fpt_block_body() yield '\n\n' yield sign(from) Here is the corresponding "child.txt": .. code-block:: none %extends "parent.txt" %def greet(name) Dear $name:\ %end %block body ${parent_block()}\\ And don't forget you owe me money! %end This would then yield the following Python:: @kajiki.expose def greet(name): yield 'Dear ' yield name yield ':' @kajiki.expose def _fpt_block_body(): yield parent._fpt_block_body() yield '\n\n' yield 'And don\'t forget you owe me money!\n' @kajiki.expose def __call__(): yield local.__kj__.extend(local.__kj__.import_('parent.txt')).__call__() The final text would be (assuming context had to='Mark' and from='Rick': .. code-block:: none Dear Mark: It was good seeing you last Friday! Thanks for the gift! And don't forget you owe me money! Sincerely, Rick Kajiki-0.5.3/docs/templating-basics.rst0000644000076500000240000001703412554436352020102 0ustar amolstaff00000000000000.. testsetup:: * import kajiki Kajiki Templating Basics ================================= Kajiki provides two templating engines, one which is useful for generating markup (HTML or XML most likely), and one of which is useful for generating plain text. This document describes the aspects of the two engines that are similar and the basic API for using them. Synopsis -------------- A Kajiki *xml template* is a well-formed XML document that may include one or more custom tags and attributes prefixed by the namespace 'py:'. XML templates also may contain python expressions that will be evaluated at template expansion time as well as processing instructions that may contain Python code. XML templates should be used when generating XML or HTML, as they provide awareness of well-formedness rules and proper escaping. The following is an example of a simple Kajki markup template: .. code-block:: xml This is replaced.

These are some of my favorite fruits:

  • I like ${fruit}s
This template would generate output similar to this (in X(H)ML mode): .. code-block:: xml A Kajiki Template

These are some of my favorite fruits:

  • I like apples
  • I like oranges
  • I like kiwis
or this (in HTML mode): .. code-block:: html A Kajiki Template

These are some of my favorite fruits:

  • I like apples
  • I like oranges
  • I like kiwis
*Text templates*, on the other hand, are plain text documents that can contain embedded Python directives and expressions. Text templates should be used when generating non-markup text format such as email. Here is a simple text template: .. code-block:: none Dear $name, These are some of my favorite fruits: %for fruit in fruts * $fruit %end This would generate something similar to the following: .. code-block:: none Dear Rick, These are some of my favorite fruits: * Apples * Bananas * Pears Python API ------------------------- In order to actually use Kajiki in generating text (either via the XML or the text-based languages), the pattern is as follows: #. Obtain an XMLTemplate or TextTemplate subclass containing the template source. This can either be done directly or via a template loader. #. Instantiate the template with one constructor argument, a dict containing all the values that should be made available as global variables to the template. #. Render the template instance using its render() method (for rendering to a single string) or iterating through it (for "stream") rendering. For instance: >>> Template = kajiki.XMLTemplate('

Hello, $name!

') >>> t = Template(dict(name='world')) >>> t.render() '

Hello, world!

' Using text templates is similar: >>> Template = kajiki.TextTemplate('Hello, $name!') >>> t = Template(dict(name='world')) >>> t.render() 'Hello, world!' You can also use a template loader to indirectly generate the template classes. Using a template loader gives two main advantages over directly instantiating templates: * Compiled templates are cached and only re-parsed when the template changes. * Several template tags such as `extends`, `import`, and `include` that require knowlege of other templates become enabled. Using a template loader would look similar to the following:: loader = PackageLoader() Template = loader.import_('my.package.text.template') t = Template(dict(title='Hello, world!') print t.render() Template Expressions and Code Blocks ------------------------------------------------------- Python expressions can be used in "plain text" areas of templates, including, in XML templates, tag attributes. They are also used in some directive arguments. Whenever a Python expression is used in a "plain text" area, it must be prefixed by a dollar sign ($) and possibly enclosed in curly braces. If the expression starts with a letter and contains only letters, digits, dots, and underscores, then the curly braces may be omitted. In all other cases, they are required. For example: >>> Template = kajiki.XMLTemplate('${items[0].capitalize()}') >>> Template(dict(items=['first', 'second'])).render() 'First' >>> import sys >>> Template = kajiki.TextTemplate('Maxint is $sys.maxsize') >>> Template(dict(sys=sys)).render() 'Maxint is 9223372036854775807' Escaping ^^^^^^^^^^^^^^ If you need a literal dollar sign where Kajiki would normally detect an expression, you can simply double the dollar sign: >>> Template = kajiki.XMLTemplate('$foo') >>> Template().render() Traceback (most recent call last): ... NameError: global name 'foo' is not defined >>> Template = kajiki.XMLTemplate('$$foo') >>> Template().render() '$foo' Code Blocks ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Templates also support full Python syntax, using the processing instruction: .. code-block:: xml
Maxint is $sys.maxint
This will produce the following output: .. code-block:: xml
Maxint is 9223372036854775807
In text blocks, the %py (or {%py%} directive accomplishes the same goal: .. code-block:: none %py import sys Maxint is $sys.maxint This will produce: .. code-block:: none Maxint is 9223372036854775807 In both of the above cases, the Python code runs in the 'local scope' of the template's main rendering function, so any variables defined there will not be accessible in functions or blocks defined elsewhere in the template. To force the python block to run at 'module-level' in XML templates, simply prefix the first line of the Python with a percent (%) sign: >>> Template = kajiki.XMLTemplate('''
${os.path.join('a', 'b', 'c')}${test()}
''') >>> Template().render() '
a/b/c
' In text templates, replace the %py directive with %py%: >>> Template = kajiki.TextTemplate('''%py% import os ... %def test() ... ${os.path.join('a','b','c')}\\ ... %end ... ${test()}''') >>> Template().render() 'a/b/c' Built-in Functions and Variables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ All templates have access to the following functions and variables: .. function:: literal(x) Wrap some user-generated text so that it doesn't get escaped along with everything else. .. data:: local The current template being defined .. data:: self The current template being defined, or, if used in the context of a parent template that is being extended, the final ("child-most") template in the inheritance hierarchy. .. data:: parent The parent template (via py:extends) of the template being defined .. data:: child The child template (via py:extends) of the template being defined Template Directives -------------------------------------------- Template directives provide control flow and inheritance functionality for templates. As their syntax depends on whether you're using XML or text templates, please refer to :doc:`xml-templates` or :doc:`text-templates` for more information. Kajiki-0.5.3/docs/text-templates.rst0000644000076500000240000001743512554436352017461 0ustar amolstaff00000000000000.. testsetup:: * import kajiki ================================== Kajiki Text Templates ================================== Kajiki provides a full-featured text template engine in addition to the XML templating engine for cases where you don't want to necessarily generate markup. This document describes that language. Templates are text files that include template directives that control how the template is rendered and expressions that are substituted into the generated text at render time. Please see :doc:`templating-basics` for general information on embedding Python code in templates. Basic Expressions ========================= Let's start with a hello world template: >>> Template = kajiki.TextTemplate('Hello, $name!') >>> print(Template(dict(name='world')).render()) Hello, world! By default, the $-syntax picks up any identifiers following it, as well as any periods. If you want something more explicit, use the extended expression form as follows: >>> Template = kajiki.TextTemplate('Hello, 2+2 is ${2+2}') >>> print(Template().render()) Hello, 2+2 is 4 If you wish to include a literal $, simply double it: >>> Template = kajiki.TextTemplate('The price is $$${price}') >>> print(Template(dict(price='5.00')).render()) The price is $5.00 Control Flow ============ Kajiki provides several directives that affect the rendering of a template. This section describes the various directives. Directives in text templates can either be enclosed by `{% ... %}` characters or they can exist on a line by themselves prefixed by a `%`. Template directives must always be terminated by an 'end' directive (either `{%end%}` or `%end`. .. note:: Whitespace can sometimes be tricky in text templates. Kajiki provides a bit of help in managing it. First, if you wish to break a line without having the newline included in the generated text, simply end the line with a backslash (\). Kajiki will also remove any whitespace before a tag that begins with the delimiter `{%-`. Directives that appear on their own line via the `%` prefix never appear in the output, and neither they do not generate any whitespace. %if, %else ^^^^^^^^^^^^^^^ Only render the enclosed content if the expression evaluates to a truthy value: >>> Template = kajiki.TextTemplate('{%if foo %}bar{%else%}baz{%end%}') >>> print(Template(dict(foo=True)).render()) bar >>> print(Template(dict(foo=False)).render()) baz %switch, %case, %else ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Perform multiple tests to render one of several alternatives. The first matching `case` is rendered, and if no `case` matches, the `else` branch is rendered: >>> Template = kajiki.TextTemplate('''$i is \ ... {%switch i % 2 %}{%case 0%}even{%else%}odd{%end%}''') >>> print(Template(dict(i=4)).render()) 4 is even >>> print(Template(dict(i=3)).render()) 3 is odd %for ^^^^^^^^^^^^^ Repeatedly render the content for each item in an iterable: >>> Template = kajiki.TextTemplate('''%for i in range(3) ... $i ... %end''') >>> print(Template().render(), end='') 0 1 2 %def ^^^^^^^^^^^^^^ Defines a function that can be used elsewhere in the template: >>> Template = kajiki.TextTemplate('''%def evenness(n) ... {%-if n % 2 == 0 %}even{%else%}odd{%end%}\\ ... %end ... %for i in range(2) ... $i is ${evenness(i)} ... %end''') >>> print(Template().render(), end='') 0 is even 1 is odd %call ^^^^^^^^^^^^^^^^^^ Call a function, passing a block of template code as a 'lambda' parameter. Note that this is a special case of calling when you wish to insert some templated text in the expansion of a function call. In normal circumstances, you would just use `${my_function(args)}`. >>> Template = kajiki.TextTemplate('''%def quote(caller, speaker) ... %for i in range(2) ... Quoth $speaker, "${caller(i)}." ... %end ... %end ... %call(n) quote(%caller, 'the raven') ... Nevermore $n\\ ... %end''') >>> print(Template().render(), end='') Quoth the raven, "Nevermore 0." Quoth the raven, "Nevermore 1." %include ^^^^^^^^^^^^^^^^^^^^^^^^ Includes the text of another template verbatim. The precise semantics of this tag depend on the `TemplateLoader` being used, as the `TemplateLoader` is used to parse the name of the template being included and render its contents into the current template. For instance, with the `FileLoader`, you might use the following: .. code-block:: none %include "path/to/base.txt" whereas in the `PackageLoader` you would use .. code-block:: none %include package1.package2.base %import ^^^^^^^^^^^^^^^^^^^^^^ With `%import`, you can make the functions defined in another template available without expanding the full template in-place. Suppose that we saved the following template in a file `lib.txt`: .. code-block:: none %def evenness(n) %if n % 2 == 0 even\ %else odd\ %end %end Then (using the `FileLoader`) we could write a template using the `evenness` function as follows: .. code-block:: none %import "lib.txt" as lib %for i in range(5) %i is ${lib.evenness(i)} %end Inheritance (%extends, %block) ======================================== Kajiki supports a concept of inheritance whereby child templates can extend parent templates, replacing their "methods" (functions) and "blocks" (to be defined below). For instance, consider the following template "parent.txt": .. code-block:: none %def greet(name) Hello, $name!\ %end %def sign(name) Sincerely, $name\ %end ${greet(to)} %block body It was good seeing you last Friday. Thanks for the gift! %end ${sign(from_)} This would render to the following (assuming a context of `dict(to=Mark, from_=Rick)`: .. code-block::none Hello, Mark! It was good seeing you last friday. Thanks for the gift! Sincerely, Rick Now we can extend "parent.txt" with "child.txt": .. code-block:: none %extends "parent.txt" %def greet(name) Dear $name:\ %end %block body ${parent_block()}\ And don't forget you owe me money! %end Rendering this template would then give us: .. code-block:: none Dear Mark: It was good seeing you last Friday! Thanks for the gift! And don't forget you owe me money! Sincerely, Rick Notice how in the child block, we have overridden both the block "body" and the function "greet." When overriding a block, we always have access to the parent template's block of the same name via the `parent_block()` function. If you ever need to access the parent template itself (perhaps to call another function), kajiki provides access to a special variable in child templates `parent`. Likewise, if a template is being extended, the variable `child` is available. Kajiki also provides the special variables `local` (the template currently being defined) and `self` (the child-most template of an inheritance chain). The following example illustrates these variables in a 3-level inheritance hierarchy: >>> parent = kajiki.TextTemplate(''' ... %def header() ... # Header name=$name ... %end ... %def footer() ... # Footer ... %end ... %def body() ... ## Parent Body ... id() = ${id()} ... local.id() = ${local.id()} ... self.id() = ${self.id()} ... child.id() = ${child.id()} ... %end ... %def id() ... parent\\ ... %end ... ${header()}${body()}${footer()}''') >>> mid = kajiki.TextTemplate('''%extends "parent.txt" ... %def id() ... mid\\ ... %end ... ''') >>> child = kajiki.TextTemplate('''%extends "mid.txt" ... %def id() ... child\\ ... %end ... %def body() ... ## Child Body ... ${parent.body()}\\ ... %end ... ''') >>> loader = kajiki.MockLoader({ ... 'parent.txt':parent, ... 'mid.txt':mid, ... 'child.txt':child}) >>> Template = loader.import_('child.txt') >>> print(Template(dict(name='Rick')).render(), end='') # Header name=Rick ## Child Body ## Parent Body id() = child local.id() = parent self.id() = child child.id() = mid # Footer Kajiki-0.5.3/docs/xml-templates.rst0000644000076500000240000004024712554436352017272 0ustar amolstaff00000000000000.. testsetup:: * import kajiki ================================== Kajiki XML Templates ================================== Kajiki provides a full-featured XML-based template engine that guarantees well-formed output when generating HTML and XML. This document describes that language. Templates are XML files that include template directives that control how the template is rendered and expressions that are substituted into the generated text at render time. Please see :doc:`templating-basics` for general information on embedding Python code in templates. Output Modes ========================= Although Kajiki XML templates must be well-formed XML documents, Kajiki is capable of rendering HTML or XML. By default, Kajiki will inspect the doctype of the template to determine how to render: >>> tpl_text = ''' ... ... ... ...
... ... ...
... ... ''' >>> Template = kajiki.XMLTemplate(tpl_text) >>> print(Template().render().strip())
>>> # If we want to override the detected type, we can pass a 'mode' param >>> Template = kajiki.XMLTemplate(tpl_text, mode='xml') >>> print(Template().render().strip())
>>> # We can also omit the generated DOCTYPE by specifying the template >>> # is a fragment >>> Template = kajiki.XMLTemplate(tpl_text, mode='xml', is_fragment=True) >>> print(Template().render().strip())
.. note:: In Kajiki, you can use normal XML comments, and the comments will exist in the generated markup. If you wish the comments to be removed before rendering the document, you can begin the comment with the syntax ` ...
''') >>> print(Template().render())
Basic Expressions ========================= Let's start with a hello world template: >>> Template = kajiki.XMLTemplate('
Hello, $name!
') >>> print(Template(dict(name='world')).render())
Hello, world!
By default, the $-syntax picks up any identifiers following it, as well as any periods. If you want something more explicit, use the extended expression form as follows: >>> Template = kajiki.XMLTemplate('
Hello, 2+2 is ${2+2}
') >>> print(Template().render())
Hello, 2+2 is 4
If you wish to include a literal $, simply double it: >>> Template = kajiki.XMLTemplate('
The price is $$${price}
') >>> print(Template(dict(price='5.00')).render())
The price is $5.00
You can also include expressions in template attributes: >>> Template = kajiki.XMLTemplate('
Bar
') >>> print(Template(dict(foo='baz')).render())
Bar
Control Flow ============ Kajiki provides several directives that affect the rendering of a template. This section describes the various directives. Directives in text templates can either appear as special attributes on tags prefixed by `py:` or as standalone tags whose tagname is prefixed by `py:`. py:if, py:else ^^^^^^^^^^^^^^^ Only render the enclosed content if the expression evaluates to a truthy value: >>> Template = kajiki.XMLTemplate('
barbaz
') >>> print(Template(dict(foo=True)).render())
bar
>>> print(Template(dict(foo=False)).render())
baz
>>> Template = kajiki.XMLTemplate('
bar
') >>> print(Template(dict(foo=True)).render())
bar
>>> print(Template(dict(foo=False)).render())
py:switch, py:case, py:else ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Perform multiple tests to render one of several alternatives. The first matching `case` is rendered, and if no `case` matches, the `else` branch is rendered: >>> Template = kajiki.XMLTemplate('''
... $i is ... even ... odd ...
''') >>> print(Template(dict(i=4)).render())
4 is even
>>> print(Template(dict(i=3)).render())
3 is odd
py:for ^^^^^^^^^^^^^ Repeatedly render the content for each item in an iterable: >>> Template = kajiki.XMLTemplate('''
    ...
  • $x
  • ...
''') >>> print(Template(dict(sz=3)).render())
  • 0
  • 1
  • 2
py:def ^^^^^^^^^^^^^^ Defines a function that can be used elsewhere in the template: >>> Template = kajiki.XMLTemplate('''
evenodd
    ...
  • $x is ${evenness(x)}
  • ...
''') >>> print(Template(dict(sz=3)).render())
  • 0 is even
  • 1 is odd
  • 2 is even
py:call ^^^^^^^^^^^^^^^^^^ Call a function, passing a block of template code as a 'lambda' parameter. Note that this is a special case of calling when you wish to insert some templated text in the expansion of a function call. In normal circumstances, you would just use `${my_function(args)}`. >>> Template = kajiki.XMLTemplate('''
    ...
  • Quoth $speaker, ${caller(i)}
  • ...
Nevermore $n
''') >>> print(Template(dict(sz=3)).render())
  • Quoth the raven, Nevermore 0
  • Quoth the raven, Nevermore 1
  • Quoth the raven, Nevermore 2
py:include ^^^^^^^^^^^^^^^^^^^^^^^^ Includes the text of another template verbatim. The precise semantics of this tag depend on the `TemplateLoader` being used, as the `TemplateLoader` is used to parse the name of the template being included and render its contents into the current template. For instance, with the `FileLoader`, you might use the following: .. code-block:: xml whereas in the `PackageLoader` you would use .. code-block:: xml py:import ^^^^^^^^^^^^^^^^^^^^^^ With `py:import`, you can make the functions defined in another template available without expanding the full template in-place. Suppose that we saved the following template in a file `lib.xml`: .. code-block:: xml evenodd Then (using the `FileLoader`) we could write a template using the `evenness` function as follows: .. code-block:: xml
  • $i is ${lib.evenness(i)}
py:with ---------- Using `py:with`, you can temporarily assign variables values for the extent of the block: >>> Template = kajiki.XMLTemplate('''
...
$a
...
$a
...
$a
...
''') >>> print(Template().render())
foo
5
foo
Content Generation ========================= py:attrs ^^^^^^^^^^^^^^ With the `py:attrs` custom attribute, you can include dynamic attributes in an xml/html tag by passing a either a Python dict or a list of pairs: >>> Template = kajiki.XMLTemplate('
') >>> print(Template(dict(attrs={'id':'foo', 'class':'bar'})).render())
>>> print(Template(dict(attrs=[('id', 'foo'), ('class', 'bar')])).render())
Any attribute values that evaluate to `None` will not be emitted in the generated markup: >>> Template = kajiki.XMLTemplate('
') >>> print(Template(dict(attrs={'id':'foo', 'class':None})).render())
py:strip ^^^^^^^^^^^^^^ With ``py:strip``, you can remove the tag to which the attribute is attached without removing the content of the tag: >>> Template = kajiki.XMLTemplate('
Foo
') >>> print(Template().render())
Foo
As a shorthand, if the value of the ``py:strip`` attribute is empty, that has the same effect as using a truth value (i.e. the element is stripped). py:content ^^^^^^^^^^^^^^ With `py:content`, you can remove the tag to which the attribute is attached without removing the content of the tag: >>> Template = kajiki.XMLTemplate('
') >>> print(Template(dict(content="Foo")).render())
Foo
py:replace ^^^^^^^^^^^^^^ With `py:replace`, you can replace the entire tag to which the document is attached and its children: >>> Template = kajiki.XMLTemplate('
') >>> print(Template(dict(content="Foo")).render()) Foo Inheritance (py:extends, py:block) =================================== Kajiki supports a concept of inheritance whereby child templates can extend parent templates, replacing their "methods" (functions) and "blocks" (to be defined below). For instance, consider the following template "parent.xml": .. code-block:: xml
Hello, $name! Sincerely,
$name
${greet(to)}

It was good seeing you last Friday. Thanks for the gift!

${sign(from_)}
This would render to something similar to the following (assuming a context of `dict(to=Mark, from_=Rick)`: .. code-block:: xml
Hello, Mark!

It was good seeing you last friday. Thanks for the gift!

Sincerely,
Rick
Now we can extend "parent.xml" with "child.xml": .. code-block:: xml Dear $name: ${parent_block()}

And don't forget you owe me money!

Rendering this template would then give us: .. code-block:: xml
Dear, Mark:

It was good seeing you last friday. Thanks for the gift!

And don't forget you owe me money!

Sincerely,
Rick
Notice how in the child block, we have overridden both the block "body" and the function "greet." When overriding a block, we always have access to the parent template's block of the same name via the `parent_block()` function. If you ever need to access the parent template itself (perhaps to call another function), kajiki provides access to a special variable in child templates `parent`. Likewise, if a template is being extended, the variable `child` is available. Kajiki also provides the special variables `local` (the template currently being defined) and `self` (the child-most template of an inheritance chain). The following example illustrates these variables in a 3-level inheritance hierarchy: >>> parent = kajiki.XMLTemplate('''

Header name=$name

Footer
... id() = ${id()} ... local.id() = ${local.id()} ... self.id() = ${self.id()} ... child.id() = ${child.id()} ...
parent ... ${header()} ... ${body()} ... ${footer()} ...
''') >>> mid = kajiki.XMLTemplate('''mid''') >>> child=kajiki.XMLTemplate('''child
...

Child Body

... ${parent.body()} ...
''') >>> loader = kajiki.MockLoader({ ... 'parent.html':parent, ... 'mid.html':mid, ... 'child.html':child}) >>> Template = loader.import_('child.html') >>> print(Template(dict(name='Rick')).render())

Header name=Rick

Child Body

id() = child local.id() = parent self.id() = child child.id() = mid
Footer
Built-in functions ================== The following functions are available by default in template code, in addition to the standard built-ins that are available to all Python code. defined(name) ^^^^^^^^^^^^^ This function determines whether a variable of the specified name exists in the context data, and returns True if it does. When would you use it? Well, suppose you tried the following template snippet:

$user.name

If you don't pass, from your python code, a "user" variable to the template, the above code will fail with this exception: ``NameError: global name 'user' is not defined``. This is undesired! Following Genshi, Kajiki offers the ``defined()`` function to make that condition possible, so you can write this:

$user.name

literal(text) ^^^^^^^^^^^^^ All good templating languages escape text by default to avoid certain attacks. But sometimes you have an HTML snippet that you wish to include in a page, and you know the HTML is safe. The literal() function marks a given string as being safe for inclusion, meaning it will not be escaped in the serialization stage. Use this with care, as not escaping a user-provided string may allow malicious users to open your web site to cross-site scripting attacks. Example: ${literal(name_of_the_variable_containing_the_html)} Kajiki is a reimplementation of most of Genshi and, since Genshi has a ``Markup()`` function for the same purpose, we provide ``Markup()`` as a synonym, too. value_of(name, default=None) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This function returns the value of the variable with the specified name if such a variable is defined, and returns the value of the default parameter if no such variable is defined. Genshi has this, too. Example::
${explanation}
In the above example, the div will only appear in the output if the ``explanation`` variable exists in the context and has a truish value. (Remember in Python, None and the empty string are not truish, they are evaluated as False.) Tips on writing your templates ============================== Kajiki takes XML as input, with the exception that it recognizes HTML entities in addition to XML entities. (HTML has many more entities than XML; for instance, XML does not define `` ``). If your template contains complex content in `` This is not necessary when you are writing HTML because HTML defines that the content of ``'.format(style) perform(src, ''.format(style), mode='xml') perform(src, ''.format(style), mode='html') def test_script_variable(self): '''Interpolate variables inside ' perform(src, '', mode='xml') perform(src, '', mode='html') def test_CDATA_disabled(self): src = '' perform(src, '', mode='xml', cdata_scripts=False) perform(src, '', mode='html', cdata_scripts=False) def test_CDATA_escaping(self): src = '''''' perform(src, '', mode='xml') perform(src, '', mode='html') def test_CDATA_escaping_mixed(self): src = ''' >''' perform(src, ' >', mode='xml') perform(src, ' >', mode='html') def test_script_commented_CDATA(self): script = 'if (1 < 2) { doc.write("

Offen bach

"); }\n' src = ''.format(script) perform(src, mode='html', expected_output=''.format(script)) perform(src, ''.format( script), mode='xml') def test_escape_dollar(self): perform('
$$
', '
$
') def test_escape_dollar_followed_by_dollar(self): perform('
$$$
', '
$$
') def test_double_escape_dollar(self): perform('
$$$$
', '
$$
') def test_preserve_dollar_not_variable_brace(self): perform('
$(
', '
$(
') perform('
$.
', '
$.
') def test_expr_name(self): perform('
Hello, $name
', '
Hello, Rick
') def test_expr_braced(self): perform('
Hello, ${name}
', '
Hello, Rick
') def test_expr_brace_complex(self): perform("
Hello, ${{'name':name}['name']}
", '
Hello, Rick
') def test_jquery_call_is_not_expr(self): '''Ensure we handle '$(' as a text literal, since it cannot be a valid variable sequence. This simplifies, for example, templates containing inline scripts with jQuery calls which otherwise have to be written '$$(...' ''' js = "$(function () { alert('.ready()'); });" src = "
" + js + "
" out = "
" + js + "
" perform(src, out) def test_jquery_shortcut_is_not_expr(self): '''Ensure we handle '$.' as a text literal in script blocks''' js = "$.extend({}, {foo: 'bar'})" src = "
" + js + "
" out = "
" + js + "
" perform(src, out) def test_xml_entities(self): source = "
Cookies & Cream
" perform(source, source) def test_html_entities(self): source = "
Spam Spam < Spam > Spam
" output = '
Spam Spam < Spam > Spam
' assert chr(32) in output # normal space assert chr(160) in output # non breaking space perform(source, output) class TestSwitch(TestCase): def test_switch(self): perform('''
$i is even odd
''', '''
0 is even
1 is odd
''') class TestWith(TestCase): def test_with(self): perform('''
$a
$a
$a
''', '''
foo
5
foo
''') def test_with_multiple(self): perform('''
$a - $b
$a - $b
$a - $b
''', '''
foo - 3
5 - 1
foo - 3
''') def test_with_multiple_and_whitespace(self): perform('''
$a - $b
''', '
foo - 3
') def test_with_trailing_semicolon(self): perform('''
$a
''', '
foo
') def test_with_ordered_multiple(self): perform('''
''' '''$a $b $c $d
''', '
foo foofoo oofoof oof
') def test_with_multiple_with_embedded_semicolons(self): perform('''
$a$b
''', '
;-)
') class TestFunction(TestCase): def test_function(self): perform('''
evenodd
$i is ${evenness(i)}
''', '''
0 is
even
1 is
odd
''') def test_empty_function(self): '''Do not crash if a function has no content.''' perform('
', '
') class TestCall(TestCase): def test_call(self): perform('''
  • Quoth $speaker, ${caller(i)}
Nevermore $n
''', '''
  • Quoth the raven, Nevermore 0
  • Quoth the raven, Nevermore 1
''') class TestImport(TestCase): def test_import(self): loader = MockLoader({ 'lib.html': XMLTemplate(source='''
evenodd half of $n is ${evenness(n/2)}
'''), 'tpl.html': XMLTemplate(source='''
  • $i is ${simple_function.evenness(i)} ${simple_function.half_evenness(i)}
''') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''
  • 0 is even half of 0 is even
  • 1 is odd half of 1 is odd
  • 2 is even half of 2 is odd
  • 3 is odd half of 3 is odd
''', rsp def test_import_auto(self): loader = MockLoader({ 'lib.html': XMLTemplate(source='''
evenodd half of $n is ${evenness(n/2)}
'''), 'tpl.html': XMLTemplate(source='''
  • $i is ${lib.evenness(i)} ${lib.half_evenness(i)}
''') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''
  • 0 is even half of 0 is even
  • 1 is odd half of 1 is odd
  • 2 is even half of 2 is odd
  • 3 is odd half of 3 is odd
''', rsp def test_include(self): '''Must NOT result in: NameError: global name 'name' is not defined''' loader = MockLoader({ 'included.html': XMLTemplate('

The included template must also ' 'access Kajiki globals and the template context: ' '${value_of("name")}

\n'), 'tpl.html': XMLTemplate('

This is the body

\n' '') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert ('

This is the body

\n' '

The included template must also access Kajiki globals and ' 'the template context: Rick

' == rsp) class TestExtends(TestCase): def test_basic(self): loader = MockLoader({ 'parent.html': XMLTemplate('''

Header name=$name

Footer
id() = ${id()} local.id() = ${local.id()} self.id() = ${self.id()} child.id() = ${child.id()}
parent ${header()} ${body()} ${footer()}
'''), 'mid.html': XMLTemplate('''mid'''), 'child.html': XMLTemplate('''child

Child Body

${parent.body()}
''')}) tpl = loader.import_('child.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''

Header name=Rick

Child Body

id() = child local.id() = parent self.id() = child child.id() = mid
Footer
''', rsp def test_dynamic(self): loader = MockLoader({ 'parent0.html': XMLTemplate('Parent 0'), 'parent1.html': XMLTemplate('Parent 1'), 'child.html': XMLTemplate('''
''') }) tpl = loader.import_('child.html') rsp = tpl(dict(p=0)).render() assert rsp == '
Parent 0
', rsp rsp = tpl(dict(p=1)).render() assert rsp == '
Parent 1
', rsp def test_block(self): loader = MockLoader({ 'parent.html': XMLTemplate('''
Hello, $name!Sincerely,
$name
${greet(to)}

It was good seeing you last Friday. Thanks for the gift!

${sign(from_)}
'''), 'child.html': XMLTemplate('''Dear $name:${parent_block()}

And don't forget you owe me money!

''')}) parent = loader.import_('parent.html') rsp = parent({'to': 'Mark', 'from_': 'Rick'}).render() assert rsp == '''
Hello, Mark!

It was good seeing you last Friday. Thanks for the gift!

Sincerely,
Rick
''', rsp child = loader.import_('child.html') rsp = child({'to': 'Mark', 'from_': 'Rick'}).render() assert rsp == '''
Dear Mark:

It was good seeing you last Friday. Thanks for the gift!

And don't forget you owe me money!

Sincerely,
Rick
''', rsp def test_autoblocks(self): loader = MockLoader({ 'parent.html': XMLTemplate('''

It was good seeing you last Friday. Thanks for the gift!

'''), 'child.html': XMLTemplate(''' Great conference this weekend! ''', autoblocks=['body'])}) parent = loader.import_('parent.html') rsp = parent().render() assert rsp == '''

It was good seeing you last Friday. Thanks for the gift!

''', rsp child = loader.import_('child.html') rsp = child().render() assert rsp == ''' Great conference this weekend! ''', rsp def test_autoblocks_disabling(self): loader = MockLoader({ 'parent.html': XMLTemplate('''

It was good seeing you last Friday. Thanks for the gift!

''', autoblocks=['body']), 'child.html': XMLTemplate(''' Great conference this weekend! ''', autoblocks=['body'])}) parent = loader.import_('parent.html') rsp = parent().render() assert rsp == '''

It was good seeing you last Friday. Thanks for the gift!

''', rsp child = loader.import_('child.html') rsp = child().render() assert rsp == ''' Great conference this weekend! ''', rsp class TestClosure(TestCase): def test(self): perform('''
${x+y}${inner(x*2)}${add(5)}
''', '
15
') class TestPython(TestCase): def test_basic(self): perform('''
${os.path.join('a', 'b', 'c')}
''', '
a/b/c
') def test_indent(self): perform('''
${os.path.join('a','b','c')}
''', '
a/b/c
') def test_short(self): perform('''
${os.path.join('a', 'b', 'c')}
''', '
a/b/c
') def test_mod(self): perform('''
${os.path.join('a', 'b', 'c')}${test()}
''', '
a/b/c
') class TestComment(TestCase): def test_basic(self): perform('
' '
', '
') class TestAttributes(TestCase): def test_basic(self): perform('''
''', '
') def test_content(self): perform('''
''', '
foo
') def test_replace(self): perform('''
''', 'foo') def test_attrs(self): perform('
', '
') perform('''
''', '''
''') perform('
', '
') def test_strip(self): TPL = '

Header

' perform(TPL, '
Header
', context=dict(header=True)) perform(TPL, '

Header

', context=dict(header=False)) TPL = '''

It's...

''' perform(TPL, "
It's...
") def test_html_attrs(self): TPL = '' context0 = dict(checked=None) context1 = dict(checked=True) perform(TPL, '', context0, mode='xml') perform(TPL, '', context1, mode='xml') perform(TPL, '', context0, 'html') perform(TPL, '', context1, 'html') perform(TPL, '', context1, mode='html5', is_fragment=False) perform('\n' + TPL, '', context1, mode=None, is_fragment=False) def test_xml_namespaces(self): '''Namespaced attributes pass through.''' TPL = '

English text

' perform(TPL, TPL, mode='xml') perform(TPL, TPL[:-4], mode='html') def test_escape_attr_values(self): '''Escape static and dynamic attribute values.''' context = dict(url='https://domain.com/path?a=1&b=2') source = '''Link''' output = 'Link' perform(source, output, context, mode='html') perform(source, output, context, mode='xml') class TestDebug(TestCase): def test_debug(self): loader = FileLoader(path=os.path.join(os.path.dirname(__file__), 'data')) tpl = loader.import_('debug.html') try: tpl().render() assert False, 'Should have raised ValueError' except ValueError: exc_info = sys.exc_info() stack = traceback.extract_tb(exc_info[2]) # Verify we have stack trace entries in the template for fn, lno, func, line in stack: if fn.endswith('debug.html'): break else: assert False, 'Stacktrace is all python' class TestPackageLoader(TestCase): def test_pkg_loader(self): loader = PackageLoader() loader.import_('kajiki.tests.data.debug') class TestBuiltinFunctions(TestCase): def test_defined(self): perform('''
\
$albatross
\

$parrot

''', expected_output='

Bereft of life, it rests in peace

', context=dict(parrot='Bereft of life, it rests in peace')) def test_value_of(self): TPL = "

${value_of('albatross', 'Albatross!!!')}

" perform(TPL, expected_output="

It's

", context=dict(albatross="It's")) perform(TPL, expected_output="

Albatross!!!

") def test_literal(self): '''Escape by default; literal() marks as safe.''' context = dict(albatross="Albatross!!!") expected_output = "

Albatross!!!

" perform("

${literal(albatross)}

", expected_output, context) perform("

${Markup(albatross)}

", expected_output, context) perform("

$albatross

", "

<em>Albatross!!!</em>

", context) from kajiki.util import literal markup = '"&"' assert ''.join(list(literal(markup))) == markup if __name__ == '__main__': main() Kajiki-0.5.3/kajiki/text.py0000644000076500000240000002565712554436352015624 0ustar amolstaff00000000000000# -*- coding: utf-8 -*- '''Text template compiler. Notable in this module are: * TextTemplate - function building a template from text string or filename. * _pattern - the regex used to find the beginnings of tags and expressions. * _Scanner - scans text and generates a stream of tokens. * _Parser - parses a stream of tokens into the internal representation (IR) tree. * _Parser._parse_ - consumes the body of a tag and returns an ir.Node. ''' from __future__ import (absolute_import, division, print_function, unicode_literals) import codecs import re from .ddict import defaultdict from itertools import chain from nine import iteritems, str from shlex import split as shlex_split # Prior to Python 2.7.3, the from sys import version_info # *shlex* module did not support if version_info < (2, 7, 3): # Unicode input. Work around: _shlex_split = shlex_split shlex_split = lambda txt: _shlex_split(txt.encode('utf-8')) del version_info import kajiki from . import ir _pattern = r''' \$(?: (?P\$) | # Escape $$ (?P[_a-z][_a-z0-9.]*) | # $foo.bar {(?P) | # ${.... (?P) ) | ^\s*%(?: (?P[a-z]+) | # %for, %end, etc. (?P) )| ^\s*{%-(?P[a-z]+)| # {%-for, {%-end, etc. {%(?: (?P[a-z]+) | # {%for, {%end, etc. (?P) ) ''' _re_pattern = re.compile(_pattern, re.VERBOSE | re.IGNORECASE | re.MULTILINE) def TextTemplate(source=None, filename=None, autoescape=False, encoding='utf-8'): assert source or filename, "You must either provide a *source* argument " \ "or a *filename* argument to TextTemplate()." if source is None: with codecs.open(filename, encoding=encoding) as f: source = f.read() if filename is None: filename = '' assert isinstance(source, str), \ "*source* must be a unicode string, not a {}".format(type(source)) scanner = _Scanner(filename, source) tree = _Parser(scanner, autoescape).parse() tree.filename = filename return kajiki.template.from_ir(tree) class _Scanner(object): def __init__(self, filename, source): self.filename = filename self.source = source self.lineno = 1 self.pos = 0 def __iter__(self): source = self.source for mo in _re_pattern.finditer(source): start = mo.start() if start > self.pos: yield self.text(source[self.pos:start]) self.pos = start groups = mo.groupdict() if groups['expr_braced'] is not None: self.pos = mo.end() yield self._get_braced_expr() elif groups['expr_named'] is not None: self.pos = mo.end() yield self.expr(groups['expr_named']) elif groups['expr_escaped'] is not None: self.pos = mo.end() yield self.text('$') elif groups['tag_bare'] is not None: self.pos = mo.end() yield self._get_tag_bare(groups['tag_bare']) elif groups['tag_begin'] is not None: self.pos = mo.end() yield self._get_tag(groups['tag_begin']) elif groups['tag_begin_ljust'] is not None: self.pos = mo.end() yield self._get_tag(groups['tag_begin_ljust']) elif groups['tag_bare_invalid'] is not None: continue else: msg = 'Syntax error %s:%s' % (self.filename, self.lineno) for i, line in enumerate(self.source.splitlines()): print('%3d %s' % (i + 1, line)) print(msg) assert False, groups if self.pos != len(source): yield self.text(source[self.pos:]) def _get_pos(self): return self._pos def _set_pos(self, value): assert value >= getattr(self, '_pos', 0) self._pos = value pos = property(_get_pos, _set_pos) def text(self, text): self.lineno += text.count('\n') return _Text(self.filename, self.lineno, text) def expr(self, text): self.lineno += text.count('\n') return _Expr(self.filename, self.lineno, text) def tag(self, tagname, body): tag = _Tag(self.filename, self.lineno, tagname, body) self.lineno += tag.text.count('\n') return tag def _get_tag_bare(self, tagname): end = self.source.find('\n', self.pos) if end == -1: end = len(self.source) body = self.source[self.pos:end] self.lineno += 1 self.pos = end + 1 return self.tag(tagname, body) def _get_tag(self, tagname): end = self.source.find('%}', self.pos) assert end > 0 body = self.source[self.pos:end] self.pos = end + 2 if body.endswith('-'): body = body[:-1] while self.source[self.pos] in ' \t': self.pos += 1 return self.tag(tagname, body) def _get_braced_expr(self): try: compile(self.source[self.pos:], '', 'eval') except SyntaxError as se: end = se.offset + self.pos text = self.source[self.pos:end - 1] self.pos = end return self.expr(text) class _Parser(object): def __init__(self, tokenizer, autoescape=False): self.tokenizer = tokenizer self.functions = defaultdict(list) self.functions['__main__()'] = [] self.mod_py = [] # module-level python blocks self.iterator = iter(self.tokenizer) self.autoescape = autoescape self._in_def = False self._is_child = False def parse(self): body = list(self._parse_body()) self.functions['__main__()'] = body[:-1] defs = [ir.DefNode(k, *v) for k, v in iteritems(self.functions)] return ir.TemplateNode(self.mod_py, defs) def text(self, token): text = ''.join(_unescape_newlines(token.text)) node = ir.TextNode(text) node.filename = token.filename node.lineno = token.lineno return node def expr(self, token): node = ir.ExprNode(token.text, safe=not self.autoescape) node.filename = token.filename node.lineno = token.lineno return node def push_tok(self, token): self.iterator = chain([token], self.iterator) def _parse_body(self, *stoptags): while True: try: token = next(self.iterator) if isinstance(token, _Text): yield self.text(token) elif isinstance(token, _Expr): yield self.expr(token) elif isinstance(token, _Tag): if token.tagname in stoptags: yield token break parser = getattr(self, '_parse_%s' % token.tagname) yield parser(token) else: msg = 'Parse error: %r unexpected' % token assert False, msg except StopIteration: yield None break def _parse_def(self, token): old_in_def, self._in_def = self._in_def, True body = list(self._parse_body('end')) self._in_def = old_in_def if self._in_def: return ir.InnerDefNode(token.body, *body[:-1]) else: self.functions[token.body.strip()] = body[:-1] return None def _parse_call(self, token): b = token.body.find('(') e = token.body.find(')', b) assert e > b > -1 arglist = token.body[b:e + 1] call = token.body[e + 1:].strip() body = list(self._parse_body('end')) return ir.CallNode( '$caller%s' % arglist, call.replace('%caller', '$caller'), *body[:-1]) def _parse_if(self, token): body = list(self._parse_body('end', 'else')) stoptok = body[-1] if stoptok.tagname == 'else': self.push_tok(stoptok) return ir.IfNode(token.body, *body[:-1]) def _parse_for(self, token): body = list(self._parse_body('end')) return ir.ForNode(token.body, *body[:-1]) def _parse_switch(self, token): body = list(self._parse_body('end')) return ir.SwitchNode(token.body, *body[:-1]) def _parse_case(self, token): body = list(self._parse_body('case', 'else', 'end')) stoptok = body[-1] self.push_tok(stoptok) return ir.CaseNode(token.body, *body[:-1]) def _parse_else(self, token): body = list(self._parse_body('end')) return ir.ElseNode(*body[:-1]) def _parse_extends(self, token): parts = shlex_split(token.body) fn = parts[0] assert len(parts) == 1 self._is_child = True return ir.ExtendNode(fn) def _parse_import(self, token): parts = shlex_split(token.body) fn = parts[0] if len(parts) > 1: assert parts[1] == 'as' return ir.ImportNode(fn, parts[2]) else: return ir.ImportNode(fn) def _parse_include(self, token): parts = shlex_split(token.body) fn = parts[0] assert len(parts) == 1 return ir.IncludeNode(fn) def _parse_py(self, token): body = token.body.strip() if body: body = [ir.TextNode(body), None] else: body = list(self._parse_body('end')) node = ir.PythonNode(*body[:-1]) if node.module_level: self.mod_py.append(node) return None else: return node def _parse_block(self, token): fname = '_kj_block_' + token.body.strip() decl = fname + '()' body = list(self._parse_body('end'))[:-1] self.functions[decl] = body if self._is_child: parent_block = 'parent.' + fname body.insert(0, ir.PythonNode(ir.TextNode('parent_block=%s' % parent_block))) return None else: return ir.ExprNode(decl) class _Token(object): def __init__(self, filename, lineno, text): self.filename = filename self.lineno = lineno self.text = text def __repr__(self): # pragma no cover return '<%s %r>' % ( self.__class__.__name__, self.text) class _Expr(_Token): pass class _Text(_Token): pass class _Tag(_Token): def __init__(self, filename, lineno, tagname, body): self.tagname = tagname self.body = body text = tagname + ' ' + body super(_Tag, self).__init__(filename, lineno, text) def _unescape_newlines(text): i = 0 while i < len(text): if text[i] == '\\': if text[i + 1] != '\n': yield text[i + 1] i += 2 else: yield text[i] i += 1 Kajiki-0.5.3/kajiki/util.py0000644000076500000240000000575312641767766015625 0ustar amolstaff00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from collections import deque import sys from random import randint from threading import local def debug(): # pragma no cover def pm(etype, value, tb): import pdb import traceback try: from IPython.ipapi import make_session make_session() from IPython.Debugger import Pdb sys.stderr.write('Entering post-mortem IPDB shell\n') p = Pdb(color_scheme='Linux') p.reset() p.setup(None, tb) p.print_stack_trace() sys.stderr.write('%s: %s\n' % (etype, value)) p.cmdloop() p.forget() # p.interaction(None, tb) except ImportError: sys.stderr.write('Entering post-mortem PDB shell\n') traceback.print_exception(etype, value, tb) pdb.post_mortem(tb) sys.excepthook = pm def expose(func): func.exposed = True return func class Undefined(object): pass UNDEFINED = Undefined() class flattener(object): def __init__(self, iterator): while type(iterator) == flattener: iterator = iterator.iterator self.iterator = iterator @classmethod def decorate(cls, func): def inner(*args, **kwargs): return cls(func(*args, **kwargs)) return inner def accumulate_str(self): if type(self.iterator) == flattener: return self.iterator.accumulate_str() s = '' iter_stack = [self.iterator] while iter_stack: try: x = iter_stack[-1].next() except StopIteration: iter_stack.pop() continue if type(x) == flattener: iter_stack.append(x.iterator) elif x is None: pass else: s += x return s def __iter__(self): for x in self.iterator: if type(x) == flattener: for xx in x: if xx is not None: yield xx elif x is not None: yield x def literal(text): return flattener(iter([text])) class NameGen(object): lcl = local() def __init__(self): self.names = set() @classmethod def gen(cls, hint): if not hasattr(cls.lcl, 'inst'): cls.lcl.inst = NameGen() return cls.lcl.inst._gen(hint) def _gen(self, hint): r = hint while r in self.names: r = '%s_%d' % (hint, randint(0, len(self.names) * 10)) self.names.add(r) return r def gen_name(hint='_kj_'): return NameGen.gen(hint) def window(seq, n=2): """Return a sliding window of size ``n`` over an iterator""" l = deque((next(seq, None) for _ in range(n)), maxlen=n) push = l.append yield l for item in seq: push(item) yield l Kajiki-0.5.3/kajiki/version.py0000644000076500000240000000026012651435356016305 0ustar amolstaff00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) __version__ = '0.5' __release__ = '0.5.3' Kajiki-0.5.3/kajiki/xml_template.py0000644000076500000240000005130412607033461017310 0ustar amolstaff00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) import re from codecs import open from xml import sax from xml.dom import minidom as dom from nine import IS_PYTHON2, basestring, str, iteritems, native_str if IS_PYTHON2: from cStringIO import StringIO as BytesIO else: from io import BytesIO from . import ir from . import template from .ddict import defaultdict from .doctype import DocumentTypeDeclaration, extract_dtd from .entities import html5, unescape from .html_utils import (HTML_OPTIONAL_END_TAGS, HTML_REQUIRED_END_TAGS, HTML_CDATA_TAGS) from .markup_template import QDIRECTIVES, QDIRECTIVES_DICT impl = dom.getDOMImplementation(' ') def XMLTemplate(source=None, filename=None, mode=None, is_fragment=False, encoding='utf-8', autoblocks=None, cdata_scripts=True): if source is None: with open(filename, encoding=encoding) as f: source = f.read() # source is a unicode string if filename is None: filename = '' doc = _Parser(filename, source).parse() expand(doc) compiler = _Compiler(filename, doc, mode=mode, is_fragment=is_fragment, autoblocks=autoblocks, cdata_scripts=cdata_scripts) ir_ = compiler.compile() return template.from_ir(ir_) def annotate(gen): def inner(self, node, *args, **kwargs): for x in gen(self, node, *args, **kwargs): self._anno(node, x) yield x return inner class _Compiler(object): def __init__(self, filename, doc, mode=None, is_fragment=False, autoblocks=None, cdata_scripts=True): self.filename = filename self.doc = doc self.is_fragment = is_fragment self.functions = defaultdict(list) self.functions['__main__()'] = [] self.function_lnos = {} self.mod_py = [] self.autoblocks = autoblocks or [] self.cdata_scripts = cdata_scripts self.in_def = False self.is_child = False # The rendering mode is either specified in the *mode* argument, # or inferred from the DTD: self._dtd = DocumentTypeDeclaration.matching(self.doc._dtd) if mode: self.mode = mode elif self._dtd: self.mode = self._dtd.rendering_mode else: # The template might contain an unknown DTD self.mode = 'xml' # by default def compile(self): body = list(self._compile_node(self.doc.firstChild)) # Never emit doctypes on fragments if not self.is_fragment and not self.is_child: if self.doc._dtd: dtd = self.doc._dtd elif self.mode == 'html5': dtd = '' else: dtd = None if dtd: dtd = ir.TextNode(dtd) dtd.filename = self.filename dtd.lineno = 1 body.insert(0, dtd) self.functions['__main__()'] = body defs = [] for k, v in iteritems(self.functions): node = ir.DefNode(k, *v) node.lineno = self.function_lnos.get(k) defs.append(node) node = ir.TemplateNode(self.mod_py, defs) node.filename = self.filename node.lineno = 0 return node def _anno(self, dom_node, ir_node): if ir_node.lineno: return ir_node.filename = self.filename ir_node.lineno = dom_node.lineno def _is_autoblock(self, node): if node.tagName not in self.autoblocks: return False if node.hasAttribute('py:autoblock'): guard = node.getAttribute('py:autoblock').lower() if guard not in ('false', 'true'): raise ValueError('py:autoblock is evaluated at compile time ' 'and only accepts True/False constants') if guard == 'false': # We throw away the attribute so it doesn't remain in rendered nodes. node.removeAttribute('py:autoblock') return False return True def _compile_node(self, node): if isinstance(node, dom.Comment): return self._compile_comment(node) elif isinstance(node, dom.Text): return self._compile_text(node) elif isinstance(node, dom.ProcessingInstruction): return self._compile_pi(node) elif self._is_autoblock(node): # Set the name of the block equal to the tag itself. node.setAttribute('name', node.tagName) return self._compile_block(node) elif node.tagName.startswith('py:'): # Handle directives compiler = getattr( self, '_compile_%s' % node.tagName.split(':')[-1], self._compile_xml) return compiler(node) else: return self._compile_xml(node) @annotate def _compile_xml(self, node): content = attrs = guard = None if node.hasAttribute('py:strip'): guard = node.getAttribute('py:strip') if guard == '': # py:strip="" means yes, do strip the tag guard = 'False' else: guard = 'not (%s)' % guard node.removeAttribute('py:strip') yield ir.TextNode('<%s' % node.tagName, guard) for k, v in sorted(node.attributes.items()): tc = _TextCompiler(self.filename, v, node.lineno, ir.TextNode, in_html_attr=True) v = list(tc) if k == 'py:content': content = node.getAttribute('py:content') continue elif k == 'py:attrs': attrs = node.getAttribute('py:attrs') continue yield ir.AttrNode(k, v, guard, self.mode) if attrs: yield ir.AttrsNode(attrs, guard, self.mode) if content: yield ir.TextNode('>', guard) yield ir.ExprNode(content) yield ir.TextNode('' % node.tagName, guard) else: if node.childNodes: yield ir.TextNode('>', guard) if self.cdata_scripts and node.tagName in HTML_CDATA_TAGS: # Special behaviour for