flask-peewee-0.6.7/0000755000175000001440000000000012624225533014700 5ustar charlesusers00000000000000flask-peewee-0.6.7/MANIFEST.in0000644000175000001440000000021312574421673016441 0ustar charlesusers00000000000000include LICENSE include README.rst recursive-include docs * recursive-include example * recursive-include flask_peewee * prune docs/_build flask-peewee-0.6.7/docs/0000755000175000001440000000000012624225533015630 5ustar charlesusers00000000000000flask-peewee-0.6.7/docs/admin.rst0000644000175000001440000002433412574421673017467 0ustar charlesusers00000000000000.. _admin-interface: Admin Interface =============== Many web applications ship with an "admin area", where priveleged users can view and modify content. By introspecting your application's models, flask-peewee can provide you with straightforward, easily-extensible forms for managing your application content. Here's a screen-shot of the admin dashboard: .. image:: fp-admin.jpg Getting started --------------- To get started with the admin, there are just a couple steps: 1. Instantiate an :py:class:`Auth` backend for your project -- this component is responsible for providing the security for the admin area .. code-block:: python from flask import Flask from flask_peewee.auth import Auth from flask_peewee.db import Database app = Flask(__name__) db = Database(app) # needed for authentication auth = Auth(app, db) 2. Instantiate an :py:class:`Admin` object .. code-block:: python # continued from above... from flask_peewee.admin import Admin admin = Admin(app, auth) 3. Register any :py:class:`ModelAdmin` or :py:class:`AdminPanel` objects you would like to expose via the admin .. code-block:: python # continuing... assuming "Blog" and "Entry" models admin.register(Blog) # register "Blog" with vanilla ModelAdmin admin.register(Entry, EntryAdmin) # register "Entry" with a custom ModelAdmin subclass # assume we have an "AdminPanel" called "NotePanel" admin.register_panel('Notes', NotePanel) 4. Call :py:meth:`Admin.setup()`, which registers the admin blueprint and configures the urls .. code-block:: python # after all models and panels are registered, configure the urls admin.setup() .. note:: For a complete example, check the :ref:`example` which ships with the project. Customizing how models are displayed ------------------------------------ We'll use the "Message" model taken from the `example app `_, which looks like this: .. code-block:: python class Message(db.Model): user = ForeignKeyField(User) content = TextField() pub_date = DateTimeField(default=datetime.datetime.now) def __unicode__(self): return '%s: %s' % (self.user, self.content) If we were to simply register this model with the admin, it would look something like this: .. code-block:: python admin = Admin(app, auth) admin.register(Message) admin.setup() .. image:: fp-message-admin.jpg A quick way to improve the appearance of this view is to specify which columns to display. To start customizing how the ``Message`` model is displayed in the admin, we'll subclass :py:class:`ModelAdmin`. .. code-block:: python from flask_peewee.admin import ModelAdmin class MessageAdmin(ModelAdmin): columns = ('user', 'content', 'pub_date',) admin.register(Message, MessageAdmin) admin.setup() Now the admin shows all the columns and they can be clicked to sort the data: .. image:: fp-message-admin-2.jpg Suppose privacy is a big concern, and under no circumstances should a user be able to see another user's messages -- even in the admin. This can be done by overriding the :py:meth:`~ModelAdmin.get_query` method: .. code-block:: python def get_query(self): return self.model.select().where(self.model.user == g.user) Now a user will only be able to see and edit their own messages. Overriding Admin Templates ^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the :py:meth:`ModelAdmin.get_template_overrides` method to override templates for an individual ``Model``: .. code-block:: python class MessageAdmin(ModelAdmin): columns = ('user', 'content', 'pub_date',) def get_template_overrides(self): # override the edit template with a custom one return {'edit': 'messages/admin/edit.html'} admin.register(Message, MessageAdmin) This instructs the admin to use a custom template for the edit page in the Message admin. That template is stored in the application's templates. It might look something like this: .. code-block:: jinja {% extends "admin/models/edit.html" %} {# override the default edit template #} {# override any blocks here #} There are five templates that can be overridden: * index * add * edit * delete * export Nicer display for Foreign Key fields ------------------------------------ If you have a model that foreign keys to another, by default the related model instances are displayed in a

{% endblock %} A panel can provide as many urls and views as you like. These views will all be protected by the same authentication as other parts of the admin area. Handling File Uploads --------------------- Flask and wtforms both provide support for handling file uploads (on the server and generating form fields). Peewee, however, does not have a "file field" -- generally I store a path to a file on disk and thus use a ``CharField`` for the storage. Here's a very simple example of a "photo" model and a ``ModelAdmin`` that enables file uploads. .. code-block:: models.py # models.py import datetime import os from flask import Markup from peewee import * from werkzeug import secure_filename from app import app, db class Photo(db.Model): image = CharField() def __unicode__(self): return self.image def save_image(self, file_obj): self.image = secure_filename(file_obj.filename) full_path = os.path.join(app.config['MEDIA_ROOT'], self.image) file_obj.save(full_path) self.save() def url(self): return os.path.join(app.config['MEDIA_URL'], self.image) def thumb(self): return Markup('' % self.url()) .. code-block:: python # admin.py from flask import request from flask_peewee.admin import Admin, ModelAdmin from wtforms.fields import FileField, HiddenField from wtforms.form import Form from app import app, db from auth import auth from models import Photo admin = Admin(app, auth) class PhotoAdmin(ModelAdmin): columns = ['image', 'thumb'] def get_form(self, adding=False): class PhotoForm(Form): image = HiddenField() image_file = FileField(u'Image file') return PhotoForm def save_model(self, instance, form, adding=False): instance = super(PhotoAdmin, self).save_model(instance, form, adding) if 'image_file' in request.files: file = request.files['image_file'] instance.save_image(file) return instance admin.register(Photo, PhotoAdmin) flask-peewee-0.6.7/docs/conf.py0000644000175000001440000001535512624225450017136 0ustar charlesusers00000000000000# -*- coding: utf-8 -*- # # flask-peewee documentation build configuration file, created by # sphinx-quickstart on Tue Sep 20 13:19:30 2011. # # 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 # 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.insert(0, 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 = [] # 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'flask-peewee' copyright = u'2011, charles leifer' # 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 = '0.6.7' # The full version, including alpha/beta/rc tags. release = '0.6.7' # 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 = 'flask' html_theme_options = { 'index_logo': 'peewee.jpg', } # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['_themes'] # 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 = None # 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 = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'flask-peeweedoc' # -- 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', 'flask-peewee.tex', u'flask-peewee Documentation', u'charles leifer', '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', 'flask-peewee', u'flask-peewee Documentation', [u'charles leifer'], 1) ] flask-peewee-0.6.7/docs/fp-admin-btn-form.png0000644000175000001440000005577012574421673021600 0ustar charlesusers00000000000000PNG  IHDR:s IDATx^w)K7i"W(RTDv ((b犢(_P" H/ ?oi|<>ww9oOd!  b,i{# Sn@@WL] T@@`=  +J  L@@\!@0uE7P @@)  +*  @0@@p@%@@:TӟAEof1cF~Nd~(O=Tw}r%ĭf+#n @LK*%}-ZP/'|LԱnLnd֬YԾ}{yVUB#n @LG-Z ?O&jd+Iƞڵk .h%T^=.Fn nG\P)@$ 5yrW{'=4K1B^~չkKu qa@R&s0-R8pl@ǎ/Ԙ{W&Nh~u #)_XP믿|9/}߬Y33fL\A0 #  2i6m|k֬)Ǐ/Ԙ?_֭[g~<4e /^XtVٲeC;v~HFb4fB @@ 1=zo!I/˹kӅQfذaltG-[f *HƍO4Wt뢫P.~̝;W.{1}ᇛez /C={ҵmŋJ*IӦMfMyӧرc?ԢFr)u]gi0k$wK/$#GsM|AyL kW^aԾϜ9Sl"UTc=Vv*u @>z_iNjYjU9o2eʘu?ywek^K+R+V!m۶#zZҤI 9@L `z]w X4x馯:3| _s=[s9Gy晰T×qƠ+W'|RtuwmРA;_24@Ӑu;yyyσ=P /ȵ^װZg THsM>ha0kS7.hZe%GG s~aٷo_k?o 2DuW6-O`qf0vr_D @: LիE覣HKtѓ.~MGj׮m ruJGm m۶-p_'TY|N8ᄸ1yB)T=tZo:uքkjvwDh1֠o~ :h{þV*QG.6}[^{޾9 %K *5ܻ[:u)?! 1GyDU&={4Q|?0aD7Ȗ^]z饲f!:O.ZjɆ 5J'st|,Z\9s1{ѢE4ٷxqUW… b0j7e7o^`dP>[o5)/Y,CHriˋ/X>kO=W_7uEZv1LjoРX-C_wpBK:z7 z/z:Fnơ\^3gq @L9{yꩧ޽{Q }?6ߋ7/n]MӧPh|W|? tgW9aE:kQI&ph:Y |VV9:oVt҄FAC-iǩu6vWX\X\Qk;t4^F}coWCDk7o9tA]'\0ySO2u @L9>rI's_:]v믿M7dYY:eʔuokirH>Б;s BGR7oۯD:-e*6]/בh]dmg}fٷDko߾Cիgho#:y8Lt'k{g?7 :$XeՐh4ۧSMVӯImmP.Шp$1 @Thc믿|4njjG쯖rذaT4iXt^ft+2GƺZGtz#`J}.4ѽ`5>䫯틝 u徵i$ǁ7S_Nё}]et[Gs-1FD&7c@Y `j*z H]Lf:z>j999Mjǻ.]ڜ_)P@GzM'9asdMBmv;Μ"amd(\kѶi5^ZXc_Ɂ^ik o#O?dNuo(#,3i .s0}뭷DixGLt 3j) TCGSXaQ.QƝ;w-Ji#[eh D*Cc]Mëd 9u~ry|bp2^DŽ~qj ] `ԏMWkpMZ KM]}AkjUΝ; rKEx)L6}Է~e")qO~D_etYj,P1#yj^pU:i} XĘu[2Y:u>}$/ҕ~_| 8P%Sg? 9jNֿ/Q:4hhx V;Y0h_?II_O#e :g2?(w~?>E"X)Pt U}\;DGt5H{#:VZ*GЕɜxp6Dz\! v>GG2AT_7imTZh~l}4:HrJm))}+@Mݴ:>2tOeA]t>ו֦I5t` w֦abx1b˾:>?>6~G}Q~8u# . 7ijԨt;Q?V :(_l}+۷kȵQ9}giQsUVYՅI8G?TêֿM6f/2_u^=M.hs.#lsfe:hM(_%Wz=CӾ}9s9_YW?I?KG6h "1jsǹR   8_3)?a[! "@0MQ]] ?]~P}54*" ip[ VX᫩.ҏЩ^?(} >^gC@E`=*5xFU^\('fEz=C@!@0b[!*ܦ  @pdz@p-=A=t7o{Cu@?ĠI&rǛo`4LA@ L]%T@ԛN@@ L]%T@ԛN@@ L]%T@ԛN@@ L]%T@ԛN@@ L]%T@ԛN@@ L]%T@ԛN@@ L]%T@ԛN@@ L]%T@@t  I8&6\@@Sv= G@%@0uWP@@Sv= G@%@0uWP@@Sv= G@%@0uWP@@Sv= G@%@0uWP@@Sv= G@%@0uWP@@Sv= G@%@0uWP@@Sv= G@%@0uWP@@Sv= G@%@0uWP@@Sv= G@%(ܹSn*999jA@H{innlذAW.ŊK@@w DL׬YC(uWQ@@ "K,FeTi   { j xZ`  {ӆ @@ ՝4@H_i5G@2JQ0mРAF5  G`Ꞿ&  ~ GQ0_~5/>pVsɒ17VLD-;6 / ) knݺU&M$]vYD:ҷ}5Jgfy 2fn9侱纝RLq_uyS_@%`wW{_>YERyni&ӹsJNNt!6wYZ&tj,K9g_2ga= hi Mb:+dmVs\LF@H STVVrŸ%cʄ`:ai׮ԨQ#" m2BiuDU9/Q6~Z4`#SFt{r Q 8 Ջ"zReoTé~>m.1GgO)9E[WH^^Z >PY-mcղmyGaut/eRMb/Wvɵd\޸{\=~.yrU nϞ=K.]DM"ٴoh)W_&wJ56o-a۞rQ+v)F;<.b5ԾP>] }Ԑ[~8T]"iwVBuZU֯_9 AVl[> eI9@/46##'Ԓ$c#w}Z<2 gԓmn{1Ys_0Ӯ<}J]j6svg־}״,U__]>[E^<6#05\J&cGf.@sR)[ ڨb tM3q9Gtɒ%j*9餓"@tEfPL_Knjڼ@ݍ6Z婓ju eʧUrXr]rۤ2r&GDhmP}hY/^\UtZ@nnӧ֓~a(H1 xAUT\>/YRGSxTmquJR[ ƚQX {eJ!o!gUHEkl0C}ޭJBa(H1 xAUTw6!Gf-K{E:#SWF&ҮFBVy"_#nM-rkk3U[#1%XK-[2{{tl\cJΝEDYm\-WڏSBZ[rӊ {l;(r /{KjP}$ Lµ xEQ0[n.%@hmo30GD]FN[VU)%-+p%eV#eۿׯBj-.rH;c悃S#3:T>BYqS~Ư/h,gJcn!oY֮]+gϖ;:w2Fk|Sq-m^#܂`B45ӕMZiNG3GBUCd#Qs0 ,`넕2Fr^&qWM1w緫y}1֐)/_,!W_ mB*]ynVZDVI>sdvfu߭#FӧKٲee@fËo;X[wbakKȨyE[[dJ&q\C Ww~9͡grdM>Pu xXF>[}a,.Hi(pf? ^Hj0؋ˊ>m]ƢUXYrN놽XX4x?#s@.if,9.X{~Z_W_}~Cx-VW_GLu5YgeS'kv˂-aeI eҬrIu^CiZ!\C eo\eh-uϗHKblB [e-242 n# GNl%J(t. gG@ I ^-Ϫc.#M]/K1F??9\1Ʉ^   &Z؃|RȕcloSj ɘxi= @di %i:Ea՞ NN8@@ aӄR0  GVWgC@@ xR  @TӨ8 @@ +VHʕ͗ѳ!  o]dӦMRB)Z4,@@@T/E_ IDATsNٺu  )(b  @\@@GSG\  (id)@@# $J`(YE@p$@0u   &Jr@@ Lqq0  @\@@GSG\  (id)@@# $J`(YE@p$@0u   &Jr@@ Lqq0  @\@@GSG\@֭[e׮]9 ђ%KJҥB 6H@ [8 X heʔbŊűdo>پ}_[QjxT`юزeJj< a)^TXѓ [n@֬Y#իWH?_^j׮@eFp*@0u*d%KqВ蛀Av$J`(YE2 \|R5Գ]Oý,@(#z ^{!0)4a7#1LcTU`J0M{z#@f L3iSi n W  L|Q< 4*6NB =d4S{v!B`J0 Fv#GՔ[U.6oFGuz68oqnC2yv='4 /YOj)..Gא3wTv"re|C&B^"_% /NU`[0Du\^u6^~A/ܧX_Ǣ?Ծ/Er~1  $cnyxI]o&Km yA=f&zwQ^n#/Q/eC?]S߭Rŋȃgr#ϟ^OOXs ϿA^@eضW4hym|se3iP>[f#m ?:ed=r@}X" ~HYC0j|aLxuh=9 {m%Mbf;6OT.=Z]5sb>m($Ln۶M,\wuꫯzo1ѣ7N6n(~uQfo.իWKNQ`B($ LFvvC9Viv\2׽U/n#UJ[s?7ȳFx-0ףm5#n{@`@ k(+!8zzW˥URfPk5_XV/u\j@oFKF mԩ4\Bn#g,yʯц5+}.hӮ@]t;GBQZnlS՜kck}e{bșO49#Wol@eHdϦJ5<뗌09w5TҜM]Ymb|CA6 N,9DU&\p2ysLC\Գ>[*={ 4H}]iÆ z',o|wH:c@4HZ0}j:Yb;r-mR*9hX"Yh>n&Y¡ŲVc:quJicB.FkϺ/ϖF8ֹKƯ U~4x,Z1ue vn6%gʳW7]w;)2.7HC߷ CU0q.r1::=E=rF9XdFuG*c6[arTu𹲶O\F}[CQ{ȡƾ72p:SOIʕeҧO믿.*ߓz7#eʔ)Th \c@ $-j(mkekl34\@0-oG-{iP_cRڛrUsio,->}\? fX4hYTC̑½uK׷?qg~5@m1h cՎ}F8.e\'w@UκѺ_Wo+?3VePsj0;ĸ?A"~k_p)cĹ@tgDL +K?t=iq-5z;9zO;+zke,G]tѣGKbd߾}gl0+wޑ"E*?\5pr Ep&`:j(\R#h 3FXq Dc4P\9ZxoFЙad}Dܘxpu+Jʟ3htNf{cžzpiq|PGLu.b߈*cTG%ڲhWf#S{v1Ҭ[(Xm($c=&UV5+Tˆ w<ʏf\@EI :g䉓=ƼA_:ե9t4iҭ(4V_j,U4c&F(xm.ZaRAikجRinouTckEM+O֘PĜίc̣fdo:_N]Nؽ{2XxpM͘W;My S_ѫu2Md0>|.]Z:w,#G' :9tP߻L#11b_IG5@$5蛎Rꢥ&*v`snU6VZ5ig*;ԾNY%;GĺU#W}EV+GV]ٺr\G~\C*Nh(??oY#\Mys0zӁ:UGSgwkeX.B%}ǬΓ4߆pz\}Ni(_]ӌu\ҷ:-0K_$tU=/o`s=A㏃ӍiIQ/3WP6VQ V{lGXi [we_b\{ׁg̘aK" ֪k5\#C {ϱG/   $:1 WG_ _5xTuevs< fO/2#ݞ:کfGih- 0F.h9 L?{VZ#>w|c2N@.`/ot1+FSPmH`ۙ-Ɏ'ciӦɨQdҼys3VN6-E#`be"ᄂF { i24 :*"o)4! C2H3)4nY zi&v) n@bD%@0Ho)4`j*@0Ԟ] LQ`^N$X`J0M-F @TSEƆ!P\9VZf4&VرC֯_ٜ i".N  XS@@WL] T@@`=  +J  L@@\!@0uE7P @@)  +*  @0@@p@%@@     {@@SWt@@ r  B`n  S@@WL] T@@`=  +J  L@@\!@0uE7P @@)  +*  @0@@p@%@@  pL;tQg̘8,X8 _~{a˲ر4kL7o.vz衅Ν?L/_#8§oI=D[ D C )tΝk_-X}rI'I+=t]nfի*Ç7SO1͕#GeݺuRjU9s̲J(Q>O?T/_.yyyҤIK /I&ɇ~( ,իW/)]t2rСڵK:,;E0;iSΝ; p.+W򨣎!CH"E}]~袋|½>*˸{eĉϛL"wqgy&`0꫏6lU@pذaO+cǎ5֟1U]lJMG'Ǎg~} 7 %K4fgg8}ϪcUSg;^G]׬Yj6%&L@@ c9Ft7g/tҥئKu*n8I.>+:q  gxyG}uϞ=?9iS$7  Hx0Ft[֯_D`S5bJsxj T׹S">Mb~|i&sѣ 8 Zڵk t~a&:u2GH_7M"i7  Hx0ӧ(GC_. z x1­R:sРAunݺɬY ͉]C^KG.~㬹&LjժMi^Wi_)Ҷs  @ƒ,]#k Lu.ҹtr:9ՠdsT5owp'T0GV(RB]?.Z|omVZ :U_fi֗#vݴ>`<%'[ tjz~`Q)\@H@ƒV\_y/w|w󨣑PT_aLW|OOnuUmۤTR@-4]4bs-I_ԸqUЏ5OΦMJ׮]6ڷHӹ'S_W/_zb],kmz~7ߘuQ뮻'w63f?  4 XD) @H4 +Z([uNuUQXnMX(@4Π*N?8@?@ VN5jTP!Y:  @Ә SSAՅRڭ+VsLWnmOҷ ! $@0Mޢ  @ L3si  Nt- d4;! $@0Mޢ  @ L3si  Nt- d@t@@@R-q0MuE>  @f L3i  6S7wC幹zc&rIYk5EH4؎/Epl x<)'L nnՍ`> @I{˓gT*,$]`tr.xM`'G%@0^@H4LO9%Xtb}vErNJdS޷o+WNʖ-S`G(@0uۍ(F~7V껭2>ϫ5th{y`mBhڵf͚ h i*C]`d}v\`.@`P^qRn 4;!. snOև`n @)FL.:q[O<83coˮ94pm)NqV PmD p[x>܇wZX`(tyzě>fj@ wm@}L)7 @ )@yIzě>fj@ w#wy7+䋹ˏ6G~K6B-IDAT ߿_=IJT# ԑ=[6ȾΐE&tH8@ 8bƥ(A`:`Hq!ve!7ʾg* 4iҨ#4p0`4% Su,4p0`MKEu%ohG04rsu8x"4)U1[quFƻVEri0}`  dm}`=#K7GaJرC~a>}L2>o?\ƌ7YQ~OgePd\_dzV]+c{+U~cfIV`|{.I~=EJʈnjbrŠIɚʾc4r 8ԯ]จ 4%FdA +@0u[׺ s1ҿKDC!CO?5{9⋥aÆ2~xYlLn9ӥRJq5F0-X-*W,O_S=0Ϭ ˲]%e %uq5$`:r5ұyy 29~u$8~ސ)ybL_%FdA +@0u[׺ [K.ҦM)YO7CjbdҵkW7n/N8Q*WQfӛSd.)~`sdݖ>)f<^3S6ڟFV9_[Yq @ Lֵ v|fNNs9n89sK˖-}{yԩ`j*Jϳ[K%$`;*.ْ+{^:Ʒ/R8.` {<3pھqah0}`!dm]`z뭷JϞ=}AS?|q+R@cϞ=2a:t|W> }XDr ݜԕ+se❲xr㹳$w~0]h+9dJRFYپ}y/Aqf }_fL u@ {LgΜiOj׮-˗/~ZnFѹuYz!zB(kT'N:sL5<#F%4^,nFNKk6xr$g~0}zm?И2Ӥiu}qf0 }_fLGL:q @F Lֽ /R^}UYnԬYSw.:w%K|I3uVyGdڴiҠAk]`#_t剋HْEeuF0)?V(UT޻SJRhۗLg;/moL:q @F LֽInkruLÕLGL]/T@ ӤrGp1i!$3t44! Su.4p0t m @r5i`=i  S.4p0"_n [ӱӰN Su/4`0vy_yVsH=`RhѸSA܇1q2 @tw `01|ve~:#9%gO-/ú7#& T`궎!ݹҠdٜ[NX)ZٻC**Gt2K"E/+grS@" FD鞽/f$Ku#֖m=6Ph@%@ L=bS}~)QWP܇r@ n.A@jn>L-#!q&B@B Lv#ެ7V#)  ]@f}H4@0u[PS`ʍ i C^@f}H4:0b= *i]*7}~ @)FLԇS@T LS%ψ䩏]S@LS7}~ @)廭@R%@0MG{?>V Q\9)[jO}2EE6ޜXx~VvmYfe @H4桯۪H})@0fj@ djGr-i$Ji й$ 1:`>   &ZiSb$i  a:o jǎ}? d lm>o}˖,~J8A<(@0MN_n]ޚ5kҠ7ݻ{!JXZjRJVG,Ɓ ipLE++V(ŊK^FWEI5nZ$\`p/@0YlIR$+]xi|)@ _`wT?MJѢE .g . d4 :ј[) *Ξ=[Z~=?!lt 5AZ`Ҷm[w"xP`NO&Lӱר3 μ8:EsY@(@0M"6^`g" .t)ʤo&*TkV:ws UVuM9*,^~ؿ1I, zG{^e>k{mq}d4MzQã޽{)"{f0bjg!&M =9^DLgԨQ1#kh֭dz6GE`&=sIʕnxΜ9?9rdLС̘1#2xm0}gd1#k0w#E"T) @0M^K矗 q^^[n||߾}{yᇥ|uUG˓O>)zsk©~&;}ts~]Lē6G4K~mG={4?W^}.GuT-Z ˗/7?eꫯO>[n_Wnxꩧ|+Vڵ˼ΝkǼ@ L8モŋO?- 4 /PkӒn__Kxԩr=H^|f?~9o߾ˉ'`zYgr֬YˑG)\p5a+vɏ?(q}rUWTjժ7y4ҺH릏kժ%vOd޽/EZNS=r;ۏ+7~h3fcذaҺuk?P諫c1 w5xjۭ?N^u3 k'L 6l0B=|z˼f:uk֬k&D( it '`-Ydk uI~@9qDs:|(͛k׮(u^ēi0հ /&4GQPuܷoB#Vz^kёM Gׯ7G]#\PuR#F=M V"-'P0 l?3:syRDpM751ZBͭ} B~|k8?>y'D?<`B=T0Ցޗ^z1ק:j͆ PP`&wL}\٨Q#_srrdʔ)ұcGg{9ʧ4(kQQ{ZNnn:P)'Nرc}S̅G.]jkp ?T0 UN.]df~#{ nE#p3GzTƍ] Q*Z*i&sK17,/9!]&C͵Mv!L_*U*IGP5PX+=\ySGR5d>CSrvRN<She< M6C=Tj֬ihir4i8Wt\UM6uj(̑GݜPAMw^pm:?^B\OyO,TXd]ji+#i{:'M_N:$?GKZ㏛ C."3C :GOZ2Ǚ:u2j@}#Fp\N|.]ڜj L5֭[7T"}TG3ua.PAվOuGk9GC8>*0H(s}`sd4ЦsWls|m?nZ5Tt'l itGd]Ixb3Du^KQBtB(iGy\kQrI`/:MBj844~\bF1ZWh\g!(Zo :- \pBsvʕ#Po7V5eu exu4ԾCy ӂmn>V35?@i(GaQu!gOSU@ 1ͨL3oS2WNO`CH4u\ف::UEk_6@ LSgϕL`q( i*@0MӎZ ^qڋ E{= L0MN 8 :LSU@H4\+jit @LӦ]Q#xC`~NVLӾ i aa8 S7u@@ Rzq@\,@0uqP  d48#ZH0͈n  r4-J" 4&>NN4Y\@ LSgϕL`q( i*@0MӎZ ^qڋ E{= L0MN 8 :LSU@H4\+jit @LӦ]Q#xC`~NVLӾ i aa8 S7u@@ Rzq@\,@0uqP  d48#ZH0͈n  r4-J" 4&>NN4Y\@ LSgϕL`q( i*@0MӎZ ^qڋ E{= L0MN 8 :LSU@H4\+jit @LӦ]Q#xC`~NVLӾ i aa8 S7u@@ Rzq@\,@0uqP  d48#ZH0͈n  r4-J" 4&>NN4Y\@ LSgϕL`q( i*@0MӎZ ^qڋ E{= L0MN 8 :LSU@H4\+jit @LӦ]Q#xC`~NVLӾ i aa8 S7u@@ Rzq@\,@0uqP  d48#ZH0͈n  r4-J" 4&>NN4Y\@ LSgϕL`q( i*@0MӎZ ^qڋ E{= L0MN 8 :LSU@H4\+jit @LӦ]Q#xC`~NVLӾ i aa8 S7u@@ Rzq@\,@0uqP  d48#ZH0͈n  r4-J" 4&>NN4Y\@ LSgϕL`q( i*@0MӎZ ^qڋ E{= L0MN 8 :LSU@H4\+jit @LӦ]Q#xC`~NVLӾ i aa8 S7u@@ Rzq@\,@0uqP  d48#ZH0͈n  r4-J" 4&>NN4Y\@ LSgϕL`q( i*@0MӎZ ^qڋ E{= L0MN 8 :LSU@H*7IENDB`flask-peewee-0.6.7/docs/installation.rst0000644000175000001440000000156212574421673021076 0ustar charlesusers00000000000000.. _installation: Installing ========== flask-peewee can be installed very easily using `pip `_. .. code-block:: shell pip install flask-peewee If you do not have the dependencies installed already, pip will install them for you, but for reference they are: * `flask `_ * `peewee `_ * `wtforms `_ * `wtf-peewee `_ * python 2.5 or greater Using git --------- If you want to run the very latest, feel free to pull down the repo from github and install by hand. .. code-block:: shell git clone https://github.com/coleifer/flask-peewee.git cd flask-peewee python setup.py install You can run the tests using the test-runner:: python setup.py test flask-peewee-0.6.7/docs/gevent.rst0000644000175000001440000000321312574421673017660 0ustar charlesusers00000000000000.. _gevent: Using gevent ============ If you would like to serve your flask application using gevent, there are two small settings you will need to add. Database configuration ---------------------- Instruct peewee to store connection information in a thread local: .. code-block:: python # app configuration DATABASE = { 'name': 'my_db', 'engine': 'peewee.PostgresqlDatabase', 'user': 'postgres', 'threadlocals': True, # <-- this } Monkey-patch the thread module ------------------------------ Some time before instantiating a :py:class:`Database` object (and preferrably at the very "beginning" of your code) you will want to `monkey-patch `_ the standard library thread module: .. code-block:: python from gevent import monkey; monkey.patch_thread() If you want to patch everything (recommended): .. code-block:: python from gevent import monkey; monkey.patch_all() .. note:: Remember to monkey-patch before initializing your app Rationale --------- flask-peewee opens a connection-per-request. Flask stores things, like "per-request" information, in a special object called a `context local `_. Flask will ensure that this works even in a greened environment. Peewee does not automatically work in a "greened" environment, and stores connection state on the database instance in a local. Peewee can use a thread local instead, which ensures connections are not shared across threads. When using peewee with gevent, it is necessary to make this "threadlocal" a "greenlet local" by monkeypatching the thread module. flask-peewee-0.6.7/docs/fp-admin.jpg0000644000175000001440000013126012574421673020037 0ustar charlesusers00000000000000JFIFHHCreated with GIMPCCS"  q    T !1QRUVaAXq5#Suv"$%346EYt 7DHeg&'(8Cscfh G !1"AQ2aq#BRr3b$4SUVcd ?wd-n`15<| C1mՖe,烰TynWrb#2w5! lccͫZڕݬ՘)ΨIy 5v~nIVIֶ(Iq}lZˑVxeq[dV4ڦzll b}fǠlN2lIir]TiRo*t^ԢḂ"vH+b2bCj?a8eTUk> I+a38;C&PrJX^0ֵ1856$yaҫ+N_Gs[[0MrlWJ'-Yl< qma5`YbM]l#t{^PzjC>k#~l%_!MnG?j;$RTlR ژI{4\Mԩl+J}ۓm6jmYKJ֕)bn*L\ƹiYX벨l/DB^K#zgL?q8uRP)]nkcvwh9/eقLiܶ(8T,kϕ1V`쯑8J+0lEvn*O*,͔a0Vȴ^M*S@2Nn/x!cN#b]&?[0'&Aq8K,})$$2k'ɤ~NI{X qYW;v)rIU\6I,pn$n$C1'Fk6tӷJW6W>nw/ d:bE/#oYfW|yv4ս't`d6\ vQF V),uz$$$NxPn1;zi[#ɬ]L7إGc~U~\w(Gn̘,oK\2UL .it@'q+Gf8-RY+=al}X`w{Skٯc_ 6v-[Y^gu/%Y4득˜Dg͚0i8$Yѱ5Z-dbr`Hk.R+,)f2ձ},WڔUԮִ٥{[4O2ÜČxb|?a<+ #2o}'ۧb~|_.J3MG IޭOeȲĉn[24Y+/zhf8d5д寈c\Ț=4~nSp,o(-b2Ax\/eKӤɳ Uc (%HҷsmWb'[* ĶVklWՀ:VrOpByG63 {|opQ%y#p*ɵI>jZb!YN蛒1[1MjHvtr^<Ÿy`ǬPa,~X;c@;c|YҔ2R~?ʕ~sKN>%\صjaN~Fﳩ,e#b5#Y%=J3V{J5Lr(t: ¥*c~nT|"~{oRaus[ ³f-$=?S_5Ԛ*%kOUx-7/yhgJnsM]|oC~/{Xa/O-/1dﵬ9"SsqbFʈYoK}6⮴Yiw%2&'p-\bIMHێ"RU:ܫ*@sXq=kSUF}oi[^7l{EETNk@j+vLnEXX =wg?BY:꾝 SVAM+j\%MXa{@Q\3E;ZDA~]֧+P_CWyOd8-$rD_^uSg_ jKa^ m <ܿyd"x|;?jAl|u֧+P]a^ m <ܿyd"x| j}~?ZDA]|CWyO7/n_=47T֭{:Kv?t>;?j_Kcb]a^ m <ܿyd"x|֧+P_^J4iMkR٭VMխWb[[^kZֽ{ [o I@!Ǧ_^.߀>A%j{ [o I@!ǫS蕨/ˠOV.n_ m <ܿzz@:PUeLO=C^ͭmLmJV4v6i^im'CyO7/OtE>ֺNtc0OTcZ'{I[o I@!ų=Q}kfA>OGډ?|yd8-$rDlOTcZ']ƀ:A: (nQH!fٶXv]-ݵ[u6ҵ]ڭ+_cN m <ܿyd"x|֧+P_A;ZDA~]a^ m <ܿyd"x@At/v?֧cV.n_ m <ܿF&5POSc٨nQ?bk?/J{|>yd8-$r_/5?>*ӷܝ1ϸuDщ桿%=~aYLP%A"[sYfL,ʵ(\q(j-eֻ4@#4)+CH?KFQl7_fu-W 徲<;WԺ=7iNzQeWPfEEW`8Rd=}Ja^ m <ܿg(W[%Drt䤩%֦'iS},)iavZ}_Z_KlŹr2by/Kp ~q@B@NW 9z_0/[ËZ4+{cc'//[^-lO~r^-y/KV_}rao 9z_0'+/[^-y/Kp ~q@"rj +Z/IZҕ)s}6;Tj}+_bjdWmʪ ٹb4ʪ^څA[)uiJKk~+ZSgcNзWvWu-ZSgo0;MQ1j9<BkRJxU9 HT) }6QsR"ԧq.k ~@%hPY>Aq!7Uh;jY[LVT턥dY}/4Iìd?sΖtŪ [/"F'\"y ٚ|,EXc2xL\YxaV.4N{J#6V/m( v/o*uқ0f-1A ֲ^ 8cU~պkܦvv;;ͤ}Yi,v|G/hNw3\j.EU~2./]yIקTO_$ZNz;Z+ģY{y2ح'[#?Eݑ)4C*vgu ɖbEf9ř/`T)cY Ξ!K$Fy :)-vɗ#ck;6i9֦H W)ј۹)֣b&xԚ8!I:[C QK^; ƹ Bۢu["\v=Z֝SJF;ahu{]CjknoLjU^mJ*enmv+ZR? k\Ωnb},k+F1 1 f}Ɗ,Xj3p)Jv%4 V֡+QNܓ)S隲eJԩy)S!%t[ՔIѣ)KKHS'I ʶ-c ڔ^&Ttoӓ [F ;= ,j5to^m6ya# Xu96osaiK1ƋN2ܭV'bPg]JwƧqx'˙䱉"\Xֹ=RMqeJORpgP&sf_Eqa:χjWђnuZmRކYB*0.gR j'Y%]ͫhzRg4O$KTEM`(r<_ 1ޡq%/TI\[-g5Cw^շ.>U/ [u]fs5e9Q8Uv8P޸O mPf^6Ӽgµ{*b=Vi,;m$NrvӗqRv6nu-kM|U 0TѷUa i#>ǡj%E:A]dϠlN*dUĤdԖ݊[XňS6ə5`~ȹǪ5L%tx?TY̦M0d")Yl{٩t=Xf3$TǒoN^ Tʶo `bؤg"JnVtGXq5 õ`+FɇĎ%qE9#+fly̸U#vmD_d tjE;2j8鉡<Ӽ:M Ǚ"^V ōCJHhwErXq^%zL-e0{aub.OӪ+N$2g>[,w)oPFTV2Gp~JWc W`Sh#Iozl hS֜K'b"=;4fLc-v {zpu̽UoBچ֐ʒ+ ]HLç9jەƝfRI+XӂMv8)W&i$h/4{wΟENݎ.Pfe`k7*gJOuy=nT7sX׹lrr O_/v{AO~v>>)CA|]PPe6˪'t׬<ט"x^\$Hb\Q-!ɱJsCS8N嚿,Es[mt#ɤZ§<"' (z}^ b. MD,0뤁\\Uu5Z]&&֧ ;.]eCe z>JDFrA#_+=_]cPeʍI,g6fLI43JͨS*/0M-NfnRYu/۩ں>jd~5s"ަ3RH20d<,(I>Ga4k({&Y%-d3XB3[#sr&r'T_%&CK0-TkstMcoZ_I 'vӚjJڅsojр NI NH˷_ՈE˷_ՈB&9j=&ޠTLRbYф{*o"ݎBR ]ށU-ZMNaw c 9wF?sғV/^}]LorM&Tz2$/;*5om:ywī1e|^j.pfV[m}[݀s$4Ι8c@pDPB96_eIEl.Ƭ.,;Jry n K}$\Sz)*lzr 6YaTj\1[C6epJ$P9~OTH1H˷ie9W0덲*h6"媼3<@MrG&ַL6[GTjU͝Q9#I:r2q8`(U Q1tFOx~ NskF1J&bTC~1~xAFFRM,!ri1Id]&,VS@Z?&ɑFCG㊝_M\bŸ/RQOltܛ^, L_\K5"iU-l|Pč6vձhXW) e V#@Ŕzn"ȳ׸i]R7Uq(R7 F7+ih7feE3ߑb8q>oOO⹗+j^5 " Px;KFCnAt>.-ɤ*Ci3Z34~ }(g1MX:V i:R?Pʼpe]MpZ 'yݵFJےT6xQQ;å}$c9PUѨ.p~Pݪa]G@~6B$PvWu:ў)>-iYv:V7ߐGȖһ&Dk+L1Q}\*N䵶[hGOv M#JڝщSj@Kd1{J/n:8*,:^`rvܢ #kܭ2ggfmv)[n\Tt`т7%~szvjs ylXc,ۇprm@#4\(0Ԃӏ)+ څ5&lm7bjF~dVtMO:3Æin.c&tp+d:zs);4-9c"@ޝmPUf}.EGFEGF (r8+\1Z;F\P 9 @at珓Ckœʟk?#8^9U S i9\Ô{ZK1T;HE%'nG %c>7ExEڞ4hRShFEGFEGF!RpTi{goo{22 kڀy?&Zݓ69kLVJ[rjV;(S+w;s&R{+ iI^TCO݊Qly!sap|cUPdb7Io9zQ&H{H1JNbqh.m"H"H )FSK!V#jڴ@f\dfĶ?zkK,Dv;#sQ/ڗE[T CR>Ph}HCDQ}6ǜ嶭o!q&Wl3{RL}9@?G\ڢ?:g߉epxc"I݊BZnH崂nvJ27G.H*:07G.H*:0k(j;K*ef^Cf=EhOK.܅'u=);57'cHȢ)#t{*k 1UZDDY%reP?i۩oON9KSZ k1N{ _q%:1ARKJUָ,'Ӭu!?H-uwtr}"tr}"5X~>hgw5IC*oPQFм~赮Z`LJbg[%ZM&!&B2[;JTd9=w&VaIB~rCT Gc`G!1̻P؉2f\ߒVϳ[UMboo)IKdU+^d B"H"Ha[$ߞ$"ȈF TE9 lʊJ@l(?vk90I3L5rӞx'6eTr8IbK.=dY%5ERˌ ;\AcE&Rܬ ^p`yʒ(rDjȫd8>dVf K*rR13%US[d4N-RIgYaye9rD>Qс9rD>QтYJY dŖ)0<3$`P#[20+dsm?ujMS BY檫 LTM15SWbu⎅7z4 {;&lGzjb򬶖[m[m-m)J%tr}"tr}"p;F0 '9$TdpĥAsaynRۊxl7}\Tt`n\Tt`K98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C$C98;$C9ܢn*]m >ӧ٦kwb;n7"r2bqr2bw &kY7Gb)ޑGI2sr gBs]JB ieK(˭ :ư@ˑm4ZZȲ/ J$J%Js*[w;liȓ m@R3_qZ9ə^< %DKKؕUwO2ܳFĤ},HUZ8`~~FC h6 *W(ۤrt,/0!czxs+Ecj)MNmZPZTm lj1eږE0Iސ5bĭ$M HL8GoyN\d!,Y{ yomoho(BΝu}?Sf=󧦻tNBe7.YnQMCU}jI5ivl&]&fe1Q՛kdzl5l6 ,zVi^T;!ޙr:o=Bz*FTPYqgYmm&MRl6+a1JETz%OR%0(ĕm'~3mW؍ڢmU1tT)uMU뢲˴c -vX1eq2*]}c4*kVJ[K[Y|`}N ^v '˻UºdmHnW ?!!}{6U5QumQ(ЮrVemwC-FܙZUo.i6e].Co&z,A~#guGObp(B6+$-fP)pTlBQ)˺Y~BJM.݊JiQjSEom0ZK;FI?Y}-UTTy$p$SqHPt qHPt ÎePu7FIkh| 9#4H̢]!ċ깼ɬm_zfpԶ l-A2“#% $Jvjw2HZ-TSzH⥷qwIazn P4,ZJ Z`nk=VPYTk9pT|ļhm/T%hm/T%-3屗ȝJ26]k[2q.cGu_k ],ȈY&!:wV!k:Ny钖rVY !26WEdhȤ74ѥvrF19ʰʰ GCt`0Cwɤ^K:8ɤ^K:pY$-&fR؁EĜҔ'PQj}ĞYgZ VJo/4uYԫu`C+)!AAKkKjuQl!2:)H&󴳗bXW7S&)MY"Be\PbC@" Q8v"ZB{;=o^J-{U?L0BSlnoEc#.Osrd+X5s o6FK^LO-ɝ"y#2 R"27x.Cu:A4BWI P$GFR^/3itmztk{ZvSmz +Dfg}iuZ>-4i3-w6}lKjݙEcy`)>""|_+O܆D~j0Y?r $wov6Y4lˣp[ʱ;S(iD~`+[ DWUhoNL>)Lun1:qw ^-)Awљ¬^Q]q&V]=2nкFqDaw\IU1y?Lm>-jtkV)*`0*FANEꩳOz )JY[) R *t%SJ+,kUe.4qxq:$"Nב'ï^SC߇KUSc$D-jp5LU0q$ҥoq.r4Zd2)K)O~V>c=6bhR4+^=gq&?޼z'7}[`VIp*GN~=#J{YpvQmfk9s̬FyaњR]?/fT*O#Z`[J/h;+^݉ЖDݭpUTAk4v.$>N>?/lSȈU-qK)I@V-IY|ع!p8% âW:I`8^=g}W +uKYJCVE ^CN)*jUAW?UZaei}kn"+) ;ܤZGFţUdjaBjۉ5aޔfBR Sy LͭA6V5iݯ6_1y?LcǬ~Xcgݏf%I$vuSZUR/JP*$Fvv ~$׏Y0I`frHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy NyI`8^=gD4כ@4כA/Ęz<1y?LHNy 2vv-Oorf=kQLxOmA7l,*m(VqZRԯ=JK,li]In\L%X\an\L%X"qEʹa6LoK JnlxsJB8=HBV؝-t). ˤ#\hMlrFG$)WQݾ m9!2F>-V .֡%P̨fHFZOa7s|:U78 yFȃRLZjB+.* E)@ȝ#d-{7HlXTaՊ1+pedu`p:{ wjlFG "1 Dۈku-t^i7ǒ6[5UsD֓Nkvtj[kkRJjk~ EamvLTB8ʮ &9!j\0Wl\R@iuyt^C z}djWq j[\G/\i+QNͺg7-n*ގtkΡ, }*ҧUVXMjV+5q3&8Do{tE!Ed@-G.{.tukƠHWHB:ܨn'1on.K뎄]Jh=oUjQ+$mP6 uGҾi:ыqcUp 0R͓A[{ҿ?~*/cTm[4IQz-)%'J\ ^z*>T*N4n.P(bYr@m+8;O##>glTBJ*H*J%IPݪa]G@~6B$PvWu-Z|<R=ox߫i8.z2LA'8բctM&IHU)srҮN:;hjndW li"bizvDFD$GW+6cutvIeZK)y~_P%Vک`mԌbeŶ UhfQWY'3$MHACtz}`a4IJma<0!h TرȻk64J,@Rpcuc3dGZ&z,uT2VA`Hq${ZvR'`D񹃤18d ޖV+FѤpn 5UH$e@.Y[i6! d ]I]vI7[T#k6{_/?bpř 琢DO`MQA1d|j UEVG*ZƩRG[37+ [*H亖R9e A\` Qs˫2x71=$DDDDDDDDDDDj{;={mJ] k wzfHĕKS.68<0m ԧ2J8-+Nq̍Z^ZAu]{G*yNX8)DqJQ(n/FbSvZYl%_049m{ޕsN/w !8*1}~tYbz;c )՛[3 p\0ťqwBƵU㸝\ǩvr &I:7TqJxbG@j䮱Yj<5IwL3 ocX7Lհ7T=s>f3Bl ʭi_ ϬeyDS.mJ*ԋ=+l\nf. ev X`X+ ۄ'.s_Q;pOl hSWy8dׂsx:E#%Ϟ-ͫ :773Yk-̔ՉXkԮWeI:zp| ˹7 !Ou$ݏ5YI%.7&RuZyudEtK2lĵޘz:bn:ΙտvCԞQhTN+; Lި'n E0Sʥ /QiS\}OƐsl9l4~:VIsU$ktj_DkC *NJZj6rwڡ8J쵁 Zj 'a1\ms?J:4=X)Wy}#5/kMBB<5<䨬YX.liX$7Kyc*KW]T20#U2pp蝶YIʎ~\dzOpORX˷_ՈE˷B_Ո{aݪa]G@~6B$PvTWQ, Љ-+5gDZ,4bmٗgC[׭'.lMH#rd"JA4/-qNWi[,jB)yX,.l)reU x'OfTءHi&ac?^Q!KSjCÃLت2vd2E:&eYP#Ub~Ʋ6$W^s(䉙:@'G22&Llh6=Z̮ &<}3l$[bf}19`Xtф;P41q>g8܏0vcRhdDˋI$jZަ#tyK=VPPŠYʫ2{+*oeoՃR3f&+`I[\W[ y aS%Zю'6HCw R2" Q%" CJq lAEM Z !lRjzښbRYٯ[ɓc2[#ּ(ǧ $Ѩm#1O6W.R(Hv #CВL XWpqY!}Mklp7U*9EF3 'L@* Cme' _N5HN&\y6_yڮ_3r~^|ܶ3C$R$of-KMXLƼNDZi!bSFh,%^J|#`r̫]UUYz$fSV/E}chw4lAw.qe?Dr. P^CAB qqe߰\9W:llF(1ld˯gy}j:y,>zg9Bl-{C4zG\$2[!]Sq 8ol|;Xn.֎#u¨z !-_rxœN,Q d]%jI- E/kZr8Qin2d[J[L #[s8(dP_40&T74lq|&us\ҤSg>>gYD4@_r:jceOnŗnȟ1t^Lm/҄bXٜGL΁e]VX2`t|ݏڙK~4^tsfEm|TwbElbsglCnCsz脜ƲUV쥵_#Bc[yn9kb2M0Ն$zXH&g +jk8L<*8I08fNF=&xup'f&f#/zʼn1)IBJbIK/X3hyvgZr8T^ǭv{5 (š59IUۙY.4~У._Ë(8(G ="lNDG ="l8BH[ BH[.4~У._H>.4~У\\?d,* .K,iaem---RmR[JlR)"Pycԍ*cLcnr彛 D#6."Zc6{4V68ڸlUj(mVyfReiN]* ɾtc{Űry6UuVBcnU(:^U/c?Sz#Vqy9(6!%02[cqTy*xLLv'0Qo&)s6C{aә5z+~'˺G\L>@UVi'QND۬N{Ye76i.H*T5JMca x_7|<i ןpٷ,e=/x[LUܗ;TjA%#!.\fFJG'o*Nf <,Z`b2FkKI;T,S\QoqF!2H凣H\+aQSJXPC8;l;d$g@`PI$)Qb`daYj; b ]/X'@"r]lG IbviVȚl!*Re8ֻl/"d8C x'xɸ\e{`1G3.M*hܮ&S'SRq9W180//7m+оx) Lx23Ǥlӝo3sJwlw5,a8\BM&#Sd'dxMT[ 0U7> i wŞm)SYw2'*C#Y rC2Ӗ!cTj% XX֎1UB6Wi)jɂ1pr1ՃJgث+b9a<%gj0,yuV'h3꦳]EȕK +9ԅ1bX[@^Aq63H@Ǣǡe#]dM#krVXѝ:DFAiH2UwcJ*ca.Ifa.G\Y" c-Ei 1e8|_dv9\3n&ꌷ)(WZh`ɊǷGggFȊcl`9KHKN8?Jcz/w)1b!cmUj⬫n80Sˀ`bk,[1 ;]#d /p統t%RW h|`vG ]c%-9*?\xnYAÞw&y}ircOH"a e6"B_*ؼ7)LTR)2ȴC1+ceVcQ[#G AD'#b(ffvf01{^3<ij|)+jn#|b/J#aci'^YrMWVǧI,U_]Dc۱2y{`&5w4(rSu5;#[52j^ڋ\<_DK=xkVp@u>eW vH wuX #^H1Y< G1@ȹn0/tqiu,Z95p#n%ܬKdrָx)7|7;eLi1SM'QU#lk8nꋻLYxbUI'0ZQ1oCqm|b;Ob[cmҝ?˯cYvBr,oO!|MH8 VtP=N1\H!A'i`]va[9='i`,Bɫ6:NPĶ{"D \jm1'5$=*ylQhlK%Ä!qhIMS,:vJQiQ,F7)Nf~zȊƹv@C8qKW X*|6H=DP P 12FN>[;%VT9j;|'d::K ʙ ERY vb PlA镭# , "3,ӥ8-dW(ZH)n.$Y+V.q/jŮM*my !Tf>[R8ֱN>fbgiHpyQ MC9|p1"Sx܆j瑲X׶$㊕D*mWiIWU*XTFusl5vJbg7+8H_ -1܆vY| ѹ٢Y *h1ȱv;VHQA`rBPO8jv8 <)'BqwUFK{+cø1xf9D$,-YUiFȠ4 -uOnC@<1M HF]0Ǧm76iǖ!LSL>B{j桍>)|zPĖxt5jSpWqؠc˱8Ssf|Ge/$fKT/]#\rj~O'j`p͍IRxj1#ɧ+p=C#ME+{`MqK؜H(>O%mNY Sb@`k倬69]ʯp6Y"#jFp?jbgzGiM*#%Bi %32bGbX ERobxfM([CNju+o'ud~t*8evvl-.7,i.\''|Yꔣ}JNuO;͛3DH`$] y, y2 XEŰ;aiE/H]b `'^,Ԃl7 @%l#Rgڧ,Ŭg[fe.L"u-1yjw;mo%njH$C)_*@lR\rrK.H fDny!A!5 E\_t!KNEU5#k̫sCzdC4OV^`i8O&;&uLbCefKkFDkLɘ Th(!:fwI6*l@|K-t6Q09K(͙bRY |q/CkMdL8Ș?=X%ȭ&\<5BFkQp%^eBS-.B;89p8,v*LVaOqCU G T^tK|}<ҚblUM34?Ek2MS:''jLmc;¹DJ2 pﭬ-h^WXk)r\lϾ\,jNK397a;qjA-•+%n4!xfqrk] *9Lޱ=scLPHխmf>+IG- leQ)6~l$sm "U{00% {e^sGl_V>cf 8tp|T 3ET^71"@W3C &kM Rqҗ X :#SQWDp pX]#0 bӿDesHYv%DbWTd[_A|S(+D ,DDDDDDDDDDDDDDDDDDDD|G$ӣRVSDh]^IgJ/!AD$R<,e.*U&*F=GYԨ:ڎ-jzԞܘ 7wě-k}ŷSe%ZU"))qW$ۭؤ,N2qqѩ>08xρ|GWgţ*L<3Sa)4y2^m"Ze]um裞CSbR%3zK%)zÔV .lVBgSm(y*Pi\a]u;oF;oF0A}x>ϼH3#PjuPwG ,>8n y]9k#: 8dykqf95eTKRVV5lKxISrEYw+g$[ԃ &^Q(˭Km!.3z5'!.3z5'9?'ȌPڵtfn֜BǖܚˎTrVժ8PmoK(d%F[W0F`ꪥs2t:+cqˏP%mllmFU o\Z!8qѩ>8qѩ>68A +jCtm19>5[x4Ĝ \vLC$-UY-ilq֫]Kn#!) lF榆cQuKFvJloLZU)5+Sq!.3z5'!.3z5'   {F׉-׊$9p+nKI(Q:H=mWnV M ̆LnA o?D.Vf+q,]<M^i/GR7!.3z5'!.3z5' dx>3e=??T`a+"a0gISģ$Hak%եJY:ƚITy^rd2NUr#+d9\}AtmISԻԝݘrTDΔP@xԟt@xԟtF118==>gy|QIiN"scRhԇߏ~uBr%J__V,ZrՊO6>)Tk mLkv L[Bs\ Orjx$fү6!s(m)]:/!.3z5'!.3z5' ||9 O&?~Y$&\Q$LiS'LnĤY)ˮm m*L뮺Vp'MJ셁91RcDQ?$g$VؕM%:+H%ȣL-m}R.;%nQ:j"+%1TЂXR.lBέ7Co0L ??~_~e?nV|V7zuu[{]ұN*nKS({-*-iZQH|]3֭LvUlVȑSVrVe4رR̵*|?)0>Y$_VVUHD SWĨPڑ(m'CywPƦWyk4F8]*{#brKՎ!BS v^|QZ3}(8P1~>cT 9vI/EȒrHָ’Д*Lڊ'GDБ"}/䥀zlQnlsLˋ=$isVpPUFfq~@/眒Ny?kfEN4 ~-z6RH[ePV"U̯ fv=c:I*;n=KB3ZE#X[ YDTR] ()aѶ˵K-*x'9Ĉ>1x,>I :Tf#wS',I%Yv[eH[q&DBSGÓdiȈh*EEKI)c.Kx@09БOɏc },,,--,[eJRm-R)JR,`5ZB䩖iUZB PUP%j%4,oZ:ħRQ*N(W -)Kq!XL-j FJڝ[ZˏmRM,9Pu&99?HumJ¢UzMJٶ+3xZo-kZi½ulVZr™E?34izT3BX9){UpaVrV3kNUmR c|{0 br' ϓ)18THHSKlqKY#} RKL}nr Se)4s*"T46 LqNjוU$ZȳmjM6K0>6."LQS01gdJQ,(d٭>Ҝ&IIaYPQG֚ZqEB(avItllǫR؁JPT8:;ݾ Qv{ztv^e0SI$0>]E2 02\d ]YLcM5Qҩ[b{Z}*UmB?&Y?e1h*;L>k77oP"\A.r3cލYJ:'&,R,4.*e18Y?pgl>0x꫏\DY?e1W(~x꫏gl>0Je18Y?pgl>80G-`YRc]mJ-j5>ڔTRYuId[kˍf>c n[bnx\y)*5QҤR *m)k} X\yﰒ`jfj.ļjb͟#ݑX"Բܭ)Q7i^ܖ,R 2Jh;$͏6.Dz<.Lܗ‘˨\V7E^N\%9 sGy!֩*}+r8jm]fcQ,R #He9 H4g]# A f i-/hXY i14Nn - X1TcIyAҴ3;beL8B&{+lCWUteG+l" 4\m<44ٺym[4uh&? &1f'tnɤnעגn'55M&]a'K,MIR ͂@*<3+ǔjP=„P/fv[bN}D{g@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@EuGt˥nj2OX_c+me#'iq*E&j$+]%MfkS(2.nP@ddFTFsIJؽRk,D_uQ<cbcMnítLsP^KӸ`9%)yJm)ͭzTD&hӔ\OGx*%jr:FGAfYG`9x[/xMcكI兆R|^U&4_S#6[FvJ/G GG#u~y@AA3n >ApD@@@@@@ #T"E*&$N2t5c$Y3VO#&9m;kDRo@uH#5v4 {Kr +密^c*(̑Zͺ%&y)} pAV C{^ޯ>S=<1B$ ar&Lŵ:;^RQ5W$)B'ki ^EX^Nk_ &®RT5Aqm^s9 ^Ԏd*EW4L=J¤muOSLp.}N]Mǿ{ߺq21#s29񌲌qg|?p} `                           '͚lҝc>-^fS:OZd[;+[sM".%A$8eYy[n^6>y[%N3p73  1O '$ˀ^6>y[n^6>y[ؒˀ^6>y[n^6>y[D-cE cE K^6>y[n^6>y[D-cE cE K^6>y[n^6>y[Dv{?ɱci_P׍i6׍i60z{ԮfG_6z^)"S;IY*B(ՕzE0JaTf/7Ĥ5ueK' M#cŕz?ԿӤR6 =e!,E MCORלE#K v4ٍRdzpv<6_<-l7<-ld(U ZP6UUdEP0F# Eb]?e%%]͎ra8z-.MMNOYsGi~xeKKʞwv]2'iHKEF{:X0NĹf.en "}.,DehM, Ȯ"(duGsRLBO+=xoa=xob 8* pTj8kf@)03XaŜXŏY;r͖9,o<-l7<-lYeo<-l7<-l"\pz"߆pz"߆%o<-l7<-l"\pz"߆pz"߆%o<-l7_<-l"\pz"߆qz"߆%o_<-l7<-l"\qz"߆pz"߆%o_<-l7<-l"\pz"߆pz"߆%o<-l7<-l"\pz"߆pz"߆%o<-l7<-l"\pz"߆pz"߆%o<-l7<-l"\pz"߆pz"߆%o<-l7<-l"\ =xobc]EnJ̩6⌲ͥܭje+JJUlZn]MDDDDDDDDDDvwTÖi3FsL6m]$ǓъzWR C}ٮ;m[8K:y+.K]X<9c튘c/y;+'VHSsCs1Xɩ%d6UePk!\a/[Q4MK J)JSBeVb9]e*k5-<ƆEYZKʚU랥y5ޱ2Qծb e)!W_W}`Ril;HV=3Lj;/ݧa2s <\ՎDRe-:";ff)DTfkrlQb%M]<'4>%jtmmHpMz5ħrHRJ\͓,JkiVk+jXtۅcRVt̡T>ZJw35 k)umAc3Z ijoME[ouk]ֵ5{uv;uu_Nj>νj!7j^0TTܵe֕6EitRn:[m.1YkQVm}_`H [K۹m}H [K۹m}H [K۹m}H [K۹m}H [K۹m}H [K۹m}HZi^Mvاl7vsk &+1,:6=cZ[yHIj$'oK$NuI xēe1)B+hv|~i35IBt幡 'YiDsd,w5$Bc.HORʭmm}/ ZYS߼w1*w ؊FV~0i{w6bii{w6_ͯ"ii{w6_ͯ"ii{w6_ͯ"ii{w6_ͯ"ii{w6_ͯ"i}CYŞ82?H4b;AbMdtvNFSTԐy [0X[K;*6sk[ے zUNܬkBrBTʜRU69wR[И}^=Ktz]m~351wc`m aEv6H.FUiZj@kBe al+x!/,zeFk[AOMepXuɕD*Up5}hW=\5Vih5ڹ7dH5M+s™kCF 񅾪w#Mv)u!jkx{6ѾVugK]*ڃzNMԷ % s/!9)I%7LjdȊ:u *$K(-mKy^Oc9jQԋu P,+Cb7ܯowJ֕5j>GW\l >ŷh+,',-9U7q}U"F02EαצSNNs)%2")TKէɯ=I`3Jyd|# VJc5#+{fy3\>Q%Ũ7\Psb.)5L5ہ\QdyXrѶrGmHU6b/Ǔ:[}]u+4Ni\廂\ۗ%[z\RjQ)N)HPEەRیkM8ރ~ѩ6uRT:؆jΙa5bo>}rr_@MөҾ׶@T@'t& fcZ)S(ҷV8-65%l.&uKw?dD4Ʋv7-!ڍmXB#D|lTD3bṚn雱TNjгQKsj*BީTi;"yˈimMVܑΟ~K2BYE[,UaeSi= Gp)h.%HmeHwFƲYn'IE+>@2JM4 ~]ϫzUmW^Ogj6K#j CǦ}bIPZYF*ЮK_KYpwޕ aißdi}aQÚ$&\p?OI]mlFЍ̤ka,H.ӍHq1e8kq-M^yh_{C Jcku̥-X[J֩[VeCͥ[K۹5.Aekҭڵ.b\`k4T]:H{Y-]UWMuVeB;Pn,ci{w6ҝi{w6i{w6i{w6i{w6i{w6i{w6i{w6N57YOZ]]+B٥i'Jӵm)I0%#]BuJĤ)[}޶nߴKv]֛;;Z㵯aCj٧'Xu*x&#=>lЉ$d39[zDh/pЯ.+rQtORt[бEd[pff!+`*j`Ysun/L5CE^FEVlS5ڀ.66c~n C_wۦk|Cwe:)e!H3(4Z%%/cqJ!¦d*(ӋŤCJYP s9g?0r`bF|9G'PZw SF;sb;MUbV?kt6tuZ{Z[]zVjޚ۶BeK+cҾN3hV֋uTU ?Xiژ 3Pk-Gvvxhv?qn;_E4ßA!x/qn;_E4q2-eZ@!x/qn;_E4q2-eZ@!x/qn;_E4q2-eZ@!x/qn;_E4q2-\p/v{?vu>>nO?+MCqr9aeև#q~*!{+H>tr\up6d9R!Z}2iPaG2{xeդ)Jv=j"> }JǑ C}ٰ~$g88ܤ Ÿ}q2- Y Ÿ}q2- [h~8/ Ÿ}q2- [h~8/ Ÿ}q2- [h~|wM-kbʉzA$>3F15w7mN\ o 4֒YU!kj 2&v_AQmNF3ZtXeB*ʮFΟPնEծQzPP}̨֣Q3S.&U6 6S,,ی/q[auu)K([ZԻ:kTvץ8ѕOp[Zc9ۼm=:L"xZקg=yݽ-.Y9%$q/G6V$r"N d մt['f3l1a\ޭ4 ӯ΃Wz tAuO[eoKТVeC|飼G\:#M^2-zK-apʿpWzEr;_/?`WŸ_EJݞw G35I`2 #-8IrRSqMw2.1j[U2HAS0mLْq#evNaXz`DIcL{oq[:.N7b'j&iNGym54H[Tq1v(VH{)aѾZEhn鱆=CpYbMZs^F֖aYki{EFK'(s#qҟ^ׂ>>7 /ǿ]CI5,H&"$K E-N!h!lm[R7Mqz./*/y>fAY]VZ+Ztmc6U]VSlVtb}O֝~5GM{5 *U(1 [h~8/ӝ Ÿ}q2- [h~8/ Ÿ}q2- [h~8/ Ÿ}q2- [h~8/ Ÿ}q2- [h~s Bˋ@""oyiإ{&-)nڴv)JlRzN|9c?G] χ>g9Ռt'>#ßV3xuМs~}XBsϫ<":N|9c?G] χ>g9Ռt'>#ßV3xuМs~}XBsϫ<":N|9c?G] χ>g9Ռs>d?:N|9c?G\χ>g}XBsϫ<":N|9c?G] χ>g9Ռt'>#ßV3xuМs~}XBsϫ<":N|9c?G] χ>g9Ռt'>#ßV3xuМs~}X>sϫ<"|9٧-ų_>sϫ<":N|9c?G] χ>g9Ռt'>#ßV3xuМs~}XBsϫ<":N|9c?G] χ>g9Ռt'>#ßV3xuϜs~+=~ßV3xHG] χ>gL666P-wFZye\eYun]awml-Vod,9Ռs>Oq'κ>*}9Ռ<G] χ>g9Ռ] χ>g9Ռt'>îßV3xDuМs~}XBsϫ<:N|9c?GG] χ>g9Ռt'>îßV3xDuМs~}XBsϫ<:N|9c?GG] χ>gflask-peewee-0.6.7/docs/fp-admin-btn.png0000644000175000001440000005622612574421673020634 0ustar charlesusers00000000000000PNG  IHDRk>m IDATx^xOz@ EDT@RDDX>EQPT **{͙ass;C9 (@@@@@@LE bTc@@@@@@@XCCX3a$XC(%4̤ll?)22TB+ J     `@)v)(88p8|JOO';@@@@@lGXKMM<]AP UZ\     E%ڑ#Gf͚XQ"py-99ԩ' -Yk{DV!@TjGA@@@@55 5U?XxWBB`ĚC <X3Y`eds@@@@@O +k&s@@@@@d LV!XY3Y5?ʚ05UVLV!0@@@@D#b={ҕW^Y;-\^{5?snذ{>|8͞=6mDԾ}{4hUZ^z%իm۶L{R-ڝF=E okL75iOkNNh]+S!MzUpE9GqQ!Hi[?|#}z5J_l?U<Q9<,YU-L?фV -T-$K%M˥m&-y"Ox1GwA4n8*6̙34~x:p-XMO>$ 6}KK.2㯿vM>,۷ON&L(QkE5#C(%31Ě1Kg}{=<ԮL7@y b:?;QL (6Y,dM>0թB#:,`:]P\Pki\xM|Db<<yTyXcVR%޽{=/4ꫯ,/vAsΕ+g!33JĢuԴiSu)v(=.v߆H]`eJy2\qꃊQ )ճNw3<JsY=k{-yIʤgWbuM MflI֣G9Hۇ. vS֦+U*a#S_0DIJ= wyGjՊFA[QXXHՓ-Zp{mΝ4gڿLԹsgy_zz:tah֬Ylq>jժE7xc%0zhymѢEL4O=%q2kʓ@zʧfN>dbk0t@d}-ß)?eѐ*Rc1,)Տ Y-ti(u*fx|; kQp3.;jC} I_i$V65' 螅{ۯ975jA7KC>Xn]ȑ#rÝw)N׮]p7on3K;vO>̙3cyszlq<AŗxNn| V zsw7NیƄю9\8k |iֆbM#@#:҄i\܉s(epԢz8}m?-㇋%"v5荿DG۟8z4E,st$#Afl=XH\~)Yja2:?UtC@wcr&ͺ`j4HX$9IӺ+}okVb# qA@@@_g4硫ygC)ְ z3 c~G~9$[C{T4Zk#[uHR[]S4V, j ƝtXd;=vqL@SɛPo,kZÝv+H Yp`7/2w?'ם^G2vhXb;+O|"ʵ2QrUR |NX7^Ik&JQ߽-jZxsR\;8-)#|=0*\+=K[o\SH[Ott׻ix 31{q2$P)D\*-Ś54|E9\yU7+glmwL PC(`bo+v WMv7+'N7Js#DUFfHGx=n kG@@@)WpavbCtp /y/YyneH+j7{|A\Il=Qh5Қ۾MgP,unՍV<^yfע]ZZxTqǎK111R0)+kbEK+VKwBupvOalҤ lْ"իg,)%%Ex)آ=x`}y+W.e6Lv7?,O4+xem+Xaӕ e'k@s'E_)~f!uͱ}$Xcխ[=k˗//>aM^|Ŵfyȧ~*к.,>_-dXJyJ%ָtkZ8V!Cxzx-Ѕ^(WPi;ޯ{^ymbU .J=aQ+D| ƻkSŚ5wG= 2jRsg8X rxbQz8+2^{pG3+{V],:@f1\A4So nݪF pWЉ/97K'TP?Cyg];[C?mqv@l)Q#SZY-bO̪x__-̼5#m< mb|0rqP5rdڵiȑ_ >ޣR@@\!袋^[zuԣG)ؔ34Ȥ$y )Z8V6{8Gʏbo۶MakPS\$#੩twnknfyĊm5ψ.1ʍ)YrߕL@@@@@@5c@@@@@|Bb' #fbO@32c ֌Bl 5`F&      `Ě1^      >!WVXP@'Nٶ'.K& .޷P@P$222ĉ#ؓ@TTRDDrgR@VV!p9իW@˗(?Bz$qK tD $pib4uoKMA7ys7v67AիTJX);-RϜoNѱcǨApͼeF 6o>U;Ҟ={(..Vjve񙒒BlF d睥oMQ9W-*\LmVl r?E٧hר(uhgnijJ{pMu#SHXfO@#);;z5LSojP<s&54񇩚AgOL+SBT~mRU[RN,SZ>k֬-Z'΂]-PYA@YazLZ cC(<;>خxly7L~kbڞ{ZW)q< R]Xqsvb;}~{ٯ[6mZ{/7   `6~a%UŊ* [Nj ~9M3MЏj8m#}Ě+˶kڵrK~kÏA@Xr ,F 8_Zu9}-+֚|2bb'u%ڶmlLֆ  LU#0@|K@g!|K&X{Xs&w!ZZᱬlj6oĚjskmڴ\&&Kiƍk& $ 3kdnXTZu9ڶ~QM d!֚ĚmFq%Znm<1ܱi&5obi!* 2+(eQlc*1 ,A%?VD'gm޼bp )ƖMT;z%EzJNl> /:Zi,ʿOȮT9.{ʓw Vbbȼ4I'5Ag?n8}Oϙ&6чj[ 2Y|k-/LfTMMXkٲW@]y啴b iK=t-[ nb2\xJlᲯ.p&>k/e\+}qsVys_@}?KQw{ʓw vkkFM<Zj78dddiϗDW ٓ{C{z7ކOE5ba?#>T| qE#GERe_Rɠ4h1yM\}КHqPY[ˋ5U7C-Z_JK.l2s%^"֔SiI?OC\)3.OѪWPW'Z%AV;\1RUB]׸VkkIe0l(΅K9A5DUGV(Dei@$/O#':)I-*[h,Kw&QsZp:µ17CO^.3;~F4D)\K|WVf+kK5&e.^FP8O>xb=V)UW]E{==gX[wk/Cbwi{a?֪ ]7&RpXŎO>M;Щuki+/Qy3}֝"X2Lzw}YywĈqoRRR}4eʔbFGa}Ν4gڿLԹsgYWMSN%~_\ IDAT=TҹKFZ|9]}% ost,+ּys37BQQQ4tP޽۸^{59Pu;vXzwe{BCCi„ F=rٔ}QOرc%1z۶mkz@!ؔkk/Ȫ5EGiļ8=RspR'2{ Mߞ8MMYIqk]O6&K{s*Q3Nbv5ѧI?3m>A#gi5eеͪүNfCmQӊW5'foUϤNf֒eQtj% :r`JbF3kYvmiʕ+iϞ=4dDEƥu%֚5k=Cw]~d)yĉe]u]4i$9E7,Eիiܹ2 ҸqhҥŅX[8^o HkQeNC;Rril-H ‹ى>;F~u^TT˥ߊ-Fw}hB1ԉG&;7:Шki?xzW=jX#i595E-+ulQӊ7G%Zz0xnn[6i^Ѵ/3XBSԥ"%ǂ1C嚞i pR2I!ڤbMI=amѣr"yW^԰aCZh۷O{8tڕFM{sӧ93Wѥ^J/\6SOIƁ.GIs+W@2>u<7Hx  `?R1&z&dc74}W {;EՉvȥ D39qZ"vshvauu~T&̤;Ɣy~=ܑLэb-iFJg )6:VMC^QlVϵ&/o̼r*itᤝtt>5B{Ʒ-q:quz~v7Q|FbLWKg6X;obe; *yϳ &ϽnO%yb}<_R^|\Moob_hdeek%<O$& O-q>-v;$v1 71%ܫL `vp,Xc!>FŁ}rNtVzz|w^'ekQ;%Uk\USXkMy~Kv_w۟~I ]"ł);41OXcw[5h  `CR2 riztS'!,\sz{Ğ)(ljʥ` *̧7/1k,kt6%uµmL_ nD4y"ZUWFɞԞBο/1ۢ/wr +~Qp_ޛ)rj Pʣ)W:]=?˛l5j,*-ΛXl<= ٳg]<8ݺu+`lϳgi":>3'5ykݧw*9B0ŞSz _hy+PɡaiC.if[Ld_} 8v/ڗ&\:!#i-6i*i豁㤈eЋLb>q#q &qcByΙI>)מ}Y'5_+kTNE jWCrk ru> R+"ZyQ)KDg3k꟝ݧdkzH!ؓk#S+-#DƒhtjT8ŏP4Z칕57<Q G(1&~JHiWMᕪ# 3Ezp\#X)[kl[|||5vdH\F+}'O,6:'񉔊5g̘!W*y?.W5a<bM){bAb.!X&.-wn5)"=k8My?Ԏ׍>n"y64G=>0y\ z5Պ4:hl݅ki۞#tu螮-ϹA ;MOAz_ژۑڼU;#% F @tGSOya].;9)H48/-fZ;iŚy3|Q#=jwoS=^zCo['g+"spusjT')L~k+oN*WRqY𬙔0kѩwQ-Z e}9JTAb/OGR厝([2o‹-NNqi_"V.25^UN$F)lq$[nsPD-'" Qq|?7Plz/, 9ݴii|:KJ%&ub?Wxŕ/&V~Sć+ f&.W5abM){bmk '-]:a+S%"V>ќ>wG8{WZ4t:?/.JOc7.+ᒆQ4Ԫvt;s}37tmhq,K[0"lQӊWUmH[h)4g;%Dٶ E,rJq6u#Ɍi ǜ\l$ou3]=SwJ5&ks)pKn{i,l^ ]A[^g]|8/,/|ks&?oJ5 5] vekFwЌm\WbOx)^qNoXp+~|?px|oe1s:{"!B')ֆkF'}?nuDgvIZe慢0`6X;ozE:rѮkv\ @tbmŚX.-:oobkXlĚrJfVBٵrQ.A@BE?`DGrRd AifyL~k+z@sMRȏM|Xut%1:uR1`k98k|z7-ɓ vor<   ( 0!bimܖ:oƜobmϤt|BFLo:ָ%>XI+O?pĕCRn3mیmќ:]DnKBhu5I **bccK5.ҞY>|N:%?2nEV"۽A@Pu9{hôfQ}7#V#ЩQumS.BK̝8o/bM=U>HgV̓Tvst&n;>eJ{K^/)5j!ؖ5gXSIi|H+ fsؤe#N4宭@7{ >-;>|Kna䮼ey@@@@@@ ^(% @Y`4 @ٽQ>KXdhX{ |     $fj     v'fF@@@@@,Ib͒A@@@@Nb5XĚ% F؝Ěk$5KV;50     `Ik6      `wkva@@@@@ ,Ym0@@@@@ ^(% @Y`4 @ٽQ>KXdhX{ |     $fj     v'[8q) LP>;kyyyTZR5++rrr(44F;\ mƺɓ,aM^_LLSUbeM1233Srg H ;k5%f@2 ֌C|5@F      `ĚQb     > @@@@@X3J A@@@@@ |YQkF!>Ě # 0Jb(1Xdd     F @%      k>,@@@@@@(5@@@@@|@b%f@2 ֌C|Rb-//N8A999TPPT,AAAFիW/!X%''UT7[5ٳj%cKT0& NYktJKKxXKII!N:+yykD`ܴW}4#>j:BxٳWb-)))** ҴUg@E㦽QթJċeGk%8z@g~ #{iDiG}~ujj{%V@T6206k.i֚] PD}-_ Eb@qh ^!q+X(xP"! Ct0g  &qM}cg \~*4?G %qӲU+ R&,&Ě +&a@z ~_k@5 =Gbs,9@@x!6#?ڂ `@8R$ `s7m^( Z -[5Vy ǀf޺e $qӜ@ @ypL X(2@`,> ^'>u5`^]#>ѩ8e&`d@Ķg~?LLJw4FO\R*/TzM9Px$.i֍ (&}Ξ=IDD ΆW^VV&Ѽ Ζ1ePNwFx:=w:@ wt#JXn q1gy6'SO$&U1xTP[j]xE%(UVڷPt5l2i҃.9:QAPR4rZ+BV饫Ppᠤ}st<+V̪Y5=LgӑRJ!N?[HOv>xƒip4:yQt咾Mhd]-n9jo֍qt4#jO@2mLx zqjNz%RldJqX]yk%am={Rs聟Ъ#g(Uu 4ufXGݻWbbJI4… _~~kfnrh}h_Z.u_.a7d)„`1•uJl$WJX}$l;EKI ~ /㜉5wcjkz( x\ZpsW 6?`zZ+A.w«_[S&qS4}tZjeu貏9SXlZFL@ora9 x\k˖-3XSDX,O.|yOs>YB4}.$rR S I#H+gNVow?)wtS͉p␑g"k|/&_O݅ˣޑ*N/Ҵ6DFb40}lvX۶mB斢+n|+hРA~}`}@^0nګ>Q@_ZDk;v 6P֭)<<>OKKo/ټ9؋M{'Jc?SȣbOZh,̜X۷S1 hlާ g@E㦽QթUJQƅfTxMoCg6aqW[@@lF=ʊK}ֽKq_3D ͊U(Zb1Ě]jDfʀ)  q#+0 \~.:Ě+c@cL $qӛt6h"X+7ܥA#q/_@5qXC[8 hGAlN+ų<QWe f٪3[7 @0n^`[!65ocQ+E(‡AG q< ؜MW0gy裖B@Xl a8X@bbb) EPʊ.>>ޢ+iClSVf`Y `4k.(">/ Eߦb@iŢX ^#qkh0xG0"2X+4ܢMZ#q/_@5qXC[8 hGAlN+ų<QWe f٪3[7 @0n^`W7r~jZ ֬U_KT0& NYĚ8_ h6\ @+0nz+@J$dĚA`4@0n= ~lĚkOeÀ'@0nZ`x!>ZA*ڄńX3aX$ hVA k7}M1ffUCbM%1D!\  qM}Ԍ6iĚ5Vc0u8iJI "`>jFhT6l={>C CYh=쳴jժb!uMmV.уj׮M,,X@֭Yp端JԷo_){裏>2?L\s uM޷xb?iĉ裏J>ʋD_|nj4Sz(T9{NJpYN-:M.>HPO`[wlĚ*Wo@VHB:^DFZU9mrx7"MwtXr-d)Xh4nXF9|0QҐ!ChرĂQh]S秕G>}믿.ζ|ʹtREw'eWtE 0 H~/Lv˖-Rd2OgbmӦM4oj[/_.ݰaC۷wZS:udhQ|衇djΜ9ҭK$$$g}&twH֭Ku駟:Gv˱fر,TTٺ8㦺<w}˱W&n.\(oYztt6j]S秕 7 +#""-'O޽{ӊ+֌4[{ݣbO.Rpl;{vBNogk7g0>vXR4!4S k}d 6]u!dٸ X8S⭆X޾辥K rd+oUx9 W^ytݩu.eՏNhYyW(..N"]tԂGbMmoX馛tFlem>|棎PxOX0c : < ٳg\l+nJFi=={,ԠAoYtlw[u^zQe{}C,@<[JNN7T%KcwZyKέJqN1+ybG 8/5Ogar_9\RR1MW,6G@oճg{{ vT32}Q⾤ZRLxP(֔;?8'O]5~md&uw n^R8eM'|nF,vGq6^M0>,R&8k8PN.w۶mU`V,4նp;믿'J(^U~E]$-۵ p. W<VlzM/I~/P)ִt~x'r;t6s_0>Nպ{ʕy8*{6mXs^߳gOC8N1-p:ӧO/f[t*v0WQwKn tv2)GR2|ݴuPRsUFMkYQg|?8X"BCCD箻 )pY$K΢)R)'͍Pkur wl|ޱӺ:G+_@#S]5~+Ǚp}ǎsN:r&ĚV:+b˂=tQ\]_U -R"P2_;x5W }or7vg*Z}O57{x^XcNe9^2*xeJ`Oq|9[n.*78{Ɣ%! zĚyA:06lL.<8uzqZq_Cb'fO.j~!% 8hCϫQ0]ZKB2c 5U;yZddeʔ)RR.믿.^΋'zX}`l>emrSWv[kZqjic(޿کS'9"=kjQŜ'W7n'|HnY< ZȆ O-VXG<5gGXvN䞵TZޯ{2hsO+kȾ9x\1*vrxe].־G#2 A",&NA$N (Tqog79)BJ^Q 3 +zXSN!=}%]ȈXcYl)I5vd{HؽQtN§x.ՓnF oi1A^ XӊhV\JHbpul?#c}L#l.y]j $)vְV@I7"@GhkњyT5~Ǿ漹1.vG@>u0>cPDWQٽWz `U7Zs0c5M=kFn?g ?ӝаO9`"> `4s6 2c5Mh+'Q 3g4=(Zg|1ϧMEi#{iDiG}~ujyTqY^gb]Xi@mpl& }@nl[jNy<.^tt6{1rO~GWV)ĚUjBvb@PeTSij (@ŀfE@BW"QQDB @ `@s1@@@M&k{8 J@gI週#{iDiG}~ujR_9"?fariڈ*c3F "q^؏*%JJJk5uVVZ\.Dg~#{iDiG}~ujYff&HGPbe-//?N!!!ruj@g~́#{iDiG}~ujHoSgddPjj*;^%FlN?xm. 5j\$+%֬R8      v&fE@@@@@,KbͲUA@@@@LbεXĚeؙĚke,5V 3JgWv=rIENDB`flask-peewee-0.6.7/docs/fp-note-admin-2.jpg0000644000175000001440000004255712574421673021153 0ustar charlesusers00000000000000JFIFHHCreated with GIMPC  !"$"$C*" U  !1ST"#4AQUa2Rqr3sV$B5%C'6Ebcu5 !1AQRa"#2BSq3 ?r8Aw952SxU^!$Q%D\#gFgڥѭ#jhjat-E ^JD=:QI-)è:e#v4ݮ\7; zZS,AZ&7׽] +],/1Lt,Hc lAcw 6|C:_jXv:`Fbaa|b?4Z&v`V;0h%.q _0tEs&F&;kTFBgtJ±\X#Ũ*(_Q*bl-/e¡4c n$in& -]Qr[b vh%+yVyiiufElP5%K ar j 4N" c;2-nSvaw:?ا$/(`x߁i|n?ũph*4KG!~7ؕu\{b{fb'EkH0sfZ؛9m*Yf7]$+͹|߇Rf*:k7$j7H6t2XIlmE_bu/_Nc)-x!rL0lkNp6Nd+n-hC zd%^8"G7Fi&k 9,rG<ݏ17c=ctd]>E4E5F X{+[y\j.JtfSA7OCq#QQM iKmKk!ev%:C7Ȧaڻaax^LrX4TMZ M4!ŮygS5s\ō`SYaT8|51F"Cpdmni@ͱ+B7w[Wr3* fޏ2HYO<6M#iWj),3SF}!,= uNXٹ.GT|^>{<`4Of - ;uCfE>ٚTj,nX()F4`9@7Qȿ&lmLNiT tu3ql3&p;Mp5?{sc4q {ɓT}B)ꧦMM<:ՕtuDt y7>G*>QƞL|h<(1 d J)ǹv5S&)ZZKMa'%Gy2rQJTq{*%c{ m)eke~y*{]);-ogG*>QƞL|h<"ʹۖ24y{|꩞̏i]ϐ=b'%Gy2rQJTq|Y$9qsJmeo&NJ> Q 5ዒw4u"XTq"|mk6+cT}Jy,rA A2}~,rA O%H>Q?=lݛͽ.B|9 Gj'$Oj p׻ `UoFKG*>Qƃ0/y2rQJTq'%Gf$>K~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>QƃiG*>QƞL|h<k~L|iG*>Qƃjz uQƾy2rQJTqRKE[/Y17aR~;le&^J> Q4eP^v}:c8ltX3iC+3XKs0i-i us WAy(%G*8ɗT}BV=+ծqTϢ3IyCo^Jf͗mo&^J> Q 4d%G*8}MmB3Hb{Cd֮m31<k~L|j_sf_^qE'K ?4A޻UT޻UG1QJV44Xt\rW7i扊W,qÛ&vWFpUYMRCL0YMDTE6K97cMI}]_ɮWh}.Tq˃8# loAFņ]5È?\TlBK|ٮMMͬ/`u|i4oJtMa^ܵ2wHI6zO&i"se-3@*% mq9:42m kp)II%!|ٳtbĴ/Fq90, 17-nyaj fw|]Y^rZ]=E|vX䒴D5.{6 Ғh6>v :Q?#˖f$]+ : C각&]U.Qđf'ڑ)?#h}4G1* fy] UsUY6a` ˛1ņV UbTTX4Օ,u2ٶZ^CyoQ7pV*e4Թ)suG&\Җزkq@ԾxX6 I+\5cl 4WiѲDN#.۟V'y~*jilQa#ZS5{rIzzG1nLZߴE3蹲q^g8)#ܡ׽I$aJ%(D!2uX0Y˓.>I&'㏧cҵä:eRgIs?6HᚩZZl6]al<ݖze̬Ѹ'ݬtm/{rch7kppj촷\y{E lQ=.k\FwioQh$P:Hgt ,1t7OU;$ck#n -9ÜcgJo @m+X1͸Yb<ͅkkgvaCں8Xkڽ~Ax7`A YXZmڽș=):)&s=gδg1H=ibXjhByP硭E- |&ŵ58kJ), Q֘l9Wѻ=c35< mn[ؼcAiv;3[ъF,dqͷ!=XȟX.<4gJx߇kj)WymX$Lu#Д=LKN@D.mQԍem[22 9ظ7H0RcUc*!:bj`vphd$ٷ#5%İB MԸieCfBDy?:٬nIz2?WbQU!J`-}i{ӜE+dѻ6K{q"" """ """ M7Mʹ*oX" vߤЩvߤЂj<`%AP~ϮGY<&X]I'}g '|_|N7s8WLnp]ҽ:EX SY߈B,lͫ-9lHt=+jdSw3|0Iڦg /4Za[/YK͞M_|q>+#Mۡ+=LnpG=?#s^lm?wMnMLnpN7s8S(#{ax͞MnɷS)Mg }}`l=yً:VJh Hcqv_mmuF 4pS'j)Mlm{g6MCcC\e2(u2š{\XS"S/k)"S/k)"S/k)"S/k)"S/k)"S/k)"S/k)"S/k)"ԕH*ߔg'{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2š{\A2(u2°Kkϐ8iX澅%ޙ}TzGOcx>UXFSkmvϝN*Qt0V _;+v?n_ONږ׌]:ͭzMzWW`>;lUPUuD3Yj}X.#Tq*pY MscF O>Nk4^'`pV35^Ph-;KhU4ޱ7*iboPb3?~B?~B \ITj띇ۻkץ?Fj?6ulW19̀c u{=\ Jjj`;G MSZ,z(4ksǻ,cl5ocaL&|"^Xd|k!s -9HNUQE=DX.ƞFҰ:"\m$ۤTr`5 h$pǨi%92KI*-*zM!jjjvQB|FsRiV[PCM\(PMS c<4˘.8Wb1]WN)Ũ.I31>ےfڨ:+!o7G[%>wtGB+p|v*观({}2E=~d.o;kj4sI ՙDDD@DDD@*oXrU4ޱ7(1DDzIWSzIWo쭓#V|~-X?_6w-wUM<:fŹ6fx?A'bޞ1oO cJ#|l .-y]mc.'oȭ| t 77o ~-Nq?S"+'D5 7`hn6/ -Yě4Q͈?X%ϫclٶZ>-yL[œ~-T~}dj@3s -pkH6"t봗}-1f#h7%,.z=.9L[œ~-U5Eb҉X@qeK\Ͷ6_kq2M%3Ia{" cs9B2I:MyL[œ~-T`xuF!OY2)0fUTn$49Nf{:yc9vhh{ pEH9L[ˆ'bޞ1oO "8zxSOŽ<(~-Nq?S s9L[ˆ'bޞ1oO "8zxTs+ֺ64kcOQHXA """ """ """ """ ""Tzߜ9A" Λ`]J*zo]w*t &w-1-T/y^HsnI?+D΋{_}'R oKy{ݕ.zA#ڶV>{|Su/o u/ozN1f'LIΘWP 2;o|YǬ _jk9mXb\7sQU_S(!v:z"5dx6kv{A b;pj.z,ܼٶsKln|_zN='RNѩ336}8.{|Su/o c:='R>{|Su/o c:='R>{|Su/o?ʧLp|C1&i-;eC,}$obl$Y= x}K⃋h ģ|18iub9' ־prahqe  }x s#nlp,#'_Zu/ozNADZ[Q ]3J$dq/!\IfPLzUU8ϸ f=+NOIԿxVh7 DD@DDD@DDD@DDD@DDD@*oXrU4ޱ7(1DDzIWSzIW 6lGU@6"]lZm1>V#q? edja..ZGY ؽVB8H\;1ǫ0JUa8blkĄ8mZ~Rf8E8 c{3WH9K+`^ӶFZy;GTN Q%i{d-e\K.M. #V&#ܣ^gsᏃIT`׵#\#cv#XJL/N݃Q_*ӪcdaRsIt\ V1ȺG1C&C妅t#9lkc`k|'O9n[Z#vS06VΝ1Ǒ`Ii{1_Yr]iMSP!)t$fg\caaب?eiUSñ:|NgUecb-ToTּ<8}b]3΅Z?D+b.Ѽ'J*%cj5K _Hι2ţ.X 5+"iM3d )?)\_G ÎSwLNd-1,l(9z.tRb/?EQEtl5`'>7/6pF'i)'tk#Rȃ/xmn \ j?TUf1XfYlύ {6۵ՠChƏVQMT.X顊hrLL-6b1,7qMJ1 FE]DkKv9k\n`HItgK1`V1tQT&E3a6!s 'i+ya'PV"-^Ly_6˲ DDD@DDD@DDD@PVŏ:-, "@DDD@DDD@DDD@DDD@DD9W%SM~rDA7p:=7p:@][?=NfկFΑkv-h##q\. mMDq@q &b8N"о{8GG~qЏVB%t9eǽ ?:ߨCğUh!N}{NS?'';kM-qЏVB$8GG~st9NV,qC%E?#CZWBI'ү5qZHSKRцݛLuQlGճT[ؙZuQlGճPmdjeg>҃k+}MT}[?5Ql=T}[?5Ql=T}[?5Ql=T}[?5Ql=T}[?5Ql=T}[?5Ql=T}[?5Ql=T}[?5Ql~9L@& v5]h6PB>e /PB>eL}D@@5ocaL&iboUTzߜgM~.%\{=7qA'6w/8rRIYjl/ƽ]l^]lc Q?|^,z?+f/m~_3is_٘ 0<48%i`ӱkiiJ+395v`I9.{)+Evΐ:2EDV4^tR'y* {075ń?e6.T&|ZEj:-w'~k<36Nr^DDD@DDD@DDD@DDD@DDDA?o)0@DDD@DDD@DDD@DDD@DDD@DD o[XXS(kr DD@DDD@DDD@DDD@DDD@*oXrU4ޱ7(1DDzIWOM~.%\rzgr=!f5KK^Z2gc`͛$ _uŧi]U/]Hţ.>խ_lK/|4.+|۽>GLy?_{O' دt|+^wNi]Tzw(~:c+ y?_{]"˾sH➩OyCg-T@ՂWnaԐPa4-&$`/4.)"˾맥M?dڶkMyp|E4.)!˾\|4.(1E4.)!˾ Qe!˾sH}YsH}|\|4.(1E4.)!˾ Qe!˾sH}YsH}|\|4.(1E4.)!˾P HANkޛ~߿9zmPNkޛ~A:(9zmS߿Nkޛ~߿9zmPNkޛ~A:(9zmS߿Nkޛ~߿9zmPNkޛ~A:(9zmS߿ܷsX3 iPL """ """ """ """ ""Tzߜ9A" Λ`]J `]JU4ޱ7*iboPb3?~B?~=5*sZƸXi. =K~°?8d,X˴6OgR߿&𦥿~O*jH\$ h.s9z 2uC0 ăj }K~š7V P^%|yk;c@ۿ_hqGWE 9dfaMVb b [keg?$,-YMK~ªjiCE.C.?cc 1 dtQ4 {}HAsoߓxVda8Mt%GM$Lds'I=~U4ޱ7*iboPb3?~=`]J5>ńG#=[c`܂]E`ܜ%E5orsX: IOY4PHͽ5or lbշ9[{Mkmt_ݫ.kVpG1 iboUTzߜgM~.%\OK~cJU4ޱ7**i}b_Pb>8^%mt][?ݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"vVݷ5ս" k{kmMuom~|][_o"5#4_,-r~gھ" flask-peewee-0.6.7/docs/_static/0000755000175000001440000000000012624225533017256 5ustar charlesusers00000000000000flask-peewee-0.6.7/docs/_static/peewee.jpg0000644000175000001440000002715012574421673021246 0ustar charlesusers00000000000000JFIF``C    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;(" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?7|$g>•O#Ҙsϣ r3(X@r{t4I91=47 uCq nH"j$dpW< i c~P}Ȥ"B/_ {wۀ*K|V%Fp;j;ɭ"6F1 9!y'<)NGA1r0F,sPs_4s Q9,Uy89iqOj@!$1J Lyk߅rw5mclbMyj0rSQn.͹8S'4͓p~5fY$٦y-Ý?Z9v_ ݜxcZqvǨ#BH8j ycB}T[4YUw_ُݒ,bhA w^4:]>HuxgdHFe5(U}`qmpRK҇Q{{o87$γr 4`/4)iv cp@a^ ¶sӌzJN*ᖛqspW FXcjD zPe#JRYO9#SR>##+;9qnە@, ȗ|<8Tɞц +v_G>h _$R^i,%+ɇ4ўq{"&]{E)XT1*KՉR)wڼ°$d쬍'v:indu/ TXXuޜpO3*&F8 XqW'MhG('BƭFli=:3ˍpv[163Y1S2}*lAbr>\'rLFg*裌W@3=M0qr69R`l>9k(${Q`:oe &㯽W{s"q?Lm? R=pæ5[Hx#!ޠm ~au1bH##y>.TpJvOck;K 5/'}yp~$T7v~!aK>YHOz ڻ(-C :$2|g5TI$9.0ki#=OZp$ Bvqg¬J+Wvy{C&;rqdctk< rncJw[Iwl~^{MGs *?j&lCՒQX>?94|jpLӥRXЯcc=jŽȸS-M.pR\֚"ŏ}Pҫ&<=S2ͷ,p=4aʰ cޱ.teHɁ?εXlHQ#2S`bHHP۱$#,phǥ!anzzT^ ԃ85o|=y$sR'gɬ?k i 6ZP,Ey{%bQW)")k˹''nƱgzI\NJԳ38Tn˔1jK)W޹S$sv%m(=֙ \Sy C1ژ;Tq؊x gE("$q;wi(Ӗw݀WOs=xҋ BG׶N*bA?( x'ShUk%9m?,6gqRj}E7Me`B썱݄/x+ė6icPY\nӭy3C3,l q^g RY|5um\IE1XuֺiIY)7{eZ:Mܬ(2X T⻟ѯe_ڤxCSF5kp"<`1sfD /^*)28ҸԬVqmipσqyq3s^} # 8l5?a#}I$~eZ&&*/8)~ZxF;;$x&bv7.٭ٰ%Cչk~<7 :{c~ػ۩jcڪY]nCSXw[C2r|x?cJo ܌s2+/yr m >o\ kK_B- *@0qڲ!re'麮Gxߕesl]pje?4ָDPĎ:\5C ozk]QֵVYȽ@$?k֭HȎ5;wڵeu2m%$**hl鍬uFr>8<ӌm8Ssj7$p1Tlvy$zvC? ?ۮ*̪ޘ\ |1ZpW= NZ\d[v6~0Cڝ< n02քHs>01ڞFFI֚F1"g;RO=:p7};q~ B6.\L=lғ$ C%so$d;*&GW?gxfmIaY&kG:N`P)TZi Eӎiˡ/˅Gݮ,㶈e5[mcUA$bmr(gh* [s*'Fjݔݞ+TEU\Os&s;P*}^iZqiGn>Cz:> )jǟŸp:Ktsڱ2<,VĺPy{V(N1ߨKRTaT]4nd~I?J1 GSZ:.itڜeaHߊI_a]s36)Y< se,? -uZH_ ƹߋb.׉'${NA+KóO'KٹP%82ȹ,[27s9y^J;[^kP7AXε25MaJqێ+&G,ܓK#,yU?+ ZBW__~lhLnZ9n)RͬmnVZ! \zQX9;O=ym 81|H'gh* dz,Z}= `|Vi#/#5}؞k1KroJjʻHۃtSMŇbyІ@ydd`S)c;6:d_Ii4{?G\ǴI>O-_GbNGcG'$Nua)>칣09A^=T+=vFz{zvcp=3X!@zԭΣQc9c*R6S(eG@^3vmፖ6=9Qn!Қ|<e?#կQHj ~sWJ9C|{S(sIGzոy@w[1tc%pAnKR]ە;e7q݁=4o!?(֞7Gi2;VP: ep#Z(ܒ8L$lMJn}dJs̍NhCƒ+!${Vkg<GPN=(N”y&3u[6&F#Mh=3XnY]cirCN8{w x“*&Eݸ${U`x֖f,AVT rLG(Y~XڔyE"NP)qXbb:oDiV'?\J|d @JgX)kq8${W%s`VvIs^ կ&t |,If(~Sq'$9մ6NK#,{K}vIzS<@=xHh\\C~UAsgjGv-0=ZosqKA9Ur9Unn+m pNF+H129O89 iץ[.,r}R6G&N1ʑ`G'*Ұ qКtSֹLK6f T>"BW+[=Е0O]EIpdl'ZۘO~+ȣ+G)ڠQKk$"@ S85= n#'r;3Cڝ 8rE™ 8!H8Mi.)$5=ADZ5Aw+n#l|ǞOQFpA-$5>jpnI8$zաڥ֨Xvb1]TMi{>fc!mմ2K46$}+ p8HAfP*(l`+- EKI=*94_|-t&EG Nj̯ځX܎Ɲt%߷(X^ b'cs]%Gu+P]]Ɠ;Om#g'5oͬo&1ymk^}eb`=V..lH0)Zfn[͸E G0e/<3gqA4hԅy$'%+wO.fA; $\FJM+!I'oaaەS!՝WP G.zUky6qVՙ`(H#>5夐NW?x5=tے=G ha@tMTSҥ@H=h` gZ2ŲҞ |0 m$`мlGqY m 9+e9RRS.r` <q6nۗT4kj$% 9#T/bflȷmI[ϋ?:ɸ8&gKҴǟ->7ID*˕e=sJ.,>hӡw|u=+&@SC[9Y .yϭ ’ԩ [I|jt[j)'*zsֹ-O0q+Ga֪NǨޤZ.>lf[hFHZܵVaz'WcG/^lLX|?RYus8*WqfJ/d˷AZ(桹Jsֺmn.m#%qt8 "@T͜ԣ^6[h+-BۓWYw."1HÑJj̺R#94sPC)ç#'gsPp?&̉ьd`Ҟ>n }(=~x$PQ]lE@&ymtCܑ1O~NAMGccE" r*ͱcV-y^08䊟h+ǩ",5z++)<]n`|=jxfSEmVʸjo|1's61[;oM8+1=oWh k#y>f5=1K]X}4Eas4jPS /sfoۆVk&fێFLJgw:DP6'kG4%ʐ# 0ݩq]K m]n;݇*dݘP1 _SEC<(ܣ' [ZΉv3 >f|_ұMk 4SRF:baޕPd* Š3@@+\k| ZAk, ǭ`G,L:`22zjv!#!9#t-dj{B8\~SVU.RRvPI}jxÇTnCKCZ-sQx>PWEH\ZΑE$d]jAa)?,dYݷLvj:=MA9D*Fx5%60UC `pw|~5QcH03`F*t2v%5hy2\Jf,aӓ]f(P!~|ϭr:/dـ$ ۬IkQ!_L66uLŤ]wړU MڡpA ;/}wM Hߵ ,xU۷ y<'qq 6,W5k_I#>G}A#1hh[C7$'"[m5A*E929TcWӅߕm)6~mpgKִEpp©M\Cƈ>h9#1F TKi+,`K!zb|Y QbNE%`zWV0rЏJo_۴Ypq94qyxlQ]e2U47 a|ϸ,3Zv[UV|Kem0VZO8짊"BCGklkՌ O~ֻT-jGk& 3iwJ$ q+EVivv(ٵQ)v y:Eq^-#I6=ܒh!dUXnJ_i{Ң9t-EΟ lu"ӭsz]ȵ>plgškoݏ=%`SKɽy= u3${,L*]0;>x R)Ppx4j_Fz˓u-}#|o#:j{븏~2o)f &G+IG .X!b !\mbRO"Zv3DoXzܿA!9=k|Ł$q\ Lٟ@OZ:DB#y0OJ ʪyҡ#n=GR UZ% odnhr@'}64[OI |n#~T5%PAcϭ^h#ݸeF)ZՐҥh;2"HqO,Hzm_hPW9#'>#I ѡIz1'ޤhYB<'jƮ@1 3*D`I&F3 J dhFyJ( Vt{of5Sߎ#fSc6z|(2/ǜSersp1-ϚGXj`{EsKsѦflask-peewee-0.6.7/docs/_themes/0000755000175000001440000000000012624225533017254 5ustar charlesusers00000000000000flask-peewee-0.6.7/docs/_themes/flask/0000755000175000001440000000000012624225533020354 5ustar charlesusers00000000000000flask-peewee-0.6.7/docs/_themes/flask/relations.html0000644000175000001440000000111612574421673023250 0ustar charlesusers00000000000000

Related Topics

flask-peewee-0.6.7/docs/_themes/flask/layout.html0000644000175000001440000000135612574421673022573 0ustar charlesusers00000000000000{%- extends "basic/layout.html" %} {%- block extrahead %} {{ super() }} {% if theme_touch_icon %} {% endif %} {% endblock %} {%- block relbar2 %}{% endblock %} {% block header %} {{ super() }} {% if pagename == 'index' %}
{% endif %} {% endblock %} {%- block footer %} {% if pagename == 'index' %}
{% endif %} {%- endblock %} flask-peewee-0.6.7/docs/_themes/flask/theme.conf0000644000175000001440000000024412574421673022334 0ustar charlesusers00000000000000[theme] inherit = basic stylesheet = flasky.css pygments_style = flask_theme_support.FlaskyStyle [options] index_logo = '' index_logo_height = 120px touch_icon = flask-peewee-0.6.7/docs/_themes/flask/static/0000755000175000001440000000000012624225533021643 5ustar charlesusers00000000000000flask-peewee-0.6.7/docs/_themes/flask/static/flasky.css_t0000644000175000001440000001444412574421673024207 0ustar charlesusers00000000000000/* * flasky.css_t * ~~~~~~~~~~~~ * * :copyright: Copyright 2010 by Armin Ronacher. * :license: Flask Design License, see LICENSE for details. */ {% set page_width = '940px' %} {% set sidebar_width = '220px' %} @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'Georgia', serif; font-size: 17px; background-color: white; color: #000; margin: 0; padding: 0; } div.document { width: {{ page_width }}; margin: 30px auto 0 auto; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 {{ sidebar_width }}; } div.sphinxsidebar { width: {{ sidebar_width }}; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 0 30px; } img.floatingflask { padding: 0 0 10px 10px; float: right; } div.footer { width: {{ page_width }}; margin: 20px auto 30px auto; font-size: 14px; color: #888; text-align: right; } div.footer a { color: #888; } div.related { display: none; } div.sphinxsidebar a { color: #444; text-decoration: none; border-bottom: 1px dotted #999; } div.sphinxsidebar a:hover { border-bottom: 1px solid #999; } div.sphinxsidebar { font-size: 14px; line-height: 1.5; } div.sphinxsidebarwrapper { padding: 18px 10px; } div.sphinxsidebarwrapper p.logo { padding: 0 0 20px 0; margin: 0; text-align: center; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: 'Garamond', 'Georgia', serif; color: #444; font-size: 24px; font-weight: normal; margin: 0 0 5px 0; padding: 0; } div.sphinxsidebar h4 { font-size: 20px; } div.sphinxsidebar h3 a { color: #444; } div.sphinxsidebar p.logo a, div.sphinxsidebar h3 a, div.sphinxsidebar p.logo a:hover, div.sphinxsidebar h3 a:hover { border: none; } div.sphinxsidebar p { color: #555; margin: 10px 0; } div.sphinxsidebar ul { margin: 10px 0; padding: 0; color: #000; } div.sphinxsidebar input { border: 1px solid #ccc; font-family: 'Georgia', serif; font-size: 1em; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } {% if theme_index_logo %} div.indexwrapper h1 { text-indent: -999999px; background: url({{ theme_index_logo }}) no-repeat center center; height: {{ theme_index_logo_height }}; } {% endif %} div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: #ddd; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #eaeaea; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { background: #fafafa; margin: 20px -30px; padding: 10px 30px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } div.admonition tt.xref, div.admonition a tt { border-bottom: 1px solid #fafafa; } dd div.admonition { margin-left: -60px; padding-left: 60px; } div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 24px; margin: 0 0 10px 0; padding: 0; line-height: 1; } div.admonition p.last { margin-bottom: 0; } div.highlight { background-color: white; } dt:target, .highlight { background: #FAF3E8; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.9em; } img.screenshot { } tt.descname, tt.descclassname { font-size: 0.95em; } tt.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #eee; background: #fdfdfd; font-size: 0.9em; } table.footnote + table.footnote { margin-top: -15px; border-top: none; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.footnote td.label { width: 0px; padding: 0.3em 0 0.3em 0.5em; } table.footnote td { padding: 0.3em 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } blockquote { margin: 0 0 0 30px; padding: 0; } ul, ol { margin: 10px 0 10px 30px; padding: 0; } pre { background: #eee; padding: 7px 30px; margin: 15px -30px; line-height: 1.3em; } dl pre, blockquote pre, li pre { margin-left: -60px; padding-left: 60px; } dl dl pre { margin-left: -90px; padding-left: 90px; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, a tt { background-color: #FBFBFB; border-bottom: 1px solid white; } a.reference { text-decoration: none; border-bottom: 1px dotted #004B6B; } a.reference:hover { border-bottom: 1px solid #6D4100; } a.footnote-reference { text-decoration: none; font-size: 0.7em; vertical-align: top; border-bottom: 1px dotted #004B6B; } a.footnote-reference:hover { border-bottom: 1px solid #6D4100; } a:hover tt { background: #EEE; } flask-peewee-0.6.7/docs/_themes/flask/static/small_flask.css0000644000175000001440000000172012574421673024654 0ustar charlesusers00000000000000/* * small_flask.css_t * ~~~~~~~~~~~~~~~~~ * * :copyright: Copyright 2010 by Armin Ronacher. * :license: Flask Design License, see LICENSE for details. */ body { margin: 0; padding: 20px 30px; } div.documentwrapper { float: none; background: white; } div.sphinxsidebar { display: block; float: none; width: 102.5%; margin: 50px -30px -20px -30px; padding: 10px 20px; background: #333; color: white; } div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, div.sphinxsidebar h3 a { color: white; } div.sphinxsidebar a { color: #aaa; } div.sphinxsidebar p.logo { display: none; } div.document { width: 100%; margin: 0; } div.related { display: block; margin: 0; padding: 10px 0 20px 0; } div.related ul, div.related ul li { margin: 0; padding: 0; } div.footer { display: none; } div.bodywrapper { margin: 0; } div.body { min-height: 0; padding: 0; } flask-peewee-0.6.7/docs/index.rst0000644000175000001440000000315412574421673017503 0ustar charlesusers00000000000000.. flask-peewee documentation master file, created by sphinx-quickstart on Tue Sep 20 13:19:30 2011. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. flask-peewee ============ .. warning:: This package is in maintenance-only mode! ----------------------------------------- I'm sorry to announce that flask-peewee will now be in maintenance-only mode. This decision is motivated by a number of factors: * `Flask-Admin `_ provides a superior admin interface and has support for peewee models. * `Flask-Security `_ and `Flask-Login `_ both provide authentication functionality, and work well with Peewee. * Most importantly, though, I do not find myself wanting to work on flask-peewee. I plan on rewriting the ``Database`` and ``REST API`` portions of flask-peewee and repackaging them as a new library, but flask-peewee as it stands currently will be in maintenance-only mode. ------------------------------ Welcome to the flask-peewee documentation! provides a layer of integration between the `flask `_ web framework and the `peewee orm `_. Contents: .. toctree:: :maxdepth: 2 :glob: installation getting-started database admin auth rest-api utils gevent API in depth: .. toctree:: :maxdepth: 2 :glob: api/ Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` flask-peewee-0.6.7/docs/fp-note-panel-2.jpg0000644000175000001440000013476712574421673021167 0ustar charlesusers00000000000000JFIFHHCreated with GIMPCCj"  X  Tv5VW !347Rs128Xq"AIQwx$9BC%'C!"#1$2Ta37AVu6BQGRv%SqĔ ?!V=D趁#%E 1]^P34!V;{c[j Tz J $Z&1qh^m3*+;UPYUUQԳ$@u9VvTE,B,zP:I $?p2oWe!km͊6s>S{\N@nIU*Spi&U)e`{@u YIeGQܬx D2JUCt`>k 9ǩOįfSmGv%ZNS%TSԇmqjRq"GA$&.: Oʥ@2Cԕ>^\2fAj} opoe++>=3[-oyǙ?9~tG@ cڠvb ߠ?̀[@O@I I=9/%TrdQ(!b5"2 '<(+} $س ]mvs * B>A"ee )C)AAN!u]obK(\}>G]) JZwhZ[SA 9j A䓮05,ʊY*%UP>IIUgeDR*ǠU$I3(P>~ >]mə5Mdmާy c2` Ɯ\`8Gx D BBB{Iө }"YA u }ps>1€ՑWI՝8W<$y%eEZ0jf9tV47kčrRdQ{~z̮-Ⱥ9Q`B,[ג]r&#pNA^Ҥ*5*‰WTa롺m}<=:z/N:>Eue^TL :JAʕRdɊ0 3BH tN86Բ(v7]4]lkDuW!w ʞ a]*2a+5k}pse~fP)~fDu_vIW`=  XPp~U [1RE==L 0c!#xUJ`vLQh'ք"+cCq1 skI9jX|}л8R Qb$^Pp~W(}"PpʟpnT1 `1 `1 `1 `1 `Wp dZ|X#ǿh}$`Oxh76/9}ƛx)iJ\m5+XT PsùQ!rE+Di6IqpK+ֻ4^يmԔV9oTiNP~ 3L69[_NgY5vZڰk$sb0q5$^Ug7N) 3) o-%x_Cy'(Ja27_R3.GcMQ?D1Lеut~CtmJ,G[w'{i;r2(̳4^:NJ,7qejr2̊J5:ǸNte'毭EUnfgKVȔd0f?7MH9 :SM uk:F&rjOޘ^- nI ]7*Qf_,uMooA. qNuJΦk+jguʬ&Ca-fFߖD[I]U5"@vkֺՠ:0y,VZP_VUIgi&~{2(#h"CfȡSЕ1݉ ==<(1şGh9bNΖvI}H kjW+@$/0YEA(gc kkZJUџL&s FlDHš 5oqrat%SS[IBKU$%r7"j$r"ߺ=_eMDYّ2CU\/xni)4?%禴DEN5VoweYlʤOSrԤWeԚ*JD2<z7Eq}^XiZn#(K;JUߧ~A p/{MHlm$pUL)]SrJ%;ivf(P)S;B3u;eiżs'-[sŽ=v:^_Ca VԇI"){"BWFg29FݗD)G=RĤ"LqXory|9o?Ks3FW~bI-ZRĕBJ&g؊V3܏)3.(=KP~n,K47[Nl[VwIڭٯ ok4Û"ef[ Be&dD9;Bj>ǧewa LQ("2nU5rx=nw-CZ<ַnsdېyڞq;Xڷ5q>  y!ԝ!'jRCXRXz2W luuvI3 'usUHInZ/XyMلy-;:B!߷UU\%_KQrG!v*tfUjty"ҫ.oޥ+ҷ[DʼIp~[g}3+): R((.M T2ǓA ~>Dsɀ)η!ͳm+1~yXZ yC93.]מNE/ō0j$wt%)Q^tuDWtgT@Bv_o)@秩B]yzbf5Ys5pܯq泣F. &7~Toֲ3+Yb焪NI%7s\nw$jM7sue}(T/ Kw)=tfɲ&R1ȣDCV)^>#>GX_/6BE;Ú˚vl>Z#N1Yz3LF~5LJVg}4t' +i>A7=.7v1m'uo}p{6|OpNMkZi>6a:t=%+3|c&G,ƎV v9;,mI117 NeN;bI(%:5 \ॹ KQvSF{7DC(U41:Ga:} ѩ淪rqfLڀZ4(<'~̴/h]K`*~IleyBۖm]?9&6i1CJAMص:ZSҗ,\eYbr&Kbl}B1}c56xݰE!<ϭg{V,!41: :F:xi{uqu:}rgnN<+t;45ZIZ!uw3zʎ8[ BJt~o#nMwI+Hˆr4Áb,oy|L4/뿃L}BcȞmZZ k\R ( k&SZ+B b5fTڭru.ݲMR7ӻ6a0z:+]/"qv₽[N6'ĝHHZDqQ<mNcХ$+hk\_ZsD;[SY$,Yj7l[8p#qw{c\?eݖ:njT2=*D~!i& TĆ1%bXRWKVŽY;lYԐfgkC5v]Qtke|ke8IwGdcG9TIe0N:}1M~BUGOY5_sa HT<RO#Nj't(HJyI-GSڗrӃ nxFw_!,'dtٕKL[r6B5TwyPK]jZ\鿂x}5G4bs_b-n M֭4jxUfIjpv?ؒ M4hRIO:ny]Z(xڲ#&D颧-Q3.J#VFګ^ܙ&ڟۛ]L473r4[k#N{ݨM[ ZӺLPĉJeZˆt]s K e|~EMa[WNlgھlY(eiDA(t$ SSt9zr9)]M rpҺ ִҭcJYY(}** >nƯ'lrFJ|/Ƕ?'^OKZ݂8ʭ~-uSӧ@L4ZA|vk*RN$k}o?yQb3Um6M?48'gKR&vJc9!r^vڦnM!td˚nnS+_ 32>ri!V8—:n~066eJ"ܝR j9.(PՍSAr }ej>*PIJ*$mX扅*c|Nƣ4ӒΠwA<񲱒CڒGjhxIl=_\ nkHՔ *M|6Q[jjMR#OcS:!ڒз'kM|GV^eeO (>./W[m=hW_sbJ:`i;nWG;l\=ܛ֢!i v*B>n[vԏsw98&m@NTRVRĮ{uĘfF;)u;\R@鳋}H$8cfYnaW+J=& HayH׻jE)tc*)D¥RӰgw28 :dDM.SkҧA:^2ys^L#5il~|ԂLǼ֗ɕJ0rY6nf´i˾%$Kmf^t~:<)^a5KKMYq"REbi-J6 ,բM#UZ-2%9PS/Mo-۳J"RDW¥q3>)VVYկl\Q \V3SGzn\kˍ)鈬~\([@<':]qTY ^S8t2黚*7{3oNi4 /UɜPN] @quv􊣪aɍf!nGaPϷ*c0c0c0c0cOQ[@sZ|X6BB;}4m :kkszlf\c9w]|9!oNN 9ˏƳSu ٦.ᇺ >%nELWJ٫ șۭkHiMHv1Q&nBS|-YohwUx:+h°vr&{ʎӦw鷥2TU.|[V{ I; u4/|qkSBs`jjw-[ev[ŁBy'Kb\Qr9gLa&#h}򗀜V %udYc>&Ep)4;ἇ%g|% x˖ _A){#kͬfZT3DW@KcDCcvTut&C9{7qxӧ./q`WIѩʠn$|+m=zDT-cwBZ:2/)pHznH@Η [*'VhS2)aWhoĚkcf8`/H{T#gq8k`WӶDP:Hc}m7鼷G!),toAnr؝N0TJ{P!|2>!{gbeĕ~\;ON`9”u~j8Tզ+|K+"[I2SxʲnA^giZKԎoΜ R;Yk`f(cL^|,96͑5/?,xNACɧ4Ӎ$6B[6tiG9K2{Qv7]UM]… G Kf?58-hj {#tm'R}&E4]Lf +;}b>,%*-o*jUxK:#\ tAI$j'ŕ^2}gƸo \[s8LJPP?ʹ:#'o%3c, mm 0XG_NZHiQVbASB"3ğGk ̦ߧ"~"b/VUPATи.x~~[؊&_1\d2͑75,pm,Q36 yO MÆ9sᇙReȝb5W.FM-TM0q*qI1!vRϣ#joֈ l{Q!k7 [j摓k7c9$)5T WZ^z"D粮J%jB s؞_*D}du\~&B28y7wer5ʙծy76+qNz ݭ[zՊSnk+Rν4ui&"1 Ju4)#*{g $ll6!Ԩj6෴M5N'#[ogev殁A ]`m/ltޓ[cVmhM^0c2PY)vٞ>P{Waj*:LF|IIjGMk)7W(wZ^tL⽉[y}F,ŭH 5daLx*}>q#&Ugz5FXRke7g+?'z:lk-YAݙGXL Շ=ren/PijmABΖRʪs kvgP9F,6N8s3tGE[=(jR2B8o\Rw3s4\ROdRFs}3} ?NiUkzDoG>!kV:ױ# HI|"zJA<\Woʼnﵿ:잝(׭b VzL `"'pEAGj G}*gѯ/ͤƵ2PmtnOK7m;Cޢ<QJZJ$+v1SqlU&71RCҐr}=+m%?h%ݶ%g)g[iծq@Z֘ɕW-mjVU85ZqqWweť 8f1.tepUdNUB)8݅PtShLe!li[e?'EϑӐ^Ħ,9% ,zkRͭOc-٥v9V_qT&Ad~c@^]@(jzh *v{m4UӰ ˹{:uDFW|9qJN4$,=> MI4>ByZ>B[tkyQ㺺{F`N: ͩ*tk r~q0v_+KRD ~zl_SKNӬ)@$Jq: c0c0c0c0c2c$*ǿh}$a֟=D趁#3qI6В7}I$gR`41hIqx4/M]s{P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 f;چVwBY@CoH, Ȁ1j}ZE g "܃"cmit%6r դ]Ж{;P.K=2 ew|ۅpzzf0KLbL虈ƣ%N1xnТntvvvtkDў|`npdEwn(j$f8okZ5*b!:V>?ˌ8 nQ(HVqJյ(C^/Y3hv5Z|X8c˖'G]qqS7SN6u%[D]squ|>OsA?һ{K7?ïJϢ?9/"?1>mG>nb|q֏ ~D_s߂__gnuۘ6iu1>mG?J/9/ҳwK7:ȏOn4:dۘ6iuwoWYG;%wG'ͷ{hOn4:dһ{K7?ë#λr#sۍ=δ~'ͷ{h]E=%V} ]9}mƞZ?lsۍ=δ~"}+>|s>Os@}mƞZ?lW}~~ u~Ds_pD~nb|q֏ |>Os@+|C:JϢ?9/"?1>mG>nb|q֏ ~D_s߂__gnuۘ6iu1>mG?J/9/ҳwK7:ȏOn4:dۘ6iuwoWYG;%wG'ͷ{hOn4:dһ{K7?ë#λiCgWD7 p<}KϫReXli&ֺ%a%Ylk֍GzӞ%_^C{>IaKs^蕆Vr)*c^ִm@c0c0c0c0c0c9f}zdrWW2-ϭwE;Lwֳ?ϮlK7L9M1 +.Û+ 1v10sǤ jm0&^Qvvw_ÿƟM]Xa}??QC>>gMizoen㴶wwvt뵻X_gbEFC??o Niizsen㴶w76tMݚ@7%A=}yZ1O_ÿƟM]Xp~A8Ԣx=aӖ D7U[ P!?5EUE9Rtm)#fB|>xӦO\ü:q#L2dΉ#Ce(ItZ\ٍpn}7HpO!OS'r=5 GocҜz=5 7]f4ƖTUӦ|tydM..:2+S.b2PV>d;f#W$yPkz3R]2y;??yK8cUi~3b9Dr$w^!8ކ q*M#N5N+q0[IƕMUkqbSN.ۥj4VםU}<9(+mR^ۜ'JS1ԧRH,U tAܶ C/c 3OzZucNGӋвpvT]fm@ԕ8H[U]m%VE{^\pƯ+ŧ%'BO9sCBAa-ƾg#luBZA܎ J6zp1/T BlN5كI$kNޝoY\m6XSKnra=zVc ;iU/OO&, ?oLw88653i w_ÿƟM]XY`oLw88_q;iU/OO&,淦??Lwx/8Zt4jW}VX[??濦|?q5w` w ,Gc_? ?>V??~;iUs#OG+O_ÿƟM]XWGt_h3cPUG^Wڤﱘ#4FRBIٖ'D^O|}hqx -ȴ6"Vw#tRZ56!I^;BK7ym7&[NopYE-͂;dKB׀1u=x7z"[OE73+wZط̜*MmUS伲EJY8{lGK?w$8-9g>UhK %Wfgxiu_[N6@t[7|9]E>ܷ 'Sf1& .2qW $ٕPRԬk unN=Iʚ6u*і TP"~1Y b3yι>XݹSjKze':28=4:bPF@=y礧Pʥ*dRS/zَ5-GlML/6imEEsDJ, TKwNj.5UeӮlWR]ff=c(fy%2qͨHDr?䔫 'u09 xSkX>)jiޛ[{)z:גi2%){%b|zn:w-LеOtrbX#ASZ XTwmq ?U"W"#9Bmm+zkvL8 KbW} I w [u$.s7s!eI'f)JPvILw<xK.ҞYwuo+?B뤉+3[>V\D #-gRNB'&qg9ڭ0ZS-΂ \s5dVd_ũc{*؂-owM[YzNB:O]_AW[k7 o&]}-Ѕ:64^EWsVr,b=7"HYWuB_j ;RڠjsD.%^<}Ei UV41lLO&=27ywY2;!G)ֲ"zd?GxN'XMo^0'o59 "oX̅2iRcI ՝+PQuchAxq.W 썥dJOKB؝2]F<^Jdm/!bitk#l{ѵ|86#JW"G3Hc&$7cʓlӍSFC{w&*t- ~J ajnKѱ ՙ/$LzC^ä=hn|g<#s/T\L%Ym2R&vz5O0鷉NmL~ [}W_`Ѵ/.˲R+xOiO6v-'g lC0 wuSc_m-&9=wHI9\J|*N+fv|,ݽԓsZۖrc]Z[\I78/%f ;Ntܖݒf-f ?$`ߣlֹg&zW#"3Emj{>?sf,Dž4ż-g%]!IѮ] gp24ٝU8e! m991cq9ÑfV;~`~jS5^myRs7 (;Sub']MsۦTihސ ]&H5EJ/M*ӥ\Wd#UaQ$:cѾSLP2\3;a"sJ6FRq*fX#UN%/%%`\5vRњSju/\JH+wfvvOyӉ;ֿA>@y)b_OZYq󓰾ǢTm$Քr֬<,-VPɩ7?RPyfHb4L9!hKR[?foX( T*tqJf@O_i>Ҥu5y^.I51yf7ZwMS2<]NR Jpvjj⻳y:8lu!T7%/ @w lcmsc838<83Ŝgbp',.PS*$N:q~IkRGn VT%?OJ_ Qx )JB{쌭̽C)zf#;Mxl͕]{Y*EeT~ҬDnw*U`1 `],ou}/QO"LYj^E<x?nT{'Ε~c? )O;OpAr}+ zs=/ w U^ֳǰk=:wQɄ@<=Qq>okwTY[]lD6;>""_?4쯍;ջqy#Xɾik}z=TKƄwId*I9L;AgmU{U: ZwҝiXKVI-]m~_^z:Df@"q#\]m97y1I8I&2`!LsQd!fDb&4'Va 47K.r?7`7R7)7)sb֗Yء߇ ],@\DbPnĀ\iCZg~ '!I/I2Z|s{v)=0 ]2j9Wp]Rh7|JțISl+sXk$IYsR[89u_%kÔ8PA.|;2*<% IqDҔYGkȕ'l1)YJj)TqʔnmJitu F:ʠ@7tz"4NbLz]av(`Sp4SV`:f^=4)\?!-cr!ݚ?=dh%BMGV3dip'NƫQܦ릺馸]qu\c]u\x1ǃ1c1c  (f.Sgdcد@:j=]sVbƂP*(^B)weAU]O0c3ԳpԳpU[(WWlXv1 `1 `1JbDT5>) ؐLzjRTY%B -2Fu #z|bvD9u) s45.%/O9͇mǷ7+TDy^FQ2HA9C`@_f[>^1f??x~?'jzvt՟'z4pVeTl<%UtQe^>R|mSk;z);ˎ.. ,`xYfTCMJSY$-8XRj9Cv!Z2vM)=&W+,QZԚ*k^f6U5ecbG#,Db4YAUP岩*Ȫ̪IM΂]1cV!6z) vCSW*Ž‚2:i$. R+nP>n/->/^v}3rZi+jVϩehY(0;1FցA)ٝ`؝lb}X >N֑RCj λ-&i|Bo|Us]C|\N }rC iDJ4(Ry΁FV^"O=E&L VoTL\f?υ}֔]@<^"+8C) ס9bQQIАJ8 `T:aGIpiK뷲uDq(z?1p'dȏ~G-M94&xP-ƸJ}:Xp.D B.XZDEVֵB$iǶWf)^qJ@s]{&xӯ U+)'Jj"W`jLfpmHSa լڌf3u+hbQe0雭m֬rpZdlX}^NT4'ڡ6i0it>67!:R0~|+ Kpƚ*SŴ]yMr=Р𵥱fn s `*]BVVXUAI-nʍ9ƝslSakOcΔ=Y*C4R$G->ؼ_GVv;=?.̕zFV7+$ij9PVziVSƹ*~C,ZC4~{`K:g\OjqVUP%{md87| u{GJ#@격-v0 u٫gb.v՝5]5M5ƺk뮺u<1c1c`@2`:`0c0c+园)d[#7[]_SȶG>}3Zsw>ҿO;OpAr5i.PN|Nq|n Hn@Iɓ&@J "2JNr{m(붤m\h~t(j`qȶ[B)~E1L^YX(n[Y|عԮpMmhT%ornh6!k{UW"TV&VY[*LB ܣ\a{3 fÈ{5;>W]3L.[t[MYaVHK!SqʺѿE/ lm v\Z4' ٭]^FMtYاy^iKW !#6[oBKMeEʏ*i_"%Һ2w*[Mg!ގo/# 㴆rf6ΐyq7::JELf$Qy<ȹ3H"t0)>/M-(nNG3t[%J (hw4Hf'kW]W77ptaq%[!X7&q֗V&>*2HPϪ 6M;.N-+heDVӭ4 x|+} m ǡp:_ Beu$8J.6ƥiT|kb̜3k13֖V1Xý/V2Nbb4$9?EƺDrY%ƪjqIzH7Ulf6ܫE"jdދ<;"rnhsfl:*[cu$%qj׶oƗ%Wl1IG(%Q!Oia䤆.H=D;cF'8n7i'H CT J/}"pR4.6ξh Y۟<*25vso7W WUD 61DI)Hl}Jr48;zBT֕䖵 ^Ykν7$CGgV,_\M]kE=']>퍷4(%*=<ÝB RT¿m ۨ$'~ď5T\U2d yt{sT\[74nRf\%Dy09~enN&3'+\eʾ][ (ERi/ۻ+z ӪVZD%r'cvCtM:$އf|F)uQlq 6E.5IIUPy2-k؉=+/ds}!VH{1řDLjZz H@1TkJ[x擨&ug \oWd>Sܗ@}J? FMs$B4:k΢rweӰL6d76ci$"s6:,f$B=JUGc}rrcJ\Q;5+-ںm2nHL,1-2? 4dSf/xm1ձL/FHzAdi֨]9Lqr,~d3nVgN$#oUqNv )Y3`oH,˸Zt\[\!+0<3spS2](0 7m:٤IUF~AEݞ%Ž KJIjkOg~\GS9Ն6s CTeiֵ)J% + *񕋆=]q-X%UT71dBJ{Fʅ}.f٭)mE'haҝ$*c|E@XUsjakhCSYNՒK#bLe`yf x< tJ$/;*EjEZhMz̛KWַR8fZݻbh<8"J,c㻌 7HgZШ݁oZlHloX3ef#Lo^~ m\auN~>MjF7[al;fWh쇤jJ/Shr\EӨ &vƢdru*kS%t]1=tVz =C\'(jrS ;RXٍ=<T (5y1|)۝p*QYXHkla~;fɦuk';9&CͲ?vݦSrk1YJS \S4Ï]{.{"m-Dt{4InteېsS 5Z2O-9a&&\$4;z)Awfhn_&"6f+^.RJQѰ3;vsXb%5$ZJJ!K>6c;^tQYm2XV|P~hдEa)-["T)kP+h^[~6tt/T%igGY;w ||DVӰRklSI񢂛6NmSE5@8cb5w4jmBzq-qWj 7F\2YNۻ7Gs S?vewOʵχ.&֪D_,;JICEiNt@>X#E.(C-Ab5FQEڗMPIH%;Jx=RV@+eg (deNVMzU^%^VDQ)N#RueR],ָ܅S^Rqc::} 2tS;V\cO&w*7w#0Xo2Ƿ 9zH)ݎ4[n0]p׎1?U~R 3V2w-Ly˕Tiԅ;38!L㻣ʝM9y> qd"LFhZ&ֿ_/x24dHڬFHIYIpR7!M%cy (DbHz$BvJ>Ơ〚TRd7Wy` >)4^zJrҹ̍ƋRQuU͝6RC)am2&5Mk\|TRKiEYZ2ȽwInix+īH|n`nCb cq|{KKyZ"}3t45B1BPi +JUe@ʥHRUf u4E]e%4UxP^3~IVY=#D;=#D;N}JcyGcX竰c0c0?ᾛm"UuM 붻c8λkc:81g?hQgi&q{ff}|ms9LJ\8qg6ٌ-+ NlIPIPXTdʔV=@# k+Kߵ pݰW$&~9K4KvcLfX[˄=y􈴆agd$f2PZҳJ\M+*.wQmc[.Kyo%qfkâi,F5ȷlkӕ'jyYƖ>2\YIoK1ǩQyܽjUƞqՎ.l/"^X?@g$i%iŒ~zSSfX2 BnjuSӏ#cazFcyK!}:?45](h՚<)Rړ!d-M@w|!mB3Po6魻Y4ЕUWI9Ǭ d-E!%<&aov67(/xE/yIvڕV'm#Rݖ3TT"ngmEq Ah 6&gR2鰟 LNkwO3%~IyAί20zK9TGjU &^g us|=ND q)U"RøU |(#yg@gj#G7EUd>eǔJivޞ\HK33ms$|Ԏ0kIUg;&~Z_*?+&x}ɞ]㋜qyRaM? g1MV <w;e3V]_6U: $Ѣ4\^~u]]i5Ot6٩-F;[%( lN2֤WLU*7;v !٩0!H2ii2.-7+uJ.lVMp%Y̩#$%cKmZ҉e8[D(tU$)$23ꗳEj>.Qy[LM̗W m™lLRhRs1 fhjETFc&d^IԿ^4'@ͺi'r.DG%&S 5;IQ'NBi5~%HNCu?68Rp^;v)@Rؼod56(Q;Qe*n&// e9ׅ_r; l+:9h+IlDAO#3tqM=o)Brݚ]EQ鴚'>Fr k=:mkEFfkatRT܁2D~o2t&^I|WyaQQ9XНjKC%[]35yjLS:vj4Bƅra8)V8z24 Zsq6)mMz#bWY[YLMq'|.7)Y< 2Ol ]Jmu-|H+}͎CVi4t3՚nܙ$q:_ƒcR^HZPgWLJɘY*8"w+g֚eҨ$VTi#[L 5vXJ^ϒisZ(Y>Y,q},Edގ_ɧB9d-yQPҶ9lRI+F ,RdqѯkGgA&J5,el:8OpRVtvwpehXL_<oPGeU<"?a^曾Vam4,5g릺;m53q^zqJa[- I-e^.A[Ô$K(g3TjfDpnPQn-H^ûʗpXZ_RZPDB Ǵb g)/AJ&;5GS7m`I#2( 'Ygoɭ{p_QY6j:U2Xg'Jڗ1N%Qt%nm$VT <&;q5*(N<]]X1rIafe*,HVl=DL՜=gPM^˱No[N:NWD%I:9y볃LM)Xb0r)CɝSo)\]d cK h!KY4al|Uy 25Rtsyn˻21zVsV8/Ne/ e /94&E_jQ- :[eMM`$fΏ4ڈ)S-j?^êoRM/V;:NT/=C^[̣+"S _%Dc'sK'2쐣\4xlz{RFe_,"dZQW*2!ɬ$bKIԖ߲ȯZ&gZJ4Js=E"fR[Ӽ ȩcv Y*P:` KRrrk3_g8k^f 0`b^2&V^{VnNFT&Kgio̍F! Ԛ'ND U&#ћ!eV&-Veq#bfS_E-YB(k;NJєf.H24ߗmlhHׯO8CgVr9F\b,dD_#2,z泔Jqmن3`ʣ/~lV2UVBcGvKyvttT ]Y@%HܾW<^%IQT؃ i1 Q ZN;26Q5$BZ7Q1dֽvʍ3: 7_\ؕ` P׀|G QKeuj5qkYM9ii,Ǘ )D,O ]OBoHQ"b͓.tmk㽄R3lka*V_&D95dLX_ vi5S`G4 Ʀ&:wit #^ V]PXs8_-z 3_Zр Jsc.bdj/- YǺ-2f€=ʾf- NS܆='3)SmjCcQd9A%xLr'666*\dH[z&3hM޳^ꕎcO 6\sf{}7VP}צXI1X8n]`PXkU3e6W ԡt2~7vy:GgwN4u'^BRJrBo 9&X^R&o R~KPmMM溝w`3W0iM5>RBxE>%TA_0[T: ̓w [v$g(ʱHo+zo]FNGՒA5fк^/*^U<ٟhZ$lIUe$M Ttq |L.)Tr1 l{Zf%*#xUS5I\w)02\ܒ6|G QKeuj5qkYM9ii,Ǘ )D,O ]OBoH߫+PDA-A"GÄt퓕V)Rʠ(yyiO}43kwBlC# ߢfy*eaqC,CڢeVވڟ;";)t>q{9W "vEkQ^RܗC մq,,` K3mɲ޼@\BxnOAէFܮn,c:}5]j(%UG:띴Ȥ̺TUf(뀬2~eqd}ded#.B,7bQ;-fUpI<&#͉ٔWf!?sMG,t{;<7sCb%5#m Mu"pهgOG!33WMdG;U P&-TkpG]I-%<ټt˭H",;wk~9! I)19IF;x m.>J9;xWA@o:!*RHm6=1;Jxڀ]IʔaU.en2B{qRJ {١(c")lIIg,0'HCrJÓem~9ƣ Xe~.6_jj.!ϓ0DFˮWb**"aE!U"U+WI(ۚ+#v8**6(=zTcMm=4+lW'-d\JIΐ͆Bw&,^ yM-1|T,>/`Py&9&Lf-NNĠOr$y:㎤[iDgfB dlDVz+p֔~-v,iRRHR@aO-T $? 0ĹI{4Y[ۘkCi,ƽ+\HS<Χ6ˈ.2 PAN-2)פ4)&JNWFuTu̍bXn+>RW_L%dBm#p ZFhUGdփ {r/^'W}DYkYBy@*,SZf*MK|of KIrʼCk {H%bi *{"۩&nP=RөPD)Pep@[QU1;7>ŞR尉t!}O>WS Q+v.ץN.,@h@Sv-|E Ejf卯ح-ጻZVxlUY"73EЗv5o48QUs_V‡s0l&} ipxV"+݀Н~l'I[VKVɩ &;]YڷEM:3Z#Rmi+(j6fYqRue >!h(nZ{(] tNL_K(HMZJʍ9}0I~=/?t퍠K4nHkbՄ޺Y6c%zƞt9 S{:_uGw+]u&k&wɵΗNn{Em\57g܂kJY#G]]5ctݭr*5 "Ѣ7t"=h7ÿnKw:dC7ѸYb4:&Vzk:"Boj31붺m|<;|jﱱLzwa>G~ץ62)ǎOgCscSJH $NE[^:./zcӿZJp<];kqҒ*CI6L7umlZ" 9[~>5>+w8xv/9,#EIZ^ RFկH ﵧ;yitךdnstv1kWhLgtq`ANJ t ˠ0&ӧO̡$ -ȥ-W'oڠ2xRr?L[Ƹ!TZO&2,ZnJpOry-l>[5wؾtϡl~ 7grYWBΨh ^_яQwۏu^}mWS`RZ$Z~FF9CjREBfrܞJ%ƪ& IsTCK )Xǻ>clZ?wvR] NƱNuŽM1AW6B)weXv<暗_cѮЩRGdվ?pjLK[ܜ' O%W}zkaҩ7 ~>N;zލJIOv"mV>Sfކ@60HkҖy~Z-5!_*-4BG\''twe/EId%J1U+.S jHa6 zl.FAfߎ>1+Ӑ[5wjon_C|neJ&ֶ** snvY&Y ŧIP>i>mR VMƄ/jvg;KIuRq׬0gY̓˜: S7Df1:kc5\W1%r)sU77ʌગ+DmV4ZњZr>qg]%,歖tQ2D'z3M\3'9<]6Ory-lQY}mY}rXC 3.ﬦ_%K}nD"ކaf3^d*LE"W}ҝQZˀqW*+Z_pz| &PʚW̖2Mϵ-vPlJR͟kjv=Ե{I6!nhHRl:+ -Ht51h8, #Σ+7U8#/v4M(91qɵ.lZ'I]'T.9z6S j #ǾKS2싗hb)y90,rwl=-|L~ktw?)Po>Sh|Wp]Z St8uPG`tГ*-MoJ}Ocaw+2Uv6[aR`ӥRHSΞztXxl%y!D} "UFrj8U86ƘLՏs+ӫKuP<V$߹7"\!T]I$~p.BM/*e9*YL4ܕ^^d]{2*6`tF lJ( "I[.cס|, VFk=VO:y$*oW lGO\Z-{wcGHTscJ#ɛƦNRd+Qr)#:XV * ^z1dGf ѕe,-1ǗH"XS]{L&~UEz@Hg6؇cӯB2GWmtjطAMj53-#61Z$XW),Q&B%cjJ=gN!X0*,f,f ) aʆe*C+)wJ 2#1םc,4WʎB36̧s94lI܍66Пl\yb%85|c/JAisSPVLUjhM\UЃMI3)EgYpet‡Oru[;Bڍr|ʴec,)3ۖ«DڨUnm;ۇ[7f=pLD0^$wwX#C/B]*[K<6"odyUh㐖3Zc_H:'jI:3A`M ʑyȽ.ud*AR6hOwc 6:tմՌE5⅙}=a n<ȼ!Z$PF9Ƙw/\qmkqv^5:tz)Fa#uueauR? [v߄g9mo+,^Q6ղuETku1 vZ"pz%u,2NyGqX<4_yK)ʉ[S'}CɗxUn]Sr$ o VhVhvʼAnތ9{ M饭uO #h_E/k(!NNȿٽgJTMm񟉶\E .hQ!:@|eN9¥-=Phw2VҠ7:/@,Edk^#*k02#r v~qkEXlvYܖ/*lTlS$#K@aǐKhF;Uդ|ZF~eIOoٺ$C2gO)&ւp_lƹTU\u$RrKpy$PVdִ+kdDk2G,GtMϻI&Lw $jksB3֍Ҷ;)gױղUU->NYSf(q(-m]m]B4oy0Wd)OIj&OƨX6m9*OZմQV4.0eGe]kzĀ]s 2/?KۙPFlJM%B"Gkte*\_/A^) UuFܡ+$$ůJ6)!ʥeby7,q6@B}aV ~DО-ڃiYH&mnk>.0efE!%6`U&n1PuW]-^˄g [c!)b[ytJ-yc4G.W-|NӸĵA8vq Qk\p+lp|e難q=?W\3 /}\>og {fOOy=?W»{8W6^}GpOOc0>A8vq Qk\p+lp|e難q=?W\3 /}\>og {fOOy=?W»{8W6^}GpOOc0>A8vq Qk\p+lp|e難q=?W\3 /}\>og {fOOy=?W»{8W6^}GpOOc0>A8m?k06_?4p3o'x^&bTޭI7l\kS²Ӭ-*5x%>Tj%,'3W%NV#*c vp&0c0c0c0c0c0c+2B>,{GmFicߴJ>h0c0y<2QiďO=}z1#z} `1 `1 `1g6< zی%C#:n1 `c0c0c0c0c0c2c$*ǿh}$a֟=D趁#3 Gc%AH{Gk?g g1 `1 `1 `SocmǫT0I3/?P&0c0c0c0c0c0c+2B>,{GmFicߴJ>h0c0y<2QiďO=}z1#z} `1 `1 `1g6< zی%C#:n1 `c0c0c0c0c0c2c$*ǿh}$a֟=D趁#3 Gc%AH{Gk?g g1 `1 `1 `SocmǫT0I3/?P&0c0c0c0c0c0c+2B>,{GmFicߴJ>h0c0y<2QiďO=}z1#z} `1 `1 `1g6< zی%C#:n1 `cKl<, I͘`Q-5V絗u]R-IuRW; #(~s my6صC]Qyk^sZS#2m}֐ۂ2k{'+`Uf/|xtP,IPrtӜIr@=p"r1g,s>fbޡ*gIyi8fm4+aH6ڛC,h-ٵoɢRۂgV7'tnsm^RRct0?ӝv6q351 `1 `1 `1 `1 `]1icߴJ>h0kOQ[@X籒CO$~O=?yd53c0c0c0?1g6cտc*$q`x[k?Ց `1 `1 `1 `1 `1 ewHUŏ~(-H9>,{GmF fc'J>\= ?=?籒CO$~OϤc0c0c0< <ǁVq`g[^?L `1 `1 `1 `1 `1 `Wp dZ|X#ǿh}$`a?yd5}<{( p4bG@0c0c0cmxM1oyJ 0Fuc*$1 `1 `1 `1 `1 `1 ewHUŏ~(-H9>,{GmF fc'J>\= ?=?籒CO$~OϤc0c0c00%No,PDggrGOڣ%Ѻ:,{GmFicߴJ>h0c>{bg6u(ݛֶ+{cC2zc6ƻwvιƻx3σ#BNf%k \)qv\x5S͑a17)*rÝI/ q$Rsի8Rj4( c 45Bm95\912qZV3O$[" #lcbVIgin^;ܭ3ϟىq]>f',bt>j_m?{;Ro1+߯!]|vby/WOcW^C/6Bϕىq]>f',bt2)g̭#96YN-S<^MLnjZ5 L)Ng4/! dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>f',bt$ dkىq]>bͱfcx~(+I`^)%.Kvt[FQ JL)doFR,anf@c0c0c0c0c0c2c$*ǿh}$a֟=D趁#3sWs)?gZ3,V1c81c1cX1ŌcсYߣDzr/֏G fw`~O7@],%PI*q3Y[ _Hc J)]Gܦ hBe{5ȉ1T5KB]c0K4&@+%y6_i-yQˤ%VӾuq%YhkOK[z@ZDd |ْv4]9ՕkA\YQ*~yrXh.skUS׷JԏӔ"Iq*yMM5oq<~QEʛBBv[yِwū{8W-$7NHtFՊ HMVE{ PZ,@F*ަtզvcOjzkQRf =QuQrbpWwk4IQZuG;}vdy 퇻><9~ cс2*l )χio) c0c0c0c0c0c0c0c0c+2B>,{GmFicߴJ>h0c0[;w8NE:zS?'v-VQRQ^6ukmQkcbOOSm(gL/96Е\3/UM)?]<[f'\!z&sm?^<\qvw>Wޖm߼}ޖm߼}3am~?ӷ ssǜl9>wޖm߼}ޖm߼}3-ʉ|C|?7pm^onۧ"յ6"B n*lRn2zՊM=Q:dʒC1 `1 `1 `1 `1 `1 `1 `1 `Wp dZ|X#ǿh}$`1 `1 `1 `1 `1 `1 `1 `1 `1 `1flask-peewee-0.6.7/docs/Makefile0000644000175000001440000001100612574421673017275 0ustar charlesusers00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/flask-peewee.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/flask-peewee.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/flask-peewee" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/flask-peewee" @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." flask-peewee-0.6.7/docs/fp-message-admin.jpg0000644000175000001440000014167512574421673021474 0ustar charlesusers00000000000000JFIFHHCreated with GIMPCC"  p   !R1AQSTUV Xaq"$25Dtu#%346BCr&(efsvEFYbhHdgw D !1"A2Qa#Bq3R$bCScr4Us ?bg>s`ٙԈ։E%1xTu7apdҹ1E K^ bT"6es閌dvFhFҙFJgbn/=:@rd%̳wTROHyK,qX vjR9q,vM664 #ϘyeQ W#JwpGoJs)9h[$̥1Ƒ'f3蕐 F& &.=˒(H[<v$y5imPX*%$ʐeBp%33GceYHRβ""Bcl $B*HdQѣ bїl}cyt6q6DiGzcӛ4n^Q\?bndy?5"l6ʢѡ wL i9թj]^ڑZG*,/w|KGL1SuH`/…D2XgMYd YhV;:S&l0HVnl"K 4~V_@RMk;'[BZf p1 &"CR jk! Xed豲dq92ƦlfjyP3Ae'cXaGX@'6Gs'۰ހvݷ>u)[t 6 4{p( iQ֙EvHHBU8\'1V"NFɀ-|MggD8k'ł28<I$3GhL.[ʈ[d-dP,ǐأ$T}čtO!R݃&G^LxvLq#\xe=sn mqGMn0}((z{:魰Ms4v8Ч삹0А&b60'Oa*a/PUF`pG8#8#ЃV#FA88>QS n0}(mCxKo_ԽZv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QnیJ:zRv`QՅ*vr[=ۇn8OϯUU/VS"S_dmoˆǥ*3~[wmv]uַ~-{Wn&z;72dr4_`E #i)a#~p̝)Ӝe1;,".WVV-ȑ|=/_=Rg6N2,=kdbTF)=B2DgP@"9Ssx`U7ënیH;z[Ue 4FXb~!1+02XA:1Ǹ:[.iZ— :q#&M 6XiǕ:)><+ [ aNJ?yYFPd4⦂Us|BE6)&nfxvLIl[cmC`p1$ QˀNk 6G\=mnW{۹zxGmn2Ru3ĕ,L}:@ P41,L%ȒRጆxã݁$4axrhI >)c"nVijXev?uHdNB1,bTxg^e(N "4ꤠwHJXxe Hc xSx$!r;8#gEC1d:NuVP{*R>YIƍmZ18߃ʝᨏsdwf `NGΰmx6})GmZ,=.l23#lal#*5F"gk;bٓ\S\}Ls#K8TƼe=u?ϲek{R8F gvmew !k~C)/|K[?p_Fzi͵0uN1A$ $a;S>S?\qr>;Q%w)"k$1 ܄0MUxb;1ӤZ]]$4ectwte? :JWʁU"z4I%J7\ cyL %5* _f1\*ض66@381\21`}:O&^4$GjWIKI&Ko1Si!F-{DS<0SݸGjm,Z`hLn_ ʝ.&0LcB pH\#PlI]EvJcDД>k{9:חmUƼ,ѽ)9$a \R@rWF0>'qe`뽭pjaݽz;]~Oi}Ʒ-6I d2c6T8?K?CDB~3^ogfIjVRIo !Cs un S&Anon/J|X5OWQJ]66~GTm{ /b4_%tji^;ЛMv<ҧ{?7VZJ4iSw˾ױ-&+MeZLWF>?#*~w=>%l4;sk؇pY|Ѧ-&+JWģM?go'gyMo^0^;<7hy1]Rw%l4i'gyNz|^2nwhy1]n /b4xJt۰ h{U!Bx@+y co{^kjZ|IiSewhy1]n /b4x|IiSx˷poާğMT/__xOC,KCɊpY|ѥ+{OͿiSx}w>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|m>%l4;sk؇pY|Ѧ-&+JWģM?g|mZɶs+v$if7]#GhvVPWPaZ <k}u,KCɊpY|ѥ+soȫKnd";~EZ\ۙ=ȯj=eZLWF<)^+;~EZ\s'2>kV;~EZ\__?^ԛ<7hy1]RW>!v6fOr*4}+!Ec 坣_,v{P^ֿnmv#pY|Ѧ-&+JWģM?g|m>$l4;s+؇pY|Ѧ-&+JWģM?g|m>$l4.+؇pY|Ѧ-&+JWN 91>VNS[ r2n8)$k r2M[Ge6׮W-&+MeZɊj:4 jj6fkFdǔcW qg_cGҏކRGK#K6OtӲwi,]1C!U$Wm޴_,]7kMn7HYIM B.X"JBem80[:uw Y!={q;m 9 Ɋ@ q9.#eq z^kd qI> DYboCW#J޽IזV-dHcDy b#MohXi#A$PTAO}v,vU $B"Vb$5#2V0X]Aή0#r;IFX.05HqU((-Zuhh1ă2pmHf-PԺ>rP̅Y*C)#ybg<.-"]k^~>{Zm[ O?'F aR=L=Ch֤INRXޏoX 7Zx6".gd7Γ߂9`YL,t5>h wYV=G&<]2iI,irl"\<[! \r]@jDL0qi"RZ֟l 3`I[%FYDz|wl- lҹK"-$I]5`x\lb뷱7tv]dM8ڨR(?k HbbLo0ĚPhrMlWI'Y2eHY##nBMdi/gDzu~q KtC̑KN;?PDgSiepXJ2$r'5M)L╅L4+LB8B鱕p]wYIi^q]' 癜iyl":s0qPRLPvrM?m {|k9ȹԸpd&6fĸM8,oc*$2Aݖbf+mz?޽k]|=#qv#iExk 싓id BV{x4)ՍhOwY1@rDpBee`~샂*4 m #RE?"**)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JRF$)39nTM-?Q[]_RkGus܇%%zVCE-A!QIQcmXSa1zI">Zۜr(9/7i1┈eK퐤I3XU0zhg0'VPWLoZ?a^ߓc @ZO:.o@SlsT74 @\Aٟ.b9C+ 2ғb%.K A ܰMMyc97E!4hHskvGD|#y:$R9ufxy"&8 &i@#"YZȩA"!G|1D UH&%:cd,トz2U#?IزWoB؟\Zظh "^ϐ۞deDdEa@31ktt|*sy|fǪcq2eNcːS7ɗ #\@' 9s`C6ypO~ABfZlc6KF4YgvmjgjPl7Y,B'J kJLZ1"+将kƒu Y?FRtop@T끝.@~i&L]ȼHljvs0G%[b2p2,r0xL"8* i>- Rq]7)# KbIC¦ߙ#;9<GF]AƏ3Fk);z$XuNG( 6e R7o8=iڄT)m0J3OH aƈ5ZFP䡒hR33l.heNHNc|CL|Eq+ބ6L/,Sigt|N<~vuKqD> M!hnҦӻ1)#)H/;l$}@)gјIHY*m}̌2snŒ$vu?vo|rw%æomRWǞnȒ iā9j$F$w?WVzh+щFw9GEˁ$v`mqDH3?,9:P)}G-HP2[o~TP['ᕑT|J'ԑpW+Y\9)J)JR)JR6U Gu:+Al]eNs}z K!2\m8s0N; u..C).fK'RTl Jh:9$N1N:4^39ܠvѐSAx2L.LWxuZFIe c]I[Oꪊ#QFB[h9ŵ1Aiܶ۲sr150ǸYt1D=t& I*e.9/=j/bh=8 aK$CJqtt9,iJGk ΃sf3;q҃G8ޓk\4ŸOQZ !HJ VjQc!kBCۏevtSzvWonE>ǡPTC.͹\Fg=P@7gR #2ceiH.z|xq|7Gמt[5b%#9(:'y!єMek!ZK(LC:&Ȃ+:h,+|[Z@T3)顚Se#ۮi4R6+w4.K{7tWonE>ǧev&tSz,L~f_;FaX*UV5hv,OVR 7l0 uM~ <ùo#'%.-hƌdbӴo i=yZ3dmJsZ|u1ΦiYi\\@KiM쉬Ǹ ^S=ۗev&tSzvWonE>Ǩ0e@8BP*BIP128ë !9dq#KyA"͜&:+! !EcYti1&Ec60weYI٥;%c]'h$356NB!)spNz6F?G`hކɖA\D"L,r:7w<@3E].IVx pxw:)=;#scԕ*WU`co;BGrų"0ܲ+Iܲ)ϣ['X[&JPJ2Q;ҶTn`Cqg{>,̱ A c.㏂OG|`A3ذs A*܊0BblMv1LAP4i"+,]IěO}bEPKm,?ym}YdTiTM$Ί}JҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]IěOJҩݕěO]I*]I1p{)L7BÔg:p(l e{ +JRěZ&G6)CZ 1X!!W+WkZ}Z{/Q)li,6Zh;+:m!.@PlBdҨ* TLSWF\SDFFc @"ـ\?![JzقVZ˲e%H[{ۜ.gݢD$94079 ~}crg} ibYKFZq4!Y9 m{Q"4<$*3Y7@L2(\$JB7P io 7DFCa>Nh)nJƱA T)RLԥNT*NAG S"Nr"P16jAI\$ 1Sim1c٤[Adl޹45TfYnYFRX%wt]7/xW6N%i<1#[.j6JGȣ-L4^7ǧ~c)6^sU1MSG"WYcrU$G+ubʰo9':4sNuA)mMn0=]:^yΨ:7󁓝PumqlیWNp2sMGe\ve:9u|pXCOK(2 6Zxt&!s6"d%񘬶ځc\Jg i$DZޞ&R f{_d+K݊w9}jfIZ@%EִgR#OU rMn7o2j>qU dVq6ɬjIǦϒjbf9BͼQ1>1D$.7>Ev~U>醱kYu҄3Cr.'}kevjlV!3}.u8 ZZxoxh['[لI_1\Ư,H෸%R%>?mw+TxĐ?iZp,QG[r-g홛]̵=k]ikpvݿ[X~JZԹ%6 'jH#.SVf#ZVC,ZtHL.%%c L;6|a'<.'AqGg| MFAݙj*#S`-4r O* wn2B =xHD)XR;dsc=UxCyGQׯzp|m}XFYUJ p1Z23wFFeV<P,ȴ,H|qἮݿgjaֽ{W3R5=!mP-АH?H0lf 1]twK=>/hC]dDUC p+ZRɮ)JR)JUZ=0/ґ꠱6TZڝu;-[6j=__؋%юq'q )##7KU<1g8*.q'YC='f:3b"7u7, 9AI%$!)22,a)SI1[C,'pݐыXD}ۮ/3L/omp<naPYRIV`yڎcwд HOqnC-m,LGtrH@#M v&lM3U.*(K&yrIH&fN|Zvl8s̖*t324y#-+Pۈ8ep{SEٹZXӗ,S63k;g-r9FPJdM{U8ϻtU8ϻu8@ X`%e;=`d" Q\ \3o & $wқue4$7em9!lՎA;?9YK36edY@el͍T3fJa7\*fm2Rl)qcLxi3VMkYSyZk>* ˚㮱{@BbeG"J+9CEWND}ۦD}ۭ{x٬/)!0 N@DCA`pp%k[pzN ex1"HUqL#dZ< ^(]DHPc ]U­C{ '_.qG0'(J̔9e20SCJOA&Կ KeV 'jsyWG>yWG>7J5-y.tXGXtFX۶xP<DMr"+պjvun 3$'FkrKC$n\M RHtue8%йr\+oP"22 (dy$)K]"KMqTDI?8Yrm&̜B|Biǖ,v˅̎>+.B+Vo1 N2ɥo+sgݺo*sgݺrj*6:tt$Lu,t cxdnƝ"횆s{<1P SY\sQ>y.;.MȤ|^bKeH',\WIX30vʍ+ ;KU +bb\c$nJR4X Au V=Z3Ԝi V rO#M_ΉZ߉uoF4m&!("ߙd4R+˳B|1hq. 5՞i'8R#FijUlmOXmOXU8ϻtU8ϻuA[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/j/:$~37:$~3)[j/ι4l2<߷{?EyWG>M6SR,1)cp؂N4O Ammop'}lMWc٩RJRF$)39LZ&G6ԥqH*&DsZ$F1b9BJO N9!q(# Akޡ'O1:sEH|cxӌi"ۿUقKdѸ&Z+4cUi-yfk07ve{mZԼ)BN'2,ruMk\V<=b1ōF e.Sᓉ᫳stٚ`EL J%1eo6`qT .0t-4N35BF /" FPꌬW9<_LE}ii#,lq:D̲ƄajUfo:{[aF*U^YJUۤ>D҆qPWrӜ$%ŴZG`m+XbKIĻ -Bh jQd~,ĩㆹT隒6z%PQ c*8#868& \&pǰH: Jh_ȑfKbk[‚6 |ymQ%17 {ݕOaqhҋƢ36v-@ry(w53I,Fy^(eh ZTǢT'}\ %gpHäd ; 凡Tk)TaidO Ns ǑYTc 8"$[/"wUCs/r2ܺ\K9LvX7NDXN3\'$ T9)`쪕-$na{q Zŵͤ &R7hgRhhY@HdIS nGVNյ"xn`fh$IbfFUYpAu*6u8)N("c $ےm2ŜY@cK0Eإ)JRohڋTM-?QjR)JR)JR)JR)JR)JR{`_ͪ?#A# ;~/ީ)Q؇jZz>A]fJ${w~:J H@c5#$ ݙ@YJ*@[0P\n7:!D6i%N)b0ӄZt@#N XCs 21W˨*ma2zAO AT|FG5 V{% W$PH1bݪ3b >%`f1R7ngN'2-.iGn=h_$+%A)H LyrkBc J|bSj f6T$:d;:s 6wy 6NFs"|@*Tq ' vc 7)^,y7b4CZDu&-6`BL$ڙͣ#msѓs,ՑlqFT (,m `!p! k[kjTI8}I I5@Q蠐HQ  ??JYSHecdɉKPҥwՠPxM(N0 ,ܥlLEV R۳VrC\61Ra.ñe!SOh.'g[y0IvDލmt*˹ 5{xnh."x\x@Y26UuV  + C'm)d9XN'IbnKbDAqLw87(Qw =EIN - DISLHCtƷCFBí%R1DW9/PhK:tf%8"T2j)'tAuw:M nQfԮX3F 쌳+I}䓞Zw9ydfAٙmg`b @ FoE m;|fntmeJ . 43fW 4@Ä6TK1LH[2!6xJ/ bv|y0AƈjbnNYǏ4)RcOe`ݪ ӦSN;oX#XJ$ʑ$2i!r{hK46C+t=%` hȷѫoզ5HM#J)!.8܁ЈIi(w`%@ PUڠyI:mPxU85vg !|3<*RNTO)?YHxƬ+JZEG$U_`,3b./tNVhO"FQ>7O t7OۍshߏO~:/MՎBڊ=TaPL]4'|` 8"/mcRܑR驤S.zss[Uƕ+ԔĜ m Bٷ V&۞SNj©'w}w+y;\O A$2?M4v*pIgĐY@E E$"n*('0+*T!HLN9 DA%I%%Qa ek[~TO)?_ebqg baƌ=_]1 kk׾JݭRSBQ@ dK{,A47.aBl 2wqĮ{k[JR[?%rod(Gת[JR[?%rod(Gת[JR[?%rod(Gת[JR[?%rod(Gת[JR[?%rod(Gת[JR[?%rod(Gת[JR[?%rod(Gת[JRn8>0خYel`vCD! f!+lJ.ŀDen)J=Ԧ.wdgx\ZVAY)JB=0$*(2slv9*Vzi-MeodOLKD.0i2oW1F 8$fsM~]:wYTGkjt3o S:@''dxȒ@ #* >2c8m7) |c1qkSV᛹iօtjSJ])=k.))RTWtkڿ)~᛾ x>k)JRۢ᛹it]3w S:R4xf@to NM*-.)7E7r>ӥ*SJnn }Mv܁OJҢۢ᛹it]3w S:R4xf@to NM*-.)7E7r>ӥ*SV!ǍӹKK#~!/Z#oXM%{%A[s]LkwE7r>Ӧxf@u)烫КXzшHbG0MoKRlR4|nE# O:ucY:rxĉGM˃s  ʊ=xM( $s~=Y0-q/t;' C#P!kkxZBRSt~1I[s؛Frlv4̹%ãpa-CePPG$SEMC1^v܁O.)vdO_kZk-9rYG.'ϏHv--;2Z썠D ^TӓxBM<*ܽ>s uHn&-wZkտKߖ' ąkѥtBYo N'o @7R_x]!jZ֭e7wquJ$97ܪp?>cqӯiemo6<Ԋ4}s.pǓRTZN܁O.)r+RTWtY{Wsl܁O)JҢۢ᛹it]3w S:R4xf@to NM*-.)7E7r>ӥ*SJnn }Zno?Z*E܁O?E7I6p):R4o xmܿwծxf@tJiQmv܁O.))RT[t]3w S:nn }JTo NE1 "BS,6b, Xl opJҔ)JR)JR)JR)JR)JR)JR)JRU!ptH6洧=m9[z4ɓȟ0#Dik))!/ `+p*oesr9!_;cάV@@DrlRDX* ?`RiGU׵l\'+۬JSzob9!4sX@z3v=r(ANj ෵R4'QH!+օÌ9 34&Xs+RRZY]iLPc%9YfU@QT2:—Z3kenTPyv2dڑ=4嬁$kLa:='mB[&0:65h\DudUcbtER9$pdjbFYiSq%H`(0v);l*:^ uY9:J,Nl!ˌu-PehȖZ}߆%4˩²U0W)RN$b <,N@TQ!2Z-pW6Zg$\SȢ!a%/LԼTaeksFɹXCcи%J))NI0"3 |dr({8)"WdeGǮ0AW^8c SK"&9GEhA>,i*faːF$Q) )p2L8Vxy)*\6Qaꤶ/>[tɍO?Q= x4ɖ7f}RBHo1];Q"Q2#c~C"bi85 tjCDW=$Btk>d1Ъs㸱F23\ŊkDg-Z0`Ll8K1}@ό-c?|hp1xnIuJ}6M65,02 X|yCXE˙r  n`) 9#JdK1`d`=M~܌(I!AClNX`6nbviÍ9T, B"ߠeFr*ӝiPxRZέ.(Z6o~ΩJlr7e-dFu=Y3WnY-=0MXAE!xAblE$[3\a 햄 Ɂ{Okm׳ŪNc1A1EߌF2 rG&R܈U\줇dyr[b, L ͂O#eJYB@#i*eq1ܻ\68%R |csPز)>bX]PAMWS\@R%Ն&q9jFXK$4vi,j}=^FZ3FEɤ0gڮKvgDr!-M[֏wfLsaE/0hZ\In2a0lA"R3vHŅ2fn &2oa|,e{9:u[NĘUx|Bf⩰ ]-FdkRԒXc%A6l/8+m0Iy.K$==d7Wx;Ɯ㎒21eNnYP{6bQՁ- FL2gzM8e¶*r0 )[(XUgYĺ[X4:WƎY݇o!ѕfEǻLN-)ԁƷ!iՊ0 l7N&^ۍ#69'H=⤱Ȗll[Y]7n`2![ɕP (Č[W/#rX_=B̊cDۖ%ݝ$Kfw6 hcf9$kÒ;x1o/'>cVJ4h' Svc4xі&7ogsq=v=&`_-1h[ě'sE <䑨lN;"w?Kk@/wnDL䁴7!\rK-.ԕ8;E$ <\xோ!1O0 J'c[zZ\Ր+ *PaNm=H\v#*|(B e-09ڻTA;I-I+NbFGU0k$$y78aIcpI3ѐ?dܭYM,a8떕/4/24B ?Dʐٹte'Ƅ xqP4-H c®PR̺ , "Gʈ"Rx*V"/"La/qU9*)̵-epZyiBj"2<GRXP&Hp0dXar*-ę3$Qݰ)#lhP%*"t߉wI0TH xPUO,o2L[@郌Fr @iGR9A#-"晉\31:0rFܮ${DJAßކ% eSH2RC_q (!B`Z\KRDW2(fm S+"Qb.K52xJ&JqknCJQ:+-%k2bhӪ-G\ hw[_Y#/snmi]cӎ :֪No\K?;I+`ty&&/|)uR6pR#ŽbJX?$PdAhp,M!UB-j[o)QV)JR)JV;~s%(IB1S Lp&6|>KDr%#xTd#ϑkxG OebɬvDf{fu5Q3:+se%cqKؖgMct{ghg2B6HbIDDâ0F+k*G$I K|cyHO3X}5`5т cy,aV/2;!}Bԩ.qL{9{ 41|%Wc8"\8nAQ\~'$9:%Mw]Z\4@EQ+ͧ;*o8y|PBRV{1cM 2U-*5<#T\W ϣ9Z98JgMyNAK%Չ"VI Zԧ S V^hicKmkm*%jm4-.wڱ,t~(ue{t,"ą C<^C29'XZ}yƊ LL[dm~ܺ968c~^O YJ\~h N=mU -XvlmlR^JA:W~,-H$Xق,TLHU69E`|A6i'J(+l)ȥ ԥ)23G H)ޒjw"`*F]7>/gǹ$= wvU=˽ˊ-Pz5B0Ops{y$sF7uHøYΫm:O78O$EK,Q8i"R6^eC);+儹u42}3vE y 4|aQcE7Pa\QRZq&PƧMZ*gwjP5!q(lA٢`qsR5kpV0k=X )myk״gHm rv;ssc'gz\*xcFڅT Km)JVnR-"5N_HxM)UR)JR)JR)JR)JR)JR)JR)JREgyw;o}R%n*+Rs,Bb`ecu\u8 ?fHEAe%ʁZHXmrI7k Pc %ȽF,Y0E"ԩn8߯S{UתJRlw~MqWs^}J5,U塨e<)jsv'IF+y*ZX%eV\jˆgt)r9lj8z77Sm RG"'ec`,!' nf>^K(^k햝$ַ-2C0͹+9=IDkc Uwnt uxKR U"1N5dLȄ2$1 b}7]z8jxW G◴6OgTĭk1SKHyf+FSy$2(kk\IimeGEWI1WP#̧V#]A YbfGn7#UrpQw]zlw~UV*T]qWs^8߯Ujn>K1(cA} ň6S$*CΈM;HʦG0eeNRSMR@۟)c_s 53ʎRߎlw~MqWs^" &N{q!0Ջ߲Z Fbh;-'rD(pÔSrb~Br]a|1k"`'&pѷxTerv|_ "Httxg!PCQ..g+V`Ȳ hAL?a*A(H T24DA쓃` \\qWs^8߯W\L #d +`ɖѣ3_(Nq:Vz@ik[qg75 wfAdH#ώomLfօ:4>80cR:fmtF u'SрnVmM)+Ke^p ye0%fWB ʣ*8 {vbo}7]z#o251)%Y^!irr7a,`yof[(1QA"S *˱=4,mK2ڦ y.8!x4wiUJhjlrqbҔm v=5  #sv 1!{lWk^8߯WY6sNڰ71NoqXHw`=D3A}Q rMQ`ϰP,{T%d]{%鐦nHc6dD8Y5 !C@NWB=G^⦨r^c*X g?LKc!<7qQ`xʌHeo}ש*wwՂz~KFU-)eTS4]7N6uJ!UvT'YBu×w=Ta-'yr8-A7 @s%ͭ0&[.+|XL$s紸-mSI**q$ew2H 2?$ȃkmqWs^8߯Ug{jϫ޿p_ZҦlw~M6qWs^)J}7]zT**wwgw;R.8߯S{UתJRlw~MqWs^)J}7]zT**wwgw;W]KIT 1=cX , d)B*nT,*p[֕]cswF7X0qe6ps_"԰{{9<,ʪ 1 F88E.`,ĐTf!T*{o}7]zܵ?Ù ':qMer\'n]1'(ij' &9m M/'mthdF$Y$K&RQ\EɒY<>};M VRgҒGm))vX f h%E26Y+7»Fgw;o}VJQw]zlw~UREgw;o}VJU{Uש*wwZʚNJzRFpVg~(qzwt9%݋U@H(sHٓclk$5mR>ȻzO^x{^(#s$ѪkV\1sdl5 ICQ$ fFy߯Vlw~]IGr\na4O E2 B/Rw|;a n9wo3#M"qA;2")i Ւsa@>OYVƛb1P460;ӻ \iD' V9 1!goF:qZ^CW bxn  Nn#؟1 YxI"gY"Ѥs F RL]]9h ͽ*wwgw;eO)4mD:xKneM5 *\$i!_4W,kUKjopvj=d̘/v2U7Pj&NKlT%ppGۏJ7cEK͍1#!\Y!:6B%&Nnc4I^4]|{.z,eH*xᐨFI g{Uש*wwgt{&gĔ0ėiAJ*E!6/ q-Iekez#/g>FYX (YI  W7rVh:lnV }7]zTzڪ.8߯W%+R4F\Sc]ʿf^Hv{XJN,"|,`mk"+ JRƪR)JR)JR)JR)JR)JR)JR)JR\KqBpSZrX <v#JO80 Fڕp F@H)L] DY$L3!UBNkMiÿY{ԩ*8sZ^4njǿ{Uگï_oۇ^}v{8oݵENíw_5^4njҦWvM*8sY^4nj54BspT Ɯ9íR4/k_v{^8sZ,p7o)U4yY~;C\ɍA}) 31UtdFAKJ P_4q::Ѝ 0K$3j ,ʰSXmQ6׫m8sZMu8pn]Q >8}j8>Yx?!SM\7߿P 1cȲy6lwz5#d]s/BՁCV^KacDBfv˅|;޿6"rqή 0;:ϿA=io_^j|8sY.[Wtzpv|MLw5^]nۿs|jn^4nj ^nMÇ[\q^)SM_=_・_U5|__nP̀eÜ:֗RWotz?>SZT*sZn8sUN;~?JRveZS`/p7SJR{xӇ9ulN֩JR{xӇ9ulN֩JR{xӇ9ulN֩JR{xӇ9ulN֩JR{xӇ9ulN֩JV_Ww_kU Ɯ9íVxӇ9~[gjԩߎwomm_o_5B*p7R8[p?]׽15/Щ_W~ݿF5[{];p7ЦֺX"pnݷMíR~_?𩦫k_]_6z]֨]+j}_nkm6W4n?ji^zkZ_j_jjNM÷nXN~MiPiÜ:6spTM)PiÜ:6spTM)PiÜ:6spTM+M]8sZW*p7JTc~nsݫ궖,6k~p_6 _~8_q?W{Vlⶫۦֿjk_U^}Wpңi׿w^ֿڭ^|4wx5[۷}Vڽk8axӇNڭvRZϟ_) p~_ kPiÜ:6spTiJN֩8sZ*iJN֪Pv ( 8XVkXV R*R)JR)JR)JR)JR)JR)JR)JRgVƩ25e/ S2)Ȅ kYա[b5", 1w0"uU="rNY#e0ɂ)eRf)FH)]S9+RJI!2`G5qhowMtn͈\`2\=!IFG]76ȨS4qI9<0D@JH(Pp\q7Y}lտMJ%rVnxyz4&U*1d ap() j++ÔmlS {P9:}TB!q ܈60Ɨ&V=/ i08vM] q4[\nWrVr5ܱb./}zo_Wibߘ.꽵jvݽ>; (폇L$9I*ʁP!۵eYV<˽F[aХ Pe+!U q`v I0SbΫ^4O,SY?YQJj pnHP/ԤuhZݝ⵬17 +Z7kۇگ{pV\Aj~z6wC}Vܷ 띩QjGYX1P&Ȍ!X%U+RpwűofiEMJITI•_Vu6MvkiU2Kd7y7,`NbB5ˁ qB0 L4S#9xʱ- rrP*t&lտ_7 Wwomvxu__w5[\c9$L7NEiXa"dw]T2 p y1 FDMԘdMP'T"G'DwL,Ϛ^ 6RGɚEiPˤ;0b'w }i4$+Y &dF¦2}elt.nQ : ,EmoWk_w+K=î߷}}s ْX$n]Tb9gL$by b@۽mmTc<+F@& g!J7G̒9*_>akyZZGreșbmәt=FYn[FNKx.1$6,73Ng8g(iw*1(ѳ-7GJّdA92rUOǭhZx%.sEc[[XonkkpvrppZzj`ĒA& ccPêz8G-ݱ)̘&> \u0i t2byIDDIfkM֌|Sicvg5R#d>&DoX+ҫ;Qf0!W?R1ƨYj.2f%wA;$M|`|<z%Q?`jY_WmZקc~h߃_kUohM˶N:1!Bڣ(Q^Nd"Eޜ{`[ ;.T㬿,oei  Α'=8ҧ"#5H%iFcKSk;#cT͝4܉"IڨaT Wˑ2(V+݉w6%t/g&ˆ] JGo=zz7nտڵwWz\w?Poڵ5pG~` )^б @!;c>꼥EP1X#G4ƒ7dxyzE8s/B s˧ͥ2T8eOy򴭱̕h4Ҧ+//OW;(!űC.dZQ=R0{ۍ9%;7J&3FXcV77,zX{"nVw#v0JdG,& `* o#ϑ|.9b 0bf9%B"a. ybo!8ݱی 9y0[6.Vޜ"\qԱ;&wa0W\V}9L@6,}0D(t010ȡXK3#hp.(;Y&;K ٘ 쓌b6ȥt8CJ:kHC(rq%%/q!BJ`(*0$ %6\++w6?u^mu'%0\KN%L`BW,w3yYryrH$r @* ǔ l84IR2_>@)8yNSHKf:R$㹼l VhcسۙH`[ֿ~zlEGnï`+/= IK7n90P n(p0{9(Ri_[EoS`>(Ri_[EoS`>(Ri_[EoS`>(R/m}Zm+xs2 =&Yұ0:ذVc~0rWHnA33[>I)d1) @r[IL@{z-;}wݽ/ڽvv J味vBpO S4q}JrW$z!HNv!?4<Ȟd9E$M]8P.D04rKCHraŲ9$sSq>yM `fGt 㞼h=- /xdy=#d+DP&1"o~kjvDW}pvZ|?~7[teޥC2fpcWc\u*jP%_(`"2L2 iNfv`Đ΃l^גe8eG7)K )+g"GxL.ZppV-n }kc_nk]ꑁ>|Lb3"9fQf.g.@MGI(K>1 P-dRrC$'I ILo"Jej,SK%f!M__$Ɠ+f!d`f2E7%| 씍Ue24ucΎd2ƶt)6:N"T^%IT75.`MӰ]2)+}srŏp _7-~Zߦc[mg*dl0y R6@$?Q̠0+#s$N%֔M5J/EoRJ/EoR~ rtU҂<1PKhӄ]HMsEy) b)=00ˠR,P;$_u|ܱ+߆{j׮?Vi;KiOj]m4Ȳ V*ű<<jj0GWrF+1KM7OB "Ջ\ͼr&[S hJQI+E PLy#;d!mIoy22 FXܦG.4/Ns}#%5K>9ǏbdAOeP)|J02aݦ?c pڵjb {Wjn_xP|-*2 i$fai%eYDTav,F+}>Z+s%`ǥ gHF4y$"Hi\=h8yٚY-'9~SxnK}7MY%CccBֶ,} گV~v/]MqV+FB(WsmD]UFz}Vp[Kw=) upŦf,Ns3mQ_Vu6Zܯ`>(6VR+7)UR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JRk/_^gWTH*uȄRu#HgS"4d )>Ŋd{+|ϫܮ '̈Ն)%GǓJx^iG M]S/sxZRYY{t+l0m< &Jb~t/p?wg-W{N![7>rpA(=(_]0 ܁km Xf$.:q]1 1`,#S|(+p50[ջX;6(!1IT) %8̱\$&<#>#޴q⤝Cn}]|5Amw[{K4yE=P*:P3IK\\qd%,ҝm0{|~]_}p;AHZ6־Aj)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JWx/E/_U׷~׷*3 3"6׽ RJ>qv9GjX7es2b( Ec + d,KIIJ9A),K%mn 46ώr]YXF Z;<.t(LpFO^#8l!"Ք?CTxh0*͕!HoꝕPHztK KJp=;IS px>;unoynQ;~݀>TϮAϮGcOQ`%q=Hnec.Jg'ei;gW".v!z$"+WJ}O46ώrQZݯk۽{]fOϿ{Vw}Z^AG!bC h5* mLȗ7;%ne$J&֩Pѓy|v46ώrqi}-X2E9A(Z48 ,3A. qKɻ*D ߙpD%msf|v땠㜔+lL!K,0Y" }U={O~OjWikj޶ZҔ)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JWflask-peewee-0.6.7/docs/fp-message-admin-2.jpg0000644000175000001440000017235612574421673021633 0ustar charlesusers00000000000000JFIFHHCreated with GIMPCC5"  b !1AQU Vabqd3s"#2 $&46Rr%5BEFuv9Ww<!1"A#2QaqB$3rR4b ?)~Px{ϔgX qվc7'D!!qN<1+jER8#,c 蹝m2, ;Dȫ J [v*<y @jWOnz]ߞ6V??W'WMM!r YGrdYk!JChQF*wt['k#utݵJy^48vX$1ŗeY&8Dk1JF[[ T@Z!Ka#PF ddo*=jR. ,LJalPFFsnQ+qڿ_oUͫծ?6{Z ѯ.f!Ad%5BjXI(֫<[8,1J̵3 |4>ʎ%Gaѥkɻ؄*QF Wix{n+[$f9 $ep/v#UA:o qʁnG{Qr.Ox(93h`I-yBИCYBX BY%1W1AHY8SI\?e hbfֱk$o*Z0"0e(P 4AeA|U<̣,eH cGnjPRpO'<;׬X)\Sf!1I(Y &+nA'.8QpL!7!0:$i 쩇2q{cwf[m-brM @ekʇs ˪F3%F9@fpx sx<ǯTA4:< qti {u`a9i„xRu Ō GehH Yܛ ͐kctὬ57m,bp2IcF 7P9`r^Jd%pNq1s7 [xֽ/JY>ambכ q; BfX(V+Z-՘U`#iK8EV׾YiJiQU,X3FӒ˞oDD ąNͅ^[pr CeBCĀyb@BAdwTR] ,@JY_92df3@,2&06 JbӋ](:XF ZL'qSs~7`h\"P{BIZJm"Ob7^Cy_1pc;\TPĀcĀ 鴜נ_U{Gyz9ö7"@'U3*g!. psQt-8oYsrw"EGpTN3)`ąH?#b#[FicX)w6v$eQlvPM{Vjlѳo{ۛuzmv{=(Ӫ 4Ι#´:1E65%. Jݜk,褝]@ӊNI4H$injIE4LC+!+ֽ$F(vʎXgdGX%'e2)$.5Ra$ĠR~c4)IMb?tt__ݻy}6Vth*Pc/^/sα\\Y`f?N'F&{E{7Et=.[qX˞/`mK(ݼopZM#4sgL Is@ ՕEƋ^豦u@Aۑjݥknm[gd׹7,F!H^^tSS5sS'tm8b7rJ0\~TPi.v M!.N>0:n82y|!XHJe ,vNj%d%R^K ^N.,umVCor,\`p|-:bKiҬmQe8{dyPkl {:48Fd GHQ,RM/-统ltTCx0 a AG 94NF͋ʡIZi. 1e|-8ץG%qeyXw(=sM `0tfcy\"sVc#e;,"/D%OwM;*r3^q./5hb|JnLMsDQWH6Ȧ.;o",nR2.UA My}m:CuyI *Eq.>DhjmYћly'gh%#v1f0w;to썈|"|9\=YcRcZ5&whn #KFA"TKAd\ fhK$IelzZ"5 ]s2dKVp X$wF}l7T`pg3q={=̠ssA|1Zf@$Q4c]ȸŇ)h4FIW8D6\VxU˧Ao!1_ejme΍15vng@ʖ6Zh׫kQ%GbT2/ۤ@HK}D)Q& 2ܙ $ې0v?3ԛ1h- 4NL%+!L,.t83Xaljޤ Ęqi <˜9?r?g$tFkRt>} b b09W<v7b]'hLvJU]Kb-4G)ĵ'Bd XLcq2=,J$ GP!HJI*/!2 9%ɺj#0c <^Q!x{7c%M'\D Z*H%5=dx5݊ОSًCo,x#n$$JJh=@7$jVZQW T`WtB>t) !Y 0ۣjs:2hqI,}뀸7 4ag^ѫRν %8cu6wC4Rӣ?hvoM$C9;!§ \b9MgP%ijd."nR(ng(LmN1'X˖\ dd`Y(XPRH.ٴ9`l! HJc!\1t$ҾR 3#հVc[Uk$=dCrtD΅ ޠh HuүC D]Ȍc%9.!lv$*0ȺKZ ȻitwIct8"{ꁜۊ.7E屡捝QK'^Ot&i&eëe%` ]`e@$O(S\Ŵ{m R 5lF",C4Hy.+&xiaG* me䐙If0GA%Vlc~ v|c-e-ni0q4Gcf˱J!9 :);oa61 $Ϗ cnGw5txkGȋ[M(c6oU#lrq-+VŋroHQ,OLe<fӂXYD⽵m AV$ttaN,nɝLr7m ۍ14 VVݗ_;IhL,9!hhQcL$ t7aO,{=n,*& |L9#7|Tۤyrd,!h̖#UTǛdpe {}nm'2F-0͙t- e)X% ؟%% g4Q5-KnꋱbTsjc ߻uK. '!ے`'BP:E=DD.(AnnEak'WDhTh*(칩D´ch$',-sT2#PnZTkU@fj];_4"6IjKDGAtnEaڤϧ0?VWSU铷qPaeܒVچ0"6ܳFp\dVl>xODU'rIVp!}'hJlZI6tO S=890D]l|.ZYuT?o>g6_Z{|՟"N܇Eg:3J#~#tqɛ֌8fTDy QjFۯ-NQւܜ[&ͽ6] 3t\`,)ǘ?CK iʁ&l a-mB^䭪/o`q'g% mi/. AL*#*j]xanMN'pEm6Hդ$:HEJ/txdh="d]3q~`Ee—$X$y4Ęↅ#bZFW.}[a$"-7fhs:-Y%֏,6LIf6c [eV:)S9$<<[B&~4xIx?pO ӤrkAKӎwd4b8͝ݹ`T*D&מQGW~fJ`vU/#ṢC:, lט VLjťo"8 ,7TGN< 5w}'c:dGOa^*HYLJ {3iå2nuߒmsXdV{RWǞtqB7ITM4f'iLꇅW!C P-`o V+3o:ו6?N۫'s?@=/prN2Sن=hI^l\Z H$iI2j)(KFUtvr*gi%d;cdJ־>ƫXeMfpVcw;zYY.Ycd % ʤgs!GhůM"-ox'ʄO`p+.䦈Dw.,2^]kJF .6K%ͬ-TJD'/T(o.􈄮tT?iG`KPS@P $LcxPN~Tpǰ.涌Yw+up#a4??6 2G|4IL0G("'ᒏXR;Z7.=.;=M,*~>ٕ,X KeoK@".B%ӌF^}鐈I4\Zm陙IɭWRmAߞٸ/dD9P _+yo_>}ڵV=Ҕ)SJR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JRC8q?t)J6_WE-k6뽹뚌qV5ʲ6ܬ;sJIwqgs,fWX;zpT`R7[/\_P{st{kl`8ug8egjP늰ml{{9y믣mWug8eg>O_fon{kٯg~kk{nU^YgfϮWz͟jOO5bJz=fqz=fR_Wѯ_׶ms[n _Wz͟ŝF}?+K:xwi_M=3ˆRJk.Gɑ2:*gJJS9QI-d1q1%-04bUmq=HmZ }*ti J3KbU/gFﻍ^Y6Wh޲}|fͯ >^Axw铓vJMLKp,hFeu`' aU! UZַ7Ett[VVujoվt{ ۶MWyjWe&ͳL,m,Jm׫=ߦV\5uNx:mժƯ},?)Ư}?*1#Ӝ˟i}꾽ݫgn}}nn~ϯ_mWeg8egM*ɷm~U}Vۯs۞۷m@qz=fΏvU_l|-P3s}ެ׺mZjlzU˺=_e56WpJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕdVý)~)8w 4Y)U>pJAqiH=.#M)VJUo;Ґz\GqzRKSJU[|ޔ?ҕd/m ګ|ޔ?ԓkNe2P H *,rN&@DBNyAQzRۃAqҎ?)S5UpR}vCm"UCI<1MS^*o|犸usVqj>W_V]:\X[VSҟH3̟"+} & sgX6X݂@JZjLOβ@y*pzF+%[Gkk.n2876ʑIJEܫm TΨUGl.&KTpO""&X́6c_M/*ѬwM!bq*H- m~j`bcnCʪ|gi9 jQG!N2\|oi@bKͫr'bzP7bDXkbyyKrbcՁ]z-sks{poýrXtkK۴bVx c*r: }HND;ѢC<6TGKY`y0 O) [p/hutq\C`ߙ-fTT gQȮ͖,q$W$u9ńL63i+d39L M"co:!'k㗂,BF6rO%(U{뱄-67@WhkhmQգLAΫ:~ѹ3֒]ERc`-,˰(䍸o|S|犵R=+3 &EǗΕey6B#@YK\u*6LW)ʯ-h x6AӧH v˱,7S4bWv|5rVxO1er:"NKeMƪHvR|~zO`-쁖i=[˿a}רaG2#"(9yH%R [p6Zr iaɸ6# ˝/*o|Vqq:غI'XPLE[Y z̒)I,/y?MFƼ-Zimߠ@sރ{M j̎mnJ @,r! C_[K[gEfh(c$Im aIKo|S|犢w7xT7x'~XS~XR-_M/*߯/8߯/8Ko|S|犢w7)R_L\#G<@Jf8!$#p6rЭ鐌B2.奸r wfJH;yiIo3{:M_ouqjKY巐RSA#8{[kȺ7pEssYU+O 1Xr_0>@t bɓlAS"!u`GkReW]̺ n&kl%A$aZ(ˤM*PMӻ7H}d8p9AKJRC{ڳ%$4䤃p?}>雉vl]=pV/SuSzI[Bzpܙ;Ou3X9ZbRJ1~=!:JWLq91)@ hcy,f%Umrt^;dq1ݚ Dq&iBeX)j2|Io3{:M9) og\>)]OQPoFŐ Xn$;G>ft,ͧٱe(K! W$aTsVi !% ē㈋bbȍ{B@œ!Zpڥ_0E|p '4i7ggEon+1m9Ϯ/. ;=s\yRV䤃pv7԰ %0 d?3A`}2!ȶ- RP=W)ndǛHYZ+FN%JE 79AƜ=Ѧ1L$aƔQeeAxJCa0Xè RAθ|SNJH;ykNI$I]Fgy;YKNI$[E10ƑEGjUczkgG HXW22<7rhygtJj6F儜$\Y'%VS(ŒoOSqZncX͑W!󕼳 *{"T#S26E䤃pv7Ց]\ <#vPyV)ᕧfB 4$)%$5q=+M$̈#S#@rrNpmWmEMܨ2͒q߽tmyomw䤃pv75]7x`o0?]) og\>)%$4tmyomw䤃pv7ҕ}iߒfurRAθ|SJWM7o~JH;yiIo3{:M)]7x`o0?]) og\>)%$4tmyomw䤃pv7ҕ}iߒfurRAθ|SJWM7o~JH;yiIo3{:M)]7x`o0?]) og\>)%$4tmyomw䤃pv7ҕ}iߒfurRAθ|SJWM7o~JH;yiIo3{:M)]7x`o0?]) og\>)%$4tmyomw䤃pv7ҕ}iߒfurRAθ|SJWM7o~JH;yiIo3{:M)]7x`o0?]) og\>)%$4tmyomw䤃pv7ҕ}iߒfurRAθ|SJWM7o~JH;yiIo3{:M)]7x`o0?]) og\>)%$4tmyomw䤃pv7ҕ}iߒfurRAθ|SJWM7o~JH;yiIo3{:M)]7x`o0?]) og\>)%$4tmyomw䤃pv7ҕ}iߒfurRAθ|SJWM7o~JH;yiIo3{:M)]7x`o0?]) og\>)%$4tmyڒr#Qsy-_%$ (S),\-Z^HIrxL!N|>ZTi Py`zRWۃAqҎ)J?_u4F&H XJ@@,Bm)=AI AW`i{JWxE^q'4XU0ׄƜa#q? )V*Uw$}'?qHO~JU] {xOi>ҕbUU9Ha yNiۛ[XĐ=܆]ZµL"XB'Baww#۰A0;w&Vf]aZ׾^)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR p~?:Qt*gU^|s8X긣4X{[[ktZkի^ݞK|9_گճxS-)lK(.Z|=yƉFH#,3UHe*ma?/uoY[qUbb~.,FT>v{^׳]<=\ZVνz:Z]tN/샌Lŭ1B%Ӆlk[ dNzDdgǙ׳qH`Y.r-1x *'%,[4:xgLxKk\" e\=k:] .' `Q˃*ra`Hfʠbx]1Vu%@PFv;{m[ZH /3. 9J1Vñ2ccf`bqY I t%!mn2D"9,T>B{sX/94F0lH !13vM5!/w5$h(ܓg A$$NF{21xz6}@Ii{__mexmZ+qH+9\dY7J^;&yXsbXҳ4ɚ‚ə)g+Ը!ʲD%c̈́L첹QQHH$i$yu&tJqV9B87]Ȥ/?%)\\#&P0ېxITO 6m}>u_^sUz%oʯo2Zo:gV_sz%wyVʪ+!sXǪmV۶Vƻ W뛧V LF1aH zlI LMPe7CEK+$BpXLCbo{{:s J-6i^iD(6Hw wI"/xm2}NZD"FDyeT(HʋpYbp+lt뷺o{x-mux+ռ]ZvmURyJ? Kw\/edɎLNmD$L,vhȡPU7y ,2]AN>(<2!f].LWY9jslVq55x/i{Է.UZXFIcetpHaFluA}ddv*#y Iኁ p`2Aծ{\ӯ/W>oܨr2*>cJ L&^W1JiTk)4JYG RZ5tȯmϚXx \S8YbFK]{Z҄[~0˿^~ՒJR[9]v={}\MWׯ^^G/ 9sX̣ȱt*:kСR : +) qUbi]ƳC6<,כQi³[4r ')]ܪ63,1H@$`E[K ׶\%?VR+?G TVגI#}nzGG<εɭ&# %rBrFXS"t9G< *itcE)&ͨ駬QKa em-Lj$jU77?wSӰŬ]to,n-഼+?YLXĞJK i) XcEyDSyqq @K S]y;e̕&Y0!;۝ IXcqjq$M4[)ĕrtǒr8]8I^/h5G"3@QaF`M84C"Nr,vufe\?!${jFiZK-ZSV+H{i"'f2T7, "T.znezRF"f|_vLyp3hghkg,b&G˭x6 Ju"bӏHW":E$Ybpfr8 a/aF2Lܔdg1!J'%\ΥTC:$Nl,M0c0eUU1«r&znci_-?8:-#MTf2 wBdP1XT[[V{:zl9m.CGX[j02">VW C^WK蕠GC9E^M -2f 5 ik߯eX%d4\ ,2, 'qj^Ri+Q #OIk%"X D]㗐7j2 +''\q$7f(B,yT)JRnJ8󎔥LqGhc3+x *=PuOk,Ȃi&h> (I$CNN^_]W$---%g4QƱ`-=ȶ5{B[֖] G`׺T H cW\;кA{MH@ؾD@E fujC5G0j jX18MUҒi'{"\XZa`8lN9ϯ0?a vz ņa,NlęQWr%%e6-j@kz"ILy1$O.ĕ?hLjַ9MrrZIu1\[k.PzV`XƜ-n￧CV,R99;C|sɩwH@|p+xDȔlsy@fak4^$&` F/Bu 4Qɯr  H@(LD+HE}fwjR/{*Ri+<E$h8wNKrnn3+<:Ow":Ow"Y$@H$ ̢Dp DG [[zroPw.AK.Fa wFQl%Zdf:B858?r PYKY^BčNVh)@詣f2 1 4DMH_;(DQ7="p$ILIv)(\ IŌ/?{ЋZp?{ЋZ?k!cVae@w,(^гm^m]ǞtM,.O,=2a. $7=ch,. *oKU9AB±9q&*:U l &BYZ[{[HQD&TYe.'y~ N'y~ TE_! L\d`UpPpE_.NwOae3of[X$=E2m\700xRh݂/otEZ[emXK9=U\E>N;[YrW+HZoRU`smֵ-*nn'( i%ؤuy!p $udxcA$ [$lw9ҫ:Ow":Ow"pnDs[bV9$Rz3a L!zsL(bGCmkӹ;+ \)owmV⌖^@Re ހ(oXx~~൳ rousS`3K2Q#eY ]3egtIsimq$OS<%02¹*<ٗt<D]Yzr7ȱ|j\ ͭ+hi4CI8DѬiIoKB2[@σ^B G,fnMn__K-a?_+s!j2`"d7IJ*V0[ɚ%'gv<5B&L2ѩOfEX !u11,q\^!4NXbdYBa`̸{O[UFS.cvFh/nfFhXْIYY PՃHm$y#Qಶ˻QYz~߹g&?oMr.-JʜSwDyyȚK~ XOUB軀$mO,X4A1p.t۬:R F+n\.,ä7{B/iä7{B/k$bɨ_+.YnI$rI95iZ[MpF݆ݪpc#nEmQ"L]X[eǎxuqсF2ne27(EVqG0/u.V$9N]0"QTWb4IrVy o׮ä7{B/iä7{B/jGywygfʝ1!$Q4H#E J01bjXnnky:-ѷeW8thE-8thE-kVXU'y~ N'y~ J^mERr6Xy(3]Ց㎩^؜7šQ%\r$77o)ä7{B/iä7{B/jfXY Y"hD! : @ U WIG<FM ȲE,R)WH2KQS&rq$c @Xqk\kdT5'f] ŤJ7QHq>u%q{ vU)^u=Vo v)JVdBƾF Ē ɰt=1ckt־??=+º ,Jh!*iH_qyh2"9,/,RB7F2J[&nl=C؈hؒ'r)G^IS8'z< `w.py=)Ut/}^z渽WMu_gPN1 ~/ukWmk\v~Wek{I\Ӥ#DM%pT$cQ^B0/ЁBcFb@IDXl!P 7I B(bL#^EghIأ.H4cjGgoRq(N\I5jXĆ=*In]FVPZ, ^ =mώ4[[9Gcw>{y,t%l}"ܺ^ەT(劬Vkճn'{[m+Mp7NxFfTmJ -]*Ť˚/ eKo .Kw[!7J Jcl$xEl8 [ ]fFI< 3SL,z=6ŕ؀,"݇Ƴ4E-$[+k7ᦎKrѸHXĒ2ϟ'⇂XMW @xmZxT3on$BGƥrǵk^ustjճUײu9^9 &ĢYl~pNLYY#r* R13s.1t ,m 7k@x8<#r9Rv($JG1OuH2QY 䩥ɞ8YdM8qE4Z\vPAe{~X{}^R;%+p1ԶrRR՚~&>vT^V[Z]3 $DDu+IgR(SJ+)JR)JR)JR)JR)JR)JR)JR)JR)\^{W5իkJRϲ]\O?תI]%_fHiĿ▔\G=:yq -<>:"YmT*5jI4Jw5{+$X]boN8/=dz3ZuAܥ&1l͙Cc/L1I vw:=@ m<'_iVL M)IkkFdmUќsw)4Liw^ВI$bHOp+#481inWϪ]]\J/YĴ{Ö]J}-tjbu2{KYdr4v7ig=9bWFdζzw,1:cy?tp9u۞qa òݢBN 挄fzD]xcWR  Hn"GibI'rU_i7d3.apT#B%L0R1WU_Uko-:rŊ #tX<-8ah#eƓk,'|qI.%mJ&5l'lN%e%5-g.rr,G$ܰ6'Bs6d3g oaY/-K8lZ4u SҥJTlxYBZmyVxnxkU0ʹrȅ Z[I& k{Z @4DYP<@L{kz:=ο+I }|^~p&&r32F&myٱ-F (Q9ֶJ Ek۫Zm[9usz4ê$6FVR}3Zu/\oբ2:<*܌$k^t|uqm55׫JR)JR)JR)JR)JR)JR)JR)JR)JR)P?nJRi_=)JV+D.8Ē,JҿLZ^ԦE7hnBµraQ+ɣ)2'v# )%ݽCy (v 0Ԉ1", ֽoFҔ-m:׮kRxI=6RvF~[V rK0ZpC\IXKijrzFXJVN,XV*H,IVRA2~jEH$gd>D9$MC1( 36ܜ&w1FfOn&6J_Ԭ\N 2İ$b;22+| nU1]zWb91?I|jNK`;%bii!H g}RؑkSyNlpY`dpL~Op{P@ |ıX?G]/(f>kėg)+ʸm5q^}w|o~jJR&8Hר|BFvld773%RJY#x8729WrFbqVXc6fJVl8/&l/VCqix\=ڭ`[cϫo]+4kk+-{S,mumȩ D3t[1G<7]O{{7W*H Syi;!EKjn4dg f4 @ ^"۝"IGƨs4тZW5K d*Ithu,o=?6z[^of񗊮L}T ԻKpbo1n/[7¶,6K,W Ɓf;Xm$VVmϐcRWMJR)JR)JR)JR)JR)JR)JR)JR)JR}WJRM5p.Ɇ\C5Kfvt=F7sѱC]$2.omN#462n4M#$kKʞޛEVf+a e2$g&j>K缟8^+5/9bp串;)0\'FFsc.kțl/-㐜gMeyvۣeFk5o2b vm[v,֐^:'٠&-ltbBm **j*sK'U>̷ӑ*ti5I14`Q0ݴ$V{AH0'Z' [[U6۟JuMbXx$vV{FXU7LT$H3^ƙX=c8ˬහ0 "6~ q kZ=>K)^]zԥ)JR)JR)JR)JR)JR)JR)JR)JR)JR p~?:Qt*f&GÑUrBz r7{յuֽmڭ }CO}eҕNd rd r*5١bE)uyn|v%$|qr.<%R@ۅIZNJc(6;YDbyݟFFFؽ_x#kbSSe5 ibPn$ Au*ɶAɶAn/{lkͳ5mRNMvBG/NMvBG/Su*qԐ@ie\n -wڐ T3*@X{rp*3lSlT$,b8%ۑsPmqw l^b #^ӺE'LmH-i1ݕ!KV0C}q?G&;!&;!.D3 ԗ10n%A;82(6縍,m8geBqn:ʉ{8{CmZ+_^VgTWɶAɶAaBo 9>dnH l V yH [:apRA ikR}vPaj 8A^mٷm;MvBG/NMvBG/_xP8Uj@ I!N1_^z{^ְE{~-7J-{Z{M06e[L/a;0 맮=xלcF?1sӌ ʣ96=u96=u}^",V#8c(I6+ac0۠kUv QtPؓX@Dn}^{Psۜǭ sd1Qܛ`_`_3x5J,PDyW(yECԕsDB *YCDjEN2\Ж5Ւ $wc 0\{"hrWn]g+lv4ْ&Dm,dje%sG%>!K:W$Ih,qT '(HJ,p|x3?Ѓrmz9~rmz9~ꂇL?8IJK|*E(/1DEܐSR~@Qz! ă g 0Bu} B-BY`ppYIʰHpP99;&;!&;!+L,j-aUuŽ"٨V^Sd: W' oJ̥^ZrWӤ55 U V/ :и ,gN=K`q4 \Fbpr{Q`=EOmz9~rmz9~'!ϝ?cRށHJ5:}g1&vHF[psIRG%(pH2KP%謜ܲ]Q `nfB"jf*G##x%OH=dY?,+Îkd rd rՎerYqm$d"^8)Om{,Ŕ][s;dR;I9 vBJ+-ɍx.!k#1)lHJ% k \gX'.K̓fKݟ٠NLM#Nig.0rTyb4OxV=Ve+ܩ:n#qF;7oۻ{ʲP$-AۛSqVFsDJ2 r鎣0iGeAVb]9L ao I"et'+b|c( KL]$;19,s*]G%6{pNhhfo*x K.InPY~`2ɶAɶA/%Cf&V)nNF3_e/g'Tɛ`չQMHJ$CZ=mxݿKlKèf&O=@l%$9rw|ϗÈoSv%N0J@搜Qeʋg߱G,2 `𥏕Wnnw)eA`IG:rmz9~rmz9~oJ\Ւ%M 6wge,% %aO.^Վa+L%Ց,yq (VGJ%bC'F3t^@ۢXJW+@ȻTkőtpɞ %skJ0{lfE]FYF;H=[wl`lv5}d r\_5)̚^yE3W ¢E)luYGRVƩ +.BF;S~Q5lml@*oytm+| gD[X(C jOc{lsisr$IQUX ʓ50j72B$EJ[o&+!b=5amK:ͥ"vGd(]\R@* LԒ;K)JWm2H\G9A0+WL7iP<~ƥcp*< rmz9~rmz9~h1שyձdˑg%Sp,K{RJy/%BRDmg;(S3Y KvیH4up܇pN zf_fr&e>V _y`7AC`E7^<Yk;6|EP2@MvBG/NMvBG/RIզT 22,ЄvX`!굫r 0 ƶeaR=~ ɶAɶAnBrmz9~0HNJRY #Q`{ 6E2𿐺RۃAqҎ?)S5mbOn9|ַ=sTB;X7mm)XO0X)ëpZW:+N3Qn]e;umշf}Z/('G$ApHެwtvrJɮɓEȰ7F%5_<~Fd!~m{x/~mJxo{wߦ)ZwrJ%R DiɑŘ܉K g9/qwyl"BF'쎺z۫Uo7[Fn0кZE=\@U/ 6"$`|gIYIRU=8挲d,+E:a " ѭjIG4T#iL:U 4Q&șqy0% \0dac{chWMVÇ$B?c͸v@r,* a3DVs#f,T=ѡo[_n^snkls3[-WgI&pa=44h=1 {`UiQ#Dո-]Wl.icVNԣsv r!ԜoEyJ@ ԊRȻ6\E{u*8rFCu _J 1q4:C(c':C Ѫ7& 6d(xa?]f>;Lb1[y`3>|D JۢM^5T,ih0v6QVBhYm*cG_ WKhy$fB>һV?I`abƣM-1 Y'njjnFPIH BL"r ,Cj~k[fwٝfwv%K3I'<o PD#45PUB uo.zj{kqۯxv[_^ݛkVO޵6l78f%bH췇"2,2ED=BkbɬJ&d.Ɣ;ӮIrsV ?"$xq;!nm5_0ɲ`2**"Qf1Mͦ?ZJwիVGׯïz9UB G~{0`  C-I“*ؐO!}{r#i_|?D ߋ7 "ʤ ­y5 4KEs8y צmZW:nͲFl@Ql3v@u?+H NA9db}0;][dۑ K޸!^\cv1)b}'aDN6= dԡ"E^[6i@LL65"jp V//ҵ=3gɣ͓)uA-2E(/|Ĕ )ƨiեVwt)\ڝ"qn\Q"T@J40W t HСB# LXIL*b ,ɓYe ,l2˨bBՍfXm2,B0L@n"32s_j vcM'b K3;k]t\t#JZSLk:`Xe)C|u}16@zp- WJPXĵ#c}$'y\OnzX`EEG3ZpQ 2lm- Z4weD6ծ+z}:dV(0;n6@h hcR6*#FPS!FUyaĮ˂E:.g+]6|]sm%dI,x .uX&dM1:*xE< As5ʜ$1 2H&l 2R JhSQ>bni6;/fP( LSz[ճV]Z?7>ֽ}:ꬣvRnTGp$@BG`q\˱aV/t('!g^E΍ Г-43c<7OǓR#Rr UJU4mq5"‘eڻ~"D@'ʰK9z6h4XI$vđDII&]Y~2Js$dOcdyu`Knu;I2,pl%Y9TBG5"ix2"upqF'V3G6cq -.=5`'ɏ!ekCKI1Y].dI3/F3n^gNnmUG~NbHg(HFW|F6=>9-lg9h+‘-e4Nכ"Ǡ^e+&Y$3|vc-ϝk3n6֦df=IXޜ=66X7N p\ŀ@!qVWկWE~{vm_W,P ϘǥTǞNy} f'ʸ\dJRJR)JR(oʕ}/3K;~17a׬&6bK@bw(tٲ2¨zS |(^V:"\WP`4سFݤΌ`A%hhVV&K}HCe\飚Qtnq9 +vUe[կë]iϫ涫[nݿMUt$OIeyW(GBCWb՚hdg/J<4J6F܅+xZ!Il/o7egY5v+0t &Jz%Ѩ92hI1ZsF2؆R1l($ՓL"Pֵ&22a%.Hg'\'V*0N`-cVի綯n[WES֘,Og9`b\dKˌ"HI^TrLv(ȓ)A[+j=JyTI2W$q~[׷W-m_76\MEz4ShDUU=IRc L2љ=e}nh 3lbIFTaבĎ5 l{uAG$r@SǓhܽ;ur9#6ssAn6Śq~ɗif9]O0 QKcNP{u+G@$p -HZ>UB(N ]r i!Q"v7#pj\ xed]ǖJXx}+#`u_C9Q8ec&$,x$Dve, *IJȓ6+`o{6 R'$'* 'ϭ)JTTҔ)^:Ӗ 8XIF=d\](5=_lgIqxq*:3DnI{/\+d \U(Lq2Y+³PxhDqQC(1F$p\jw }w:5x~_5}}ui,l,lUnmunz:C kh'̊‘j~ԵE.akH-' t-#H3fUq#!9j5YDZN>+4Hb,&@"Lպ7[rXlqea NϒgD+ٞSՈJg*q(.ALrvG2:гD%b[#/!ڥ ‚@8g.攥+ɯj<g O5!t~?nJRo~nzy!&Zv =z7r&lql+X-`nwخ RE2ώpgg}|^JU;>;/eUz)T^,ﯜv|w_ UꔥQx 㾾rjY_9|5WjytW:ҟQx 㾾rjY_9|5W]ݵ)T^,ﯜv|w_ UꔥQx 㾾rjY_9|5WT=3ڕE2ώpgg}|].}{-ktlRx?iTn,ﯜv|w_ UKtzw?.x?l樼Y_9|5N,ﯜֿ뮺l_Ǜf%2xqjeT2ώ᪼[]mM*eT2ώ᪼˫\Zu~kt[o eT2ώ᪽RێNjgg}|8 㾾rjl?M~u{k׷y<G752?w?G2ώpgg}|^jjiTn,ﯜv|w_ UԪ/v|w_ S;>;/JRY_9|5N,ﯜ)Jgg}|8 㾾rjT*eT2ώ᪽R/v|w_ S;>;/JRY_9|5N,ﯜ)Jgg}|8 㾾rjT?AҨY_9|5N,ﯜξ㳞>oeu_]_WFͷ۪Z8?o߽R8 㾾rjY_9|5W~}5OkR5F2ώpgg}|^[_潶s߮?v|w_ S;>;/~^J^QsZgg}|8 㾾rj6_]s_Jgg/v|w_ S;>;/Jg?ҦY_9|5N,ﯜ)sڕE2ώpgg}|^JU;>;/eUz)T^,ﯜv|w_ UT^,ﯜv|w_ UZ5m*eT2ώ᪼}?U_ L yX N-:r!^ָPiD ^0X-q ֺK2ώpgg}|^JU;>;/eUzWKN__kuۯN;QE*eT2ώ᪼^O-\ҨY_9|5N,ﯜ)Jgg}|Xp%0J2T\ BܭW7\V],6 zU_R5׫^onJRk趿|N时oWUJ³"Mj&9 gwf pDV}!LR{1Qn`znLÚBuiLծ .qlZD[cѸ!*D@(݀V}GĥNHĎ.XjҿLZ L\nM ׵ʸEFc&Hclj ;IM51/ [PYCiH b !׽z6m]5)JRבIdyzw)_pnLH pSƣ9RQg7'^I"NjL H -=Pc>촒*|x1#ml}!rVC&5-/iƩ4n6ݱ2ٌHnsb_;S:VDm:K4r2(,tprvH$gBtK. (rǜnЊ7:^<54=I1us}<&+ QD:d`^.;}mtxiF$p+c9@άɒ-)no|J$k,1=?>&+$9.[12x7JPIaBHڍK ::b1( 8*\4BC2ht#HCF!7is;H:ZN̞ؓqC3rcM5:IџF !vdbhO߁?ֵ)^;VF gD WuIJe@[#U_"#r@RHgIePm.Z q@la7.},!4ut,YehKAm|kZ׿e߯mwJƐ;$1 DĬjҼ©Grcd;xcS4k,̱I PFXR8e4A* R]]\^^KVΛx uu{կT;W3iQe7N7`͸%&@+# 'e r\$,1g Guɦ6l8̏*LIPN9AlB*ŗXɟ }Jp9j5VB`6bۊrvn" 6@ᓊ'OȦApadA\H& >%[8ɘ9fqjѱ"J$\Z[Ѝ*-e(*&v Bc,BXak:o}Ȇ ,0| |qKKۼLi K kf%k=7Eq\Y+&LZjA{$0$ŌJŃEz"SSflH%@m$0@Z9rrGH,B>co2ಂK[pi$tJ#Q|ifCq|F!nA] \f,o!LycFk:cv(i)7L D;]3ePơ 2"\%ae5} JԜY #(jtubYHC@dA3^1e.5qBJdJ*,Je9YEcl)HfYVPbرTXG'/u0ibe@saFm22AK%z>GCh ҎmF2{3I_B|!)Z[fM$"C*IL7P>1i-X2v4V<#u-l8l`)H[@d!&NfҎ"G(jh%K2\=D-LclNq>6hE7+T ws j0JdLj)"topd6-A&ZJ304 `_%.6S Wp .c')s~5^{ڱ4T{tx7giˌ\.9&6-p$̻ 2 ;LBAUNrYMwfcz~X.\1BsM1{Fʟ!"g8$"eu' b!sy [iDdqBy#j(ὠu p D[%p`Lijpk@M3 W(`l8Eh!" ľNc⥮E>7Bؽ}R˗bT*IB21dSY`M48>w wK M%Fܞ)@  nB^\nRs 8(7I)_2ٔJ+O99i ܍TGKM!p19G%,l$Yj 51bGug/Z=-9󝱌hҥ{t SG r)aQv[ǖl˒ZqsrYDɁ#tw|h6SwB %p/V_'q2LenRg<ЩNՙ@Vd3#wDZY KIH[“c:dO=d3qD6vCIʌeip3S\yx17=88NJ'R#k|x T!A41muY7 & /wNx+H2 6r0bR𭙩[ZfW-wgD'NF@H!0\.ڂtnKҕN1 }I8RO̓Xڠ,@;)JR)JR)JR)JR)JRiCfT1E;дO*َ|[[d!3# a(ԞC.n>Qg nDdMsNeMϑfq`ѫ\k*!Ȕy$扸׉]c%kq!F'E&LM1>wuQ$N7e\LDZgWroRB('4Q%&]RedE[^09} ccoP j|wm I ^0YZw1iҙcl-T\U &.pCW aY\9mc`Ees,A S)rp~9l2I!Y5':f\FmĩZ.҃OJ_XGd2FfΦ#W (RFPHs,9:' 1} 䦎=94(&AK2) *(ɂ2l[;Ea쩑Dy`_rbotM1F!(MKjw=^ .>HVwb27:=0y A-(kf#qH% q;<Zݗw9e0g$񭡙6^#xETB9q`-l,qn~y:{I1"2fչ-Soh&65Xb9^ .V$9N)=)K2x$_ ȓl\ BN)\x:eR~42&vFXL<담Bط"HLŅVHXtbώ]dHH&|Nؑ Mo6#ʋ`{$[g2,tva՝e zJ@P023#R)Byvu_\f~~y̏jGY)x1$ nSӞ-5-х:BlpVfel\erh~$978c}a8V(Jc !aҜsH=yɆ&ͧX!w|pn7UĴwefK nw3=H60bfN`SR<6E29,0rT9R.~=#2bƹ[E=gs#L~L̻/a;'mӤQĉĵS֑d$nuU(旚Fu3 G6YG!Ш\&:,&.)fs >.D 9=Z@9..>Sr&',l#1*^@n1p)!C5; LLneJX#H6<BlT!!FGr+acym&8dFx/!qwv|ni_(_g8BRE puxHe7Hle!Sдb9_6X#K02),M8lu8]^?e&կ%8;̝QSkOj3]M-A$KъY,H!VUTP@HXrYY02@m2{"'kqt-i :Qb ǎ}3ĀsP82'yb"(ʱ`2,5yRVUrPӐQ5iT7F_-L .JXgdG_A!e6tFa "69'NJ{v ̋QCcc֛~MLS#M ɮ߲/.,e+܍Օ{z!DWGJJpnZRY};GPj֩mzsZmܱDvU[Y|_&}q_={i ڭ[SnKƸIcuEmiL|n3Kdl肈%HnG=F]Ghc{S2kOM6H2QHVReĨ/g2B b$԰Ne)fZDEթɓ+ DLa*9!Hַ"hkdل^zB2_(k!Tڵ==GU 5(,i ؟E{v%IY9c&no RsSCHN v ` 5sI^θ }|s$ܼ\V.5ڵQ(̒\(g ),hZ4Mr.ﺲ2 H髥 9F JRiJRgۃAqҎ?)S4Um#Euӫ!QbyA2ˑn7Vٻuw6kRhcNMvBG/NMvBG/JVKcNMvBG/NMvBG/JVK/}V{mz9~rmz9~RU۷U|Z_cNMvBG/NMvBG/JVIe]-W5viɶAɶAJtiɶAɶAJtiɶAɶAJVu[krmz9~rmz9~RMڃnGNֺV4d rd rҲ^uZ96=u96=uM+%^mtֵmz9~rmz9~SNcNMvBG/NMvBG/LcTcd~Y"mÛ/6}vm^^~s^&;!&;!MdbF{6j۷g5]{٫Wmz9~rmz9~SK5xux:9ˮ&;!&;!}j1s5-_>g5ޱ&;!&;!MdV4d rd rԥdV4d rd rԥdV4d rd rԥdV4d rd rԥdV4d rd rԥdV4d rd rԥds+rmz9~rmz9~RUeWk:sׯfWܛ`_`_JƜ`_`_JƜ`_`_/O+%s~y6=u96=uM+%[_V[:v鷃汧&;!&;!;}%[k_W?Evmٍ6=u96=u)Y.mqkj;y{y6V5d rd rԧY.96=u96=u)Y.96=u96=u)Y.96=u96=u)Y.kXדlSlRXӓlWB/VeA#Jv{uv]cNMvBG/NMvBG/SQsk%_G5c^MvBG/NMvBG/Q5XӓlSlT?JtiɶAɶAJuk~_5z+mz9~0FLRbfAbqB#/`Up{ڹJnJ8󎔥L+Kwq'״JV>~Ɔ1">;>l\n)pRDMHp3QILRnaù%Hx'}dT,v&Qt͉MZOIT~M)9A2<(\2L;6pZ^kuL#q^N.Cs`^o.۫o?N-)YJ{k}WͯJ_t+m_ezyqJRU vT:{}V<򉹂m,`q]mA﷚tL!~E‰'j[N:dEI# G>u~(Rqĭqn!6?VWZys$Q2Gs4 ɸąRGjWV5孔Qc)fv,c L2$6KQZ"a.^z:з1fīnID%cVNFmc]ZPXZ'v-{\^k6KtxʏyYEfx.?N1b ,Y|8W68ZQB;kӓXߊ=|壴dRr՗ XV&8Of,/9BPBi 쩄> ս7yYnQcHfDQ/,ZH"mo]s Z%au ӫɈ┘wF*m̷ܤIZVg˯mujHRMB#{k©k,% ga\5%o  sF.ew0D<<1<,|$/1a4M+Zo7nsfpG׺B$ʒ*#388]FÝ mJ$DRx#rHq )8(t";w6t1bR,TYkI0i+ -{ZDgO:v|7DfTijVx#>3i"ķp.yBT΢tmPEV3< t%ͳctAɎC/F!z'M(5LJ;*l?!Bpdlm#+@xU" 2Aef!W(ގIж%UcOo!Zgpp)N3 N*j{z0"X"{붪ēm 9q&%ctז&8Jc&>zy}H/vUq.񷤷iiFJ F:z `3Km96z[MdVr,6BBCKOOPtTJg's+FYVB:N?ðZyJǠ&+6s9CAB1o_#>S9&!K*1]x+Wf G"@T4/IxL'8E% 3 tij1h3O.MDLwŋpe8X@=p uVVAtHal:1gD%:l7e%$F. SDUDKr5%:JMσ2z v*1$5F;qOF3KU#F`;4K9*`@׽ WyUs22:.KB>.Y#dٹI] dDV$Q۲Riw&,A݅=.Ljbn-{V {W7&v5 K Q0Xa/]ǫv \#9XV}uƬ)oro'h§!MtDiay\A  IKiGVX(s+V"h;9d;:'>;Src'1L3 !Aji>P'vhz$ilP+Ȟ̠ic e # )9 DK=Y86ʡl#vg0UoK-oNM:ĵ T s JH ¸k*Xw{nm`k]k G&-[@- ; k7^zGxASw(n&mcZ~ɳ UY0l3bG۲ކ8$ssHOƺ%&؟FD1޶2[T*+W e#ݐ}o#i9٭%. @2@ &rkV݄[[

֍'7L"m(Lg ˜r6Fn{1t&I3+=7&-j[eiҨRF4l^ϯU鵯 z` g%,Te@V I Xp@UÃrg"Ad,ڔcYҔ)JR)JR5ի~tiJV)Yg怹+x]7IFp qNeN`lmqtP=r9#[z%a! 5* nwhY{J!|eU# R20rpfN-kR-m^BL΃D1r! řLgj")eP\>l%0.žB&Un#0>S0fDطFݤƌ@C%pxfW&KN~fH:1D&v(s+fnIͶ 5oR!wY(/R)&_Q#ᲀ*-`D,ϰ4H/tF́#2Bl¶ÌLipV%YAdU\Z%W\TIH~\e N'1|ۋTY RGF SFIs0tkcb4L&$Ną{,mcXӭH Ni(|,==3VS&(n^?4*.?N+t&z)OHO6)V*k+. hL{;!xVc;#P#{ղv$"? P1&,J dАFbVHbs&)-C̘Wb1$hkXJc?6үeɁhsݚDȱXɢ4晖F&r 7*4ǝVB_hZX. YZ{R'YI|3ǤIk pxv/gKc5l7/E25L@V[rSq{C^_qLω =ũ$3jnZn(y3/qSbQT& ŖesՀhC :a8yd0UWz+LTdȒ6ϘH}\dUVۀa-I ˸-@T}秕e7,7a:9Ym͹(V5S6å Xuft+!2|$Y(-'iX-y,>91u0\ݩD = mshi4r'vK6ri`oJ@;3!$>0H$b<>GGL$k. S)HC ا"LH;,1rqedCQ[[ d)9"AWc$!89m^3rBLȻ ܹ)IibDN,3 ew@Htf-ҥ5Tq pVąX2 LQ$!\7 im\xu٪c@2RX @6wydgnmrT i, kiUMSHL9)Mc0Ƿ\qrE),|#(}0RNxW`zsU{ o&}-mV趫W4=;zV#8p34)JR﫫omX+e6m[,P"ש66F rI; r mgT-صp^D?)8ݒLɘ[1aP] wdgpˍ(\KFӒ:XMF=c$ ySJ Gě&3G$8<8Nbw@=!nBAU4WW8,O1rW sNAhcʸe0ƺGtz=fS ϔAR#0:0l1&@5Bf^73jPjZM{mۥ[Jmdi#I&7 `+Uu-nkk{)# 7d7 tq;"!V +3 p'Y̚|hU&㼲G5RVȩ*-Z k*ԁB'3cUbŸ=ãi[J87J{X҆; $K~j)F0yMDr!hWtv-g5BcR}RآKpD@ 42f֌xR16.4b88a0dpXkUljt= JLԍԬ̈́"Qb@etħrj7jZwG&K o%^(ˁ"$ EeM#1v|j'*ve>4<9߉U- RZ"#b.n.P 9}Dކ.:V{sR"sh{jrJݍ'v$[Q%X,#E9j+2YDZN\].U6T OeI oc(]rL(!8`=;dX s&48M%V8CypoȲp8˫2U+t`rsRX%Ԭ]^Z64%żGm=īgr6ں߉+RK].S6"{KI$ԖWrS4RDb4d$q#E,pk+h8n^Gc{E6\,w2Txg"%mN*iT1ig#ۄW,B܊6Uֶt\i+RGh%Ogw^zIQ\I*4t-!嶩<<$I07tkєxM\6wik} D-&"Wd6bFVGuRW݌|Y#OT29 T0)^E{t8|/.jy? +q?t(p~?:R3P'o.V]vsuno:mφ-mV;~%6IiDb;% @dWUg$x/ .}c.-E:oh_GM?(/̧2mVׯn{ׯ|LqO>)?(/̥*[tmkT2S}4Mϓnnn{9_^[5_'OG^^M}[*g~Q_N)G~e1ךT-7_VjjNkttkmujz⟔}S~Q_JT.6zڦ8e⟔}RboooULO>)?(/̥*6]OGϮn;*g~Q_N)G~e)P}M|>sy6jS)Jճg7Un~~ ͖S\SqO>)JM=q{կëgW5k~Q_N)G~e1J{]}zZFޗU_]\k~Q_N)G~e)T.o6lm׷]~5?(/̧2 o߯j\>N{_o:o{S\SqO>)J}mm]ٯes6g~Q_N)G~e*u쾭Wm{m~n}{m_]VPx\H$>- eP!gǓYFsˉ/vq0,qZiq )G~e8e #@R}H |3r@9Ƕ>;3_?kxum׷_E.u^ Z⟔}S~Q_J~}5SU׳{:5D2ST`v1?(/̧25J⟔}S~Q_JT=*c~Q_N)G~e)P)G~e8eCҦ8e⟔}SJE[U~j5?(/̧2n饭׳_N⟔}S~Q_JT-kU_m[oWS)J]s|۲kWׯg׮e⟔}R ~mUUj\}6yk~Q_N)G~e)Pj٫o.=s߯ۮ3?(/̧2m_U=qkjWGUk2SRSSqO>)JLqO>)?(/̥*stxm9xe⟔}RCZگ{mkͺyn-5>[2Sߠǯ> {[W7ͮzRUbT|,&>FPR 6pL˸+2SRw6۳7o&t^kF}Gӯ]O>)?(/̧wݩPmߞ]m^U_ksT2SzT6m|[ݪ)G~e8eCҦ8e⟔}RSq_]~0 e1&0#Lec SXc21V>0 e1&0#Lec SXc21V>0 e1&0#Lec SXc21V>0 e1&0#Lec SXc21V>0 e1&0#Lec SXc21V>0 e1&0#\86rxY iB30&d-ל:8ij_ZLTxTt?5ep▮7畑DGTH1Z4 Hi_Z 1]_[ZSq_ZKx A銟o_"׍ es/ !ڞ^t A:))jIKt4 po{/Vyߛun#=/ߓBbƴ[ش\NlA+ ;:Ҧ 4,n_r6;"_̃]~F-f5kvbg㱔V8xLaxW謌e>01>?fL_Sf˪ăo!=eb5_?? RR' [ZB몞^ꙜH2IyyOM=<&NJU m:,Ҋ$3ξAv{UK Z \G ݽ<&NJU *f9#W;kRg㖺Gga nJU's%~xQ Vk˞F ti(ʇ;yĴ  yJU's%~xJj&+{s{LĚ?s%~9+sKMUq q̺-/~^H Ua?w*Gj ~| #H Ay#5Wiܫ'As4wйo~w*Gj ӹW?CUOƃSw-=eIqs,zHП[_j~~$.;;y+MWĝ<&AB^bs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<1xw0W蚯;y+MWăSjs%~D|H<J9.{D|K.JU)_u˟,igs%gDKGn^}/0QTtRSZTL@]3{a#o ۖg/Vw1rW蚿;+M_ī܉TL-fcr^S+eIYC 0T2W Ciqc1rW調Yj~~%kګ5Z"3{9gMz\>ڽ_j~~%90eL˪ i~Yyxj/nw7re躯wM7wVt-=7wVă]IFrowAcTXt|ﭞHm\Ox qګ+7'/2MsB(9Ms0ݣƣ'nQleaSndrq"/Z˻z쬣,B'[sJ{bA:z L/E\reevAGsMGfFyNkk!.w??ViWsK%EIOn\n+r;FdàۓSAKV"x4\\0sb'3˿`[6bК^ѥiT^믡&jYܖ}nudk.kލ_ґ9BeY1-! ݣҳir&jmXEeOiŦ:A#7<~K/rmvlvL=tTޒ Ea^[榅]a*4-_H# d\4(~?}nç N`+ni[t [k2 ^?>=1ͬOIJ*(_m(⽴ {ev^ޱ^̬~PYƱt)䏛~=A(EdZQAGSmasq1t:ЂDA:o ﴭZzo ﴭA$QOhIDlֽI}&-ǃn,7}Ku2vt#)2bܴrޢX 9 fFit ;G k(3J-.,F.#\}ʸbK(8lI^ ]z|2s'jMWsXG%s8I+mvFޑpN7,rS?EkF"o|ܺٞsyGqN\OW JkOfh*z؎˴s ,Q-7- ʬl ^g(x\ooEvݢa-%9_<]RNˌpy/3r˔4ٍ5 |fZhV.tgl!Jddn`.yxp5ܫ\ܧ-N*c_<hshI L$tݣC:E--;7-ttk(k),N{bhkX ZAayMeC.yx|>,'Cc-l?\A\ݦf:$ӦE;W Z{*vJeMi+kl*_;(hkE9=eTb\/+2UADTMem9 p^^G_AhnJUUE5uOQm+#{)sbq-hayzVނ۷,+-*`@,%M񲕦7"ao˟v@}SZiYPTۜ$31 !8GyK@t"2""$DDD@DDD@DD n~?}hti[дi[ЃWiUKR'K׸ )Xۻm˜D5ݤN<ֻ7 6nx1u4sXwnLֻ7 6n+6PdcTU2[BdcyKIZNG}N]vZ抢 LWL<,E`YN<5BǏ saq9Hv/&ǔ>7疞6yi{k/kԸwnLֻ7'CP{]yi{k/i疞6K{kr{ɴ-q][`r k,*\]<0GLelq{ɽhʰK:Ũ}KU-ЂDA:o ﴭZzo ﴭAC|6_zs%UIa塯sΏ)ee[?WY(y \ c\?xdYJlS7I.cKZnq*X|Sӈ呲?\yʲURwk4;j5RCYM=ѫ)4{ kHӛSvNChANV"s*MD|<70?\.{nolt/#5e|o=[&ܣ7&/Q eM-\{|[+҈˜]y?6ۮQnη[fNeF=1Ůc:[ >97Hy\8I.:@LDBo'й\7r/7z ZE+eIpcok􅒉'( i92gdΝfql!x7hq zoq&Od<ђƲ|Fq9oUyilZ*jW*[>:gasߣ7+̩,)%69OD%ÜIn iҵs1TgU"&bf60mx4`{g6Zzqѧ]gtFZ3Iq+-GBp4u QWGj*:hB 6kҷi6kҷ$rI#+_/ ak݌c$ jd$gdS 9C'// I6n܁ޤ7nSEZKUNf܊|tniF8:'w19hA ɸ,ɉZS'rQ4K@xY6n܅,r.*il N!Ue8: 11=t,K3$jlڧURAmkHpn F.:/ihс}f?R]&?V])8[Ó"zvB-JFP*YvkX)$/ߞe.i~ ''=f\t"k54571`^t\n_u$ٻrb$ٻrjx%OȺ_ĘaE[KQLuIkq^ y9UY)$ gO6ry9fͳ}'8nо&ۓ&ەgSvg3)5g:ͦ|..b_wzh@$'JP:lݹsԓfjjic($ٻrc$ٻrE~7nL~7nA$QIvIvE~7nL~7nA$QIvIvE~7nL~7nA$QIvIvE~7nL~7nA$QIvIvE~7nL~7nA$QIvIvE~7nL~7nA$QIvIvE~7nL~7nA%7Iv:# ,#;f7roBç-Ut" xl}nBxl}nB -3Zd) 8ockHU*JifZ"x֑ AİK/c"ñd\okd!71f \ gXFwD]ƶG8&q 윧6tRA2pۡ_}zĶMP5SnK p_ʹcms[nc.uدхjFW;)k`\EH.}#u^/.Jt٧;Uݫ+ YQ|OxBȮl:{$^GKXmm'|&C6Z晛/G68oBc쾮]w#'mJӺ1iS#xp,7_7бlQڴukl1 K i%X?8bx~+ຶRJ\eQ:Hts@7p-i }g?;-t6ś8Z@4m~#M V\3s4K p]mbŖ4dRASC :Ό}y踬JYt9Qe+Ʋs)8yUARZlc 9ڰG\A,e9Ϩc%] *1G~Quuk d j[RhJA f^>< T"޵͊åM.f_L)p1yn;e::?pu|>y\nq79^4AWr*G͑,H>97o$Mk~#h[ofp6:y7^M5O fS5vS[bx"/" """ """ """ """ """ """ """ """ """ """ ""MBMB .W \""" """ """ """ ""UtZ>ЂDA:o ﴭlji6kҷ'uo)|ŕHru4kg\Z[sه@7x}CEȣrt܌Utiuwjĺ55?u?9ré;G=#皟?w<Ʊܜ?:ߙH:55?u7'05nNg{ôs>yJ6Yb/ &b "2ɤi2ֆn ;=w7-m٢wc=^1לrArs嫉S]MArsE>`uܜOw7'0:nAS]MArsE>`uܜOw7'0:nAS]MArsE>`uܜOw7'0:nAS]MArsE>`uܜOw7'0:nAS]MArsE>`uܜOw7'0:nAS]MArsQCV K\DD@DDD@DDD@DDD@DDD@Z>жQWGV'M{] OM{]~?}m֢ç N`+p:`+qA,O6uIw"瘗'3"Ria25/nyPYK{œľy?+օT➖ Ӥbyko }/a~@F..??m1A%Nb_=-"e 05,m^tHoh鿤xm>~sMk_]w@{dEd F1h9E W?o<ľ{?)Kµ6DU,sZcltC n{h dZ жQWGV'M{]-=7wVt Lj&zc/qUN7]{Z~9zڝDC "ǐ9ne@?/ث߽38;wA'SӻDq{;or dFC^Obgnǭۿz Q Gn(JDFy7:(zvtQ'oP߽38;wAs_mp*\_9zڝCLȟG+]D@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@Z>жQWGV'M{] OKJD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@Z>жOUGApo+EmoZޫD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAn{[֧kzުD絽jLOAi#=;-\y>U ""flask-peewee-0.6.7/docs/utils.rst0000644000175000001440000000505112574421673017532 0ustar charlesusers00000000000000.. _utils: Utilities ========= flask-peewee ships with several useful utilities. If you're coming from the django world, some of these functions may look familiar to you. Getting objects --------------- :py:func:`get_object_or_404` Provides a handy way of getting an object or 404ing if not found, useful for urls that match based on ID. .. code-block:: python @app.route('/blog//') def blog_detail(title): blog = get_object_or_404(Blog.select().where(Blog.active==True), Blog.title==title) return render_template('blog/detail.html', blog=blog) :py:func:`object_list` Wraps the given query and handles pagination automatically. Pagination defaults to ``20`` but can be changed by passing in ``paginate_by=XX``. .. code-block:: python @app.route('/blog/') def blog_list(): active = Blog.select().where(Blog.active==True) return object_list('blog/index.html', active) .. code-block:: html <!-- template --> {% for blog in object_list %} {# render the blog here #} {% endfor %} {% if page > 1 %} <a href="./?page={{ page - 1 }}">Prev</a> {% endif %} {% if page < pagination.get_pages() %} <a href="./?page={{ page + 1 }}">Next</a> {% endif %} :py:class:`PaginatedQuery` A wrapper around a query (or model class) that handles pagination. Example: .. code-block:: python query = Blog.select().where(Blog.active==True) pq = PaginatedQuery(query) # assume url was /?page=3 obj_list = pq.get_list() # returns 3rd page of results pq.get_page() # returns "3" pq.get_pages() # returns total objects / objects-per-page Misc ---- .. py:function:: slugify(string) Convert a string into something suitable for use as part of a URL, e.g. "This is a url" becomes "this-is-a-url" .. code-block:: python from flask_peewee.utils import slugify class Blog(db.Model): title = CharField() slug = CharField() def save(self, *args, **kwargs): self.slug = slugify(self.title) super(Blog, self).save(*args, **kwargs) .. py:function:: make_password(raw_password) Create a salted hash for the given plain-text password .. py:function:: check_password(raw_password, enc_password) Compare a plain-text password against a salted/hashed password ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/fp-admin-filter.png���������������������������������������������������������0000644�0001750�0000144�00000123654�12574421673�021336� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��p������� �IDATx^xU''tR]+vް+^v^P }_+XX@z]B/!<fl%\$;of7sLR)BA�@�@�y$\̟#*� � �X8.@�@�@ Npqr& � � @@�@�@�D�''j"� � �8@�@�@ Npqr& � � @@�@�@�D�''j"� � �8@�@�@ Npqr& � �,[ܠAρj5"� � @ Qu@�@�Yu9Z@�@�c^Ipe]~ǞT!W~ &wqx6뺊zD !� �Ĝ@.33S~'INNpp%%%rAIAA.N}WhȐ!2y ;ׯ@XG` � @ yڵk5k}>zJb,$`V\) Ȓd̘1ҤIyXGDP � @L D$tM2x ?NS_zkF9眈TF6� � !ZjɎ;C<#?Oýo~\^8BB{>#믿ܹsgyBzpad# � �q rݻf͚ѣ++V~\�WFU7o~-Ԯ]ۺ>zزe}o>=J � �ĉ@K.#GNT/,wOի裏^ NtB#Fcm6gMh"_^=͕8P'OWOeڴiuپ}^zY޽{oC2efRSSw)/W믿dԨQV`VM,w&ng}V|MϢz/=#<ea /P⊀s?i$ٰa4jHg9UV2Ǐٸqc9/lN'̘1C}5}gHJJJz:i&'Re˖Y:qgCX@X�@�@ aBpr5-:]<P}vm={:J}r8 )5kDoذ<CVV.nv7iVeZ+ۙw((--~k~Z=ܨ5 h5x= ^{YJإe˖gܬn멧y.=}]y']{ / ^{5yDPY+�_p V psX@�@ 1Bpwy,_\t -+Q%:iiѢ㯡aP{@#PƳ>O>ۖ?* MYMjƍ5_^.ȳliLQ￞5,iheW^ 7Vz+Ժ*:;+z5, ذ{뭷)▟@�@�\ �w}INN\~G|뭷<\:̙35hi]9D{CN:$YbgO͛K^^['O'zBt.W^y5N:֤Zsz^!Y"3<S̙cmVn>@ :|Oĉ=ҥK& Zog/ͫʷ`kKU}hϨwg]'݃c?xϹޢWmV,Yb>~__!:tS77NKz z-aÆ+O@]GbN*wuWw]4R@�@�P9),,c*4ho8:Ʌ67]uUΒ^x{ ~g7oVO6umhX;v MNvyWk=zX:}} VM $!z.]~}kvJzj`vٹO{w5_ו^gG_إjx0eӧ[E'fq(}ޏp=m0Y@�@�9=rZ4 U߫o߾2aK-am<kc.7R_s6pFE_vرYҞc9{ !֯_y]{ݔHl#~4|h]t?l%v Y5\{E[nmzNIo-Ciu<c֗Eßu{�*MÔhXt^Fn v/\>NiET|  � @ t Ξ"xXC^2 ":DLgQs #an׮]&4h.zߓKmd+ڃDb֡z:ˠ茔C)} Ή\t}һ}[k;rusNo<D% tJ9щE;DvuICnu{+nݺUX'Yq9ATL@WvLګfy^e@�@�!r{tH hZ-D{a7F=IWΦu6Lu݂սiau{7e m>>!x:w}vWr tb4tr:LPEpMu{my/Sw=lof 1v\e=(;\@�@�#r{7DKFmΈ q[iP :A9a`w{ tvB?h֭[}nJ =64jȭlz_t8wѐa/ΉU=cnϟxv]Vw{}>P2-#� �$@NMֹsgKBgFWɞ BMZt:gC{Ƞ3g?P9Tn aPK.) :!6*/MC>Oޭjڵk{t�7p@YnZ:KeA3ʪpJgl&GLE7D%PWe=ZnBSe}>@qkr � �'rӇgZ~mOPi/-:RgIԢ3%z>C-7Y}]$u>H.xnl{믿^΢=:F׫w΀ WuR{>P$}gzgWG , � @ >sMî;X=MZi tio/_zߛki#hR8we߯6RY{R!SC]c:,鑟oCY&.b ŏ<g1_ "vq>Zό>'OMHu[<. = � �ĩ@N{K7nlΰhf;,R{|GnhkщE3/jo>pYiuQᚕ=M{4LEpN}rzz>K\-}NnHl裏}]뮻NZli=\48')eǍ':u8M =v:TQ[IgKw^� @׶NbE׺*st~oګC#Lzxby'*5Jv3$1Fm/u@�@�9i8IKr7{NlE| aLq)x>qDʧR{ HlC{)آLg94׶rsseU8tAyBymZ_{ �8٫l;u&Jו@em#1].@�@�_ �ӾkϘ3郹O;4P{w+WN)=^a 6̚_Ѻs˜Mwkr>ڻ.:iԙ*8z?M&j$25ECre?yY:>zx?Jȹ==:V<pPRu@�@�x9y?K{ ۷h>*_C~M=vwI{tNp3P:ͳ'Q߼yA{}giZ_U6pǫ$Ϸj{m4 :: OT_@]4Pj@ۤǠ4lϹp]+ȵz|v=+7>{,ұcGѡ2i$~J-[$''zVy'm۶ 8DMV$ @vxС � � p5RgSCC � � @ bj/N:yw7/Rϯ9{e UC�@�@� pAEsqsɒ%]4~s3?>S#nF  � �$�.ϩmiҤ5<  � �$�.ϩN#PcZ@�@�@ pqp>7r]ӉKtVN}Xzdfդ-N&UD�@�@ \x� � �DS�Mm� � �!@ U@�@�@�h ࢩ;@�@�@�0pa* � � M\4 � � �. <VE�@�@�)@6B�@�@� Ǫ � � @4pf_ � � @0X@�@��. @�@�C�"� � � ES}!� � �acU@�@�@ Y� � � `4hP!`C@�@�@ 6pq � � P�@�@�@� y � � @@\@"@�@�@�bC�Z � � �pX�@�@� \lj� � � $b@�@�@ 6pq � � P�@�@�@� y � � @@\@"@�@�@�bC�Z � � �pX�@�@� \lj� � � $b@�@�@ 6pq � � PUۺulܸQ n@�@�@�BȐ Hfff$//O4i")))Ղ@�@�@� ի%''GRSS+,0X@�@�@�!E H#S� � � P`…K ( � � @5 {@�@�@@X]vnr � � �a ,Z(!0Y@�@�B�"� � �)Vk۶mu֝}#� � �5J`š$ըkE�@�@�j U ` � � [\6mrOL.ZIޱmNBަnޕnkaBƍeرr'֞oϑkșTX y9]m@�@�@ 6,Yp\-<* gP<M!.ܴiӤ@c,K:%W'{Y_P"}8_mj]퀅@�@�@59{ɒeg $^a$Bꫯo߾ҴiSWz܄Zr=<YSCm%Ε$ !� � a֭[|diON5 qD2_niL]S uӒ?4wtF9k)--3CZ6=y\6wիe;f&dX3UC^*,"-#hy_]t\1CukYȄ屃[ȥ.po.~&naƅы䯳;yV\yY:l^":dl#[KZ:\g8xZ[ wT6>Y@�@�$tЇPF:n~sܷs9cyoZ~j<=\'G>Nny 0]<9䛅^vN6 a-׮1KL;GF\+y_]4<=7ڵ4H+.7Lv6umPnl29]_v Kfת|e2. &_d{Ly}6ܟϕcn9Yr^r%uuq},� � @ �*V/[$I擻zx^Wi$-u3Ӥzb`9{4̻,%Y2nzG2=h]^Zl-LY5umb7iQ֋2<;Yl)#~gG4keh^# 6l7!\1vx^9V;:Kf *ɦso^߻ss?#f JԤ Y@�@�"N޽<yL+IPTӳ6~VI5I:Hߦ� /oY/wflwSe=`c5?=wnڃOfBf;E}]_;vQFɩ*)))/Cm*~o͖Yv&jT?\ܮznCk|N_]\< "� � PC pZ )} ו'|6ou_ۖkv~u dr`ҹQt{uzu%L_+w[./)I޶gJک_C{fzLm{ެޘ#K.-ۦx/Y\iS7Mn*#gW8V_p+W)SG?Epڃ|]iBw_t2$'xtvxKP,� � @ V24wuTiE2ix;ΠrL,kM^!ߞArMM?.7>;i*'t+_."g^ ~eɃfBM at57[hͼ6⽿~Z%&?]~7EKj׮-ݺGYgY'7s@ #kׯq\dKtyk:3r\\˿{7ƭWxcg9@�@�j@8':>WFe|392bf~&r qvW( B}nN5,>9fJVrYV`n;NP2[>7$/if'm% p:Lqa1Cf]M)|}Sq jxtn!oN:+ӟ rdfVΖrޘE, � �5A �ײe썡 $$vxkժeM'3ZIJ{}纺m{9+8~벺-d'>+j=t[vtְÝdV6K uX%ǻ�� �IDATr\G+ǥܴ<`,lw]Y: � �5M` '4|mF̒W42fWMѡ?Y-9v@�@�-@?*GmrKeŖ"LJ4#*f' � �$@XE >(pW9@�@�p/bŊЇPC$ � � �.\AG�@�@�$Vk޼yn@�@�@�V\J � � =\ � � @nɒ%ҰaC@�@�@�())M6IeN*5eݺuR^=INNښu@�@�@ hx۸qՉUA"`5njmSr � � @ dddH $33 pU[E� � � F�Fe@�@�@� I  � � %A�@�@�b@�'* � � �npnX@�@�\ � � � Qb@�@�@ p1p � � F�Fe@�@�@� I  � � %A�@�@�b@�'* � � �npnX@�@�\ � � � Qb@�@�@ p1p � � F�Fe@�@�@�pJKKeƍ/1PįBFFdeeIz$)))#D�@�@�ܒ%K -)))7 ͛ڴi � �Ľ@�a)**?x<<IMMc3 � �DP `[b4i҄)[zh"X@�@�P `[`&!q\QS@�@�R�W6.Bl@�@�8 $I � �DA�pwA W@�@�H \G\$� � @pQ@wpY@�@� y$I � �DA�pwA W@�@�H \G\$� � @,|2h 9*/"GG}4 X2e|rWk&ӦMӧ\xR~}y㎓^zTH17ʱ'O(t>IL[UB:]IWeSjk4NMM@� Dɜ rg N忳{ 6˟nL/O$y^l9I,K,X(G}8Gf]3F/Zip* pv]w%ٞCزe 6L,Y"~aZt6}뭷e]&r衇Z;OdrwˢE䥗^~8JE2y$+U䳓;Xy<3YJ �+CceiI*;Ңv\կ+]"?/,#&ś CZۈi4>G8B${*4i]y䑞:~WqF>͙3Gz-ͻ%\"s9G:wT[H~k̻t1UƟMZݫC*&l @ j?[},==o3plG"}Z/w[._^8tzy<yXk2<?ùr>ֵU4ƑG8g]_0EzJ.=XoFEoiy=zJ233uOkҺukkXbn6w\y7eֶ:,9蠃6o,O<,_\N99rx_]6m*G}%M_õ^k6fYz\pAw#Bvȣ曗[Z.{f[ tjƿŞ ^> }S|D[yU|ӣߦع Eo:I%͇gtudm]e2ov9|̻tׇPЈ! ~Gs=ʀvuK3DIyM]գu/>M'v0=)VmyZߒl,<4H^<5mL2vX @ ~p޲* mkWx-=+5֣JMj%˴a?[\S:&cO,mLJ]^&.%ڹiVf{oP{T\;Q6^#'S}sci-/HYIr릭ԿYU﶑ӎ BuQN =Q;vyYA'흳oa =lٲOb JgaXaޓgy&k]w <Xkw} jZFaA toݧxP{dv</}}DB^7MC7ap%)E:7L9ˀfod=� llj޴Ke5�5o}S]7G>|kp.ص& X5ʐ7 +LwMލ?5&05;m.Ϛ.]90p\^@|nz44=3!Stkq] ! 㝺:_F]v\e>;7Ȑ LJɄU ߧti 9& "� F o^7ᅦ-us,lWGxAk`z2lD/µ=qˬEm5 < WS_jd>|PK+89q>:>9ɜr @>'OMXV!=*vis Tl4*p~r饗/,5zN'�yg%99꽺瞳LtxbjjuQҥKIO/kz Z\\,gy'=ki_]OoҬr/ر 3f̐zM{J^`K$q3=bųߝ-7zki뼲azkKS=kǣo49?$ڽ8IKd+t7 L_'kn+}LcV<lO= gyI?<7_lm^Eןk/t4N{z:MV^Uv/[{;Vf Ww+&g. �Dlծoi0vYmWgxzdN^2Nd\`^E7_hV}X7AdŰmSkHCǨ _#+)Ir |m%йoOQ:XzN0XrU}]TyvM7YL@hѢ\p!.)))VO tt8{ך%k:Lo ZhPCi\Z:ÝxO?ڎ˻lݺU.bq̔:>Dә'u)ryafԒɿpUhrK|'{{Rgmnׯv4wNLǗZ߬>= 8s{]K A#�7 ԡ M^Lvc7cag{#b } ޯ~wr[@�Tn{|+`&)6D7f󥰶r <{m[͸~mqmsۊm/96~ʧej4?E!Z{>m'fYӎ"vmҰaC+D9{GL7_Pƍ'F":Ke쏝:uݻKfDT:{4H֭[W157u=dԩS<uiџzk`KNCYVOWcVR9]ʼ3ֱK:mLp\^>NЄ2 f[K}sd2~gO\nXmp8WMe[fzմWspwsoߒl_"S.am Lϥke?G �6kWW/PPC֛>_;&49kݴ6$Jζ6;]fB{so64璞V/_ӎ!*No[x≖3i 8p3r^{Ʉ  M}k^t)4X^=kvL%rرj@袋N=Y6Ҭkz("�IK6%VW6wMOa:ƋyڅMuyQ˃2l&m<d~wf3Գ:v̐PK ~j%#̸t3V\8S:3JƦ Ԓ+z,' PC+`x=׮p7<QNVͳߞ6_"_#>^N3s}Q6EWWvZ 9ܣm˹=7CԵny]s-ӎk"*n͚5փu pl8{͛СCUgTT,]T=3k cBfBrJk6 Y.>UyϚ5˺'C›=R\a9쳃. p}:ۣwhz~wn!tvF95ou5yr^ަ7vBhL%C6Pvo\vtoΔ?Mڣyn}gL23GnR6+ib,יY(ul>jsjٰT] 3=&Df^4 ZtFF/fܿUmy8Pq G!�@n? p+@iLLz߽]磣m�6ݴyB9Ĵ}Ľff쳳M̵xc* prч3QÚ|00R} GV =B� � MtأϜ^9=҅Rt7סCϟ?ߺoG eB -&V"i � @�ϓӞ[&0C!C)&MO2h ӧO( +b<P @�@ QjdG\1� � @5[%E!� � 88u88IT@�@�(ࢀ.p > � �!@HD@�@��. � #� � 8888IT@�@�(ࢀ.p > � �!@HD@�@�@�'999Q %eYz5@ � � Prss+m�W|8T@�@�@ p1}z � � K�Հ� � �ĉ�.NND�@�@�p\ � � @DQM@�@�@�5� � �ĉ�.NND�@�@�p\ � � @DQM@�@�@�5� � �ĉ�.NND�@�@�p\ � � @DQM@�@�@�5� � �ĉ�.NND�@�@�p\ � � @DQM@�@�@u۶mHQQj � � �HMM T֭[';v쐤$kC#\_6� � �H]ZjՒ V8yۺuHrr2F^N4 � �T)..J{ 6X)0--Vg#� � @UXXheWV^m%?} � � �TH&Mಲq@�@�@�G pU@�@�@�p@�@�@ *0@�@�@ |\l@�@��.*@�@�_�![@�@�@�"@ 3;A�@�@� o@�@�@�N@�@�@�p@�@�@ *0@�@�@ |\l@�@��.*@�@�_�![@�@�@�"sD}/2kFTBIݥa='IRrrغu]VΖ̬� f_۶mKLG>jըQ#U5X@ ^KJ_V33֕#ȵ6䤄o7Ue'܎BY~UҨ^=I]G$%%ʗV+.dÖ-VZZvIkAEc\\-MJjjjkҬY3_~Il^^bz [?%k!>nr+5I2=%#nʶORګcdLK|keBR.kծ-RgowEۄ%KX U[̞ULߠڴi٦^ׯ )ev56hР@�пuWY$/,陲DNA2 2S _kWG;-hLӊzi`юuʯհ7AOU9s/n'0a֭g#z=+:.C)ûXn[ ,\Taq"ЪNdli;'r*>1J̽o ;S1C'ca翛7KI^8\|DN9sH>}"̤Is/st  Pso]~9՜jO y}=mDo7ESn9KSA}T5Stx\}޽{zգ^ɓ'ࢮ@� Xno"uG~l16M*Dm7ESnY6uzw.?j�׫WRO2�U�$&%!hbKvS>1fy pѿ {t}={aUIݧNJY6�DW pwࢫ {�@�H}b*:in p]?/.A>SB9 _nv es δip }98)V! ܶQ$oHNGz![2AM'J/C7]Xf~sp>b*Dm7ESn6upv|ᇕ6l`=�ףGb)8b_Dυ>[s9Մ￿믮Wقk֬ƍCC^ON ‹E@�Xmco(>=NƬ̊!>On5!.J%ke9MC37)=ͣ{v8 g!Uع*`Mq,{n*m˄Vt'ܴN&7ryn~nȐ!2rȰߓ5q\]s}ҵkW9E?6M|M<Knq\ /"mZyƌ@H�ān !gR ǿ<^(SYOψ�� �IDAT&�Crw.Y(cfmBdz넳*i7igϐӲuV5j̟?_ްk"�7 pY'{6nunySio%upVh\4sԖm1ˮپ]vK_\~_\ btÇvjw衇_i}8.G Ǘ3;<Ah~Z=UY<F*6 +|kUkm {Kw_e*ԄmE6,I5srMK){k�w�rI$%] '/Ǩm;j15S~keQ"~H&;󨫆Dj%[/۟dG:q[Zu,.#DZo;%3,pc+)}]<U9}6>%<y?37=V1m7yll33_}ZL(mH}b*M:\ϿworZOx_Hx1iԼyLYnޟ}oC]OG<􀴨dXbګ\X p}yH.??_^xѱm|UWIG)0zJV\)g}<쳞aܹsŋ[:묳䠃WHbC{9o nW^yԮ͕L.?\�~' pڣuAM\pkI=pE-zNy8qrmIvvu(Ak9݆6/i޼zVϟ}2zUUf͚E*\�DQ p7"YcVG75Y` J;K&Ȥ%g)ͬWt}YwkW9|߲p{m阹Et{lv:'X'`L_U'66[J^to9K}qZ9w_9cW][E{=˂5r Mc4.Z)G/׿7Y^9{`_,9w63şKP\0&gާ8mCrڵkW;*ԶR>19qdoJ\nYsOg˶ム$M"/Z6\@)\Tvl1o޲^m,J&sW]v䋐o!ڳӲeKрb '-t:˫jd+뮓K߾}u}]HlޯpJmk~7Y`\tE.Dcg/7=Z_K.04͛7O.nzBϟw wo^ƌ#-/ p/ n'= 믿.>#U*g&U.E�(`MvtrY}dK dNv霓.c/˕w.%e>Os x\g٠P|fz\tmY{f2}ѿ?2ok#7^]N5o##,'o%Z:=`zLy,9y\] o ]l7=z;br/[[.MOnz՗h.=M6ʢ y<yĖ2dߦb~Ϳ[qŨ)$ok3su n5Ɋ.vݣUo<>@ȵ^+饗6_PJnTx1AcN?aٲ-_z_֘NuJO,ӓȷ' dI;,t<UJ6tE\_PMhWi~gB+Dݴi~VpӢaIC4E&9]\\,gyz8qӞuo44]S_z p:TmU?#&Mz4Lj9\/]vaNS?|-8Sߗ4kC`2g\U]@ V.�7MtT'9]rqWs%e>O:7U-Y2.'kIהv+)G\._^R-_1C+)^Q 3_L欖Ӵ,t})Q*9u3d'Jxir&-EúOΕ囊}TY0Wuܮڷne3f.A p+8&ܗ9'MoYRU't t{ēBm+ESo32ݾ^Uְ-2 ݿsrzaյ\,^vwlϾZjRx~ܑ֏m�B8 W崁E_{wu _:DNXpCzszPLmפb'_\Nf}E?|?6L>w|fz=֏?hrz^Eoo#@J�ľ "!~^*2zR4f+}C %EKeS{HuXkz-ihYQKS]|0iury8wS;E;.[JvAw ZZ<GSw}A_X\*Mޟ .g4V㱷hEOkTI"unܹ]7oF-c[6]Џ+Wvfbz:H;E4i;&PIIy睢3Dj{Jo[IBi+ESOrv&f7'?χ/Lz^.Zy􍛤y\ìl8i}E2:=J=XeP֚ O57۴Ln_E{.z?ܣ>j]:eU=w[g@gi֬sιO8?nz+%!sy|m\VgOҞ1-|ɞILthUhak9ݮ~HP8*JsyQ V>I]/ݳt6C dsϽҢR|?i5kY^P(ܷ{g\ג5 k߳WHn&rK}K6ۮ\2j7fǷwo= &4f_#-? L\R`nl:RmmY8mG_qN^#K=ҳs]۹ k_~\]ܶ6=H  6c3_l룜>#M妽L[)m pTXᶛe6.l]7G._yY|5У2k-^&,7 /]/+Ϸ?y4 i{!8XľN<`Z5iĚB{ⴧbgqfK/=!N#[oY2nn_< N֪U+=p:,TUR* p釅ޛ֨Q#1zu Sûy-<{Һuko&]_Cr `=oW~鵨S"|uz_\Q P V}T\<6hl"Em#K-m[6?2sz-]#]Ƕ?X$/y2nrqe^meM$^h-/Gf-X!CM}|JSO{{np+q|9~r +m/2B<?lڰV PV{:u`܆˟KQvYvmHn+`~=m%}|=]J[)m p} p6�w^aZ>r8@kn7JfVvȆ+{FVr:ۤN~R`&2YR`flw/mڿzB p}kBV : MZ zϙ7Xjb >ܺ?NNrb.kc_C�]zE-ڳ[d@ZueQ pfcE?d%>ՕևpGWVgLj2C=zGgmkMkӦAPg? NoC&!b@ �w pY'1I63<NLټ`2[J{KK=|?sBTPN_KtW۳Mqnx]O̽gKg3!G,O&ͅv^;9[]oBr$&.-WH\ \$mŹ2W=Z6DvH2TF]ٿ]7_fmjM{bsnr{0mhUgb:j4ۍt]rVrsnTH h,R ~<-.+ln~ʹ돔 ba=ihO< :{=ta Zmg7ǪfH  V] HJ_1r(!Sɷw+=+1Đ*8&m8=m)$P{HRVmiC֫F5m p84n@ss'2>W$ "Ts_煮D"sU, V Hp~^s*eo&wח;>)ĎCFT pɶR>1~6kA޹PftsVtڶm݊88QT ` n>ל2aq\KNh h{bKvS>1~< i?.3Uљ,*pQ+eK,!qQ � ` #C$.QMnT68\7k+D#K.%qQ � ` L <I.Im&^1%j)m p?Jl/<!Jqpt"\8'%.rs~ݺuC$C`4 P3͕Ɇz5\VC^^KnOLO>&k-yqS9:Vr\TҦ72LG7>XVP6ol=4qƼ7(@�8пuWH/I)q~4T?ZIrYܹDm7UE'f5]z~=8.ȗL3g-%<ȏGKjVV}ڵkEgIb>VMgpFbOl2Q�L|~0kg8+z �'߶n+W.sbSv nK,]c H 2%;sףTm p3MCoGdՄ?%o欘suf֧tsw>[�))-999›n˗/[FE�ߠAvx~TWoby2vr0Ub~ɀ-s%=-\9MU�lj|U>*Rק6@ude-R`;+`\Ҽ_Z#�o]yx-UU'=8V.\$zr<|!Qz_Z#�#ߺqǽj $ڵxC=1B=C�@�@�]�gC�@�@� %̩@@�@�@ p~9>@�@�H\œJ@�@�]�gC�@�@� %̩@@�@�@ p~9>@�@�H\œJ@�@�]�gC�@�@� %̩@@�@�@ p~9>@�@�H\œJ@�@�]�gC�@�@� %̩@@�@�@ p~9>@�@�H\œJ@�@�]�gC�@�@� %̩@@�@�@ p~9>@�@�H\œJ@�@�]�gC�@�@� %̩@@�@�@  pk׮ IJJJt'@�@�v pEEEҠA uI*5_ m&۷oj?*� � �$@aaKfffNݺu$%%D\8>@�@�^ 64{쁳+oiW@�@�@ V[VV p[C�@�@�V�#� � �$@&xv� � �+@ V@�@�@�j U<E�@�@� + � � @5  "� � � cy@�@�@pn@�@�@�`p< � � PMjg � � @`X@�@�&\5[@�@�@ X\b,� � �T�- � � �.X1G�@�@�I�WM@�@�V�#� � �$@&xv� � �+@ V@�@�@�jpdڵ}v)))[@�@�@ q%==]5j$h�mիgm0ʂ $777ު=O!�q(go4\5{m޼Y6n(Z4 pyyyjѢE r+p'[C�Fe�Y]ځci֬YnʕRn]Ύ[SXspw�5[ޚ}9 𞋾yMأvXBڶm|[x}1ƪ3{W|G_\k}][{Lc x<k]x??x$W+hQ'g E@txE׻&�GZ! @@ w ^vG#Er- q e;QA#~urv��(נpQ@:9;D�p\DYNkp_|E"�8,@{'5hw8\/w>ТN@��Qe;.;hQ'g �k�( މ2x EKzduIsiTt݄u|˝,nKu49keR'VX`e@& ~6+#n' 3]7ҹZIҹa<rp+9C=Wc!bQ{.Nb[�Gms:Hƙ2rrTn]Na%eد+3-@J@uRyxJVZ_:>וeN(]WP"g}@_Y>jj|bb( }EJ*AdӦMcǎJ233UVQ'uƢ.ƭ]V37l%vn-FFJDz{ [ޟc:S^zlY[f=M vn2#=>Xf Ty6~xc=$;;[JKKI'N H>0DT}c p͗k.IVR"[^<f D(iIrvF-$ boNeͶbwVdz"eTqst@V\KN*;J֟SHFJ-ҫ aTş�� �IDATۿ9e۾$~:?/l#Ga9!;~|^UM@ Vm-Mf(v/jZཎo 3r%'+Ҫ{5|z䚿/i`v%2~),).2CZy! \0dY $QI&XOZ^^n/5lX%4WDF-~zTϊcຌ&soYE &~NW j+4!}}(GPܦ4-0U3YOLmfNdJiO3Zrr~VrM>`h-Gsӡ~̻tJ!nϗU1%G�\ uZC}Ur W`tWͱ_}tsM ƾ*=KDN@&ߜ)m}ы// xyQ{.ͳZ �7w\W6g\ZZ|'rgGT}c2hDfidLیӿo9J-`݋SeBYsuoIO%uSEz3,R[tǻ/'ЄC{[稩9]..ԿNZ?>Ѻ)d4ݞ/۫ cD�p=I}3qqfZ{N p٬s,-HefDEe{{E? M �b|8k|p5BC/* p>Qxpc#�=p))�_l~/6=揄3#7$ oG\/|H6Ztl+o <)fE^p2UϥQu{ufl.SJg7Ys ùhؐ3Ww`Ri dDA%)OŜŀ9t(3Q"$HX@9WkMowuNW#0W2 � 0{MΒy` 68`l.稭Msa{l9Kn<d96MssrI0sɥΧL+]t1bD 8WH,uvqjV(notgskV(|@;979?af,i t@ȅ'5-/1impDi霋kt}'Z_Q间cyHk^"&3!q^-HalgMg+Ƣܰ9帷gyԐOw۬Yt}P͹X%Ȧx5ɜg >-a>3uV)S&=;pcǎXwsmTGnpί=RjB:䭗Eu*HIer}װy2x2uFMrsu*8j 9M#u91 g &/+aqWpr󍸻3ps\ugʹauaMzȔIH 1ck\*EʝS3k{ZA|6O.ٷ< sw7[t>#w%' .xd\;:o'clHiK<e>wVƍ >qInݬևi*#>&ʔ򻳛 kQ,v\:|v)׸,"U PޝRg s\tu/^Uq^ZXb5P"7ALnp evBߩ+ĢCr֗O/A$@vL>Sc2 tz}f{&VE&o:N7{Yc=KὙ[(3u5.ONXDs;i%L\H>}l޼YFe˖B>/0fѣGrH)v$1r/"@>N$@I؛4>BE >Wx|TK n̙2i$iժ/_Pf |j`rgZ.v, {z* @ pw g)p}jС @ZjI.]^*++t&pU xg`<.S.�"nӦM߂ΜTU;V%pU xg`<.LɎ!pU xg`<.)4K]gL99eLU0#$@1"7F͢f 8 8 u4H$@±`;N((ଷwh֑ � P eX#spp֛;4iH(H2w,9 8 8͝u4H$@pl$`�;:r$  8Lcdzsf9 � �� X&e12W$#N,* � � � � � d&Pv8A;(zeD… ɖ=ϑ{:6 @\ pkͳ">.%.\ɯ*!fH &8ƤY̌!>1UQ2B廈"9ec1$@Nco m粭Ʋ'pp[+4iHc/ %>gwQQYoЬ#A c 8߱ <F((7wh֑ � P eX#spp֛;4iH(H2w,9 8 8͝u4H$@pl$`�;:r$  8Lcdzsf9 � �� X&L̓j)((7d֑ � P e8<YazCa9 � �� X&L̓j)(R(=4Y6jP>F:_NhZU^?At=zxraȑ#o)Rq9"ha3<We˖I͚5+t67őL(gJ+;o<yeԩRLA{8pTRE֭['vRlY9蠃dРARzlܸQu&n2~s#llذA}Q5jߡCӧTV-gM6/,~\R7o.W]u4m4t/_X7NJ*%xb.J}˶mVq1fW~P?;XKQ>b޹Ko:rB ˓?9Ko '7jTsިc$ פIB$JpϜ9s^ ŏ1XŴ1{ӯam\Er˔JtF?g/o]M :vXdUDfy,w|'ŕ\`:~US&3Bd=ϖ?\ ˚5ko_|QVZ%}?S "999һwoUnIB7/ zJN8}ݕy뭷V.(ټ{|ҥK%>#W^I(/\89sÆ c_(ME O^\8<-F 0sx*b3uE El(t@[Hę!*lGf(R(BMyƬ3'Ǥ8Hb:l&o~6lDٌ݄w&$]L^o N;4ϕp+Yf*J^^ի\{浧qꩧ{Wy;S/0ʄLBX::uR\r*J,|嗑"'x.);jU;{ A%3 {&*-SquZE&`/`#XpK.U+xazX KniZyl NWˑ玩/wΊMۥ dLzP v~^H8i\B`ttйT-S<5VA괕ù{fU36 0Nh#ȬYrjR&vָqc ivo4^z%;_Ng^%K]B"`unXYׯs=;HkQ=SNQJ/w+JRJ:,`s3<#[ W\VI; W^`|}UeZ5n /?dv-C=$ׯߩ.tsW/<-j[ +'ݠZ!"`2@_袋V,E,gq|^-b~8ckf WO>YƌX01.\'MBX:]vtYr2tPy' s\;x7qLƬy޻}hR6I->g"jmY  9 AKDDx&l?\7ݩ\A_{۶m4X~'T?Ո;]~:?8rK9`U2MH=oFŨEraWrԕ2sf%̣&*ʭL.;pq]vG!&nz1]X@:@mC|W*[ԩ\ *6F:x#xϞ=[:=餓aÆl8A /oA_{Nݻ+抸d6s$ALƈ#dƌjFΐ.']vP\r<z"*.M;n9_'y,j[uSz&u8%DW?+]:npt?Ֆu60w ζAa&jqoCU Hp@߱A]qgϞj1p+Ÿ9}xתU+e8s饗@, "` ޒݺ3t} [ê92}M4r8eE! Qb(t.kZ͌\\aR q,x+�o.`f0X.S79/-oh fjm?3evTo'j>xLu.ݰM:1[~ѢPDYЧ2rp^8xÙ3<Sڴi^n@zHX-C3 ~HimڛO^j׮܋{7~jsU=]8ZVWIg}v !M&=]d6`u.6@?G|W~N 8LK GC]TzmDMzMqHtuI,J?P cp:k׮U8g>*,�E,]s_m$t qs7xCp?�.`o &swH81m,!?2i$}.Jt!.cn*u[d/gY $EpsYxȟ.nzj-;\ ,aO]&sUj uU"+7ݹwWۡo3"r!4:^37K3 bk1Sa+81sL_eѢE" b/a@<䓲^y9jt6&d۽1nݪ|`2:vܕldy7 O5CNSXIJl2iGV_|v0MvAt~sOޭc7Q`&?oV)LZ$BtE藸qrB @ c[lQc <AԇgMmX/MGb1ɽ-;h# c n^vݙ<oZ׋+?~6CϙJOU[ n'`^M\Լ͏i<Ԋ.nzj-;ZpX4,@Lp͞.Se ˥o?:gа?VCf|gg ۡ8x3zP:3Υ&? IwD6oެvFj!=,q�U-,lDvp n8] &حDgH+~+!=g4g87ٴڙ &2i ѺvZpV\ŋɓID\"˖H(m.D OIpv3\֭ ;tp[B7$" <믿[oU"hluw1>a-QqE4 =z(A87S+Cz99.MA\Yf4s<R-KMVtqSkaՊOvd;SιunTY_E>F3p8{UuyzyһͮB[\>JFwL3}&;߹4\M N0{ \.$`;,3Qnzp-+au6t"а< x) .a$�B=3bX L,}YQ.7p{\ᢃE3y]Q j(-8Nol7qD5C48A.~Х咨\i'VlD' &c/ΒBb!^xsxB$\p;+ـ6ƶ:J^c92]߮7w�W8gtacQ<IsA&j<,B;P.-'cH>tw7{byf@YZ~ ԅ23R]<tqSkaՊ J,Sn s e]rYɶVV.TPn%ys=Y!+p[eoB9Y50gLv4si: 8&>j7%wILqq"aWʠ wpB@.&J⺇q&RŁx|[ t:&H'OVdg⢞ץgu3=f9\POe `ܛtyՅ.(Ǜvm5 `2bwq F_-XøGQ.B7p4ͽXG؟^,\ UbEmE-Hpx溘zc [vT~x}νa΅A!tdF,0s<0˶ڙl9k=&p>m:/O䶌̊%�\η~&6iDz8"Z*Wk xꏀk d!YXirV>yJNSS.b:@?`.gX[Fl߶={n v^" s8 6HRGco2e"}.֓8 8( .T+ݬO?y&m 8?l܁+iٸvۭg:$@c 2ebJɰrI\�pn xFJi{z* @ pw g)p� þAM@.9IUec>]rOwZ%7>9bъTXrOwZ%7>9b ]5 �l$`�]qFGgs@IHm,|29YGN$@$@6@ pcxQQYoЬ#A c 8߱ <F((7wh֑ � P eX#spp֛;4iH(H2w,9 8 8͝u4H$@pl$`�;\\8$@$@$@$@$@$4iR(v8A9sHЃQ"L25{FU3C${cR,f`˘(q k[p%3@2. fI3�\fCI\cIL*L H .8ƥYL!>)5QAGgUs@IH@8]svy:r$  8Lcdzsf9 � �� X&e12GGgs@QY�� �IDATIHm,|29YGN$@$@6@ pcxQQYoЬ#A c 8߱ <F((7wh֑ � P e8<YazCa9 � �� X&L̓j)((7d֑ � P e8<YazC6< /ߋ ^a8XlԬY8ɴHbDd)SH2eC+RT"֭nI~)[r![W^@qƍrg\77Ɔ /R?K/jժbM6ɋ/(C+WJ-뮓f͚%^J*%|b.h[O?${.x%*>ޕQOKQM2VquKo:rB Syr9=y_Z** RQYoZ;Lƌc//ҞfH ; ]vs=W:u$۶mg}VV^-~<j*%O<x_@|]{Z|楩I'${챇@1SOVH;S*T s[|{o$N~rΝsxW<C2p@ %{NyB6哝8rm\&J&j=:QoὙ܏ʫ'66q.*U-g:eժoCq⥻ O$>c7A'p5Jz)\s*J^^q .oQ ߼t6?x%܀wqW_B aO7t;9b)WJ,,L:U O?Q"y뭷drW2(3R9SL3Qiv""sd˿eM4^G".]*k֬Q+vA+aճ^v,os;dZ5WVeYy\o2bZ9AyR% i<ة<eLpoeOAS&/[oUƍ'?WTISN'xB֭^x wyǨAo7|<#* LTrssMJ}rGs6rHY\ꪫd}UesC[)~ {ayjuUVL\:il #&qQ]2 @>ӱ c v Nw`䠃Rc浧qG*LVX!{ra a6z,Nt#M؁ g}&~ڵtV?.HrE{VZ)Q1);i356n.ϑ/+Bu KD޼Ek]aKhK)poASo1}vNcys?#/ՒfkGɯ}Zr @z)-w-/C&/+6G U եVŲV˝ncܽşgŇj5R/v߀{ DP.]kŋ$ 38C6!رzcᅶL&?8Cqꩧ*A?t2൥{{ _~Q+$ô\:r.:HD{ƤNNtrk.}Uoҥ"(spqO-Iq-1m{bNآ[8@ΔuAj\95,Wgʗ//Xf͚9|ɝDn"9a G0`{HeM8Frv~IEy+Lぽ.n*&N={XjԨQVؾ}|ÍfHcyW27eKI吺bN Se#:An&Z4~VjLMv xw]#;nAnݺɁhVіq6 ϸM'-:a%C_h۶!j{OT 캭_^}'*ikZ.o?d˩ͫQE2 @ӱ}�t߯κaU*ڵkQ8gqGˢ;yEAr~[ॠ 1 mڴQ52c1.YPE)ر?K$?l8s16q.nA.:}.Jt!{<>I]RVɑH'[pQZwl/jS.~W5b`WaŠU>d v,oG0;]z)SJFBשQdws!/?bsDl>}L8uւ@ȹpŃ{G}$a6lj&!LUm:3 B69yd%JqXe˖*({0rX0tM˥+?Qy S^MqH >'~ Vwai˖-J`WLq}"1cn^ ??5{[$v tpnKL^M+ Q^>!`L\}eÕ n-9s̠[(*\Լ͏i<Ԋ.nzj-;Zp؁d4,@a0dܠ-޴m:u8&O_O'&܋[Q,;Or4L+W^�aD." pU\&4޴qcJpv5L܉N=8`N;J;̉Sg#J&" ăػpBy'݀,#`.Xh ~Q}؈ Lp.mb<uw1&| 8'\Fx7/h;ѣ eczAbp%K9\[O<ZzJiL愘S~s^Ҡj,XE8^^pKLL給P+驵jEapXTsn1_?Qiy~|r󝌏f鶞͓-{3p%:Ig͎&x.M4w]w5L2ӆ2ΦWR?+C<ӐJKn.Yd0k#82 y9/[pg1iڴ]r„ B".oو/@ ؙGՂW:uv"q 3ؽ+7$ };cL*LrG‚??]v}{jHDҁkix` +yJ$?pyDxQOpӻᆱ&'*=y&} /|T-WFnq會;4Pa:֡߂3݁ Vϟ?]ɗ'8bu+,`nر+:֕Nz|hM]Qy?zbv[([#kW[(ɤg:8ܮxm8Cnhq.nw/$#;mؙƹ5LB\I0B{l 1QvC,vpc \%R(r'[N :*\68dɒBl2Vqp\Ep:ӧOWc"f`< [�~Zt3gTƊ?: %Z)xә7o:8qD5B jäϹs0F|ssyWJ|Pz8+ LR'}t^ϟ.n\ۍI8lofY%6iDz8ز7|ZJ]VSxXL#$@6^V @bNm8`tj\aEgrFö$�΂ #E̎2gB, <XdAn n*vѶqX'Rii� KK$@2eb^'rI&OzDw n\ )؈mۖ-vg9*C Q>*LHlN$@6Z)ppć6jժ>$RY|RI7<mrOwZ%7>9b1 !p7H MwI*+Ud{z* @ pw gV\dJO͐{z* @ pw gp+R.'t�� đ�8:˜Ns_mSQYoЬ#A X-$P pSk7e9YGN$@$@6@ pcxQQYoЬ#A c 8߱ <F((7wh֑ � P eX#spp֛;4iH(H2w,9 8 8͝u4H$@pl$`�;\\8$@$@$@$@$@$lB]իH6 .2$[t>GO$@q%75r�\ȗ|h[p%32: f13�\TE\"fc䀖<� d;^`˶˞RQYoЬ#A l$`�]qFGgs@IHm,|29YGN$@$@6@ pcxQQYoЬ#A c 8߱ <F((7wh֑ � P eX#spp֛;4iH(H2w,9 8 8͝u4H$@pl$`@&w21ODސ9xXGN$@$@6@ d|'dZJ9 8 8 u4H$@pl$`@&w21OD+fWɲyPG%l(0<9oT΀"g!|'q"".[Lj֬YKt絸ʬK[F?i;o<yeԩRL58PT"֭nM~G)[tA2h ^zA6n(ݺuw}Puu66l >5JСGU'M_O?TV\)͛7J6mP:˗/Wƍ'J<Pe]5aKwz(]| uh:ѮF8>1 asJ%JJ9ɟҥ7U5bylT1ZkҤI!v8AgΜ9Rŏ0X˴'fIk;i>#eĈY"[q'|Il-G*M*l0MHΓ>[?pٶm <X֬Y#7|⋲j*۷2dɑ޽{B|tMw߼exꩧNw] z-矕 a6^)_tE>H>CyWJ/#8B>hܰadرrk+T|JwyG0;3O餢1͝ 9<1왺O"y}[VNyHa dȱDi6dFEi6t@w}Y$[?ZT4HUi Di&n͚5SQbPzkV DמƩ*^AtSN/"_MeBz&!,N:)V\9 D%xdM'x )Sk&wuWh&,M1);iKfLTZ%6t*D]7xc[tZ JX:vL;7ȿG/6I2rǡɹ{绌,۸M@A븻WBF1KTg+eJIsޭiVG֕/k$ ٔ{DvO<V.;v �GyDf͚%+WVl.D"^K,I:oӧK~{M4~QӼ^ZKժex]Xoy衇d;u&zƍ+ڵ kʝw)?^[_5DW^zIskAo:묳T֭+ ,PuGwAl0D9Ə/*J+21#`:z`L袋V%o38C>cno^{:{rͬPzdŊr'˘1ck2&vq:iҹˤsj.ÇC8\}ңG [Lڵkd͟N˰tL8Kϙ&vϼna8mr eұ^%ys}[ZA3?][%+ 87L>`5Eqm*]ӎr!ɱW_^= ְj l_S\,/NYvWGՑʽ!'6&)#iU/.ivgPrpX9d;0vW_}sb8 l:w}ԩSG9^dw393Ԋ9B"e ځC.gRp*"0Ƅ/(`CcA ꫯ{Λ69 D<\5j\ qatyׇw|I'IÆ U{"w4c7|Jġg!1WKqwO?]p " <an96=P{(*~W=]𧃾޳gO<,FícpP={ڭbT/iL4Lk%)?} \|lQb(QV5d+erOUys%-wYR.0`AըQPޱbW6ii;#S DZgسJ*92w; }ZJee\%-5ʗ)})lI-SahO8=^!Ɂ[&YrEdDWp/pw`0&68C]72-L 0޸oE۴i&4a Mo^i +~`L,r]%]u a5U}钀 ӱM t`Q _c 3p:ص"Ιa?%":ŠfH`Woܹ @"v[n;ec7=Ďyyw}K$?L:&mq#`DG7mgȴ KY炓9-oL9]㩔 86; l \59sR7Xwg'(nRB(,ֳeyAnų (EL 8ݶ$4VcҊ̙3_Erpt09rÍ^gw` 0qxc]OUTܰA``O^{ؒ 1 JC�w&L~Epon?5`7cQP]W`v .dI؋Цq n{#Ďeu 'ސc <\OGba˽-;hX".˅3pp]JugB|M;g8'=Ki3pQM*\ w_e0ttq''8`R pT No͑T*K]rRv&MQ]H9YDp-t@ p^%4m{キ:3p LnKbgQnp0HqnsL`=H:Qqu7o,}<sj0Ê{n¥cc9)<ۢE %M. ʻ@ԍqyLtE<x\݀C)EܩP뿦! ř3\뭷j3N"J~%*E�O"8tV}?pU7 Ad1x0s&tV".KL=[M 54tq''8LТ&{*j?9M>=4qe&C_W r:yN߼Jx��7IDAT.h-0L>{1%lLŕHtxsIp8Wm6qD5Be2bw yw{0ʎ]) gc۷o&68;=:,M<YRI갠˻~6"/>yYCdW2%XS޽Zx6΢]p;KdOg.GurQx ת<~:|S.и=/Vt|A#'];*͘d8'=KICQ qL83Wo \6"OzUZ3p+idt'zˠϟ.np ؁+U kTozߺC]V ΍<}@87TJ\8}2Њ[=\0H!e06C7qCnr݄p7{TuIYp{(._r/ro19&s0ߏ {g?Q| VH X?O#S8(Ng2a G3 .!nߟ^b pXN\yÕu1M$qE*a.LkqȏIsOD:Сs~&p>bv&uJ"=[([ O7m$2Zpt@]p\ 0L;<ǡ3b˜1'$`�^i2ebR'r3;sp9 2l6bEGmk&v?3q}=2ebQ7n3. pM;Wu?;q Fl6\zh*܉p &D})ޤX8;/2fLsLlK\'q" b-(c}3*@وSA5:Mrf$@$P87QGzsl!"rCokT7H1%.oZ# v@v 'kV\eJO͐{z* @ pw gp܁9YGN$@$8Lcdzsf9 � �� X&e12GGgs@IHm,|2KZ͝;WԩG~رdb{bH�4H�9+4'!I&*CԢE+T`n1bcB==iH 8ƻYz3ŋKÆ pƍVZYˊ+=UGN$@&7'>gyI 6͛'?DmݺU-[&999j϶#pU xg`ϼZp÷ׯ_/V|:H{E 8�rEܖ-[?]R!\$@$@$@$@$@$`@2e$77Wj֬qf$levHHHHHH Pu� � � � � @˒b6IHHHHHmHHHHH�\TI$@$@$@$@$@pl$@$@$@$@$@$%(ತM     c      ,!@%l� � � � � �� � � � � � d  ,(fHHHHH(HHHHHH KPeIE1$@$@$@$@$@$@6@$@$@$@$@$@YB^Z����IENDB`������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/fp-app.jpg������������������������������������������������������������������0000644�0001750�0000144�00000167141�12574421673�017536� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000�������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���Created with GIMP�C��C�T"�������������   �`���  �� v!678STV"1#2A 4Qa$%Bq&3RWt59DHUbr������������ �>���!1"#AQa$2q%34BC DR� ��?�˛�1YO8~z}g``'I#~՚ ͪ! e진O9E ۘaqhzUXc+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~E|1_ň�c+_"W0Wȿ{sX2/l^~LuXwXD+wG]ו:A2pN˄S{}S)[) Hm?†2rR2$߽\Α".bX"ETu> `1lcCѿ}bwȀ f;qhzUXWG+׺SP^[QОfQu[m`m őy{I[`B6|BQ@E3li.Ճ(Uy3+WKCXT4=9|YJ!yjGE^dbu`7]OAýڝfh`֏V1[X'0PB2ݚ> ;[Wѵ :kíx( 4;+0((ΑS'-y=Aĺ[bL@q/b%1U R̮1Jۋ&X fMpIJ'M;yqr*$Ռ281qu9ל�0 } ;2F=46t`Qe=f5!a a$Hzmv=}*hLM]GWh1x5rK>#���1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `���3?wf Hm?†3]o)X FR߻"�1ţVAb_-X^  f'LCY,D}XtvPFZu`|Bawij]fF,R{u�)w�57ˆ]ӥlٹYw"( xɔUe1SI21s.3gX⿥^Xz5G e#uS$sb(ēPn5[,zL?Pk5f*akR @Dq]KbYfD#=9)2=g;$Rw4BVao<" x* ^ݶTJ7t.1L)}#9ÎH1ֹGz~r;9Y#,RLYKT6_*WT}N]R'mjb>r1rJ)>pCaN b8^Mh<m+!a{6FeK*9Rb3hKcRd*-f})5r|c&=?}l'{]L1 r5Kn* j 3�K~*z/kK{Ebť!�0�<)mWpHWݰd|lEezJv5)b( ?S$dIjbs=*r=!z1V--AFۚ]v#eY*;AxJt$K/&j*B>rL(^=dx_T+--vPȭU3=eVN\eP;E향vuL0^~T=~p#\U9Ku &}? N$ 6VSHݲa&VIVVW$9^0D&K'馧/%hj>ͷ.[`aw_Vq"-_,_'ݮPߦǏXzS^'k>bRT]ۧ]|�Co76jҙ}m0ZTV 7ni+7W sIOT˘b2Vo .K>N' -FұhI99J#%-aޑwe\ =cVÛT51ݞ?WQ:Hc*zF(&0#&*tS5[0gNs_R疹Pǃg' -4wZA9U<9'f \4ܐ VUQ':թl kɫOevggrNi6,n5V'n۬Oa=h^:˔!LmkD\]!{b/d"vUZ}N֖k%*gtWh|y97>XGmHIKuKf[tFR1uB&nYM"eͺ~W / z$棼߷.k_{ˋ4Bp޼]87,RUiH˜.[ 5M+j{p=Ul^G1)02P͛<¦ˬCWXѨ7v8i!oSveYk27^,bn;e]˷<cW4џ4m=FU6auwXo׬m]rt#N\l<i^AX9++уGIN\HUČ3Xf6b1WF`(vIYrKm\ ^z*9iy4Bf#(MW HdK%+ /IGg^PUZqGON/%z3o&'#fMxz W.Yhjs?pr"A/v/bg"eUiTØRbW/.׻SyUʇm iⴥqmZѫr6PJWmyM-Λf~RS9im5NJSebN:˚FCfC?dw "y)SQGzJln$ߌqrn9kTfmYا9EH0REwEo |kf21v9t=F\xde; )!򪄈a"DO@rw]*F^�gz>1O#$ \m,VWHLڧ1*ﱓU뢖ǀVdUzYRQXY{T4+Z;`Iďpe%ro5~•/[tDt-�싊|͛,h Q3 e`Ʒ2J)zDck_7f2{UmZe:dJ<3n+x˖ Bz!$Wm!!"Фg%2"97{^?yvXLl ##kW*3L;K&TcnNqWn.aS{#n2Zs;65bW[tRC<-1$?"0͊3t]9pT6z|A=Í_jYGï7q^snW,^|6 eAZOaYݴl:lkhLկW[V,_,Q0wZ{"֞Gsn/Awer?i6b63q!(dUUYX[GڼxI E -~Q9'Uk ^ސE⮙Y nRv (yF4s2mc#Y0^k-J5NX7ǗoĞIδF21.ʹlS 7NS}# E[݁jOZqZ'|XjU}{HD I6K5f'9S/Mba伽oz~.MqKP*L,YSj[\V:E:Q>KksZI.flΛSJKgcFL ,PHq6zCα1j13T7˟(Lូ>\#DuQ̜8r5\îdZ-±9`Qٜ͖U =-d�yAݣ0#_@olt(Gc:w}PUkYiWI1dd˩xg��"ˌ��c���0���c���0���c���0���c���0���c���0���c���0�g$6D!Aۿ~' fߊR>;d@#vD�c1WG+׺w꿜Z>^d {ٚ*fy~ibXgO#Q~QSpU2G2MVF`h��oDs뮻~U;E2HK19Os1S}:oMq/G ЖiL6̔L.qN[}2- pBf# "#1){ D~S_ 5kAj *]%I.LQ7Rc`*fnIXyxȝHL]AV9Y3.f�߹}u}͗:i#$liH̰LDD|Dei뫨Pt S-CRE!DE#]mW]csk rrOVn]!=%ݬldەETT>sxf keAri[#uZد:Ym5jggexUMC1fc9lI~Os?T?*XՖ[:gd~Ϲr#&'$%"2Q=#ǵpn]ꍦ\]S H{ϤtvvKn�Wߺ,Пqjl}=ezgc),;\PbÓc^P9pR)qoDSpxO> 67vj뵵3#U@>٘f"f>#<57༫W%)XTL;&b'DI׺?$yK]rkvQjLsԵ q+%5ng. \˓gTQu>rl{_楽2Mvva)d|/{6O Մ 2ɩT;f@uqOs?T?6gދgv, &RQ3]=g<7*ēfivBW3+s301񚉪xY %7fK ɾknA#eDѓ/ ]$ "&s̯J֡sIsm++vG\HɆ+SUvn5v5gcQz"AHj]bI.|'~"~8loC};JYhli"uٴ@=&?1Lk<{>=Z:jXύ)z@mU&dwY�viAp܏gF푻2Bk "G LHJl&aCo3 $Wr Enbr5fȦv|=EDM$QI>)4I2B!pR0%�߹}}(E֘M:6GP`V (�]2eq ~1:V wZnJalbkh;{e(Xi&ֻW3Om컝I%lrˆ$E }<nqA"rl&pcu˄ʹ"MmŮ\*U1BA ݑܢ̸GO<<Y˞'{1}�߹m<rU"YQQSG_5`y҈1ŴcrvQ~zލ.LM枣g|fGowcG2:ǣo֜,R-e,KJUSH\G˵X`dxv׺:IYMvudnk>ៜ%l1%>ff1SlJ\R?T?OsKMfSM*{WG^�7V}zwز\L۶&YL S5r3=l+QP1fdocXyaJ MԲdL $dLs, #��߹}9)ffg@Y11b"#"#30"#f bHGH""E2S?3333��"~8<'~H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H�#��߹} d?}�߹H xQ+EE@Ivns19V1$6C7┏N~)Hݑ�wU ]WuY3�IWg=*�� C����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1�,�ɑYtzv?XŲR{p0614}iZ5n]R0b涳עPELVf8b%k0djEدɪ2/XoEt&0Wr&^q5mehŒ u6dz]W^65n2xY Q0'[Iڴ)N/k7JlZ{ֹFrM D38Uck yr _KOlWF6<u g0iX{M@ՊՒRms,Q!H+<m=f[faaX8U(Y+44MvFi:ٓ;t#9/gç8|ިm r2E!*&-&2rWIDSVro vn0m.e$'Oa<ugbsK:wqېuGU=TiPqgwKTdL:c-^]2@ݱQ3>gXYB[7۱Xjݛ#iب sȭAׯpk>+׵e E'+vmy"w({B^Vjk ؍Te;ź >=軺źT)|q:Ef\ULy[kz&E&q"v4˥$;=\/yZYc)ye�6Y a]5%Lx3(:m# xѳؚ7yr4DnhIu/R6X1,FHMͮĒ*S)h6[2?a5dDlk[]x7JeUB2b*_g vgFTٓ])ǩS"e("̬.S[jFuȆ+e'- !{(VQ!B¯cC5RZW'uw킈i#]^vR2&Vӷb{ZƴNmEuYuCm҇f!5 Ri710o̕o?gnM0{'wXX5Տ.7Yۚ\7S[_ao+mq/\$ȾD$YƙtZz|!Ġ_47ɋ&Msjnea*֣ ®ʓDO#g5V.ni6В_ZmV)bY]%!,UxO1RщZZԬ4/˕0TRT00tAXU |uՁ'^Tfj+ nܹoLVlA@׆Wђ��hq<(%�?# xQϳߊR>;d@#vD�c1WG+׺w꿜Z>^d �0���c���0���c���0���c���0���c���0���c���0���c���0���c���0���c���0���c xQ3g$6C7┏N~)Hݑ�wU ]WuY2:kMD[#Vm}ɭҦD&% ĺ$^geZNI7&kYg ݚm^@lǮzq]qjnUu4Um73\3q:f.6xwB>÷fЅB\cbPƒl*&պp4i*&6 bS:JڹߨbhdeՖA˶M,U'Bk)]Zuj|bAM/bԩ۟ 9oaIU*vV ! hg n^U=S=.WY{ף^;Bl*fA 9kdP2㻍E4:v[-{ >,бGl7oبXTA*]wCvuKgs#]Sl IK!&քHpr'S^]g[>\ IKǦѺ%)6jDȘ*_,ffƛ(6G.Z6:jwJ^iyU.f{vC}}to;bɓifF6蒰n1NU95MKfKϦKw}QN8 s랕hz[GS,eJ[! à% 1&TyX:dw9 zMcP5w\d62a7 \Ne֝[c:xEa ~}/oi 77zSGVq\ b䗮26 5YK9ein~i{_Ƌu î_FK&Jv+-"&\LF9<>b˴b߳|fY֝0¯)a!t˷ʋ(vr 94>b`Փx$ȴ;Y&ݵS\;cUnhj.YG _ž\W2Z".eVQ4(-F(BJ7H~Gm]Qc5uJ~ћyfVn3YYuJEm5Fx򯼚*UFѤ+j볓_E{ Sl\mt[�ݥvlJHbK6vO\6hi9'sؚQ4ojγ QZVˡR͕Dqѷcl6�8Ӧydixod-:&)SP}Y4Dt*h(6RyyҝƶQ%"vf!7n+uԵ3zf c ɟ+׊đ_Ed^dӛ6:RiZqviKP/okRҨILlŚ4ͭұN.xVx>V&<Mٷv޿Vɬ"g4x*nu"yu>IG3rOre[UuAE�O~=`}B{ݴ@O_RE <n~E H?Y;b}BCQwlvU7BYTl%juEھ*P_ fٻ2/$~ŋu=ŷ8#*kS'"R6Xz'b&š҄vT$&]Glv蠊]`j.R. "JpWpLn(ZϥegL֨2;ɜJ*Sp)Te"bO- RlF6HvYGD}~LF V~$ AFG[�rTI/Q+l ܿ ;cGVa)VNؘ0'ۅ%?+s+:Wupvɭ˅꡹;>rsl.bt[ +4^"j[Jt¨.IHxl^i;nX6V'mtiL8` IDx"g$U /I^'UnK^G9jٗHvE\LVQrOί4OK6+dp|}]sjOWRZEyY"DԢ%s^I.: ]0钱2eR qm.zrt*{:$�:VfȮEn-t J z7CssV»=uuY'y YS?WGJ2H cߛ:MK'{61n岤H;rd"(CƗ=Z%Weآ !9y0f1,Tb~4ֻvsdٵlARG<:W/(ӇϛCr6 R.*J܋ٽJR:׼J|:JtiR6jhH ٦n3ZPQ<#8r?8ڕ^}J4S .T/V)[e2YpB |×ֺ!Hk(&qu.qigRnٶM�H'`i)7[掗*/{__j봭zfRtkt4@{/*<,^Xi<'Q\maG=(jF~%7Z+iNp5cB4)MK-#uqWdM'RlKҼ4N/!Q-!#$%Q}{)$E*>Uā|EwX:Yu� EUtФ�\l\ViVVXe;$(|S>M,C]tg@Yٰ"ڼZHi߲F@]Plմ+ uKkEho.{_ZZK~j5o �eth'Ѳu4o(6]Dݍ+XE)"k@DCSyNÉ9s?mTMNtu5Gy/y&ת)` SFIy[X_f0l~M ''!m>ojƓrtOc9V_h-ř 9.݅68Bԟ@HRq-,Vq8;`mvh44g c㳻zEo�13K4$#-JKMv=%vqh=^ڂ״lHBXi \\Wc�lWEo=4P`uc_ܹkL[̜HaL&5C&[ }9jTy5lU$+1e²2I:*-/^ZKPtĬ˾9l}yx国xXI~Abd7feY,Cr}ˡ6{3hO^j7]oTZ.nqXsNkf}̝@ќI+>> j=^}۷o[۰7dyV]ʾD]lZIN8I'Ol;~U9Xjr؝F_CKaCvuQNv[CòZ}PζmQvjmz)T}}~†KoM; od&A^+2åE �:��1� `�����1� `�����1� `�����1� `�����1� `�����1� `���3?wf Hm?†3]o)X FR߻"�1ţVAb_-X^  `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1 <(3?w}JG'~�ѿ}bwȀ f;qhzUXWG+׺����1Ȯ{,QvneG4<P:ؑۜS;XnW TʘQ\2#ɞ3=zDLHQ3?h-(9kc"%0 9 ]�b' 6􆦲Ėq:ʞ]e|;~$V*OrS!:3GoyUr{ovo1b:w?R,j?)3I41q\.\&J$R,IE+R3ϸeFM~s#wmߞ)>ixf+Ft=Ì%(ҕSkZcOR)1j!2bNP"#f b>'-K{[�5r֯n+[X[8I+HjNkmNTY)x tI^ݱv Qr{FQ W9s*l [ j2{T2+g0l\dA$ eX1/;+ۻo]j}scs|ٍM4`m UtYڑddvP<ۻr&*!.v1"N[Wt|m^ʡ"L21S+a#`oԡo~?'v~{/�1c8FH>RW4#S|~7?puSN&qϨCkb=!rߑi"^Ij Td'!vj0)s1ce5p8pUZq�L9�xBȸիjO[ 6 Wm"Tl:KG:K" 9LSg7\9^Ad}3Xե˜`̹"Yp&A4"rfLAr嫼Z[Kl}XXbkWnVIkɌw&eYplYu,^5kk}/ӟ_jN;}C"qZm8ή붚EN-ڳǵ˳?tnk[MM[¬k8B!x:9&.\ܣDz3G*,4hل{3bŚ 6f͛df["R"ݻtHDE"4!HB1]"wnk}} BYyDed1['"uC=3;Úel޷*c+̮,O2ݫ*+a2="=�F;P/ȥ6y = rP9'1N�Gus5UkVTi)hA\[flٳc@+Sn̓H]鉷lgvW]Be2f+羛<cCy$2% YXU!mRt-@`C2&=f"0c0 C?3z=ꆣ_NxǨ=~U䔊5VKs*@_IpUӓ}I p>˹gB_v7g6Vu Zj,>?b~;dg\ܬkrOFRwW=k]$ߐl-ShLW  lo|UGǖBHUJVMâ}t|ogGG4w;�I~-vڶoFS$"j%f@;ԧ %ߦ_uE}q׈"_k5_rذS ꘫ䊳 \ost揈y56DN_j)-^łvg6ecШ:k9xyP6ytVzoĭMrV!�;}w Qk2:y}\vb [dJ=tmS~[+5;v^^0 [F֭w ][hMgn#\+u:tT9 %rQ4\TFu[6ưQXG4y^mժVB.T.r͍C! #jۍ\3GkvJYk�mq˥ZզժU]ZE[\ĭ||~Ѭ603F,kQNJ9/QNfUdzi&ZĽ0ȹ{7! zXsŸG '+|ݷqQwo_)niɊCMvz~l\U܈Uᮦ`l"?pop�[l kamEux5=gzuK_[iq$25[fZ Kb"* Qw2lc=YY,kεp!5) ]ܻLξVEQu >-Ѭ3JĪҌ.p{C7O_vgŷvqZOY=jTT$!="uNmDm!E=iIboNɄV&&i֢vu)`]QX(ņAf' fmk.f`\ԛRW[YyH6 ͍Oc %cp xs+ :7^<uߖwle,hL#y^ <ߑj_i草) X|y[6]nŌ݉Snb̢WhffY"޳4Nkx~]\R4TjpuUݭt`{ñipsInYākHjaSWo/8C̗n&b 0'>UV̂vafMIFT͗no)?qś�Ys6jTatRwNmʤƋl{d;HYҲ 8小ھ]:Z}R.avȬ9Lr .Or_HtXj܊^ٽ ]{3ƛ[uT`ZEIX=N8\frm%[II͡h zXsŸG '+|ݷqQwo_)niɊCMvz~l\U܈5W+qX5eeg _5Dt$eU伧ʥy]qwS$u/!nU-_G2鵴f�]XDT[pohn(\%-xi2{G-F{jų, -8ze,<6%9/^"R޺]4غSiX"ljQܭ=\ "X/'z/dü[ٝN1c$)1J@4W476텖Mv茅dʶЉ_cN fp’Zlk8sEr*5cͭ33ʲy&HWe{?3 N}^+GMGחqJr0h2rO5MKṢZ֑U-j1SR! G藷Gnl{v'ޚV\6ծN1kWl՜ٯŮq-,vGM%+(v\Elu^EbT\{7~żY*-usa%'p;NR:5j^VQ*}muݮLIŷ&fj~Q龲_9g#Ϊ)u{T M]Ӑ?-64w?9 Y."԰}N.[Gk="%*в{e2WKT5* )0v;>X"XJ"pbY|Sqc8Y33#^Ew],mv؝-v�|ݺ%7mN#mىlZ] '7bETyD\o_?mlOtZ$ia])sOUs3/36֪y-p^1H3p}uWEDT<M8Jڋ;QYjX,) W+A`z^L1)`>E_�- %w>⾧larCtmuc -M?�U̺Y ;@pgܐ.R)~Ը`jm:hj}_j n\mv fGYEjQWIlb%+NSriBL; e]M~zЊ[:dvMs l*Zӂ+hٯ3Rw.*YeV H2}zʗ/ CQ.ԛ#sZB,I =93C:0<Զ%V!vyWDVgg3KvĄu�!$w7D6ۜk|cZFlM{JmY^8l]opk.6ٷu9ZJ.`Mr6bT+h1uW]q1b_wiZŧ7mbҡkEu[\eg0B듺!"i^dHֲt�:k;\Pr{/@sݷ7>Tg{ڌv%h-UZ503*N>N]˧'qc/7L#7ً9.d}gu-%s:%AF NիR]c<.+[Ikq-u֖~:Hu}֕kkNL-V5A 5lBz1Feo v},& $쒍u]tw|6^E%S9*i&u6 cgL119씹61Gw+<U6Rn q`xrKV-;$ UXWkK4Q:%"yg?!RmrK>'NwXlt>ֱvҫ/)yqMJd,+꼴ZuVmN~[3{jyd"t|cTkE$l2*nkۊ-Mեsai4ҏ hV`\ Qea0ej5ΕTVP 8Xh]W=wTfkp,;MÌg`8$9l֜!syݻwݶ>*m-I/WUW8uVV%{.wD֮usiv0%:R]v+ߵ^g&:nen͒0IW 6,څ5 bYN;AYY]` %c"LձL`�2|��c���0���c���0���c���0�g$6D!Aۿ~' fߊR>;d@#vD�c1WG+׺w꿜Z>^d �0�.Q(9AuXVREdQl1fo;*+`0\G7RǎYV^.JOU|YzҚRdcvc<33xUrcjֳU:a,$D"!!.Ǯo�ᜣղ79;6I^ͷSJDfŚjeRpgT/m#ͰQ< vlj0Z].0i$2d u# ;|<ca0drG^űq;1Kl˩YwL٠d;r F)&%E;ĶdWY$0SW)\91Y:tG*4Q7'rj΋ts62\ӐMhVY"QBB5"uު^QYUگ,e˼K/%m!3y2_?7z;5ޫS/-j[6{5v;\vא߷Bڸ[kheœej̆ĦۅTO(kc.PAHTQ) aH0|2dU<ݚr>X޵eq~Ø٘#tC$]G$]Zۢ]CK7SQ*$! e4hCa7wNgIN\7^? m J6[{4rdr5H\3VfXD[&g(b͟ϤOfX/-o͙'xTY&x'A9Ǥ迣șg/{}7>LEe:[A~1ypxGVWl#9<uO`b[j"^5gqs2 YNPv\fVWT{f7y'g=}s*iϖuL6<]ruWq_U<W")6pT*XȣT6mW#l$ 2==FFwa9f .D͓+ 3i2DaH#M<G k!: 픊ZBc2%2r{'"�E~4M�Oħ�RAz?i%+{k()iubd9m0].:l~p۝hk`FmqXȋLDcSrij >9tTZ˵EGY:r G[d`@,HMN3V>V*CdRh:j31LS`"f""n&kUVmYsk7+i]ھ03ͲCBe2O_%kẋluks_3GW0]xWC 8uAtOU]S]&R!Cә5tSw5v.=Uv QUuv$KBƈ̒`R&~⾷~,}?;;M/}*;�MAriG(W8֏ bKGl?N;'giEUw)芥Soi*4EE0T۵n^z8eYU u:\vU:Yg *9;<S9UDV>fESUDQ4tB.,rTLlbxW·-9a9#cTZlpd62E[C%%$HdbP^V,YF2iѳ fŋ4l͛6ZDEv萉"D"i&B)Kcm=ڐܻ@A*yZl,EUc1ՑІP߭? z G.~qLcU5Zl~$�] �ڮ85Ob.uwu# Q2={vfk/fݿ~I+y$Tj-A[ԛSM4핗;e niQ-+S~>ʱcs="ѪxԿљ~df͚jX=:ƽ6UUHX}Vs,LjBn*íׯDՇ@ sa2-Bw(>].Uwbr~R\k^|xuNIӄy*Ɯ_%BW]YBw&8`TkAQ.{% s[ 8UdjE+a'Pe"k޻`pIJNRSJ&(&;VtuȪaUӯHT c1,4~V.C:}^}/;Zc{È O[8^?>>srml}xu}e{'jK^_+p F$1m\oN-S}O+n;e/jd]NfKP[m0Ѳ6$|ț% % v$Ej.VvzFU$ϐ#ለ01`kXE6jk)wBWCYnrwg0ܻTMlԅ.Rq2gFj}H4d>pCfk "!)OIMx]� S˽bi^ VggVZg,H/Y\j:Nm|K[  -b�B|0?+oGgޑ[tDV;'ɜ&R \2Je4d {&9ԦO f> i.3*g^A.jݦxD1]veU@K,*Ù8v.%<,=+gkhQ#z͎n߼gjn+1R:QY56rLDjY2jmi5زT涫ZB!n]e1VL7n`qsg%v_fMttw l} 6v:?I:t@΁QGmdڌx[AjW3T{SۿKںnxYL4l�&&G,ᢳ 67,ŸDղο 3&&W3#Y"k%kMbR5JkZUɕBU!йZJ.4G?VXuBV+V:[`T"Ӕ%zw 4Ù L܍QӬp'pT:OQtrM*o'ޥ_"բ&fdo\Q䍢"rUȹdH5LLIOI]1*%ܴ26["`4ֿ͑`(Ȯ rN{S=Mm[S] ᴖ,ߝF =gS2BytejI^k]8U}mFG7-=0ٰo $m=ƶzk:.gmlL0YAkf\"m-7S)mGe.עZW鶕Z^VuS�j.쩳/Ue5ᆭϑW_jl[Y +tmYIKݧ/Msb89ϭxa-I縂7>R�D`[o2[uUp'RùކŊv%]=X)TJZH6t&ìшfMZƵԦ[Z[lT(%RPzd,TI[X D^N"-IotRJׯz .Ӻtk Nڴ*Sݫ4 Swՙ/ ^8*I$ [w#\j=fY-+Jt~h{ \0U{~n]ot*OBɴckl,| "Ln< $[:O+*)]X\<e=293%>&;Nfr24uIQj 0JF$K�1Ez9xs͜rn=Q%5SRjڭKBM4 6&lђxu m,v?x$BgFr1*IKIJ&�,5wk6MZS鹏N?bg1厮C5BCֱ��XgMDD_7-= |wx¼&+uEtBFz¡ m,wc.?y =an^ juk\қvLw\/k!wT!<&.UT{Had(RB4'IGȭ=JPw};gDdh40כN)k3V%$֫Rkԯ ,,`:;b F1 Y@Zɯ;6^�= l[q[tt;޴2gӝ|[6njJܶ}^zMð]4i{ZQ\[nfpκ>ƙrʙëolB#inH;g<Ya0OE,m~cbrGODȰAdVD UrB&`T-c5cMkvTL QvUa M-=e4[$2[`&*=tMxW/һZ rZ&tƣqVAR/Kzvʞi$ԓ7?p؟�%5{+׎Wʔb*\v)Ack G:zcz>G9Lc)�0���c���0���c���0���c���0!Aۿ~'0yCn1~)Hݑ�7┏Nu_-X^ ߪqhzUXc���09ײŰiTw3)4&X1cΚuݻ\,3Gr듦٣dYe B#1\i9 {,JSN"׾E5%5"YvQD+#zdw`u/ZژJT}˽˂9HVC?~:>z/CcyOqRtϟ^:oq o݅^}e{ }Rmʹ>gߣ]�^RGRJ؋YHVVlxvS O Jt-m1 QfzG93gbDc^1rt6vGr?Ιson>MѾ Y ҢuIrI'W6,+zj7""*o1BMY]V�l;|OL ɵ 92b?7dg]g_x;SCik- Ymlw`Oakgj7JիثdmQ2T T޺VES0IWL@.؆7oL&I<>:4RɼvzmT#V3LLG¡,U6 | )Hu{&uQA{exKs]]Lȧ sཛྷbEun<%mUݺlӭd"ыD*֤VD2A@&#|}J]<m:2whpnfO'f#Exχ'fŞ!}_jVq$4Rj#])C~Q2wE_|7;!"-0M= ZnK.I#"g 7̖hNA8|))cIl⨋Yțok1̑!u"IU� ]͑U× v&u]uEUUT1Hd)s.2lǖ_.^ÄfpY5)fFC]~{)ܺXőw84O7z\3F׏w!껍MA`nƝ 2(2iK8鐭mV3 xߋ7-@+Ѻ{oQ8StQm&ZrwuGQ4^veU ^KrarPOkҶvEql 58ЏeˢAgrd'*υg'󋙱2cPLl) Yy\ds$,UjzUkupA#vUyӻ:t#_WN0"шCJզd8{9G`i(hAkŴ8}Xc{?rlfY,eP9-AUyU7Tʟ .r�#Zݥ i k|GVUWRu(&::WX=kү_oMO~=U\o~6ktj gb-Tn@Ƌλnu~9|vh-biM|e5n ȢTZ2lAy[$:.�U=#m7pa#ȖLM&|h#̻%"q͚QI8)MMhSvI?9Y4whw:oVϽu26!K4E3Qlr+@hX說Y9Ģf D`A50�# ?C=|Mܓs:Bgj%`֩]Ч:`4۳� >�0���c���0���c���0���c���0���c���0���c���0���c���0�g$6D!Aۿ~' fߊR>;d@#vD�c1WG+׺w꿜Z>^d �0�_5rd3x]tnj3"g-)]9YHdL!b8Ϝi?/Nޤ5ȵ]'YurO*0c>Fʱ{XjjF?opgNKkiaC� +'9_(bd"z GR2(GMv$ln뵵˦O~o萭kkݻ%~[WZ,XV< $+.\eG^˃2 1 #2b #w-]]VIqPei kWHG`+0Sre{RۢDڷر!L^}$;IUDgwH@ɟ 9pgYW+|\*g,븷]ۆ;[_nW0QoiUM7 qh(˧ ]*:~uk+0TZGD[C6G_aj()aA ~Gz1G_#zR*WG_ё^֫q`u=꺊Z=^[Փ\~PxXR]N ̇tp4L_&n9VܱR)c ʬL+z2߭wUKFhd&ępV]ez3N%a7-TIgLug|FBbӶ$Oˑ#E\1lu][8p8a˞\JC{j62J-sD1U˜9?1ʬEY9'(s;U1@{(T&ܫ=uĚĄza\�C_W=wS_k/ >Zz8b[ }c.{.QGnaJ;rFb*9$)5q15`IFڲܥ')1-L^) <.|co"YrQK TX^47#jsGMPd9M"= ᤏ)C/YU e.-ZAy狛+k jA*շ?9LTRU8GW6C"gXh<c/0jm]J[c6oU5i!j822 c zEx=V-lzcnK<o^?6״K+n|ӎV|okRU4JiCUjpuݸt]e3d˔Pě9[#X˜EݔQ򩦋NţN5 {wm뽷 _ֱ/lno1PS[)fs½m_µʮ:vջR,29iY'gqF*=iM]H]f,L0m 7N;+:)Rn.wYSN?&SS8U8>Y}J\72S,KgoNZ{u[ U\6ܪSa??,-3q$^ocoBח3ZF�ue^,tyg5F 㔵 ۺ[VŷvnLU6$C\5-c4E,ӕC*4EebW*8�57<�22nPq~ =!oP,j}dLz_�ij%1.,ˏJ%8VZ)&y9&2Ŷh)fع&{ArL`m]W67$_gNySڡ"0}a诠arӜ{(wJY.eWKutS)֨˺pEzRY�:&~�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `���3?wf Hm?†3]o)X FR߻"�1ţVAb_-X^  `����#Z=[̳&nޤEnuZ<@&G E:*Y.s)M'I3zDHf"f"g1~C%J@ *0d +q,AR(Y@΢m�Œ^DvH/3ci>zܶMZj<fh5tfEv[S s*ɪC6qiqт�;P4Je&7D Ҋy ~e"H҉9{cCG@ttǶMDLګpdI2eg+*/mU|xEhqfej@GlHd;'{>b:W*i8=w,Ku+kTTU='skjV5Y(D;Ly^/ŽP]8SWT#WGɔPdD]+pow#[+e2rU0sFƩ޵yx\ ld7XJJI,GH ^alf:v ayB2 8h floZbo\:HE~w9|vh-biM|e5n ȢTZ2lAy[$:.px#|uTGJNix�>��{a � R9�j;8}h%lRTnb8DKR5lr.m+-Sq'cTQ.Yk SfA2aLK\v"R*E)C&[WCzơ-(gzq$1c s9ŗLVe&5ʍM/tK^RXЛ1b1k:ivs`׮NfQe) oM.S]/by)wڏq# %lEя$T+e+iYX<;LN'S%;NN]_[QwhVn a%(A^ϒXi˫&[z�U=O\Mp>9/Vx9V}N/>0nmlx7]A.s۱6muPrg{Z,*yV"k;yydpYթHдkdlt/df:QH~ۧGjtB&L`ԃ={n՜״BUl;H͟r\wOc^] dWD3`-s/r2^*+YtR3Xr'>[1Y)$*%;;-{3Q[F́Â!R1M_ Čt? |�70k_}wXi\^b1oGUm^tT6RQVW38hH*k„kΔO2|R:E2uv?QԏLk$=yh N;םXfۣۡ:WH*TSdHTPO%1gR{7+On 5DRDH0ôؘw|H>J]ޮhP.jdQZͺ1 ^XMMm4ee]��\����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1 <(3?w}JG'~�ѿ}bwȀ f;qhzUXWG+׺����1� `|dMKWf4 M^W&IJKG"9AW1ȑ xR\0BC=zHI' l!vXKZxJ{-.(]/^wSǏYӷn:p]˗ ksʜ*s6szmv ܷU5۸BLEtDQ%U=|UU% S SȲ@j}z>z׿^ׯ߯_9 t7%~IlYߛww^9/R׳;wݵ ڬcD}r &GQqPo?f-)'UҤm�Ϣk/ąg"1f0ɌaL#cDl232)=Pf][YG]h3;nliɺ6.߻erbØ ;+'aDkV\zxIIX(3ȵ[K8tEsA4]7:y39@KX9WH sƥzh1zsv(PM:u!-Уb%fku>Mƕ�I����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `C<!@O &a <(c5FR߻"�4o)X 꿜Z>^d +U ���1� `jw%6nLo,dM9X\W\8&><ug0OdXbx\[lGvۮj[l",udAtT)U1U% b(C.K8޺[f-= sZk/W$wa sior f}[&} ְNDʉ8ڪs=koDR!⧮kk&=mvNa3,s `o$ff[2ϭ-Iukw7:'v!VqMƷp`kk::[*E%c�<yEkldǍ9ٲ[R⌚,<n %$0 c֋0c&Q:/txIOGK{͜X!f ^d ޓ�xֿ7ÆŸ8Ir8w[[mD۔֗.A X[[EӭUMP謊UdET͒(Sg.Hr1 q AbAEMb` L61c g6qg8G:nM%dtJQ^Neyd+ӾR�!u?@8<ЯݞL)_ ZeY1gNYd[ &u]c$QE"*Hi9s`.2cgr }W6`Ir 4l91N&xՂķrDf^.(eL�|mFkH SHi2rM&*َY6pi zI+a08z/KܝW\ڼH=zb-Y;x6e<g vN{Z%w3j(i/'%s}~1ښOP탰Wmq#l_:Z~)*`|ZVM*T?2+c<;Em ԉ @lkZ'lI# T]u3UeMׄ3CvR-Z(11w5WBsV)c$la�đLDDLεnZl]a5)Klڵe%sJX@Dbukԝ$\,Z9QuiU7^d gvڝHj 0\.p{8ġ>W (<#P2ftT#UM"٥M�n躔ZʖY*$nfFG$ve}]FMf6}HEZ >m~=M=Hcίu;KL:;cp6:Eɂ4 dS a:A_?NrS}\qxnm.VvlջfPc MheTjo;7"iO6<ymn ޢh}xZ,pm MWWR'ݴpN2 9o6/K66܅~7lwv;<R>WX%<V>X̋MԏOC[;zb^َTxX v'fUI%iW% YeQWّVͥsG0g6enyȡZzמ1oM#XI64[Hx~7X jT5�KX-}pF3dly5[ ";Pdϥ6*>T|U?'%*?O!ԉ{�xH; u%|5cXu-=N<^ƛǭ%@[MUkX,W퍨^Qbf,('/w3<v06I%#W.fo+={{8 9StzbZ%掣J5Yrwwu(Q"> ]>rזjSr|Mm4VA쐩y;+rimM4U^ޥeK/iBx%sgm6mvGBkP*>__KEyk}B=JyuJjSi(U|Q^',V|Tj9-vkebݚ4W|bfQ 9<xg (ʭ#z_OܯS])naٶ;ٴ]t[j1Mnc_&'n<=}T[M9 O5}]qC xAd#=6߯ڨi RTLK!"'vM+a;A&O^yʫnmA qК%Fu榻n [bؖͶu^ܕY*DP؎qrBN^R5e }xޖ̷ln*݉+7`#i7 V؉+FE3y gl;o O5ʅ "@YB F(ƃԺ-*;wVԧ^^4TNhD[!InՔMWmiH~|84\.)PrDo=XCPۢz [+ npk 0clZ]~ YS4/K"+m/7FݚSz/D,ˡWwlhmc vߢܹ=)`K 1ɼ@{E㗌0ҿbd_�m$Zʒ9M#-;,@Pn$Ggq%̔u�mQ-U5^uKT`i;Z {Ygugg*ug'7Vz{TR6-NyPlK\KI-$2lKnGl&+闑gg9E1seݮ߼?+i.XRvTRMY^theH.-XRsqf} 3j G^E<ڳS=[zJ>r"cmIK:uM}RK!8:^i ]B<9h554Y6{Fbg˸o^&2ƪok<@Ŗfabl@]= UP< :CfTԀq,y#y]�yNϣuy9oZ>xϷͥ9wKlq)nV)UI*T+dч7A((6nmG)wMJȏ{KO}ڎ#4EJ1|ժ"2M=4v uX,P50ŶiR@̈%=eO`1n\ݣOkQ2D;;,]6E5}^]U.,[C5th_:7H;TcN><W4eE*uՐ1;Y73w܌&;ksWekN]OlztNp})Xxzzf.om$U躤%h&r/T=}zDvCᚦ ytMwkqV6Ҳ"nb"gX\9pXK\/n KX`,jațUtV\kv{0\I@sumZ ؗX͋P:IjZm["Dpd[D-�()={e:gS"aAA�cd*ʕ zG$ZwX,Fh<r-/X t6rq܄ }4lR!`ٸA$J0DDĹ,+ja u 7+=-A.ZCg 4TkK^<ԱYl:w Mơ-;;M,w%k&q\31T)IJ5ͱ@ieKtrUnn=/Z{[nl=x= :L^@c}wa=!n`\޹ճO{ҘOYXnVї,*X+tB.+rz[kWS MVf3$3?"RB{kSn;bECjciG(Nc9nN#zMk{KFrfϯ#tɸqmmVA-R,@kQ,쳍u,D*/$c's3/SjDKUgҲnH"e]tu\P*sdI>@%ڗ>Υ/)GǷ#eNX;\*56& 2[0I`kx&aaCm�&�0���c���0���c���0���c���0���c xQ3g$6C7┏N~)Hݑ�wU ]WuY0���c�� ݷ]t*rDYɬS&+&c&JP1\9k�t܅mi]MV_83$9J5$WE @ʾiw5W*5aEWrH QEEVUKXd!B6pR904oX3{fؿŜTș8HkK$Ҩ ,_꾃Is;^֮ӕʬnj@L~њԿ_AˀVr\鍋7clo5OENSG)!H,[7djkvoYWm^+ 5t2᳖JTAR%TQ% b1sjx &;c1M{ D)(^;vLBXb$&s!)yu4[_#B$V$. I&Bal 4}Zy^W)ލ;7hZl{e0M� q?Wy9pk/*lBŊ:ض6\Dx9 ϨipVlb{v��228Z1tVFgȊr4˯0TL &$h?[=XDuLB&O+NIq&H:;atIhfΥ-mkj~UquG)WW)\L*R&HԄn\ ϘһWIJpP}ݘ^\GiP8rjS*zUg><{ꫢʵ6fDk)ck%^@6Я^ӗd+ڱ$-kMMeS vO -TE%WW) /m>LR_Ri#X)ie|,/*ݻ>{hkUU^O:Br^I\>~ڡJUZ@,9e?.N32{6+\g\Q : s%$nl|vNq3ic )1i";xZ:[]Z))- dME!G~�mޟ_Bk_l>˄FZtN,aSZMM֧5TSr95&9\- b2S؊ Sc83qg]&Xb% f31E|ڮ{ԉ޷Y%MB3_�-?c[CyIbdJHJDt2OV%NӝkjK]4L#?E3֟3mlp<o|k~_{kkG_m]"ۅ|pu.󻗇~Bui{ʨeSl/8 VP-n$Z2veb DDcBlcCd G\ku(Rd{Txg TN5,ZͲmM~ArA3e۱:'?6ݜݷ<[-;pzc^h%gJ+ES%c-ʺ]%pT%oݝ#{=mU\-8]77eRTmR ME+y!geeq#8~�SGJU N( dTЈmz[2s,&X&͉ @uνM>$AպR9_.O>u\MuJXk}6W6W+dJJu 8k RaXhTӒ!V8i۷i2Q˺旳n>?gy-kSy7N獓_mԗY""0y3+wdu/x kzLgDr2#PlDȸh5J+F*&:j#'J꽓([{|ɽYds7"oF❂'*V?6c*%$`\q0mQy>k*\;dWZb[*VV;,k:ļFM&l5WC)=gV/KڈGҝO@)T:{U2�9| ͦI wgo|OVyQϗ*OA}Zmr#h] km/wM5WTӚUMyb^0w6eaX!Tg8dE[RL}iIKMlMIi gc}%~% �oDFļzD�`GU4}~^x;Z50pԺ{5. uغφSfCC>EM*s'YF5-)Y 4 bJ٭d̃틵7FufRjbۯb#y*TFAjre%G4h7+*O ,7lm75+znT{󊣖o4-,x8*Pj�[QvkK *-6n[ dRI5CcW ~I!*k$[BSX&'nKXB{}f7R3ʚ;`lmm-VJF&6(?pE~mNuLS*2v[]gO+&zrh_u-YHE8`Q4RlMLImY"5_6ko]gɹjLg;ȏ\6/.PԪ+oNj%oQ5jZ}iϝ62w_\{݃omw+42/+"e67G M%o}ՐӐZҩ^oYfvҚRU`BN귔k3<xη<-fZOkl<=s%XַScX}k̊JiW& @*% H\^e3�12p|<atgtQțgbؖ%bmm~cȇ7mmkN;&j$\.E"@Y3J[so=,u]"_+b{U[Ŷ=jem;KlA T!i+\tEB*b"<S#(0PRqw62iys ;`-vzY;DOD�~hFz J6ڲmYlH=SuNm,z)g)v|=UHp$VumN n}O p-`A='Yի5ueB^umx,z<ʺõb\̾XNq:/:[2m6$-5 զwmI Ǐ\ix�VXUޝtz(BaB5J)kN:3^m;aиڭ!dוm"5 ,n홮;X'3&vHJJʼ{1`�VƵ1a}ϩLs_v=q1S@-j,b�`@D`+,#A1�W� `�����1� `�����1� `�����1� `���3?wf Hm?†3]o)X FR߻"�1ţVAb_-X^  `���rsU $ZC"�K2.ɹs)I$3De$SM)rlC;ﵶu UjGwV_1׸ d5kkdˈE;Md"e)YIA))]hIšG\\ ^2MmެFͭ32po2ΜI*eL \g).NZ(NmQ+(lQVnLEP2f*LATW"jGjv,|ɴZ36Si"BEF& Y%K o򲦊0¼4\W-Ŗ'+rv@vv M[GQ? Al12O}[ۧlw:.)žǹho:UdgzJsVid}V7cN2)٫*-p|vpMwpσej L7zZZXĐHd5)˻!qqK31 Tb xvT(6׳c'(.+LNZj2&Z9卌 c˸DI8q=_kXٲ6Kԋ,E¹YHN=#Fµ)KOMvNM5*+�f؍FįZkuy!!?Nю4/Q'KvcC]9\W<iwy$1WVsӮ&=s6B:1,yyr0ofa�tp&`Mӓ9a˗.3kt33!EvU3c62}|)e +|?IUpH EQ!UeT6I&L(͂.Lsg.3қhGaj-(K_2W/&9w+aT\8T}}XjLtD]xJCl8jYV ̓#_e( K gv^ʄFW>k{yϗW/56$-Z1A}ӡ{UXUzWO4sȊ3M@1ֹsk-BAwmlՂnPj<.)0zb|[3H_{) AQ<nNLY]l3uѣZYPQ%PMD)Nb63zz`|O:o]>Iq KBUuUR&s%$m69nc �rUx(\[Yζu+e[ kӣg_U@-)̯N5 c6 ^"d"i! R0RJR0\c1coysoE"٫&WU LIF»S*Sy\$GW[gtm*,@zز[Tp,Sb$3FAyN!Y^Muw ��fg���0���c���0���c���0���c���0���c���0���c���0���c���0!Aۿ~'0yCn1~)Hݑ�7┏Nu_-X^ ߪqhzUXc���0�0INa;0Ϲș}~.I7I)bAHwWA=D[& ,ZP!"ȠFJDHbz ON=-.(k/]A&PQ4V,y% 2(3&%/C|eGί�6E<|¼|Nj<aQ{}.u6choPEVY~,UA=12DQhu!~'*wMBC`3ϧ6X8=/rL�'rcptUSѫLFM*%[V>L.Yo%pVYY3q!"M1H=CocWҟl): : 4&{6$B0l0wg^oZn-~U1Rۙ_q={* ̬VʝbO]}JEfɻJFUD됇RU+*9T.HTpdI?5V& $K-rrt:Q;dlw&b9M_\Q;u^o8mUjʛ1&:o ͜2*&wu]kTԎv+Z%[!Uc,V J epqG6Gn kƲxk;=k[/oFWf(sWՕF*/g[.�tHӚUd1ipV26_$Gͳ)3ua,cbhGk<m6dbaۻn|#^= ݹllvT!]4Nؓ5y- M:+4KZyi,V@6PP$tGSXHI-O26_g*} }4]Lmu]XCk0^ _Q>zuKeqoNWzPkKF{D&ZW֍l5PUim:[F'Tl&M v [U[ɪt;)ʪȔLTn<͝n)j3lo(V~ N ē$X4VJA\S3/޼z]row7/O5ƶiɭ0+9,EQHNO20"u{ӽ4Em_*Χw`B㪝[ٵM'E@Eٸ6X _ 'lʝ5n)&ff l]֋`,L[V-<$bQ5&%C^B)'H;t՛vU:O+)@d8 Ჭ3QZ8zGRctB09Z3^W=1]b(H[c]{#d;F.!$c kcT,^,%��mҰ���c���0���c���0���c���0���c���0���c���0���c���0���c xQ3g$6C7┏N~)Hݑ�wU ]WuY0���cy�?\^ФNT,WZ]*X嗧 ѢV1\ʸplͲX2ݮb UNR9GהW=T kYְ32")KVNx:ujݯPVuJR1kAk"2(aT,WeVܲAD1c &%." !T)sy\zwFW{%%'%YU<&'.m \c8pEW!^<)rVYǪKK]eOK'w笪xLOx\*qȮBxRZؑ/ޗ%{DRөTwfFőz!-m@=�drT涓^v:Uw-V. !HӦrb�R&GX@:+Yl^-gRiWrC><)1NE%rc<jZ-@۪,P/g,X pd‘ZV1!Q}D4&ۈh}*7+i]]L[5M˦@Hly&k 1]Y5D[*rkEME-n,Y3yټC?ٻb>]5[Idg bz*$d2jF'`{74L)IVt&9RK Qn$POZϐyRZ</ʼ7Ǣ?y/q^H׿=wtGmZ V^^FұKcKa2@dk)!=cLcuǏ 墷Z�˺ޯrD5AvT hYyem{ F9R]a GR_M=/^Z%^^%u5t\v+]d\QrWԘ띌4.&F3Tҷ$z"vD_?fKĆG_cZXԴšjUtS<|{qy$EpL*vMg8U5ItQP"'2jfU% 59prl`3dp>a˹w+ u66cPU_*i*kkTmz"JE}S>:/ԏR=!Gut5⶯PO"'ج P v,֋=PE;V5Ӡ +\gɡwA27pr$FϞ&B 2\d$0r:߁G䚮UFRjQt԰"2ʶ>7+:Y F_lp~qǽB9*X"O}E((ImY.v6T��f߀� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `� Hm?‰C<!@O wѿ}bwȀ JG'~�cWuY 8}b{,@1� `�\>B\-Qͪh˯"cbƱ6H\vg&tYŠ&i5�BUSNb` ,x[_̩(^wBi^9kb;lUQa^@©sYʟnZ  2��.0ƯQG>%rc*dÙ)7X! AوS.RMK4 VvhҢ=(y�T$pyh}{c(mUC/SE-VxRى5ѦOMdu�e`3^ZD Q<ce7OLe2jNۨ[fi!; EIiz~[q35= k-Ƹ1Dvӈשh^ ̯g8ƳuEEMa5t\dZȎ{=&"4Y:TB״]+#;VMTUL:j)e:j&r9 g8(aaWV=mM3:%$0;$^Eh1uvJDUU> t_AǍ֕.0&K{f &pmWAOFwkeEE$2ƣ5IE P,d�7 ��c���0���c���0���c���0���c���0���c���0���c���0���c��yCnL xPk#vD�hߊR>;d@38}b{,@W~ţVAb��c��vzّ)T6z1 ;]L3V?�Ea3�dN)=v�Q?x�S�K�h�&3\x^>ɳ՜1ל<9)p_㫫8_IG��󜶖�csu=ysc��ݒ�i*!zҭ<H;*ّkdFE|2)JSa2D9sd1r\%s-ѾYǼEi$%{'*ykԙq`qB8Yr^gy}Ų6 L5rʫY.LwvtE!0BcFFY"]c^ޓ۝�;Ȧzt�3K)jnWu3/): ^~Tu!&K".1YL\t2gdp4Ylzŏ7kܙee#oijV(3U-%9VM,vbf5 \ V. Q</QpnJYL)K�,7k&^kVtؐ^{MN"W$ٝ;8y2ndh(Le �0:GI��bJ[f>>?oߤL�^s-;*,^13H s)rRⅷgKrƛ歠��bAkբ:!3&J0C#XGGZ=  ^˪frٝu1;W:**C**9P)N,)՜v~zE ' GfE~+#֏d~NT)S:v`pbH~?^y8<}#^ͩ]%joP„IV7ADT˜ʹ#(Lr(d)1fx淦+ H3Uȼk8]*ey )giFШV_puTOr7K}mw:5*;p,ʞ6j7 B26Wݿʙ;$KΊrbgRc1zɍ2je>c"uӬ>~g2OT c�x{ܢ<?Տ?"ovnYĩ+˄*-f[PmKerMMcyW9U#Lz'ZFIYz.wJkZ+uMT[c!^,F  "E+WӱRj�wc n==Qa-&5ղ-"|ׯd#I}$w׮/k>(m9e]jjڵ Fr1zk [MBjm[{K_,1u tM3a+f7+lւ{%uI+p+ sPU^ q%B nlXV*>\hB#uWMCiej]SqZKn k+]ASe,^ey,A<-mDl|IfqoN=K4Y;TK;ݓ<VǸT6W_dyqRtu4M;M8rWHvFGeþum"&kMf9kA%Dr-lo-5AiM Mr$dɔt�ܲ᪻ UՊZ݃KSi9(Գr7C5#Zǽ(TbGy۸ 0r=}x�)se ӕ_ߘͪwfމx֖jw9V}bts YȆUZ7bmٽ}3r\KרNs<𧈼4V4{:M 伾O"eBV(Qm+`(--|wi}c16|:ҩRN[& W; !>{cEqAqT5yח(J tVЩfj3=j.Z\Mg9�#ss|rS򚑯-Mǭk[ �n}"U!Yz:քr:'"ף{܃Ӯshm Itu|К3(*A]ԍ˸;X9+NYRR 7dd+9eq,<^ (K3d,PXY0SX2.&i7.^lDt7ޮ-WlΑVm+,NJWVunyj,˺YИEtuޒj+c܋TRmqc1q:&b96H{$VVj=Svr%t؜2{ψ<溚#AεYn,"v|;"fZpZzqq=A4L?n|A6FRlu=1qez°4eurB<NC:k1FmY ^4k`*;O%3"�r w�-Mn|eZ�JtAȞh ?iAl|IJ侓^/c/C (~%yO̮Z%w-3q.9rﯺ-7r.@kh۶ܙӹkꦸݵRo[>hhTd""(u+R}Ȫ "HZ=jZYojVw<.Z kV026X�r嗹4Ub$Vï{瞼⮟o-+{ReqϤKҵʣXm{Fٶ Ƶwm)ȝL mTdɞ` y|�N=^rsbݜZV/*&aYVܜch}+"gρ72>734uvwX ڳibo_ObQ1Zas3n5(Xlj7 tlkb =t⿊mYQzIvzWv۷G ѹ.!^Wdy\zB+iw=/$t#޻KӰofn_S#KSڃ{ߣSXxhtiʭ~K E; 2lLe2T6ld=٩:\% 'F8ck^1`4D8,5=TfaȈLʸ0W6MAsVMï}7VVl+7靝#r:'{MeYHO*Ic2jAPQkX{3[Ȳ,l$\Ac>bL5vVt ʠ¨f)'Wqӝ=.Ln-ͫ{+lKqsiôSJ%3Z 4m 7볡!_% S kz<l^kw;k&& drZҫ:[2ZQ^ўez}沈wJM=0@~f'7܊W!+WrE:w(vŗ}1x3i ۰L#itϜr:LQzeJ-:)d7!bw{w#-6>![ Xk>r?okڢmuk4XJtiGVrTv1^Ж1uomtAxnƅc |T�sl15Tq \�Z='|X1Ut>/9@N4m^LMzQ-kH􃖵)d,U;-˄ُeQ;wһ߹hͅ7M Xj!Ū\铻UЎ7znV-(+f77"(/ݱ%VA묋 1-=sr9ǛWndSm㲔9dk^"kл\Yaw3, 1*Ki,iQGǵ@[$0mN%mY➢o @xBa)D-뻦c9!9Eh.N9im�ɝ ^ﵶ*}ixmZV2nnIg/5v:68ÙtY?-g\ܦSj}9-e~Ri= "5EeS-{vDVc XjM.Q'_q"Sbm"N0^W蔟#U5XI; i +@nƤ{|Һ[͵]F[z ԫ[cȵאgs\]Z/cl>DooZ^m[=$8L}qGM¯dәádҎ;N Ό!ym6ک\Vֶ^Lrs:.Ok hƽQ;aU#3Kw/WʙgR4bm5Go_eF"U+s6mתҽeO];QsI ȣc_7qd=;DS,Y֐7UqjzֻWn%G[59c{*3=QvV0Ùf˥#tYo4܁K+_kl-!uqVXuZYWUeQ)?Jv|ZEi;NWu˥JbͶfܫs*A6DAF2C^i\_cxFZc@FXpMMOFֱ[+5;va\m>@5TveLJP^7PRzJ6&I =dLc"KTRL&zy됽cd8k�K[!z_k˽|J,'\+e*ig[1ܻXYwP=);UY72fHƦ;x֯]I(L3tMڵn]tNz| [EPΪ%~VI՞fc * {Wد<): XI&7=}'<k$jk 78^CҔXFyaEݥ!HV{U-aUTХȌu&�Y]B1X9%FïW:ԥ>,[m5aڡau5DObJEvMV+eɽ!~c;WחMInzm*%$ :ߏ7S~MؚkuYS#IviPm<M*~ؓ{䥮G^Ȉ;#i |9`69ILئ%<cɷ9VM#3'tOGjWQT;CEU\q&q-c& #m@xa.zLևUw`2}(YWLtYcL�̯���0���c���0���c���0!Aۿ~'0yCn1~)Hݑ�7┏Nu_-X^ ߪqhzUXc���05R/dmSrhqy$BA!Lɞ/',;N1 j"BِܹXV s8R)/8 .y*H>j4޹bidgvKzՂ#A\*z6N{zH?L$G~"?[nXʉ�eiG1|sX.1yaNHc'u3ۭV g41%6Y7zwd2 (ceʗ͓17o%V2b܂ag9{ M;! ݋X6r.d TW|EfkD{aLR9{ra\hw%ΥSN3i5Yf4|u'+B yy&.^eҰr隮3JkXtIBF??i~fz�0ma&f 8f>fcF[8rJus p|c*c:19t hIaWD<1V\뜅.U[3稤.{9!Qeȯ*kgySUHWɻgb^39:.UL(~@,ٲpnE \bM t C&l9{S$1>?i?6~;vͅ1 )>>c1'+G8W,9M7u 1U+6;TUxDC$~Mù6P)Cu%OuÕvưbK-pҹ 1T1TPVTM\<tLs`lk62 ΨWt׳*qK)ɳg9gYZ4H|Y�/=sijh lAi�O|vOۧ_�غ{G"t,xpk9_'2ʡ͂}&RB+ps?ZMJ=QL9rw1ug*.s9shi<mL4^p�1rg=$lOnc;X:li`jW=:M❬9> \2\g81�TtW=~�uu�_횮81GNoyO;+QE<JE�q!2Iȟ)d(3gtY;;hg)HeMqչv1Ռp\g9g9qՌc'wm$]Š/hT9EP!I!1헡ʯ:78e q:鳜oͤ\ccq?~^sZ-E?>dgG�u I<g9{Amʁ*~v^(4Vfa93ςB'D7Ƹ3xI˦R/k+g*YfѣlZv]Nڅm5w1Bccb XfnHaDM>uINș"?B2^%j`B[AaӶmsJtx*['UI@Q٥mu킏kNo36tJY ;QԂq..֮tP"6^ed嫻gY{{dLeVܗf۪רhrWjg|ee<0 l,mHvkxT5kbg0�ôf# 0&vy�(bcY��xӤ܁rK&*ؗ%NA9;-%eJ1<ueJVvcKk[h_6۶0mԶvkMv$p/ƕl8]7faRl6vCf(  k0Rޕ�6o.< \62Ȋd1#82iW&05ꑔOS*e)BTXwvj͢Z'%X'Bmi#rr/(@TQA8w{^Z [H(7kf;`X,6{#tU6.+hOi={Le@L+3dX̶aݣ].f,gpl0T *~#_@tu ׌R gªU]qXTKeY c y;<.6 #PI?EÆK>yZlLn6�(h-ꊵגkfuzӘۚIv{^փ}JWlٲ^8 ]"xk+<I*΢xs=VtzUbH&EevbXfOTD@YUv6m7Wam0{;gAyсU_ߤ՟NcW9ܺ=MUUb[zQ*,ǕuڳQF$бˬ�cztnpoI:Y&otEmy'5�iqP.5hh \Ê %K KZP�ȦaC`v!};!A6#Qe%>fwM,9dL岘-d"9 Z Z@Jt«b4B#Rk8w*6ﭥT-TI;FUĦɴ+)-yJȕ̕G�ݼh-zIKY=D襡(ՇyZDZJj,3 [0U�XrֺLu/l]bz.cURدVZFF.F(TW1J64tT9&"e<*]t]xWoһZ rZ&tƣqVAR/K|vʞi$ԓ7߸Y�{km| /(l-5vj~ߢ^ε2V>=l/*v,z­P:v$Lx'?|_kNΞYϚ�¾2-l�O|/2]e�Ւ^�ak$nƖTnWrLeѺz X8iM,kR'{8$W*Q3u(iYoG? w.ٛhhk�sjF7m-1f5zZ"ڐv)zV.7vk8Ҡ �#%(k� `%BuUr_rOl116hHuF503Lט>{EsӺ38ՠ5ⶽRM*(,*Jcܭ:z!,�SE[ (3hDܧZeZw}\Uұ]xEs{ǖ{{lZN9J2;j)dhBp)7-J0M&DҫNd بD>>))D`6#:qq &8d4~AB`H+h)WeKww[jWkUa[nKPS6ڎn=ߟh*EwONS֐$:f 8>Acw)-0ٰo $m=ƶzk:.g֍lL0YAkf\"m-7)U DP$̨D2*Hvhk6!=F#VLN�6x]v&-Dű>.݉AvalW\,]f ɨ8,K괴ú&klk!WY޽s%))+{UR/Q%vro}Ϣj}vuck"VVS'BMflٻBÀGbT^UkY\Y$J)k$VPRe$z[iB&V�۫ѪE\WiIb0Vw*ٵZ%l;?{$1-Qfn:xLwUET=tVz6jtX.;;Mmc+{CS1ݼ雥N�IĝkLfŲ_S"j +Y]Bbc W˳7nM؛j|ٙKjf'&\% (*ZkAL$xT*k̢W)Td~!F5M ;eJf6Ǻ$Y] 6Hًrex$STp3<j]:3xKͦR1{,<g*YfѣlڞZv]Nڅm4w1Bc%b"+Y" RUHDv{(BJJL%"#6Mw™#uԳe&Xe IR՚R z%:<k-Fd$(u6C:^vGڧm7:r%,NMA8RkWk| hlKFw^W`f6 &g 06H.m81xA{"Q6+xXjz|x>;zgDS�i&"iet% {  xæh�CUBg&%,co/-}vuBm`M2e˄*ɉl�̤ȍ"""74㙙k0aLb��! P BWUJ눈UʪRBk� r��c���0���c���0���c��yCnL xPk#vD�hߊR>;d@38}b{,@W~ţVAb��c���I�UFVHx!*CPE@9ΊgEg!JD2O(fU�\ܜ-GpԦQVzUCog@7YPvC"Ȫv꧌t\)'"%== zGU|�O&#?Ff:G|ջ_:N}9dUvĠ.y#\яb)Uv1*~ Wwm,xHN9܊1l u& %S/Kq6OdpU!J5D6+3q?bRP&gя~BL%fWfvGp rgl/s$,A3g,*ط:+B|^Q8Il4pX_kv堪QO_r?Ϭפf3XPh%Rg孖 'dK5R=Vr.vHtp3$t "O[X@ȡn6*,dfL!d0|HL[kshdc:eyyBc)L E7fsص]I2̎$wN(+6So:: Re\aL&:9 .??�^:k[133�u-E-(QNC=z�Xz|5N3D[ȘM=G" 1qS&slqB˖ecLgCd¦O  %Y[ܣݣɵRir䉤܇6JlsR x7TwkD+8ѫΉ%IC';~�91'V0\c�EqY9]KDL|G�vz̳�_N1K'�>ske v >CSc>qdug1ל;r\%6<5\?*NSu:V1uT Ut̐Y̅䯓~TL=қ=6OKe>ì\mgչv!DJ$yqv>L! v 1s٪(_ )�Ժ}פg*m*]beE0��Y?V,)S\'YSOsbxK/V g8sWB[+Jۣ7Y3.>�1>M;X19WI&fXSS !c8%V?:R2=<dLDǦuY g&P[ =cco) X,I̞ӧ)HDw|�f� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `� Hm?‰C<!@O wѿ}bwȀ JG'~�cWuY 8}b{,@1� `�;s`re$^2ԳF'<}?^UcwvP/:nr8YTV3 8{/:m&SUȝv*nͤRʽG*jMT129C9sc.IEH`1V2Lo0/w"}QeҩXe^ +a.,SQ|c%"TFC+f֪v/QupܫV)9O=Gv;2^gYUV]Erg9Xgq稽Esd �"kUÅ_^3LT`WLB�&׎jy^!C=0?ϤwG=@1RQ=gO铍ڡ.LRz"=Yq9ETZ8)dڭ`Y8ʙ9cfDZ+$1JsdʡՌK% ccQ=yΏFXrIC<K0c*+ c6:cg_o2hi;K$ pccݞ~rnrմA3L?h�,�ot6)4H $ftwkh쩎f;e6zɳ8xc8w T٩9:#*\C%׌8W9YD{'w1$rR%|]_Üq$. ݼeC`?=:Fz�XjK,Mg2]c:>;Ͳ,"TOOc�ȱ;TY«"S9sB~.H~{E!Hns& y%Sml-ME3Ze,(Ly9PWU ગcP[?"Y)Hoʛ NS&;^ Ռ�,2&+DP"HɌy6sP1G }}1d.T �X" HN:N?fx$f>:L}:hzk41l[�&Tg8.1q՜g9Y]>(ʽ6ݦkۓ%>%&J\qÜ$n"dO'!L?˷c.?o8?D2\ ?'_r_1m4 @XӠ3iu]I.ZB�t˄�F��1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `C<!@O &a <(c5FR߻"�4o)X 꿜Z>^d +U ���1� `OS{Y2eKO`{8E@R9~ug~ޜ~-s ^} \V^Je0#Mkg2nSl-H'n^Eظ–d,+�_Al'^X!&@iDG^0A%lyϜ*~"1&M;2fOaSg8Jl$^Kd1Tʦ; luy;&{8rluGY회v5ͮVl%(KK6x3æիNSU69}[q۝mUMhr2M)g$#lWv.Mc&y=*a? ׯN6;ff&GGN~c>nd E#wj:dV{9V18>9ϙR 3fP2RQdn)d~g^s!wΝVHɗ"g…:%He|"Qx\ 2,eU֋f4n&`2aW '%hkQG8I;=^S#;VP�=G|Du"=F'?ۧ VjR*NQR "eo* g`1nze֟㫵�/"u:�.|Jr\YW*)&2lu ng8{fKg \E;JRHl9SpOlu(\g̪mTS(x*UC`ttD_^?pa tz>c�y"2/2R6XɤSg|cSc=E:׎;oZ)!8O�ɒSlgNIR00N|^9Z1h\ ̋2Y?`g%yGUXY|)Yt0ʆɺ;2l|c=x`c8K&=j0a]hcX>['ۨO?f0ͦ˯e1S1Wo&8z׎�N)$LC}�7WNJl?e � .%\ w'xWlT:ꩌ4")(L� f!3eCЍ/SQ'M3pj9r!vÂu2HrC%6qלOm;"LTq6tX@t q�7 jxdI,�e����c���0���c���0���c���0���c���0���c���0���c���0���c��yCnL xPk#vD�hߊR>;d@38}b{,@W~ţVAb��c��wϖv㌐^̝^b]}ň71ĵ;I5&2KL u11=b&cG] NBR3'HF#)mpHGLn:[k89jVnu%(tKJr[ fO�psj&SEEŠ.g5b.엉nP;MbBr$79UU/ A\=q$3LVWȓD=:OL;4!bv뿬Z-NU3Vv:WX4Y8xwK62X˔%$Q�-mBng-/-?_%";yԉ7B%0fTfXn<W{VfU. #~gFcʺJ{c3K�X:<r=˜EIP [@/ܠ؇ R&{(M4zQ?Ʉ2c}$BxԏeTTZhc 9SE3\w 7auB 1(Q31?Ƀ$?,Ocω/cĭ6MT] Kn쮂6ELS"0~?nPUJ>T \*cdQ_%cbw) N {1qU?o闓=:9?>#�O}N7_b%1;1mZ̦63�ƣ�6I?z!㖄qLӴmJ/RyŘ { 9s 5^Nxm 0I*uQpWY .@{;^ّў> *{ͫ. $b~"'I���1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `C<!@O &a <(c5FR߻"�4o)X 꿜Z>^d +^IGDo�~1{H:A4; w\)w*)^ڪ2w>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc30g}yD>yLagH3ڈ?33zGןo)A=#Ϸj �\^}{Q>S=pc31 <(#Ϸj �\"muD|U&ǂy;觯Q ܶlUIE݄:! 1#vD�hߊR>;d@3]�mM@����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�Z7┏N��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/fp-getting-started.jpg������������������������������������������������������0000644�0001750�0000144�00000030412�12574421673�022051� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000�������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���Created with GIMP�C�  !"$"$�C��"��������������� �P�  ���!#1QTVab"Ar234q$B6RUsCEeuv��������������.������R!1AQBaq"� ��?�#?og9udPZeYYPC rBx"#sx%юeu1%%#>'5spTW#psqv *\v̽VM\Tօ</ "vf9#UEVZUTEUMZ0uPRKUc^5cj98+Uފ1wilƶZWy΂ٝrԗOfْqG#RF#\7j SBFܴmKc-%IKdRҾ4Es&r`\,Ē[^̳lJZzKN7IE+fpr^: d2_߲ᡖzjfA3e9""Ev-Oe&2[%}eClVUٶEV;ilش4uRW+cHrXFt1Iei G,^ztH߳ ll=۲-L r;>[Bjxآ ʊ֢$ev.`VRږ}eMڻxpV>+7Hؚ5j{U]\&ev#>1u}]� Q.EUں]]%u2>;fr- j2Ѯ:HjQs"/KZӸcxO>::XjGI#ED\ש=}xko7E:m~j�e펵G*2:fQqTE]"3^�֊f�%kkA֌Ve$*;J6:Pcs^2ك"Ԫkqhjg ;#W6%&;U5Rsf7ܬdi4QP4ֵ26zѵӫX̑2;6eUje\ - rPQ /{Wƒ̘hGHBGϳ O_YUj,ItSiC;JW*665b6EkmOTT:݊l/ԚլgOLY̲WB& ;"z&8E_w6zIN2kYdI_8˩#ǣHKga,OnYtE]5Sȓċjܸ#QӫfY 6uce%D׫+W5\MeN'J*ul#?#z,6x29dGc;%Lr9nTbCg'"?[.3%q #?og?[3p.3%q #?og?[3p.3%q #?og?[3p.3%q #?og?[3p.3%q #?og?[3p.3%q #?og9.զ,f%+c"Eʝ*Kdk>[J�wҖq:jG1X|mkӪ&uq_8A�U�jGl5zL}c*fjٳűի±?9Gm5Csĉ#W& n9r*]~˰ZN3U?izU5~ mjG#Pj?xMl,*@HꨗLWF#s".WV a{)::h$=DdͫS X�/沖Ӫ:iVz=3:|~z{*ʒ BI75*jT^:s_i]VC>kJ8!Ʒu[I_W3υķ37Ю38:o!\^m2cr֥W4/:x*Gtv߼9ࣺto$ȚrrZ⺵*rGt6߼9ࣺtoEr+r&t`3"1zӤ~mx<1\qO\u&uzӤ~mx<n8NDLà3 ;IӤ~yR��# �pNVR**`/sͼ3''y{rosͼ3''y{rosͼHN'c?s+?pK`ˣH߼g^о@x(& <wNmyFu= mxrGt6߼g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬g^о@x(& <wNmyzu= mxrGt6߼׬zݡauVU}@(& <� RmxzwRDP{qN2}6s_j)%-;\jb∿}Gt6| Rm?xOΨtiȏXcV%Z+Wu8e�zҤ~ Rm?xuO_'[k?:t n2A2z Tz�S%I=ӥ~PH8u {ӟnyyzu7 YReեFEw+xo4':} ࿺o�dÎؿqUxZ&V 8q\F*'Q|cݖЯ]sېRiӝqxnj*Z9˭ۧ.ng5$W*"&*"{ϵu<k%C] Dʈ1NMҮ0G֟Y�[O3>]n?ϸkT1W{W)pV̋dK\a/U [O3O/eDgqF{+ԽJ[\ao5 [O3seEΝ)+ȹL)^tyul.ng|ݺp*9�\uLM#tGbW&8u.q/U [O3ڨ1cX*ebKǠ]*y?:[O3>]n?ϸkUQJdR#1TkWB*EXc:U]*HN>]n?ϸ8ut�>Q%֦0`xut�> iF]jc0>]n?ϸ8ut�>QZ{6[O3>]n?ϸkiE֦0^ [O3Qu`xut�> iF]jc0>]n?ϸ8ut�>QZ{6[O3>]n?ϸkiE֦0^ [O3Qu`xut�> iF]jc0>]n?ϸ8ut�>QZ{6[O3>]n?ϸkiE֦0^ [O3Qu`xut�> iF]jc0>]n?ϸ8ut�>QZ{6[O3>]n?ϸkiE֦0^ [O3Qu`xut�> iF]jc0>]n?ϸ8ut�>QZ{6[O3>]n?ϸkiE֦0^ [O3Qu`xut�> iF]jc0>]n?ϸ8ut�>QZ{6[O3>]n?ϸkiE֦0^ [O3Qu`xut�> iF]jc0>]n?ϸ8ut�>QZ{6[O3>]n?ϸkiE֦0^ [O3Qu`xut�> KPڎU2FfcAuCd,kbZ+KCX.dd5T< C_x,~ntĆ7zTusK{-'S?|_ȟNi��s�NCؿ7.u� �jC$axCmjI3%G& SШxn4NZ_uOUJ:i 3I6Mҕ d9;W=:\zUZߑ*~F~Ӳiϟۭ?"ӷ |nSD W:^6f$,>W;+yS]Iͮ0wB`Dk{Dk{Fsvgy<vtz9mJ\O>db*⨈(7SM>ZgإI2#[.TvU֩vDk{Dk;NsFw<u ]jֽHtQ1j1U"jEkqcdZYkjrYqI9㊫U^z]9t+_9t+_Yngٖtt ӵ#"#IRDSޜGķc3G*2_e1Ř Uu/vF~F~mw1<LOrѾeZ%lYU�2.vl舸.Tė !nh$EsuaSMzȍo{Zȍo{Zutyt^y]IT;DG>U\c�MgoO_4*cQ,vV=QQ0_wDk;Dk{uGVw8O2"5k"5k;}|{yx8,aC'#[~Vxr#[~Vx[k<i ȍo{Zȍo{Zoo%sXA2"5k"5k==ciZ8,aC'#[~Vxr#[~Vx[k<i ȍo{Zȍo{Zoo%sXA2"5k"5k==ciZ8,aC'#[~Vxr#[~Vx[k<i ȍo{Zȍo{Zoo%sXA2"5k"5k==ciZ8,aC'#[~Vxr#[~Vx[k<i ȍo{Zȍo{Zoo%sXA2"5k"5k==ciZ8,aC'#[~Vxr#[~Vx[k<i ȍo{Zȍo{Zoo%sXA2"5k"5k==ciZ8,aC'#[~Vxr#[~Vx[k<i ȍo{Zȍo{Zoo%sXA2"5k"5k==ciZ8,aC'#[~Vxr#[~Vx[k<i ȍo{Zȍo{Zoo%sXA2"5k"5k==ciZ,[6YcXޮʽ(>ĭ6=ZIqTN(#[~Vxr#[~Vx+;y[f]cg"D�o$61: mq,[x*į}:;DRhQUs˫V%!QJӫu t)}:h~?=Dp��/rs�@Oy(10% G u֎;IduK>lT0W!-nȰlW[V-JF&+ҾOIIO jȗnͬjϯJU^\3L1LYhX}w+ukEO'߇lYd+kXek-si)ktEׇ>^z2Ͳm9(~4YmBRITիG*uEy, SSjLu�6ȶ6D"lsX<G2GW�iYeh2vh5˂ YUu*uJw>/mm=AVijFr#2ኣN1윻!.껗9`[T6B<f8&U )]5{ѶU\eMzX&ш1]w R\5ZZ٩n=$W1v\>p/8N;/{B\2u<iaX"\#1Oq9�7B]q( 5-35$5 W#n8Mj.=⾗RUGKn :ΞFdsֹ[׆8u/Qgv�E^ Kv֡V6F:v.kʨp\qL:-7:(--"ʔ5b/Bt. щl{t퉩!>jzGJ2t.p¥`vkmص�Mzf1kWr^r2h#.t֝ײ*bMWG #QcT, r����������������������������������������������������"'S?|_ȟN����S/MM ٷ#XJW,*hըvN:VMೖζ W#UЪ:bx[xa7}H;3Q3*?W*1sfn=T"ݲ]ּ ĺ֌/hTХBb1ԨV rt2.diN5n\ua"]*کhr*EgUU[jN֋S)�,X&Ȇ/wQ([EڅYt-#3#Q{D閅ް7]'iG,iY?J7+S^6SEܳ:d,U\}97RK}B94Xvev(xn?~yXᆫ pVIg[:T#4br#K.]kS[��-ECkOfI_gYIPj _r`Yr$Y5٨ͬ�|nݰ ɣe$dNU{[x>9%7UMOn$+w{:ɤs_DNJ@[Ն BРTSTF襉^LPꉏ�b �7s6SB**~mKRY23F1j".+L8 ǵJ[Bҵ9:COڟkڹW8+[,w6GqLiZ�T]JL^wU e4vv2V Y)p׾ *^ou-k 496*b*8> .uiUV9\_fD\qԨZ`meqZ=߳'-:QץJ**+ࣃkUJˎIr5Шr1'rY6=2س!meK)Gv(Խ V5=? mME}ڕhD2X̼/,k>ќǫǫR"[u%_OjNz%Gfͯ7܎ .*Yy]KuUzqe+\kẺ;¦*pdh2Z̭Er"?G⩭/B)lnMm՝Ih"`٣ S G2ֲ޻5MDM3ڭzt#<q,5´~.бkSU^a6Ы|1i&s;^\G$2׆Y�m7foʚU k\j.}A-NR葬SmˆUֽtEqnYmw(*b`lEqVN*8 Ղ4l:d)kIVX"r5�˭WW_궥 )j6׵[şMd\*mްlfͱ,z 6\̭E^ৃVTպzqn" t!/w]7M'N*h(!A lj`j&13i" �@���������������������������������������������������vs/O���ؿqUy=ǣʩ@G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(|Q~` 9/s_XwV�G;(M&)\<1+@�?|_ȟN"U8���s�NCؿ5ѱl^PFƲ'&NÍUx KB-FڈHE\}I+}Ӝti)jֵ}7`lR.,vlܩ]jÙpTWس)k*ɄLl4Ҫ�<#}ؗ-KՎ]{ZоǦlZu-X}$bȪx_q>P[veuh+%udZ7&H֩zp%o=%N[J1AlTG;6SrjUY\kiYz{Nϙly_=4pJ7GF#n͹ jH䣶.O2FC=:K3V(Z{ѮF"˂`]Zެb}1G�6=bڧ:,~9#J/κ5`\p �(�������������������������������������������������������������������."U8{CT���qU99�b�ʠO {Ϡ|Js") {y-"U'Q 5=4N櫤cUZȒ"weOժ#k`̈Lmf[7Y̴)JaRHHIVlFȩڵ/<=-e;Ff.fFhzYUjU]X_}[]ZbyxFLKQKqYQ����������������������������������������������������������������������E/Oh~?���9�b�ʧ!?_T O>���������������������������������������������������������������������������h~?=Dp���8�*LP :ӡz#dcQHƧB`}Vv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6!t՝Mz 5gmaMMYdgVv6-zX1'Ƣ.r�������������������������������������������������������������������������������������������������������������������������� BuF N6TU\+tjhY\Ϭms� B*RMLZZ5\k;lsֹEk=k.VXscr`Jf`ãGOzg^(m̡kHՙZ,˙1E5b.U/4}tk,J2Ggˇ0~:ebAAKJUL10kvS0}ܰ$dij\ULU;iz: rKeV暑j^,jkR"/Ev'F:Vt7+:ɨ} Z,F1cG)eDVG.Zׇeef1cl6LFFr|Dz u<mU\5ʭVaS?Z頳XƶDXeU3a⊨+$m<7~;J*SFf14 Gzqdx�xblxEe1]"J7z9\]Z3Wqw)cc$66h؋JbFUˇV)Ф^aVKGRI3蚫_ku"V7w^ނߣeL44!.*YSWs%d,rfQ>H΁\QqER∿}=%tS#b5L5"{�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/fp-panels.jpg���������������������������������������������������������������0000644�0001750�0000144�00000051124�12574421673�020231� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000�������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���Created with GIMP�C�  !"$"$�C�3"�������������� �T� ��!1"4AQSUVaq26RruBTs#35$b%C7Dc�������������7� �����!QTq134RSA"a2B� ��?�XA^,9s sї5Du1Å3Ŷw팆c7xEP|=9.wtQCujW6Tg鄬h;@X:{*ue9 o.Ƣ}qKI<HZsҴ Zh6Bm-D GEqT4à LkQ%p\Z&v`Xjji"|SBpkA.ح4Ew; >B\ڪH.h7ً&]i(!jWL):&Pz#Z U^cx\<}V\ i**$lP˞p\rٙWqQU([RF,-jݖc`h!Miݵ [?(4Ti^郣&l-9Q@8L5d \A5,z٬7]u7 y3&(*FAugv!ibF~j5�lo.+??NNv~[&QPj#!{Ns*b1D+=l3S<lC=�C%j9nnlnn6.0kl8o'S5aV.P5zpuȦep!CGIPئkk̑ ڀ-!(;##SEw%8nRQm%3V`u@g2=�p@ݼͤeÓk e/ nѥlOpclnΧ kNJ鳡0-sPHWqev(?UVٲ-:g][?];$ud19ִDOsw;q㗴?�s8֚+}Go?fx%:RCy[6b|w)bwL ;bd & CDHpo#S^d}뤺,m ˫S 1n~|mz6}2 RsqPqe;p]HX�9e5 UEY%H?k:eѳ~4.9ΰ#YMec SYXk25V> e5&#YMec SYXk25V> e5&#YMec SYXk25V> e5&#YMec SYXk25V> e5&#YMec SYXk25V> e5&#YMec SYXk25V> e5}a5.⽾u;! 1$>]x�Yrq6�R6� кv lm.Ӽ@n|+fMWqҌg\ܳ2PՇqZ�,Y?שYl.�Z<ƍ-hv5t3zvFI#I#ZeH̔m/iq�-&,tåuWLL|�?9ie�ةYF|4R{vrs| _B&淘"`zvI2~IkO WF%\-f?mU_d]Y<#\8?YUWy3w9�~bu1MTe}SU5O\25X*ֱS_{ǒ h-JfV1S�A]~vXᨒ6?嵯 ;ǎ+= ܒ7t3rKޒ<ʩ�G4K<Get"49 :A㳼] ܒ7t3rKޒ<fw7w7ջ8q®:ʈ u33@:4Anxz%~oIU{Df䗽%Ux4[Ҽ Wc_E\5r]½/{zJ'C7$*hLeq-nupn5W%~oIU{Df䗽%U~]_f�a�+F_s$R6MsUG;ڛu~8 gB#M:j \w7>vsC:joITZs'WP~y [K[L~^Zs'WUؽ\F,ـܪk^f䗽%U^WAix%~oIU{Df䗽%Ux$? ½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ'C7$*h:)½/{zJ/ ܒ7uʚ-k[ zF|>nI{ޛU^:%~IU{EW;kXDLC?a{jy>fM(s_9Y-*flnIXܗ8IW:%~IU{Dg䗽%UL�ULSeN.ok 0χ!@Ͽ%~IU{Dg䗽%U.?j]r|횺f\HV5Wz%~oIU{Ef<T?0p-�ul_)]s]STOEE1L}E.K;7*}//IG�kG�h6( m+6`NQ5df^Vpg#~8n.;qU^+ dc4 =m;-+clՎElOE,(.ei''#DkvȢK9Mrs`چwz^m9�:v'9M)*K| %ۛ3#[EnSɕ~lE_T>7skpqd7+P[,mZs,V˟# :WnA٢l4=z$ˣq.;G,:V_]w $A+vn9Yr}U@׬>z` ZH*Um}l�}516Yhߏ i,UPOjkV2fLk~Qsq[yKZ몚f9FьFd C[mKͲo]=o.p0^p c7(?9{Z {*c>c|NkArX)Wα*"wmOh3[{EnUB ơz#­@Z;Mlݘdjfw_Gi;Icx(-I3C$2'73cgvfv}f~fL1AsxppH߂Eve/SAjU\Mnk poyT^g+ٝT -/`c3 v7)3Ғ-&;d֖gCtSp:%nΤD-ר_X^o5ȈVUiL�VUiL�` ͞MǖM[ 6MƮC�fnxWF8%l%%(SU7v�tQ>Ҁ .]mLo'1K {~:߅ck9eRQ%V}G6ǣ=0&]\8{տaGEz%S2BA78ui/%-AbbL0\Z]s5ӷZQyɗ#Ȅ[C4Fx9k\;;#rhvGeY_m'e 4F\4qqJp&0({5A6+a6ǵrmS'ԐcV?dub֌z<t?1TQʽ;tS|0pkEDM�GܷO\r5mCYG.B SK6{&ٮv(.zlYZ<iFKk,/in`8⢛J# gg Jg{G|[h,-hࡢ^)`dm$@N7 'wd>wm{ֱp\�w:Hvi˽dBT5H�F~zegk6k`9-W`y&IVdJcԘ싽e;At/}rAPpx2p ڷQj{ݮ uw=R6N|/2L;)F[qikd{:Kt_vf9.ڛ7k=& _R�79NIN jsnIhCbe3 oh víٯ|)oڭj$Zo Fp'%MtvLW;U<F[+)} R;4c16ݛuiX73G[;eLZcDMtLN˒/vz+LML"Nh>YˋsOJ7ad[Z{ٻO#_xfI?Wl{g[fST]2ڠL%'.ݽ+Z?K靈>KRju^XH d;"Ҍ#\}c:�(nivV?&qbojѥ8qflǀX\Ql]~W(dܟYqVz[P1/]Inv {5\-28n#ŏX=h.^h`( Ic cE~| w'_UtmZC C~[uF=/%1M˦SM-򍟓mnZ2ASX5KEz*,{&� a7njó<XuAPcJU\D ;$$g3kD㯯CoqEͺ�umgQ\=aֽk;w[+8+ e<΍&s{sYwi^١{7gcQP9 Orryĕ5O<8h3�dҊE=no�L6_ojVqٛmCsCKMb1Tƌp 'vm�̳SkD8)1lk~f?|?cͿu%a=%[$Z߇}ٷ�2oe:J6QE~ݛ,6�YӤl%[$Z߇}ٷ�2oe:J6QE~ݛ,6�YӤl%[$Z߇}ٷ�2oe:J6QE~ݛ,6�YӤl%[$Z߇}ٷ�2oe:J6QE~ݛ,6�YӤl%[$Z߇}ٷ�2oe:J6QE~ݛ,6�YӤl%[$Z߇}ٷ�2oe:J6QE~ݛ,6�YӤl%[$Z}ط�2)i`l4NΗ88<*bjTTOB" """ """ """ """ """ ""ź 0YK/ ɵ?1YPpZO r͌˖R4_n˺ʭZ*wKJ5S'5I 55e۷ *[t_Y ئE5#po߃p/[+[)` UEO?#{?f:lkWlV棥~5j�>rAT4qc`;G 6VyMہ_piȷ*cաNES}̡_v+<kgQML/Zև!@Y7O_v+<na4=˃C~ m}ج'S}E7a0~B?6VyM݊)Mr?!_v+<kgQML&yph{ S}Dbo&Cܼ4=G݊)|@Y7Sv ^\#kgQ> m}ج) /. sBboVyM݄h{!@Y7O_v+<na4=˃C~ m}ج' S}E7a0~B?6VyM݊)Mr?! _v+<kgQML&yph{ S}Dbo&Cܼ4=G݊)|@Y7Sv ^\#kgQ> m}ج) /. sBboVyM݄h{!@Y7O_v+<na4=˃C~ -}ج' S}E7a0~B?6VyM݊)Mr?!_v+<kgQML&yph{ S}Dbo&Cܼ4=G݊)|@ZY7Sv ^\Wtv#Fh 'wuK-ۮO^źi)[H0#w<Z1Ϫp/IܩWZ8j mr֨>䋕ou0v2&SeKip yc�tUO'P*V84[dS[Hx8vӀ8%F}J:yK\?i|%>>&ޭyTk96mMWKTk09UaWr9UaNrO WiΟU9ʮ>,s]:}T*L>t Uv|S09UaNrO WiΟU9ʮ>,s]:}T*L>t Uv|S09UaNrO WiΟU9ʮ>,s]:}T*L>t H9X^o )bz�Y ""ZZ}zy_ Z|rF17Ax+hVm~`m_nή۳rޯEIJKuxο[Ĥ=ٺn@)#%tOiӆs4q++|¹'¸\xm B8$f[X)Y \"gOf PjCn-όd-ʺoViibtHh%> eifڽV[Nms9M+u9AG�H SUKj=ql}DthcH50T|ًOV?6 emTKdI ;^ff_N-jzIMKZ0%`s0 _6&vWHͣ:Ztlup/~3Vო.7)#/#7\bhmr6T\]>&%ZIg$qLN""(HJ/ Vmel7IM::VN,{XԖaDTN= `#pӴTq pђ.> '6XoNKm[µ׫|ƞfFË[pr_Rǯj'R~{ [v5wIAz<~0V$�SapZA;>Ux[upݝ Umꢒkt-#飍xS:=\_P>Y%^[ti48&ڜp3o}쩫]5|ʪ64<x$uu$Zvz*ltp;){!;p<pVQ߹yhmi%( j*bVJӮ8en2Γ.-n9a>=%jgmT}UQh{&rv7 e:~ؑ2m =f䮍ii[): AzgyfࢬboIڽQ$.4?7gt#]-inp]%^D"iZ9%uI3#^3""" """ !x /uW"CDeE~duDdyI98@h'�H7Uu4`;ܕC$Xb2Qׅ^1BƯ^"" /8 5l; 5폞u6rvMnG_j<E,͖7p /<l%EsvJᬘS'5o㲬Mձ[?Ewڋ-[nu6G=6< I]QLӗKuյ0RRR<#lc-sNA%jjvl궎.ѺIEw4kX\ #oaK\rm6O-G،$_cp2)q6YMYN9Zy[# i!SI{,Uޭ<y <ꛞHYc�A^*CU TpfUi?Hh՞8hߝÂ}'Tڢ"" """ """ ,[P7nB�k�Fڿ''ZdOOU[vupvݝ\%{Fv i6kUʞG uXhYF2 9‹}0n_ka] ߔ(vfZ$ƪHDt:Z5X7@\y'pqg?� ;`{R02A<9)dٻJ =RLN6BFMvmsO 6KmLOG15�DNtӜqo r&hJmC88=�'q-'4 ؍6?l0TأTXmZ9Ԭ0T^nWJ[\SW%c`lF2i'89SL6 YN~@yOֻPq#Y- xmv]E4-lj p޶ ;GZJ9l󈢓-cMwJ8`Bճf9e)&N~b 8{\tI w(uncu&J&CW+9c=| {lg8' Cc1NcW[aeD2f-`sFD zJݢkLV�ژꇶ*%g0␝M `�0nO7[;4me4&57#È*GF7O5{͵M$]( &&c)R_e45X516s?2HXD\' r;IѴGK\:Wk/נ`FYAOipl'es<6GEA=CH8~3b%]]5I"bY�6I-[49.s|sg=_T4Mk~ds3$lðwX;\$mr(%3ȭt7"13!CNfyU>{{c <08) T5.xl}0OHG}Gms sfy h`8n\P7CmfI$7[L0I1i�s?@A"*U?KYpW?1$ia1i!_akw]Dۢ=鵵v�g# ަKU5.ls'OJ"v8g$I;Ԕ1Q { "11qt~m5Zvv90A,ᤵKr4 ^P[~o,1J4?l6#,�J1wBS#$nc FA Ed͓׾ͳv}[~mn7ku-A=Tm8\4.!;9 >*%{Fv־^j6<5d:v^_}s{l2kd}.*db{_81KJߓnYhocڊM |&˹3Qn0%ϔcMVAkgGS\9* ts<I:ZS[-=$5A8Zf n`pܭ߬v{(T[#Cp@p.;Y]U=$Š0s 'v@[j*y(`[͆/x8 -m[+9; - ;;51Tlh4o7ŧNz]=.;.9_6Z mK\utuidΧPK:fHӟoiw\-QLi2\0 {;,6Kls)XL;tѽQl͞\_l9p n''$o9+*jL F6"*\$G'ɌȜIËݤ t(쒲fDy;-Bn3 An\NH!DNdً׺FT6R,RG4Of1=;s9ӓ }h.5L94>0 쉥QΠGp[ə8""" "" 5]O'?]M>:oE8u<T %u6 MX~^ʽw8"je:<)�uQ;/zUaT[GPbI\HnHð\az J6m.և4Q☇ZH20xddwhoP&}E\W褒8uVsܼI# �JprQ3.H@1î9*�CQL e c tNт ǧi s3GS]X湥.]sFTEœ: \mS f4R/飐ߖ].w[j*5ҟD^^D@DDD@DDuf`-ר_ r" _WD�+Q06�Inή۳/rܾ֓aR\{$4|N1;NdӇ7`o(ܪ37/Vj6*5EEM+(*SpHNesZZ;-1ǒJV|6vF(bl{ 3�۷nsGCoh 7H&h+�ݹ5q , 3*ci6 0 t]m E֖*H[+pp־8#KnZ0mζQP@D!=SAf Xᬂ/yzx٠kF7bO2ۤ ,4BjL`pwwو ȀF ck4 =(ửq=MvZjm,>d"Ӗl 7aU o.j.f=hwH077prDKg ,tTB]HkH.7Y.[]%<tј{itL#8nܳeAaI)dk pxr* 8[O7Ιk//.%Q [S* (c%[Z�q $XLً uQ#u\)Xsa7 «*[SUov45^u� GLA$�cw_D,zJxD" &DZ^C@t<c'9t*FJJJzvI(&=ぼ묤AMhSG,68kZNN�ȩJz[$r49iAqu`j <FO0,n#vP[EL"G9/2or̜d 嘈0f{Ns!4&؈`ݹ~~:x!?%?d" wR=ϦĻY&0Iv|[6j*cTLl0.iv3ޔ8;[A_n}$pk\V=;*Lb.y4?@9 ՌpYH�_ !B#ja 'G`+mx6S4/|HaisqO\=un}Dr24K CWs(i#Z2\׷~[ tR!xbyn0FIG[.qd~؞X5͖A,4!!c{I]W,Hعm2s`5qῆUm,6hSJce�)ա݌i[mj4MuAv2tRI<SPrgkwq>m#'7+d#˷n{wO�HkzntbQX\7cw:/m̷O8cO{*5zzJxg!Mk#q$9IOW<pk]ScPn^Ogv۴JSS$TƠ3wtǥ;uTŒ푦&/vOm[CL!xPb0wJ8i͘A^鈔Bo c�.%g(4tnF]mne10A܃e gigQ79xdɫ":J|nuWj;%=]#43sn {20A#g6[/4ji$uqZ�" """ "" 5]O'?]M>:oE8u<T %u6 MX~^ʽw8"jT1:\ZMٛuUCϙ.Sj;`tDz|;XgCE$JjkkZߴ0xFY}RZ;|Wdtr8姾l|)멮)fscɒ6>S]F:b^d%3壒6K#YKwt=tc1*яgd-g|悑0M.t@on^'m3iE 8ӌe:H� f>2e,n@p8[D4Uj_M]?= %RSCN$y(Cx=8p<xlDC&Q""" """ ,[P7nB�k�Fڿ''ZdOOU[vupvݝ\%{N6 �F( \Z\8$.QOi?F'Q_ܸOr=ςU?'*Z-U?'*AkOzʧ=euZ@S| rY]D?T�GܪWQU?'*AkOzʧ=euZ@S| rY]Dy�GD^*ă>%U,B" """ ""WAu]!d5ѱK\Ӝq1ZuS3CtW(%/I$w�hٹX&x8+eѯ^unn寻l[]G 1-0G1 8_ ]z(c|=ET,uG4$pƃf4TtE3YP#CK@.q';)F쵕#S6w3/lM;9 h�ޯڬV]UMU#&Z'|aqhˉz"9z zh�Ƃډ22:@GM<p9�{`Rcfa?7Lt2{��`[TvQHB#;@/~ao;�`nVv+eZX^& +-#Sp1 lCA䮦7"jO{h|t߄&߬?/He^ pDk5DD@DDhZz#M*j,ٓcޫNLb~Xŧ{6GSsu %ƞltƘKNG?8nwe`Ƿ*#HwKP5ťťg AI-MvӇA:Y:GnMï3ީmXր/34>L@vp] -)1qM_VOOO%WryHX궻;n 6޸1<g>)ikOg Ɛz%eSm-L3_#xvv8q쬜Q6X�l-p۝}⒂a1`as1ʨ!P73�Μg$K#`v3!5ͬ{c1dA#8me&Z*#rrCDE  /e,[P7D@+Q06�InVm~`m_Vݝ\%]gW r~?W?TC%<ܧ ~DǓǒ{Iv|hD@DDD@DDD@DDDA�$gm/Y�$gm/Y!WSOrWSmN5]O'?]M>:oEz2]8"" ""0 X5V^nstvIm3rںKrj`n57 ~j(`1R269 CHӀ mi"}]lf=Z;Mu3T|Lqjzp[5NFRffq""-ר_X^o5ȈVm~`m_ܭFڿ'':Jnή0kI0>Ky?9QOi?F''+$+></"hI/_ I/_2CA䮦7"jO{h|t߄&߬?/He^ pDk5DD@DDD@DDD@DDD@DDD@DDD@X^o )bz�Y ""ZdOO[rkjȟ*:K)¹'¤/F?W?TC%<<ܬ8OsྈE""" """ """ ""'ľ?i/'ľ?i DDD@DDD@DDD@DDD@DDD@DDD@DDD@DD<jO{h|t߄qy>Jm~,~!z'qpEbz�Y,uf`\j6?=mm "z۳.Oܧ ~DǓ{a\֓aR}ȗ~rOr=ς"->?l�m ?�?l�m ?�!D<Yy>Jm~)ƫPw+MHo]UX~^ATDDD@DDD@DDD@DDD@DDD@DDuf`-ר_ r" _WD�+Q06�Inή۳?r+~*O�OTaSsZOхI?"_=σ$;> 舴Z" """ """ """ �|K,�|K, D@DDD@DDD@DDD@DDD@DDD@DDD@DDD@CAfPw+MHA䮦7"ɽwWazBwZQ-ר_X^o5ȈVm~`m_ܭFڿ'':Jnή0kI0:Ky?9QP`_kI06& Ik z$+><2Y*?rgGSyLAyr)zT~7YVyʏܦ'9QS=dY*?rgGSyL^Ego)sM3Ayr)zT~7YVyʏܦ'9QS=dqVyʏܦ/t4s{(M~n'VFtݎVU,keii*p?=&!ӎAyD<Yy>Jm~)ƫPw+MHo]UX~^ATDDD@DDD@DDD@DDD@DDD@DDuf`-ר_ r" _WD�+Q06�JEUgW Wm\W i?F+D{XIHQOSi?F'O 2ܸOr=σ+MOnY4|[Kʙdګ ,qk_ӞjAlGs6&kMc YHDqkZ70Z/toav9Y–]z�@DDD@DDD@DDD@L"" """ """ """ """ """ """ """ !x U}S(;ܕC$SOSOrWSmd޻ ~!;-f /e,[P7D@+YpKU{KIO{dso�!lȶyKtT;^kcj)][͉`sdm\l$jp 1Hcn'-}==DMQOĎ> %<H+rÁwF@6;i-{Ufi>tc ǎ# qr- 9ת5.DYUtjX B<? +F?o]6 vqQVUWPOՒ8%}@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@C222@y'Ay6 ]Z@Ws9Vg<FIa>X"ck߽rܼrG`HdKKkr7L?e6"RƶLU_8Q�&1gṃY�N~"oD@DDD@DDD@DDD@DDD@DDD@X^o )bz�Y ""YV3*ɵ8 x W([k;#s3.`yO]�=ܶWM/o Fu5q󑽚N=V,̾;Qi4xf_r]ꨴk8tWf ;<48ǎgDL=If~i#_C[*ߩ" ~0, ~{>:"aTH{5<goܚ[)/,'4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4"aTH{4艇S!Erhgoܙ�x4}pv2MKr Jvj\؜ $ĸ/SoX� Lzf6DD+ɷhmmcdDB%䇒HnxwEWuh0|t~۱3�_@_Veui]nW[8 DEbz�Y,v#e.hP?^ ;x#*]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8SKlp]f4 Qݶo8P0jKGZ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ ""��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/getting-started.rst���������������������������������������������������������0000644�0001750�0000144�00000023730�12574421673�021503� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.. _getting-started: Getting Started =============== The goal of this document is to help get you up and running quickly. So without further ado, let's get started. .. note:: Hopefully you have some familiarity with the `flask framework <http://flask.pocoo.org/>`_ and the `peewee orm <http://peewee.rtfd.org/>`_, but if not those links should help you get started. .. note:: For a complete example project, check the `example app <https://github.com/coleifer/flask-peewee/tree/master/example>`_ that ships with flask-peewee. Creating a flask app -------------------- First, be sure you have :ref:`installed flask-peewee and its dependencies <installation>`. You can verify by running the test suite: ``python setup.py test``. After ensuring things are installed, open a new file called "app.py" and enter the following code: .. code-block:: python from flask import Flask app = Flask(__name__) app.config.from_object(__name__) if __name__ == '__main__': app.run() This isn't very exciting, but we can check out our project by running the app: .. code-block:: console $ python app.py * Running on http://127.0.0.1:5000/ * Restarting with reloader Navigating to the url listed will show a simple 404 page, because we haven't configured any templates or views yet. Creating a simple model ----------------------- Let's add a simple model. Before we can do that, though, it is necessary to initialize the peewee database wrapper and configure the database: .. code-block:: python from flask import Flask # flask-peewee bindings from flask_peewee.db import Database # configure our database DATABASE = { 'name': 'example.db', 'engine': 'peewee.SqliteDatabase', } DEBUG = True SECRET_KEY = 'ssshhhh' app = Flask(__name__) app.config.from_object(__name__) # instantiate the db wrapper db = Database(app) if __name__ == '__main__': app.run() What this does is provides us with request handlers which connect to the database on each request and close it when the request is finished. It also provides a base model class which is configured to work with the database specified in the configuration. Now we can create a model: .. code-block:: python import datetime from peewee import * class Note(db.Model): message = TextField() created = DateTimeField(default=datetime.datetime.now) .. note:: The model we created, ``Note``, subclasses ``db.Model``, which in turn is a subclass of ``peewee.Model`` that is pre-configured to talk to our database. Setting up a simple base template --------------------------------- We'll need a simple template to serve as the base template for our app, so create a folder named ``templates``. In the ``templates`` folder create a file ``base.html`` and add the following: .. code-block:: html <!doctype html> <html> <title>Test site

{% block content_title %}{% endblock %}

{% block content %}{% endblock %} Adding users to the site ------------------------ Before we can edit these ``Note`` models in the admin, we'll need to have some way of authenticating users on the site. This is where :py:class:`Auth` comes in. :py:class:`Auth` provides a ``User`` model and views for logging in and logging out, among other things, and is required by the :py:class:`Admin`. .. code-block:: python from flask_peewee.auth import Auth # create an Auth object for use with our flask app and database wrapper auth = Auth(app, db) Let's also modify the code that runs our app to ensure our tables get created if need be: .. code-block:: python if __name__ == '__main__': auth.User.create_table(fail_silently=True) Note.create_table(fail_silently=True) app.run() After cleaning up the imports and declarations, we have something like the following: .. code-block:: python import datetime from flask import Flask from flask_peewee.auth import Auth from flask_peewee.db import Database from peewee import * # configure our database DATABASE = { 'name': 'example.db', 'engine': 'peewee.SqliteDatabase', } DEBUG = True SECRET_KEY = 'ssshhhh' app = Flask(__name__) app.config.from_object(__name__) # instantiate the db wrapper db = Database(app) class Note(db.Model): message = TextField() created = DateTimeField(default=datetime.datetime.now) # create an Auth object for use with our flask app and database wrapper auth = Auth(app, db) if __name__ == '__main__': auth.User.create_table(fail_silently=True) Note.create_table(fail_silently=True) app.run() Managing content using the admin area ------------------------------------- **Now** we're ready to add the admin. Place the following lines of code after the initialization of the ``Auth`` class: .. code-block:: python from flask_peewee.admin import Admin admin = Admin(app, auth) admin.register(Note) admin.setup() We now have a functioning admin site! Of course, we'll need a user log in with, so open up an interactive python shell in the directory alongside the app and run the following: .. code-block:: python from app import auth auth.User.create_table(fail_silently=True) # make sure table created. admin = auth.User(username='admin', email='', admin=True, active=True) admin.set_password('admin') admin.save() It should now be possible to: 1. navigate to http://127.0.0.1:5000/admin/ 2. enter in the username and password ("admin", "admin") 3. be redirected to the admin dashboard .. image:: fp-getting-started.jpg The dashboard is pretty empty right now. Go ahead and add a few notes (http://127.0.0.1:5000/admin/note/). If you navigate now to the note modeladmin you will see something like this: .. image:: fp-note-admin.jpg This is pretty lousy so let's clean it up to display the message and when it was published. We can do that by customizing the columns displayed. Edit the app with the following changes: .. code-block:: python from flask_peewee.admin import Admin, ModelAdmin class NoteAdmin(ModelAdmin): columns = ('message', 'created',) admin = Admin(app, auth) admin.register(Note, NoteAdmin) admin.setup() Now our modeladmin should look more like this: .. image:: fp-note-admin-2.jpg Let's go ahead and add the ``auth.User`` model to the admin as well: .. code-block:: python admin.register(Note, NoteAdmin) auth.register_admin(admin) admin.setup() Exposing content using a REST API --------------------------------- Adding a REST API is very similar to how we added the :py:class:`Admin` interface. We will create a :py:class:`RestAPI` object, and then register our project's models with it. If we want to customize things, we can subclass :py:class:`RestResource`. The first step, then, is to create the :py:class:`RestAPI` object: .. code-block:: python from flask_peewee.rest import RestAPI # create a RestAPI container api = RestAPI(app) api.setup() This doesn't do anything yet, we need to register models with it first. Let's register the ``Note`` model from earlier: .. code-block:: python # create a RestAPI container api = RestAPI(app) # register the Note model api.register(Note) api.setup() Assuming your project is still running, try executing the following command (or just browse to the url listed): .. code-block:: console $ curl http://127.0.0.1:5000/api/note/ You should see something like the following: .. code-block:: javascript { "meta": { "model": "note", "next": "", "page": 1, "previous": "" }, "objects": [ { "message": "blah blah blah this is a note", "id": 1, "created": "2011-09-23 09:07:39" }, { "message": "this is another note!", "id": 2, "created": "2011-09-23 09:07:54" } ] } Suppose we want it to also be possible for registered users to be able to POST messages using the API. If you try and make a POST right now, you will get a ``401`` response: .. code-block:: console $ curl -i -d '' http://127.0.0.1:5000/api/note/ HTTP/1.0 401 UNAUTHORIZED WWW-Authenticate: Basic realm="Login Required" Content-Type: text/html; charset=utf-8 Content-Length: 21 Server: Werkzeug/0.8-dev Python/2.6.6 Date: Fri, 23 Sep 2011 14:45:38 GMT Authentication failed This is because we have not configured any :py:class:`Authentication` method for our :py:class:`RestAPI`. .. note:: The default authentication mechanism for the API only accepts GET requests. In order to handle POST/PUT/DELETE you will need to use a subclass of the :py:class:`Authentication` class. In order to allow users of the site to post notes, we will use the :py:class:`UserAuthentication` subclass, which requires that API requests be made with HTTP Basic auth and that the auth credentials match those of one of the ``auth.User`` models. .. code-block:: python from flask_peewee.rest import RestAPI, UserAuthentication # instantiate the user auth user_auth = UserAuthentication(auth) # create a RestAPI container api = RestAPI(app, default_auth=user_auth) Now we can post new notes using a command-line tool like curl: .. code-block:: console $ curl -u admin:admin -d data='{"message": "hello api"}' http://127.0.0.1:5000/api/note/ { "message": "hello api", "id": 3, "created": "2011-09-23 13:14:56" } You can see that it returns a serialized copy of the new ``Note`` object. .. note:: This is just a small example of what you can do with the Rest API -- refer to the :ref:`Rest API docs ` for more detailed information, including * limiting access on a per-model basis * customizing which fields are returned by the API * filtering and querying using GET parameters flask-peewee-0.6.7/docs/auth.rst0000644000175000001440000001312012574421673017327 0ustar charlesusers00000000000000.. _authentication: Authentication ============== The :py:class:`Authentication` class provides a means of authenticating users of the site. It is designed to work out-of-the-box with a simple ``User`` model, but can be heavily customized. The :py:class:`Auth` system is comprised of a single class which is responsible for coordinating incoming requests to your project with known users. It provides the following: * views for login and logout * model to store user data (or you can provide your own) * mechanism for identifying users across requests (uses session storage) All of these pieces can be customized, but the default out-of-box implementation aims to provide a good starting place. The auth system is also designed to work closely with the :ref:`admin-interface`. Getting started --------------- In order to provide a method for users to authenticate with your site, instantiate an :py:class:`Auth` backend for your project: .. code-block:: python from flask import Flask from flask_peewee.auth import Auth from flask_peewee.db import Database app = Flask(__name__) db = Database(app) # needed for authentication auth = Auth(app, db) .. note:: ``user`` is reserverd keyword in Postgres. Pass db_table to Auth to override db table. Marking areas of the site as login required ------------------------------------------- If you want to mark specific areas of your site as requiring auth, you can decorate views using the :py:meth:`Auth.login_required` decorator: .. code-block:: python @app.route('/private/') @auth.login_required def private_timeline(): user = auth.get_logged_in_user() # ... display the private timeline for the logged-in user If the request comes from someone who has not logged-in with the site, they are redirected to the :py:meth:`Auth.login` view, which allows the user to authenticate. After successfully logging-in, they will be redirected to the page they requested initially. Retrieving the current user --------------------------- Whenever in a `request context `_, the currently logged-in user is available by calling :py:meth:`Auth.get_logged_in_user`, which will return ``None`` if the requesting user is not logged in. The auth system also registers a pre-request hook that stores the currently logged-in user in the special flask variable ``g``. Accessing the user in the templates ----------------------------------- The auth system registers a template context processor which makes the logged-in user available in any template: .. code-block:: html {% if user %}

Hello {{ user.username }}

{% else %}
{% endif %} Using a custom "User" model --------------------------- It is easy to use your own model for the ``User``, though depending on the amount of changes it may be necessary to override methods in both the :py:class:`Auth` and :py:class:`Admin` classes. Unless you want to override the default behavior of the :py:class:`Auth` class' mechanism for actually authenticating users (which you may want to do if relying on a 3rd-party for auth) -- you will want to be sure your ``User`` model implements two methods: * ``set_password(password)`` -- takes a raw password and stores an encrypted version on model * ``check_password(password)`` -- returns whether or not the supplied password matches the one stored on the model instance .. note:: The :py:class:`BaseUser` mixin provides default implementations of these two methods. Here's a simple example of extending the auth system to use a custom user model: .. code-block:: python from flask_peewee.auth import BaseUser # <-- implements set_password and check_password app = Flask(__name__) db = Database(app) # create our custom user model. note that we're mixing in BaseUser in order to # use the default auth methods it implements, "set_password" and "check_password" class User(db.Model, BaseUser): username = CharField() password = CharField() email = CharField() # ... our custom fields ... is_superuser = BooleanField() # create a modeladmin for it class UserAdmin(ModelAdmin): columns = ('username', 'email', 'is_superuser',) # Make sure the user's password is hashed, after it's been changed in # the admin interface. If we don't do this, the password will be saved # in clear text inside the database and login will be impossible. def save_model(self, instance, form, adding=False): orig_password = instance.password user = super(UserAdmin, self).save_model(instance, form, adding) if orig_password != form.password.data: user.set_password(form.password.data) user.save() return user # subclass Auth so we can return our custom classes class CustomAuth(Auth): def get_user_model(self): return User def get_model_admin(self): return UserAdmin # instantiate the auth auth = CustomAuth(app, db) Here's how you might integrate the custom auth with the admin area of your site: .. code-block:: python # subclass Admin to check for whether the user is a superuser class CustomAdmin(Admin): def check_user_permission(self, user): return user.is_superuser # instantiate the admin admin = CustomAdmin(app, auth) admin.register(User, UserAdmin) admin.setup() flask-peewee-0.6.7/docs/rest-api.rst0000644000175000001440000003205712574421673020124 0ustar charlesusers00000000000000.. _rest-api: REST Api ======== flask-peewee comes with some tools for exposing your project's models via a RESTful API. There are several components to the ``rest`` module, but the basic setup is to create an instance of :py:class:`RestAPI` and then register your project's models with subclasses of :py:class:`RestResource`. Each :py:class:`RestResource` you expose via the API will support, by default, the following: * `/api//` -- GET and POST requests * `/api///` -- GET, PUT and DELETE requests Also, you can filter results by columns on the model using django-style syntax, for example: * `/api/blog/?name=Some%20Blog` * `/api/blog/?author__username=some_blogger` Getting started with the API ---------------------------- In this documentation we'll start with a very simple API and build it out. The complete version of this API is included in the :ref:`example-app`, so feel free to refer there. The project will be a simple 'twitter-like' app where users can post short messages and "follow" other users. .. note:: If you're using apache with mod_wsgi and would like to use any of the auth backends that use basic auth, you will need to add the following directive: ``WSGIPassAuthorization On`` Project models ^^^^^^^^^^^^^^ There are three main models - ``User``, ``Relationship`` and ``Message`` - which we will expose via the API. Here is a truncated version of what they look like: .. code-block:: python from flask_peewee.auth import BaseUser class User(db.Model, BaseUser): username = CharField() password = CharField() email = CharField() join_date = DateTimeField(default=datetime.datetime.now) active = BooleanField(default=True) admin = BooleanField(default=False) class Relationship(db.Model): from_user = ForeignKeyField(User, related_name='relationships') to_user = ForeignKeyField(User, related_name='related_to') class Message(db.Model): user = ForeignKeyField(User) content = TextField() pub_date = DateTimeField(default=datetime.datetime.now) Creating a RestAPI ------------------ The :py:class:`RestAPI` acts as a container for the various :py:class:`RestResource` objects we will expose. By default it binds all resources to ``/api//``. Here we'll create a simple api and register our models: .. code-block:: python from flask_peewee.rest import RestAPI from app import app # our project's Flask app # instantiate our api wrapper api = RestAPI(app) # register our models so they are exposed via /api// api.register(User) api.register(Relationship) api.register(Message) # configure the urls api.setup() Now if we hit our project at ``/api/message/`` we should get something like the following: .. code-block:: javascript { "meta": { "model": "message", "next": "", "page": 1, "previous": "" }, "objects": [ { "content": "flask and peewee, together at last!", "pub_date": "2011-09-16 18:36:15", "user_id": 1, "id": 1 }, { "content": "Hey, I'm just some user", "pub_date": "2011-09-16 18:46:59", "user_id": 2, "id": 2 } ] } Say we're interested in the first message, we can hit ``/api/message/1/`` to view just the details on that object: .. code-block:: javascript { content: "flask and peewee, together at last!" pub_date: "2011-09-16 18:36:15" user_id: 1 id: 1 } Customizing what is returned ---------------------------- If you access the ``User`` API endpoint, we quickly notice a problem: .. code-block:: console $ curl http://127.0.0.1:5000/api/user/ { "meta": { "model": "user", "next": "", "page": 1, "previous": "" }, "objects": [ { "username": "admin", "admin": true, "email": "", "join_date": "2011-09-16 18:34:49", "active": true, "password": "d033e22ae348aeb5660fc2140aec35850c4da997", "id": 1 }, { "username": "coleifer", "admin": false, "email": "coleifer@gmail.com", "join_date": "2011-09-16 18:35:56", "active": true, "password": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", "id": 2 } ] } Passwords and email addresses are being exposed. In order to exclude these fields from serialization, subclass :py:class:`RestResource`: .. code-block:: python from flask_peewee.rest import RestAPI, RestResource from app import app # our project's Flask app # instantiate our api wrapper api = RestAPI(app) # create a special resource for users that excludes email and password class UserResource(RestResource): exclude = ('password', 'email',) # register our models so they are exposed via /api// api.register(User, UserResource) # specify the UserResource api.register(Relationship) api.register(Message) Now emails and passwords are no longer returned by the API. Allowing users to post objects ------------------------------ What if we want to create new messages via the Api? Or modify/delete existing messages? .. code-block:: console $ curl -i -d '' http://127.0.0.1:5000/api/message/ HTTP/1.0 401 UNAUTHORIZED WWW-Authenticate: Basic realm="Login Required" Content-Type: text/html; charset=utf-8 Content-Length: 21 Server: Werkzeug/0.8-dev Python/2.6.6 Date: Thu, 22 Sep 2011 16:14:21 GMT Authentication failed The authentication failed because the default authentication mechanism only allows read-only access. In order to allow users to create messages via the API, we need to use a subclass of :py:class:`Authentication` that allows ``POST`` requests. We also want to ensure that the requesting user is a member of the site. For this we will use the :py:class:`UserAuthentication` class as the default auth mechanism. .. code-block:: python from auth import auth # import the Auth object used by our project from flask_peewee.rest import RestAPI, RestResource, UserAuthentication # create an instance of UserAuthentication user_auth = UserAuthentication(auth) # instantiate our api wrapper, specifying user_auth as the default api = RestAPI(app, default_auth=user_auth) # create a special resource for users that excludes email and password class UserResource(RestResource): exclude = ('password', 'email',) # register our models so they are exposed via /api// api.register(User, UserResource) # specify the UserResource api.register(Relationship) api.register(Message) # configure the urls api.setup() Now we should be able to POST new messages. .. code-block:: python import json import httplib2 sock = httplib2.Http() sock.add_credentials('admin', 'admin') # use basic auth message = {'user_id': 1, 'content': 'hello api'} msg_json = json.dumps(message) headers, resp = sock.request('http://localhost:5000/api/message/', 'POST', body=msg_json) response = json.loads(resp) The response object will look something like this: .. code-block:: javascript { 'content': 'hello api', 'user_id': 1, 'pub_date': '2011-09-22 11:25:02', 'id': 3 } There is a problem with this, however. Notice how the ``user_id`` was passed in with the POST data? This effectively will let a user post a message as another user. It also means a user can use PUT requests to modify another user's message: .. code-block:: python # continued from above script update = {'content': 'haxed you, bro'} update_json = json.dumps(update) headers, resp = sock.request('http://127.0.0.1:5000/api/message/2/', 'PUT', body=update_json) response = json.loads(resp) The response will look like this: .. code-block:: javascript { 'content': 'haxed you, bro', 'pub_date': '2011-09-16 18:36:15', 'user_id': 2, 'id': 2 } This is a problem -- we need a way of ensuring that users can only edit their own messages. Furthermore, when they create messages we need to make sure the message is assigned to them. Restricting API access on a per-model basis ------------------------------------------- flask-peewee comes with a special subclass of :py:class:`RestResource` that restricts POST/PUT/DELETE requests to prevent users from modifying another user's content. .. code-block:: python from flask_peewee.rest import RestrictOwnerResource class MessageResource(RestrictOwnerResource): owner_field = 'user' api.register(Message, MessageResource) Now, if we try and modify the message, we get a 403 Forbidden: .. code-block:: python headers, resp = sock.request('http://127.0.0.1:5000/api/message/2/', 'PUT', body=update_json) print headers['status'] # prints 403 It is fine to modify our own message, though (message with id=1): .. code-block:: python headers, resp = sock.request('http://127.0.0.1:5000/api/message/1/', 'PUT', body=update_json) print headers['status'] # prints 200 Under-the-hood, the `implementation `_ of the :py:class:`RestrictOwnerResource` is pretty simple. * PUT / DELETE -- verify the authenticated user is the owner of the object * POST -- assign the authenticated user as the owner of the new object Locking down a resource ----------------------- Suppose we want to restrict normal users from modifying ``User`` resources. For this we can use a special subclass of :py:class:`UserAuthentication` that restricts access to administrators: .. code-block:: python from flask_peewee.rest import AdminAuthentication # instantiate our user-based auth user_auth = UserAuthentication(auth) # instantiate admin-only auth admin_auth = AdminAuthentication(auth) # instantiate our api wrapper, specifying user_auth as the default api = RestAPI(app, default_auth=user_auth) # register the UserResource with admin auth api.register(User, UserResource, auth=admin_auth) Filtering records and querying ------------------------------ A REST Api is not very useful if it cannot be queried in a meaningful fashion. To this end, the flask-peewee :py:class:`RestResource` objects support "django-style" filtering: .. code-block:: console $ curl http://127.0.0.1:5000/api/message/?user=2 This call will return only messages by the ``User`` with id=2: .. code-block:: javascript { "meta": { "model": "message", "next": "", "page": 1, "previous": "" }, "objects": [ { "content": "haxed you, bro", "pub_date": "2011-09-16 18:36:15", "user_id": 2, "id": 2 } ] } Joins can be traversed using the django double-underscore notation: .. code-block:: console $ curl http://127.0.0.1:5000/api/message/?user__username=admin .. code-block:: javascript { "meta": { "model": "message", "next": "", "page": 1, "previous": "" }, "objects": [ { "content": "flask and peewee, together at last!", "pub_date": "2011-09-16 18:36:15", "user_id": 1, "id": 1 }, { "content": "hello api", "pub_date": "2011-09-22 11:25:02", "user_id": 1, "id": 3 } ] } It is also supported to use different comparison operators with the same double-underscore notation: .. code-block:: console $ curl http://127.0.0.1:5000/api/user/?user__lt=2 .. code-block:: javascript { "meta": { "model": "user", "next": "", "page": 1, "previous": "" }, "objects": [{ "username": "admin", "admin": true, "email": "admin@admin", "active": true, "password": "214de$25", "id": 1 }] } Valid Comparison Operators are: 'eq', 'lt', 'lte', 'gt', 'gte', 'ne', 'in', 'is', 'like', 'ilike' Sorting results --------------- Results can be sorted by specifying an ``ordering`` as a GET argument. The ordering must be a column on the model. `/api/message/?ordering=pub_date` If you would like to order objects "descending", place a "-" (hyphen character) before the column name: `/api/message/?ordering=-pub_date` Limiting results and pagination ------------------------------- By default, resources are paginated 20 per-page. If you want to return less, you can specify a ``limit`` in the querystring. `/api/message/?limit=2` In the "meta" section of the response, URIs for the "next" and "previous" sets of results are available: .. code-block:: javascript meta: { model: "message" next: "/api/message/?limit=1&page=3" page: 2 previous: "/api/message/?limit=1&page=1" } flask-peewee-0.6.7/docs/database.rst0000644000175000001440000000344112574421673020137 0ustar charlesusers00000000000000.. _database: Database Wrapper ================ The Peewee database wrapper provides a thin layer of integration between flask apps and the peewee orm. The database wrapper is important because it ensures that a database connection is created for every incoming request, and closed upon request completion. It also provides a subclass of ``Model`` which works with the database specified in your app's configuration. Most features of ``flask-peewee`` require a database wrapper, so you very likely always create one. The database wrapper reads its configuration from the Flask application. The configuration requires only two arguments, but any additional arguments will be passed to the database driver when connecting: `name` The name of the database to connect to (or filename if using sqlite3) `engine` The database driver to use, must be a subclass of ``peewee.Database``. .. code-block:: python from flask import Flask from peewee import * from flask_peewee.db import Database DATABASE = { 'name': 'example.db', 'engine': 'peewee.SqliteDatabase', } app = Flask(__name__) app.config.from_object(__name__) # load database configuration from this module # instantiate the db wrapper db = Database(app) # start creating models class Blog(db.Model): name = CharField() # .. etc Other examples -------------- To connect to MySQL using authentication: .. code-block:: python DATABASE = { 'name': 'my_database', 'engine': 'peewee.MySQLDatabase', 'user': 'db_user', 'passwd': 'secret password', } If using a multi-threaded WSGI server: .. code-block:: python DATABASE = { 'name': 'foo.db', 'engine': 'peewee.SqliteDatabase', 'threadlocals': True, } flask-peewee-0.6.7/docs/fp-admin-modal.png0000644000175000001440000002643112574421673021140 0ustar charlesusers00000000000000PNG  IHDRY}j IDATx^ 0Ȏ,ʘ7M !毞7Y]b+hԣFk"QI䍊Q 0\NM=]5˷3KWݪ;ý***Z@@ EzR  Y4@@ >(F/_n555q{C.EfMl͚5n[3mvVʖ,!$5dl--uևaR1VȈel,l 7r> @,1cXnv9Z[ti#'dR}ˆOرcK.Fl9R gEEE(!+gjȐ!ַoVu4\vڄ0aB(mݺu dРA֯_zK *#@0dhȊ XY?7\aÂցrL@KYҽ{Vm2ZU1LR ^FJJJZU(SA+c!t3f̰S@@ 6l`/7|̙cK-Z Y~a+뮻>l1bDޝ* %h"{gG5jojwRR~~Wʯ3@m@@ oz->}:Txjnn+W2D͐! :2eKfeE Y'@ʺS! @>,R@: YW6|[~{n_Wγ~ur8vNZe>_~^z%dIVd淋S6B@onz{キۻ~r~߽{,+C*^UUUVYYvŋ/m۶-gЕQ#[QǑy`}@RXr]m2b4hC?ݐ!Clذa˺.2?&׿u~2fGlOGG' @HA@9~չX瞮SFKnl}qYY "d|V[[nf;]/_O~~߫W/{ףu]6ol:CK.qwoD#*g͚5~mkhh=.B?-}Ov[ÓZ|Glٲeُ:;̦On={Lfx766ٳ_tҥqgg}믷[nƍgw_{;" غu-Zhǻ\ޥ BQGe6lpV3fpac 6mO2|p^ڮ~gOnީ=-SON;ͭ-֭ym*y^0]BY v1W\j|PTe_ N Yq@@#Y;@@`Ys( t!# !`N5E@ du6B@ d̩  Бf_  P09T@:R B4;{fwv þ@@zbLqq{ZNEԴ X^򞈝nl t@Vd:?@K," @A  Sy@K," @A  Sy@K 'B{V)@E`ҤI[8!r t@N 'zOV޵;* @ SA@ BVgO@{BVޟb* !@ u y/@SL@@3Y>@@ Yy  t!3' !+O1D@ȺdV]]mW  -0tPݻ>(2B+))u.@:Q z]ҢEĖ@@]Yjkk,ڋEj׹ec@DYr\fmݺ5)ЫW/6l+  >dٲel֥K=dX@lذFm]vp@އEgϞnv? dV@۶mk3[8!9,!k6qD׋%9|~9tBЕz"@ W "d~ѫsp䒀krq !+tbv@ SCH][ @!&*@ȢU @Y&C Y܌tŊik;scC 1# Pم{SO=tL d) !+ !+ ! O;F$M RUJ#!+%K؃>h˗/ݻYgev#۲evm駟ڹkwuÅ9!@E@v(螬N;46dOn7x 06l`_~9=YA[!N9F;w $~vaڅ! d @!O>V\\^EEEW:^E-lmt+L 㭬,b;H"]=h]k, ;ԓ!k֭zj=z4AV@TC^zDrS BV]]dtPeͶvZSbA (X)`;S Y4Ccָed@@ G*di»UA  $NztvM|W^^OVUU{~   K#G츺KMcE@Y@@ BV h  @P)@ d@@Y!R$  @Ȣ  !B@H@@E@@B dȢ_,YVtKyGl  d0K &@3Ftv @ |O>!ӦMK4_ͮze~)+>bWΆvӟ;k٭G^X.Tzk^[֝}(ڥ~a'ͽgo__c[[ d\)S-ܒ>~|P;f7ڬW+'2F5ffUȺ|P6~q}mK˶i|fLcK[ҁ2 "@Ȋ릛nF\RRbfͲN:)-+E߷ ]jKm YkgLA=XcdvV7XyՓmLT  "OB;޷7Ϟ`#يwj+,R9  @d]Ȫs=IZ4 *++;DLÆw*=XށvۻlHѐ֧k߃ #ESN@ȸ@V,\5779QWGif_Wf72+uu&ڣͶ d@V,͉RҒk!+O5G )U!0!!#B@L 2-Jy  @DE3@@B dJ  !6  @ "@@Bm@A*E" ,  !+TD@Y@@ BV h  @P)@ d@@Y!R$  @Ȣ  !B@H@@E@@B dJ  !6  @ "@@Bm@A*E" ,  !+TD@Y@@ YzUH@@ <?˭ؽtZTQQђΆڦʬŚݫ*++-@@Nȉ?Sp)  'e;@, Y VRRp!!E@tk/ݻ.47+]s4{d9l )U=Yl @2)@ʤ&e! ;Y4@@ BV h  @P)@ d@@Y!R$  @Ȣ  !B@H@ЍB]JKKk׮11<&ҭgvA*Կ T@aڵ֭[7Ӈoqqqmu=ޅ ZN=sBV5P/@v lٲ^ѣeK555.p'ir/z6V@@]*6&m.J= YI+  Z`ַo_Xb6mdCM~AIJX@BV64|&Xyy K x αUTT9n:?NHC@ m\ iW<Ɇ`L|Z (@Ȋ Y2d555^,}Օ /VB@ ,BVgܸqUCg_v uȐ-( @ %TC7ܪ2k_u=}'ZY3RVՓ}/|աe[n^zT̉+(h7K!kѢE)2 H%dw⦛n믿}~iэ;?!n ڙK𑎟n qg{qi\ ]A뙨G{:}{cccЛNJ=2 @R /ifjy_ھd:#:T!*~{ߋTknP ZϜY*׋EOV͈@2)NH @{/wo:?s9vVYYi#G4 =#iӦnf7o'x."7\}v{lŊma!6K,g}Qߎ8>|x`#ԩS?Px\y|I;lԨQ޳O<љyK*CAI tX@R Xp{׾5Wo<Ӑثj￿ 4}]۰ava믻N4Ʌ} o_vw^o;#o<[`A4d6e-4A\=F z᣽~|]hzymܸўy7:s1nb1}hVF  O!!3ް -[뮪Ӣ!;4s=oinoRTRy SzttZtU&k9ܧl Y_+!coK=&ϟ?M~W92UJ? $JwDa%:'fW~[{jv,H*K7\=E9% >2'4co֓E*'˪2'+ig=@H%$x7ɿ?F^lm.AG~JV?$de=@v r9hu$drk@:E CBXhAG'!+F y+!!4|_zji sx>}dk_SSleTIJx@TWu SL_*$d%k  @[nѢ[ S52:th޽\KB PPM;nj۷ooWYqݭW^6`@˫k[xdr@@ kYY{j80@eBV.=@VC@\ d@@ kYY{j80@eBV.=@VC@\ d@@ k:d.UUUhѢ@@x YJG% MCC;=ZK_>SӳX@@\s.sOZY2mf , A@Ns.8ٳgv,K=Yݚ3gM8ެNi&@RP/:?|z:'tӦMaÆR9ˬ *Pl2{g Yd^x|6n8ݻ7aC ;C@m6o<={bu,,/dņz7EﵵJR\V5lܰȫsdcD[Jܺk%r\ }elMTo%lڴNd߾}vz^v_~?<}Mu"85v-ӿxLZtu떴kڠA@7p@;\zu{5kD^j@֭]{kׯ'S>ZwfjcC@j*w;yлǮVXa#FH}9aT]:E3&߾AB,m{n؀d=Y L]_&uH۶~5E>g}X݊ՔjmV Y=J^Ⱥ[κF2zuk{]G56X#[4dm޼]ɠ0TSSc:SK˖-[\{އ>; nX=*SPc2 EǦ2t|*CuzTzBViii`$k :ի\J9rG;T/dڔڎΫڏλ,ŠK%|P4"ÀA+XYT+Ȋ{,_} VRUY$P {%Ho\C佖CFH#c=FjzА"}CZR!BHww==i]pV\]/~:}z]:6u*y,MBtVWOοڋ´G~Flm{*[m k2u.|()/dÕ?Xuj*h׫U37kKS$GîK:Ĕj==n ((߅{Q:.q8JM pFrwV Z*<0aam}Ҝlis=CYRcGbXb^NJwZ/{9aW>ҥ\hK ث3ՃCB?Ty~8$%nz-k,cѹSǛ(d2' "p!!P6D ;h8PhȊ& [KYiQ 6D>zΦQI[&dV =,\ElOVZUG{D&&޲#dhA/ (L+1Rũdq䆡m߰42;bU^=c&:B>{/di 7{jH/f+U!nkn+"aݬ0.B;NI ޭ $Q}u[NN@BȪx˧Xqk $N&ݧ*2(0}KOFw/yWzwzہ׃% bE荒 @dUȒV} ;7nҽ[N=,؀v`Vkna^DwH^(d: Po S B ZI$Mgcɥ /a S>d@VlX@@tY騱   DEA@B dJ  !6  @ "@@h% IENDB`flask-peewee-0.6.7/docs/api.rst0000644000175000001440000011651512574421673017153 0ustar charlesusers00000000000000.. _api: API === Admin ----- .. py:class:: Admin(app, auth[, blueprint_factory[, template_helper[, prefix]]]) Class used to expose an admin area at a certain url in your application. The Admin object implements a flask blueprint and acts as the central registry for models and panels you wish to expose in the admin. The Admin object coordinates the registration of models and panels and provides a method for ensuring a user has permission to access the admin area. The Admin object requires an :py:class:`Auth` instance when being instantiated, which in turn requires a Flask app and a py:class:`Database` wrapper. Here is an example of how you might instantiate an Admin object: .. code-block:: python from flask import Flask from flask_peewee.admin import Admin from flask_peewee.auth import Auth from flask_peewee.db import Database app = Flask(__name__) db = Database(app) # needed for authentication auth = Auth(app, db) # instantiate the Admin object for our project admin = Admin(app, auth) :param app: flask application to bind admin to :param auth: :py:class:`Auth` instance which will provide authentication :param blueprint_factory: an object that will create the ``BluePrint`` used by the admin :param template_helper: a subclass of :py:class:`AdminTemplateHelper` that provides helpers and context to used by the admin templates :param prefix: url to bind admin to, defaults to ``/admin`` .. py:method:: register(model[, admin_class=ModelAdmin]) Register a model to expose in the admin area. A :py:class:`ModelAdmin` subclass can be provided along with the model, allowing for customization of the model's display and behavior. Example usage: .. code-block:: python # will use the default ModelAdmin subclass to display model admin.register(BlogModel) class EntryAdmin(ModelAdmin): columns = ('title', 'blog', 'pub_date',) admin.register(EntryModel, EntryAdmin) .. warning:: All models must be registered before calling :py:meth:`~Admin.setup` :param model: peewee model to expose via the admin :param admin_class: :py:class:`ModelAdmin` or subclass to use with given model .. py:method:: register_panel(title, panel) Register a :py:class:`AdminPanel` subclass for display in the admin dashboard. Example usage: .. code-block:: python class HelloWorldPanel(AdminPanel): template_name = 'admin/panels/hello.html' def get_context(self): return { 'message': 'Hello world', } admin.register_panel('Hello world', HelloWorldPanel) .. warning:: All panels must be registered before calling :py:meth:`~Admin.setup` :param title: identifier for panel, example might be "Site Stats" :param panel: subclass of :py:class:`AdminPanel` to display .. py:method:: setup() Configures urls for models and panels, then registers blueprint with the Flask application. Use this method when you have finished registering all the models and panels with the admin object, but before starting the WSGI application. For a sample implementation, check out ``example/main.py`` in the example application supplied with flask-peewee. .. code-block:: python # register all models, etc admin.register(...) # finish up initialization of the admin object admin.setup() if __name__ == '__main__': # run the WSGI application app.run() .. note:: call ``setup()`` **after** registering your models and panels .. py:method:: check_user_permission(user) Check whether the given user has permission to access to the admin area. The default implementation simply checks whether the ``admin`` field is checked, but you can provide your own logic. This method simply controls access to the admin area as a whole. In the event the user is **not** permitted to access the admin (this function returns ``False``), they will receive a HTTP Response Forbidden (403). Default implementation: .. code-block:: python def check_user_permission(self, user): return user.admin :param user: the currently logged-in user, exposed by the :py:class:`Auth` instance :rtype: Boolean .. py:method:: auth_required(func) Decorator that ensures the requesting user has permission. The implementation first checks whether the requesting user is logged in, and if not redirects to the login view. If the user *is* logged in, it calls :py:meth:`~Admin.check_user_permission`. Only if this call returns ``True`` is the actual view function called. .. py:method:: get_urls() Get a tuple of 2-tuples mapping urls to view functions that will be exposed by the admin. The default implementation looks like this: .. code-block:: python def get_urls(self): return ( ('/', self.auth_required(self.index)), ) This method provides an extension point for providing any additional "global" urls you would like to expose. .. note:: Remember to decorate any additional urls you might add with :py:meth:`~Admin.auth_required` to ensure they are not accessible by unauthenticated users. Exposing Models with the ModelAdmin ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. py:class:: ModelAdmin Class that determines how a peewee ``Model`` is exposed in the admin area. Provides a way of encapsulating model-specific configuration and behaviors. Provided when registering a model with the :py:class:`Admin` instance (see :py:meth:`Admin.register`). .. py:attribute:: columns List or tuple of columns should be displayed in the list index. By default if no columns are specified the ``Model``'s ``__unicode__()`` will be used. .. note:: Valid values for columns are the following: * field on a model * attribute on a model instance * callable on a model instance (called with no parameters) If a column is a model field, it will be sortable. .. code-block:: python class EntryAdmin(ModelAdmin): columns = ['title', 'pub_date', 'blog'] .. py:attribute:: filter_exclude Exclude certain fields from being exposed as filters. Related fields can be excluded using "__" notation, e.g. ``user__password`` .. py:attribute:: filter_fields Only allow filtering on the given fields .. py:attribute:: exclude A list of field names to exclude from the "add" and "edit" forms .. py:attribute:: fields Only display the given fields on the "add" and "edit" form .. py:attribute:: paginate_by = 20 Number of records to display on index pages .. py:attribute:: filter_paginate_by = 15 Default pagination when filtering in a modal dialog .. py:attribute:: delete_collect_objects = True Collect and display a list of "dependencies" when deleting .. py:attribute:: delete_recursive = True Delete "dependencies" recursively .. py:method:: get_query() Determines the list of objects that will be exposed in the admin. By default this will be all objects, but you can use this method to further restrict the query. This method is called within the context of a request, so you can access the ``Flask.request`` object or use the :py:class:`Auth` instance to determine the currently-logged-in user. Here's an example showing how the query is restricted based on whether the given user is a "super user" or not: .. code-block:: python class UserAdmin(ModelAdmin): def get_query(): # ask the auth system for the currently logged-in user current_user = self.auth.get_logged_in_user() # if they are not a superuser, only show them their own # account in the admin if not current_user.is_superuser: return User.select().where(User.id==current_user.id) # otherwise, show them all users return User.select() :rtype: A ``SelectQuery`` that represents the list of objects to expose .. py:method:: get_object(pk) This method retrieves the object matching the given primary key. The implementation uses :py:meth:`~ModelAdmin.get_query` to retrieve the base list of objects, then queries within that for the given primary key. :rtype: The model instance with the given pk, raising a ``DoesNotExist`` in the event the model instance does not exist. .. py:method:: get_form([adding=False]) Provides a useful extension point in the event you want to define custom fields or custom validation behavior. :param boolean adding: indicates whether adding a new instance or editing existing :rtype: A `wtf-peewee `_ Form subclass that will be used when adding or editing model instances in the admin. .. py:method:: get_add_form() Allows you to specify a different form when adding new instances versus editing existing instances. The default implementation simply calls :py:meth:`~ModelAdmin.get_form`. .. py:method:: get_edit_form() Allows you to specify a different form when editing existing instances versus adding new instances. The default implementation simply calls :py:meth:`~ModelAdmin.get_form`. .. py:method:: get_filter_form() Provide a special form for use when filtering the list of objects in the model admin's index/export views. This form is slightly different in that it is tailored for use when filtering the list of models. :rtype: A special Form instance (:py:class:`FilterForm`) that will be used when filtering the list of objects in the index view. .. py:method:: save_model(instance, form, adding=False) Method responsible for persisting changes to the database. Called by both the add and the edit views. Here is an example from the default ``auth.User`` :py:class:`ModelAdmin`, in which the password is displayed as a sha1, but if the user is adding or edits the existing password, it re-hashes: .. code-block:: python def save_model(self, instance, form, adding=False): orig_password = instance.password user = super(UserAdmin, self).save_model(instance, form, adding) if orig_password != form.password.data: user.set_password(form.password.data) user.save() return user :param instance: an unsaved model instance :param form: a validated form instance :param adding: boolean to indicate whether we are adding a new instance or saving an existing .. py:method:: get_template_overrides() Hook for specifying template overrides. Should return a dictionary containing view names as keys and template names as values. Possible choices for keys are: * index * add * edit * delete * export .. code-block:: python class UserModelAdmin(ModelAdmin): def get_template_overrides(self): return {'index': 'users/admin/index_override.html'} .. py:method:: get_urls() Useful as a hook for extending :py:class:`ModelAdmin` functionality with additional urls. .. note:: It is not necessary to decorate the views specified by this method since the :py:class:`Admin` instance will handle this during registration and setup. :rtype: tuple of 2-tuples consisting of a mapping between url and view .. py:method:: get_url_name(name) Since urls are namespaced, this function provides an easy way to get full urls to views provided by this ModelAdmin .. py:method:: process_filters(query) Applies any filters specified by the user to the given query, returning metadata about the filters. Returns a 4-tuple containing: * special ``Form`` instance containing fields for filtering * filtered query * a list containing the currently selected filters * a tree-structure containing the fields available for filtering (:py:class:`FieldTreeNode`) :rtype: A tuple as described above Extending admin functionality using AdminPanel ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. py:class:: AdminPanel Class that provides a simple interface for providing arbitrary extensions to the admin. These are displayed as "panels" on the admin dashboard with a customizable template. They may additionally, however, define any views and urls. These views will automatically be protected by the same authentication used throughout the admin area. Some example use-cases for AdminPanels might be: * Display some at-a-glance functionality in the dashboard, like stats on new user signups. * Provide a set of views that should only be visible to site administrators, for example a mailing-list app. * Control global site settings, turn on and off features, etc. .. py:attribute:: template_name What template to use to render the panel in the admin dashboard, defaults to ``'admin/panels/default.html'``. .. py:method:: get_urls() Useful as a hook for extending :py:class:`AdminPanel` functionality with custom urls and views. .. note:: It is not necessary to decorate the views specified by this method since the :py:class:`Admin` instance will handle this during registration and setup. :rtype: Returns a tuple of 2-tuples mapping url to view .. py:method:: get_url_name(name) Since urls are namespaced, this function provides an easy way to get full urls to views provided by this panel :param name: string representation of the view function whose url you want :rtype: String representing url .. code-block:: html {{ url_for(panel.get_url_name('create')) }} .. py:method:: get_template_name() Return the template used to render this panel in the dashboard. By default simply returns the template stored under :py:attr:`AdminPanel.template_name`. .. py:method:: get_context() Return the context to be used when rendering the dashboard template. :rtype: Dictionary .. py:method:: render() Render the panel template with the context -- this is what gets displayed in the admin dashboard. Auth ---- .. py:class:: Auth(app, db[, user_model=None[, prefix='/accounts']], db_table='user') The class that provides methods for authenticating users and tracking users across requests. It also provides a model for persisting users to the database, though this can be customized. The auth framework is used by the :py:class:`Admin` and can also be integrated with the :py:class:`RestAPI`. Here is an example of how to use the Auth framework: .. code-block:: python from flask import Flask from flask_peewee.auth import Auth from flask_peewee.db import Database app = Flask(__name__) db = Database(app) # needed for authentication auth = Auth(app, db) # mark a view as requiring login @app.route('/private/') @auth.login_required def private_timeline(): # get the currently-logged-in user user = auth.get_logged_in_user() Unlike the :py:class:`Admin` or the :py:class:`RestAPI`, there is no explicit ``setup()`` method call when using the Auth system. Creation of the auth blueprint and registration with the Flask app happen automatically during instantiation. .. note:: A context processor is automatically registered that provides the currently logged-in user across all templates, available as "user". If no user is logged in, the value of this will be ``None``. .. note:: A pre-request handler is automatically registered which attempts to retrieve the current logged-in user and store it on the global flask variable ``g``. :param app: flask application to bind admin to :param db: :py:class:`Database` database wrapper for flask app :param user_model: ``User`` model to use :param prefix: url to bind authentication views to, defaults to /accounts/ :param db_table: Create db table using db_table name. ``user`` is reserved keyword in postgres. .. py:attribute:: default_next_url = 'homepage' The url to redirect to upon successful login in the event a ``?next=`` is not provided. .. py:method:: get_logged_in_user() .. note:: Since this method relies on the session storage to track users across requests, this method must be called while within a ``RequestContext``. :rtype: returns the currently logged-in ``User``, or ``None`` if session is anonymous .. py:method:: login_required(func) Function decorator that ensures a view is only accessible by authenticated users. If the user is not authed they are redirected to the login view. .. note:: this decorator should be applied closest to the original view function .. code-block:: python @app.route('/private/') @auth.login_required def private(): # this view is only accessible by logged-in users return render_template('private.html') :param func: a view function to be marked as login-required :rtype: if the user is logged in, return the view as normal, otherwise returns a redirect to the login page .. py:method:: get_user_model() :rtype: Peewee model to use for persisting user data and authentication .. py:method:: get_model_admin([model_admin=None]) Provide a :py:class:`ModelAdmin` class suitable for use with the User model. Specifically addresses the need to re-hash passwords when changing them via the admin. The default implementation includes an override of the :py:meth:`ModelAdmin.save_model` method to intelligently hash passwords: .. code-block:: python class UserAdmin(model_admin): columns = ['username', 'email', 'active', 'admin'] def save_model(self, instance, form, adding=False): orig_password = instance.password user = super(UserAdmin, self).save_model(instance, form, adding) if orig_password != form.password.data: user.set_password(form.password.data) user.save() return user :param model_admin: subclass of :py:class:`ModelAdmin` to use as the base class :rtype: a subclass of :py:class:`ModelAdmin` suitable for use with the ``User`` model .. py:method:: get_urls() A mapping of url to view. The default implementation provides views for login and logout only, but you might extend this to add registration and password change views. Default implementation: .. code-block:: python def get_urls(self): return ( ('/logout/', self.logout), ('/login/', self.login), ) :rtype: a tuple of 2-tuples mapping url to view function. .. py:method:: get_login_form() :rtype: a ``wtforms.Form`` subclass to use for retrieving any user info required for login .. py:method:: authenticate(username, password) Given the ``username`` and ``password``, retrieve the user with the matching credentials if they exist. No exceptions should be raised by this method. :rtype: ``User`` model if successful, otherwise ``False`` .. py:method:: login_user(user) Mark the given user as "logged-in". In the default implementation, this entails storing data in the ``Session`` to indicate the successful login. :param user: ``User`` instance .. py:method:: logout_user(user) Mark the requesting user as logged-out :param user: ``User`` instance The BaseUser mixin ^^^^^^^^^^^^^^^^^^ .. py:class:: BaseUser() Provides default implementations for password hashing and validation. The auth framework requires two methods be implemented by the ``User`` model. A default implementation of these methods is provided by the ``BaseUser`` mixin. .. py:method:: set_password(password) Encrypts the given password and stores the encrypted version on the model. This method is useful when registering a new user and storing the password, or modifying the password when a user elects to change. .. py:method:: check_password(password) Verifies if the given plaintext password matches the encrypted version stored on the model. This method on the User model is called specifically by the :py:meth:`Auth.authenticate` method. :rtype: Boolean Database -------- .. py:class:: Database(app) The database wrapper provides integration between the peewee ORM and flask. It reads database configuration information from the flask app configuration and manages connections across requests. The db wrapper also provides a ``Model`` subclass which is configured to work with the database specified by the application's config. To configure the database specify a database engine and name: .. code-block:: python DATABASE = { 'name': 'example.db', 'engine': 'peewee.SqliteDatabase', } Here is an example of how you might use the database wrapper: .. code-block:: python # instantiate the db wrapper db = Database(app) # start creating models class Blog(db.Model): # this model will automatically work with the database specified # in the application's config. :param app: flask application to bind admin to .. py:attribute:: Model Model subclass that works with the database specified by the app's config REST API -------- .. py:class:: RestAPI(app[, prefix='/api'[, default_auth=None[, name='api']]]) The :py:class:`RestAPI` acts as a container for the various :py:class:`RestResource` objects. By default it binds all resources to ``/api//``. Much like the :py:class:`Admin`, it is a centralized registry of resources. Example of creating a ``RestAPI`` instance for a flask app: .. code-block:: python from flask_peewee.rest import RestAPI from app import app # our project's Flask app # instantiate our api wrapper api = RestAPI(app) # register a model with the API api.register(SomeModel) # configure URLs api.setup() .. note:: Like the flask admin, the ``RestAPI`` has a ``setup()`` method which must be called after all resources have been registered. :param app: flask application to bind API to :param prefix: url to serve REST API from :param default_auth: default :py:class:`Authentication` type to use with registered resources :param name: the name for the API blueprint .. py:method:: register(model[, provider=RestResource[, auth=None[, allowed_methods=None]]]) Register a model to expose via the API. :param model: ``Model`` to expose via API :param provider: subclass of :py:class:`RestResource` to use for this model :param auth: authentication type to use for this resource, falling back to :py:attr:`RestAPI.default_auth` :param allowed_methods: ``list`` of HTTP verbs to allow, defaults to ``['GET', 'POST', 'PUT', 'DELETE']`` .. py:method:: setup() Register the API ``BluePrint`` and configure urls. .. warning:: This must be called **after** registering your resources. RESTful Resources and their subclasses ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. py:class:: RestResource(rest_api, model, authentication[, allowed_methods=None]) Class that determines how a peewee ``Model`` is exposed by the Rest API. Provides a way of encapsulating model-specific configuration and behaviors. Provided when registering a model with the :py:class:`RestAPI` instance (see :py:meth:`RestAPI.register`). Should not be instantiated directly in most cases. Instead should be "registered" with a ``RestAPI`` instance. Example usage: .. code-block:: python # instantiate our api wrapper, passing in a reference to the Flask app api = RestAPI(app) # create a RestResource subclass class UserResource(RestResource): exclude = ('password', 'email',) # assume we have a "User" model, register it with the custom resource api.register(User, UserResource) .. py:attribute:: paginate_by = 20 Determines how many results to return for a given API query. .. note:: *Fewer* results can be requested by specifying a ``limit``, but ``paginate_by`` is the upper bound. .. py:attribute:: fields = None A list or tuple of fields to expose when serializing .. py:attribute:: exclude = None A list or tuple of fields to **not** expose when serializing .. py:attribute:: filter_exclude A list of fields that **cannot** be used to filter API results .. py:attribute:: filter_fields A list of fields that can be used to filter the API results .. py:attribute:: filter_recursive = True Allow filtering on related resources .. py:attribute:: include_resources A mapping of field name to resource class for handling of foreign-keys. When provided, foreign keys will be "nested". .. code-block:: python class UserResource(RestResource): exclude = ('password', 'email') class MessageResource(RestResource): include_resources = {'user': UserResource} # 'user' is a foreign key field .. code-block:: javascript /* messages without "include_resources" */ { "content": "flask and peewee, together at last!", "pub_date": "2011-09-16 18:36:15", "id": 1, "user": 2 }, /* messages with "include_resources = {'user': UserResource} */ { "content": "flask and peewee, together at last!", "pub_date": "2011-09-16 18:36:15", "id": 1, "user": { "username": "coleifer", "active": true, "join_date": "2011-09-16 18:35:56", "admin": false, "id": 2 } } .. py:attribute:: delete_recursive = True Recursively delete dependencies .. py:method:: get_query() Returns the list of objects to be exposed by the API. Provides an easy hook for restricting objects: .. code-block:: python class UserResource(RestResource): def get_query(self): # only return "active" users return self.model.select().where(active=True) :rtype: a ``SelectQuery`` containing the model instances to expose .. py:method:: prepare_data(obj, data) This method provides a hook for modifying outgoing data. The default implementation no-ops, but you could do any kind of munging here. The data returned by this method is passed to the serializer before being returned as a json response. :param obj: the object being serialized :param data: the dictionary representation of a model returned by the ``Serializer`` :rtype: a dictionary of data to hand off .. py:method:: save_object(instance, raw_data) Persist the instance to the database. The raw data supplied by the request is also available, but at the time this method is called the instance has already been updated and populated with the incoming data. :param instance: ``Model`` instance that has already been updated with the incoming ``raw_data`` :param raw_data: data provided in the request :rtype: a saved instance .. py:method:: api_list() A view that dispatches based on the HTTP verb to either: * GET: :py:meth:`~RestResource.object_list` * POST: :py:meth:`~RestResource.create` :rtype: ``Response`` .. py:method:: api_detail(pk) A view that dispatches based on the HTTP verb to either: * GET: :py:meth:`~RestResource.object_detail` * PUT: :py:meth:`~RestResource.edit` * DELETE: :py:meth:`~RestResource.delete` :rtype: ``Response`` .. py:method:: object_list() Returns a serialized list of ``Model`` instances. These objects may be filtered, ordered, and/or paginated. :rtype: ``Response`` .. py:method:: object_detail() Returns a serialized ``Model`` instance. :rtype: ``Response`` .. py:method:: create() Creates a new ``Model`` instance based on the deserialized POST body. :rtype: ``Response`` containing serialized new object .. py:method:: edit() Edits an existing ``Model`` instance, updating it with the deserialized PUT body. :rtype: ``Response`` containing serialized edited object .. py:method:: delete() Deletes an existing ``Model`` instance from the database. :rtype: ``Response`` indicating number of objects deleted, i.e. ``{'deleted': 1}`` .. py:method:: get_api_name() :rtype: URL-friendly name to expose this resource as, defaults to the model's name .. py:method:: check_get([obj=None]) A hook for pre-authorizing a GET request. By default returns ``True``. :rtype: Boolean indicating whether to allow the request to continue .. py:method:: check_post() A hook for pre-authorizing a POST request. By default returns ``True``. :rtype: Boolean indicating whether to allow the request to continue .. py:method:: check_put(obj) A hook for pre-authorizing a PUT request. By default returns ``True``. :rtype: Boolean indicating whether to allow the request to continue .. py:method:: check_delete(obj) A hook for pre-authorizing a DELETE request. By default returns ``True``. :rtype: Boolean indicating whether to allow the request to continue .. py:class:: RestrictOwnerResource(RestResource) This subclass of :py:class:`RestResource` allows only the "owner" of an object to make changes via the API. It works by verifying that the authenticated user matches the "owner" of the model instance, which is specified by setting :py:attr:`~RestrictOwnerResource.owner_field`. Additionally, it sets the "owner" to the authenticated user whenever saving or creating new instances. .. py:attribute:: owner_field = 'user' Field on the model to use to verify ownership of the given instance. .. py:method:: validate_owner(user, obj) :param user: an authenticated ``User`` instance :param obj: the ``Model`` instance being accessed via the API :rtype: Boolean indicating whether the user can modify the object .. py:method:: set_owner(obj, user) Mark the object as being owned by the provided user. The default implementation simply calls ``setattr``. :param obj: the ``Model`` instance being accessed via the API :param user: an authenticated ``User`` instance Authenticating requests to the API ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. py:class:: Authentication([protected_methods=None]) Not to be confused with the ``auth.Authentication`` class, this class provides a single method, ``authorize``, which is used to determine whether to allow a given request to the API. :param protected_methods: A list or tuple of HTTP verbs to require auth for .. py:method:: authorize() This single method is called per-API-request. :rtype: Boolean indicating whether to allow the given request through or not .. py:class:: UserAuthentication(auth[, protected_methods=None]) Authenticates API requests by requiring the requesting user be a registered ``auth.User``. Credentials are supplied using HTTP basic auth. Example usage: .. code-block:: python from auth import auth # import the Auth object used by our project from flask_peewee.rest import RestAPI, RestResource, UserAuthentication # create an instance of UserAuthentication user_auth = UserAuthentication(auth) # instantiate our api wrapper, specifying user_auth as the default api = RestAPI(app, default_auth=user_auth) # create a special resource for users that excludes email and password class UserResource(RestResource): exclude = ('password', 'email',) # register our models so they are exposed via /api// api.register(User, UserResource) # specify the UserResource # configure the urls api.setup() :param auth: an :ref:`authentication` instance :param protected_methods: A list or tuple of HTTP verbs to require auth for .. py:method:: authorize() Verifies, using HTTP Basic auth, that the username and password match a valid ``auth.User`` model before allowing the request to continue. :rtype: Boolean indicating whether to allow the given request through or not .. py:class:: AdminAuthentication(auth[, protected_methods=None]) Subclass of the :py:class:`UserAuthentication` that further restricts which users are allowed through. The default implementation checks whether the requesting user is an "admin" by checking whether the admin attribute is set to ``True``. Example usage: .. code-block:: python Authenticates API requests by requiring the requesting user be a registered ``auth.User``. Credentials are supplied using HTTP basic auth. Example usage: .. code-block:: python from auth import auth # import the Auth object used by our project from flask_peewee.rest import RestAPI, RestResource, UserAuthentication, AdminAuthentication # create an instance of UserAuthentication and AdminAuthentication user_auth = UserAuthentication(auth) admin_auth = AdminAuthentication(auth) # instantiate our api wrapper, specifying user_auth as the default api = RestAPI(app, default_auth=user_auth) # create a special resource for users that excludes email and password class UserResource(RestResource): exclude = ('password', 'email',) # register our models so they are exposed via /api// api.register(SomeModel) # specify the UserResource and require the requesting user be an admin api.register(User, UserResource, auth=admin_auth) # configure the urls api.setup() .. py:method:: verify_user(user) Verifies whether the requesting user is an administrator :param user: the ``auth.User`` instance of the requesting user :rtype: Boolean indicating whether the user is an administrator .. py:class:: APIKeyAuthentication(model, protected_methods=None) Subclass that allows you to provide an API Key model to authenticate requests with. .. note:: Must provide an API key model with at least the following two fields: * key * secret .. code-block:: python # example API key model class APIKey(db.Model): key = CharField() secret = CharField() user = ForeignKeyField(User) # instantiating the auth api_key_auth = APIKeyAuthentication(model=APIKey) :param model: a :py:class:`Database.Model` subclass to persist API keys. :param protected_methods: A list or tuple of HTTP verbs to require auth for Utilities --------- .. py:function:: get_object_or_404(query_or_model, *query) Provides a handy way of getting an object or 404ing if not found, useful for urls that match based on ID. :param query_or_model: a query or model to filter using the given expressions :param query: a list of query expressions .. code-block:: python @app.route('/blog//') def blog_detail(title): blog = get_object_or_404(Blog.select().where(Blog.active==True), Blog.title==title) return render_template('blog/detail.html', blog=blog) .. py:function:: object_list(template_name, qr[, var_name='object_list'[, **kwargs]]) Wraps the given query and handles pagination automatically. Pagination defaults to ``20`` but can be changed by passing in ``paginate_by=XX``. :param template_name: template to render :param qr: a select query :param var_name: the template variable name to use for the paginated query :param kwargs: arbitrary context to pass in to the template .. code-block:: python @app.route('/blog/') def blog_list(): active = Blog.select().where(Blog.active==True) return object_list('blog/index.html', active) .. code-block:: html <!-- template --> {% for blog in object_list %} {# render the blog here #} {% endfor %} {% if page > 1 %} <a href="./?page={{ page - 1 }}">Prev</a> {% endif %} {% if page < pagination.get_pages() %} <a href="./?page={{ page + 1 }}">Next</a> {% endif %} .. py:function:: get_next() :rtype: a URL suitable for redirecting to .. py:function:: slugify(s) Use a regular expression to make arbitrary string ``s`` URL-friendly :param s: any string to be slugified :rtype: url-friendly version of string ``s`` .. py:class:: PaginatedQuery(query_or_model, paginate_by) A wrapper around a query (or model class) that handles pagination. .. py:attribute:: page_var = 'page' The URL variable used to store the current page Example: .. code-block:: python query = Blog.select().where(Blog.active==True) pq = PaginatedQuery(query) # assume url was /?page=3 obj_list = pq.get_list() # returns 3rd page of results pq.get_page() # returns "3" pq.get_pages() # returns total objects / objects-per-page .. py:method:: get_list() :rtype: a list of objects for the request page .. py:method:: get_page() :rtype: an integer representing the currently requested page .. py:method:: get_pages() :rtype: the number of pages in the entire result set �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/example.rst�����������������������������������������������������������������0000644�0001750�0000144�00000000046�12574421673�020024� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.. _example: Example App =========== ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/fp-model-admin.jpg����������������������������������������������������������0000644�0001750�0000144�00000053162�12574421673�021141� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000�������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���Created with GIMP�C�  !"$"$�C�d"�������������� �[� ��!1QST"2ARUaq34rs#B$%V5Cb&7DEeu�������������8� ������!1AQRaqсBS"#$23C� ��?�rʏ&p\-y,82609&�6NFarRG)JʖS),Ƶp]."00z6 E؃ìݭy�EqC趒h|i!�͡ Culhsbds\&qtM5]3"}E,fB#-�ZN�\xah~%޸}.?==LT9M0jjbܚQw|rf᧨?tu9#7�e s\"qYp)ذpL%ldiw$(4UӺ 8<\1{ kF0l ຣH$3Ϧ)*s8V雷j..4.'2\p8*_A(%.RMg:$<qHmk1&Jh>{wkoCܚC> E1A.N a5r? _+)?#H#ˀ췹6^hԚQ;Ѽ,69=5ml]Lle`@F]mi:\SAp q>վ6He3Ѱ3\.3:,��/2يI�B4m^a[1O4}[7c#cyBsv1-fNoһw q#ƢuK Į}$eľ"։Mi!4Ni%h*裢iȉ`d^$6ܹ93uMKSVï-f6`iF)$w]�9Z5<.'[Itl}M- DlÕg86c!v]f%#..}9~5O9p=t1-hT )嬧앦hKu|ۃqqbFLbp9L}/A%DxlWPjbdfeN/y6 I M]5$XD&q9o"v(Kd$7f_Y!yf+pLšǧu{$:�<JCmնٮtWM<M'\LvS!q#ٯ$ |Nr<V Q3>6JEHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9QHS9Q΃cEŰ[Q> !d!FIpVZ<T�o]qE��+t~|Z N::i[$1}tmqۓ޹#ʽhGE۔F?]wQjDLn�h<St�yާ3z 85v#k O{1� 20llVeHPft`Hyp7-DNV5nc=o]�L޺YRK$X{\�lؘ3F5Tx|&]c\ە$DZGjoI6~<'CvUQG,[W(3:g B9$g(()ҽÂ{OQ~e1h'!QA "lFwDj$t$q,mؽOj}QN> |S  eFX3eaM`XS-Di|;qs%^c̵>s>eG]TTf!'5Y³Tbe HۂG<]|tc̵>*5D=kwkBWյmT<`e Oj}QN> |S cV s[`&69+]|tc̵>z?k6\й?y{*�{! Gjz?=` ܯj=SN~|Qs`NְW5r>aO]p_^WU>|t = ql^c̵>s>eG]K ^c̵>s>eG]sS?{˹2£|t L.> |S w1SZxTux7?3W)-O*:Oj}QA^c̵>s>eG]sS?{˹2£|t L.> |S w1SZxTux7?3W)-O*:Oj}QA^c̵>s>eG]sS?{˹2£|t L.> |S w1SZxTux7?3W)-O*:Oj}QA^c̵>s>eG]sS?{˹2£|t L.> |S w1SZxTux7?3W)-O*:Oj}QA^c̵>s>eG]sS?{˹2£|t L.> |S w1SZxTux7?3W)-O*:Oj}QA^c̵>s>eG]sS?{˹2£|t L.> |S w1SZxTux7?3W)-O*:Oj}QA^c̵>s>eG]sS?{˹2£|t<|b Y\8یZw 'mt�2ws'>eG];8)5O*:i}(M'yGV/ު?vAtU-h-Es\ \$AV5MGYU%UN#Js=o zSOj}QNN |S eޗK.^Y:=:t�ûP+bq, �%>N |S w2pSZxTuUe꩘GzjgJs>eG]F? !5@.uQ)E7_|tA2xԮi>sMxlEKxN 83F#54uELBFF E� ֝E%e<tqcFFqFJԋJO\f 2T ܗE|BtDjSiF.#̫al-OOr3Riގ>&cQxSP9ÔnB9ρnVL006vCG{X[FRECcAT\HFv7;c66VcN;ĝS4MVƽ'gR>n-8N<S{"iZIC´Fqj( kj*!3 {$� P_"Ӧ"1ѝ';ev/eYkWn;"+\o@p7FZTB5pk�Wf^=h#d|7 Q;NH B1 ǰS6 p56$m]6Ѽ>(ƴ 8z<W6RvZn*(+es"2-`6/ &%FkcW2\[ݎyg _7龉atQ9d,k.h 2 +l>,G @:zR7 """ """ """ """ """ """ """ """ """ """ """ """ """ """ (XEST,_ؠ1>sMx4+oG8[�K?�Av( ЬH4[œ8/�Xo{3p.u%dx-p vu\V ` }CNyQ~{�'wp<2EtMpͯlaӘ)Y^ڮ <<L)c5DXָf\ )3FK"1u5&WY2.61C*ol?Hh++.leZeSю~{gz9b|(4KIt*fk֗:0cpA%yU& &iGšn4vES}E1"3ދ`nA]\h>]xuUl``7 KHoe* tF`iggq7\Nl{ `a9,nFKt/pWGfs~mf_3< Gi0*+Q3h9Ilm @4G삹i%1a˝mmMW\+L ]9\nv;Eԝi84 6WZ)$ikZ}kQ'3A#xbCAdUb'X5<_{΅Ţ&օaCs6&p&26rx,[p)# Bi4z(pQRIR٧%<OŔ d*Q>ѭı\8;$s;q.�M� -VGYR(!TFJ[s< kWoΫ2L0f-oBY[f͉3 nF {/anHHչm %mHؿ:ј⪧pVM<h-;Ah?~薏hv.pc<־Bqs<M5BfH="˜K]!d9v:21s^a+?pI䐴;Moz6l_t ǿ|.Hl5wnjq_v+R]qTx@M{gy=\[薏S<zMQ2]!K�[_ҧφC8_|>zûsuwlm<[uI/| :GZ >!Q`=@�?]h7AMj׽5{qupOehc v ?daLȓ6k=m #o ;.4I6:}Lu1sz6J_x5Z+s0㲶6pё p#ĴU⁂}kݭ,aD4KGJ  *DI&y�q6$mD\E),_ة/Q}PADDRd~O�7#AcZr8~jSý=U ywyw ywywA=O3S=O3VdiSý=TSý=UdiSý=TSý=U#NzfzfȤiSý=TSý=Uo"lA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3S=O3VA=O3W!7 6[�(XEST,_ؠ1>sMx4+oG F;k\%T85$Fj(!84#$ )r</lM& uK /sLwxٱrVZ0r7Z[Fեhs d<,v:Fh#g]}6=L⮲,sZvs.cle(ͫmhd=SN۸k gXqXEs5졣s\.V}5,%xlx[Qv4XGt;r!`9F"Kݹ sOH"}{c,J:h2W5�6^ݠGH<bm mFs9\K\x jtgh?"g\.M;{4ƂH2Ď1{zBj*?+ !%va"('|@# nfN}"DL#'sb`{CWz݈Z&UEOK+LJ=.!6�\. +AJ1Z׌&8\E[0t b M#%cZHg;8@ZYA􎕁4 5ĖgfoF?Z-MﺀD?Gg TCz+Js�p=2XHs =a;6jtM>E}WU xWx`_66ܹO|>)EL:?W5mpsh曋@A^¦z:4Qq.v<kAֱ}3idA ɜܒ3:m#Ľpa?|I�Oj3=tMZ+^-DD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DD�$*>%�gTӿBygH.c8i=VnLVmp-X.^s<1ƆJsKi~Mg}oB,oI3CARqޚ<9NpA rvSLaUu50gE@c[~2lvUU=-4USG3`$y=OQi.0MM ve;rCH4&9%[1zWRl; /kn=I684x+5t# faS)fr`|EI25xnC$DH,_ة/Q}PADDRd~O�7#A8  H�z_+ M_tbv>W4܆I +A5L[K1L[#W<NH6a&fOߤ_zBb6 ۢ(ȹU5UN{boN"�ק9R_>#GOg>猼ߤ_zw7Ņ޽=qʗ#{?<e"�ӹH�,/vTOh/07 �mк7Gt[ A*fBe-˜bm*gqбk8[LSz|"7O8r.9R`o.9R.9P.9R.9P.9R.9P.9R.9P.9R.9P.9R.9P.9R.9P.9R.9P.9R.9P.9R.9P" )cʣcNY!]rI=ş6*9;I06#pmpyP-mȖ8gffKkCj%5<GT 5ki_JѼB1TRZ5d<mvVݮ+ᚚ&# -5Qfk,WUp;a~U \3:I"v6wvΫJ`F#f2N'5kHq_EAE$$~SA,5Hc�n洖mlj_UM5s+1U<DEUD@DDD@DD (*j_yQ2xԮi>sMxe'oQ/Z /ժy Aqy6Vi|_?oAμsS{G5㚛>*~%OE&I1@�z֟w[&a1ӺgF�;Rr]`I\86.@!}MxbtdH[Җٯ{' ^9M ^9M ^9M ^9M ^9M ^9Mʦm"E4v|rLJSkIv@n@6`o pj2V淖]_5V5)8e$4>=$Yi_N0kZɜ.E׎johTG{6�r ԡM@` eE|mMx)X?ލ0ß`q[͖-b4|fG>&S\l|nYvmAM׎johEtx| mRqMxqMxqMxqMxqMx M26VZrEiiZ3*0FZQ"3s<{Mw~ bP3U mdjw SM3TG9EUE13+zO-w|D"apF2jIݏT&+C/#^cAv*—M0ɦ j,dY"v};'Ʀ�3wsoIm6GPʺjŭW�]hh&ش'ҼŪ*pF`s#&6{.*j-%jeڹw2]\2]L{W({S/ /wr8w2]\2]\Y!A$ܛ#Vk<eVK0N:!1#ihk\ƀ@f2EeSD,Zv (ays^E|,=7F].UzSISQQN{ lWkS6,vJjm,Np@YĂv6UhvGcHQX l q`Wް8q@~ uU_lbX]_OP@[sc1}$}b))MSTղ9,kj)hs\|�l"{|08ͨ�(p6Q4t',PDyUVT8VߥF!,#�R :<R�p,hx\QV3\27k\(n깉UvSogi5,L*7 Y h Mր�-emQDDb�E~MP?b " O�7#TxԮi /Z (@KwX^#B) ;7+!=AFava0\#;ߩ9^ɛX,�kfh,Nsac̀P[u�J![SZG~"z;ַ߄%5w*b o# MkyJ![SZG~"z;]ppV\=oQaWVOU04CFCC!o}e;vq/qldQ>#$oaF9(nAQ&C{W%q_|pq S"tZF'1'(16ݯ1yFbMp.l,@ :XFg|r\;nַ߄Cַ߄%LDw)o# S=kyJk[TAZG~;1Cַ߄5mPGy$:F[ChVHq /)KYP]lXS㫑�1kG‚U#ݱsOs܊,9&cxDc*|DfԺ]kL9X�[hޝ/k~#0haj/1iZe~S9Aa:GRڨ4J#ZZә$ ;]Mðz>y3 .{];I.9XZ˒IK2E#@" """ """ !D<H0?iߩY wVh#b2QUpIU$0FA+$4zOV-R4HNfYx;m~!R@V {c(: QX++#]JɌmy95;-e-vs4~DOlW@%2desZopHh&EEY*9g6M hg{\x7)*J?dpi1/p8-WkEˉ8-sq<"c mߚVOvSNLjcKFfƲLoɲb-9Zhf|ۖ乧)d;3p}1)Cr,xJ,_ة/Q}PADDRd~O�7#AC־7]zRǮ$A;E6_s'0IoXI��w Eeube]֒tN&!}aаsNm0X9.6rbR56rɛVKFB].R݂Jݝ~zKj!ww!]抭?[qK>L:o˳+ӊPbTUоJ\,8 /.&IAEe=k_!!$ٔ'oo�OzV~,_hU~uE3ɈQ�LJ�LJB uhJ�s95�˿/p*!g>insXmv׹W忇{Ge:U/gu. X$a{ZC",=�_U s΢ 4fJG.35s}d𵷿�j Qq ypdFKJu|[rMĤkH|wsX66A|v tUR9q+,FZI,!.o-H�@EHqZR>2ݶ;IIiŲE6;v \<[l"${K2iquv�E"U43Ób jwH[#`\ֆbd�|m${x*fb:f _1r{Z5Ĥk^;/܎?R UX5t-ds02ְbbFfƴnc=>9dp 7Xm7.>2͖F4Hq;-\e*\RI|ߔ l6�[m.*� i�0 |h,VicZd .A$\z7>|4q:ڂb*nTf.l!/0\o՜kƒekmzqqE] UELE/}{86رetm;!-q[72ւmEs<F e1k/q9GC]6q}l(.VEMR#DxoqCec�MOR Q)Q#9.k] qK@DDD@DDD@DDD@DDD@CĈxa~ӿRXAԬF(pڪ L/Ll|FDGZl&Һ#q�qRi)ښJgUTE  62Coآhuv%SVxsZLι,ctx9|XuؠI4r,2�\De4�n.PU WQBf|�@,$eܻ-bYaW3dJ|S,,Iًp5 Qa5ge/:v4WcnD걷S߹%3!dӘ1ͬ~R/e4W<L\2΄pp`.z�tϦ c&-a%$ eZژ /] hԖ vekE�T 'PFʑGnVxc,nbc>n&&;%r5 /Q}T (( " d\}^??EM'}J N!]?X4}3basVfk}+$6ֹFдi5iSz9pXEL06/{ *; v5zUauSRcR{h$ �,Kvs[ot&m:;Ua-V= YSVSG# VOŋE3FzW~(g{[n4L3Sn?3bd8"kyh<B<LJVdb29ivwO%5OS-\>yZH/!4l�I�Z~!z<؛q.F]f>5�RZ56o%K>{63#˘Q;qp$N"%�q D.Bte ҹ]EBte ,K�sA\xY]._I\.f m6Ye1-W684H|kkd{$Lsٵ-|K'1`cqq}+q2Jte zW7K(Lҹ]LֲtYrK"].t%K"].t%K!KANJk?iVX尰زD1#{ gj<loKj"1 l8HB/b�E~DA+oG詤\}^??D,x#ykag.4Vocg&3ɓv 7\o"\&M۾ {/kIw̭LXkɻw5dݻ<LXkɻw5dݻ<LXkɻw5dݻ<LXkɻw5dݻ<LZD`i6-ιL|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n&L|g s<7n.;"<m%22ag&3ɓv 2ag&3ɓv 2ag&3ɓv 2ag&3ɓv 2ag&3ɓv 2ag&3ɓv 2ag&3ɓv 27ag&\7n ,8+8=,_ة/Q}PADDRd~O�7#@h-u5t{&3_.@ێ[fo $=ng Dx@LMYM3͖9Zn[Ŵ)*:v+$ 8ߡV Sϲ-S߰݉u8op%~SM:F їn"[W>= lSCllla.sZ&!n8؋>3>Ik*2 p$Ϙɫs1�pi$_`ĥ"" S,l�k͖ZH>/7 L mtOai9<_jb)r#/؛SSPD`f'as %+a:/%+ݠs PPt[LoN6b*s�%8]ۻgu.Et劉ĩ}C;.FPX5S1~P,[qk p$q*#V[E@ai�Ӱq\ibLqܽ\ܘ{~.VFz_gG^]ii6vh**8fGY/2y^l]8EST|"b`׺{%1w^큮,nV4Wq?殺&;rbl.0%x.ë+dcY"mS5<ڰoc㺡^afaXRQy-@-xs͚'p qn+ַdDcmTDOBf1slMtk  )i+!X> 溲W_wf̵}`/_pf-LDU{sL;٢"""" """ C.?Eлd-b�E~MP?b " O�7#TxԮifo +-Uka^Ŧ "Zn.{û'n>˿Pv-7Gv\)� (P;û A<�*<;M݄û شA`btxwa;û%OltZ 䕗btxwa2NƦ`O h h@Zn'btxwaE_شNƦ UM݄Zn E_شNŦ UM݄jn E_شNŦ UM݄jn Ei<;M݄@Zn'btxwaP;û شA=Ŧv-7GvOZ?ߥ~Qû Si)Q 0 r <\do"NŦ Be btxwa;C'ބ�`v57Gvi<;cStxwa;û,W57Gvi<;btxwa;û,@Zn'btxwaP;û شA"]{�S�>} """ """ """ """ ""_y5B/(<W4WSIRd~81ce顖IWΎ O}ҫ ]Oc0^cki؂<q bᒠI tV=6=}|z&RdKA6q{N߲ekwӷ;>PP2z vOͩkI4Sq.G 9$m\Qս2:7yie.'tm.#!۵RZ(E1fu: "==+]UN$QE+*c/1fY b ^i?Ai!vWW9WcrKO`mڞ/W3D+NNf%,b" /�*M+1:Y0XҚMNL-!s͛ Wq}(:Me<8S\R*rD1)\^V!:ő'Y`]|_J!S*cU}SlOuL,\.웻>'!up_ivK#)")l$ W,%#˴Ljb=-\5qCSs`cdnϱh۸q:6TB_oE=45(ͫח>3 l'h6C @Cp"H<sju_ɎNh6>C֊cp+-[yOjhꪎ4SÄRJF8\ku$f{@Ll,|vf)fSAjdaT5B4Y+ H.6<{R;_K&`UUU<U.FkHFs $p~J~18,飊)ek$j׵b䉁{;z`Ӎ11+Z`zgñF)%0 sM16capl :O1#.mK*y䑱<0A 9{qlgmfhJp*+VTST!g".8>f7X4ȍs\ܥZU|].WHࢤt5t#ZKI'3.h6ҼWHUDh"h9SQHlq:=qg} wK!+0=mDY$pݮ4fq#[dY6 E'Dʸ\:ncʝYܥF7vPm>).ĹD@DDD@DD}nOgi[鶓Pic07HbfJ2c[-dwlpFJ f'jV2j#Y9^\ g4xmMܓZF1\f,Obݍ]T6(Q>/{nv qI8xֳIvZh^B:sGf]�a9/ I.gěKU's쭻gq7Lff#V+#|oe$>Ƿ.8X۷&ڭfWM4qzyN#tQڇ8dP9!B},omEYGW@?>m l`qAd`s\$kFW=v_|.8͈£.Iq<b)TV8FWC#NY,ne.7i&9ICTTQgt Z&|uY#)Vdkل񔻶;Ppx.Qr(2~O*B\TD@DDD@DDD@DDD@DDD@P?bXEAc'}J*i<W4W#3.G|8:j~&�W4FL>jGW6 W#6VT\QL=]=Z٦wp@M@^O~c ?I|Rq�>> ĸTwK{>/Wjjۛ6g\ q)Ť�I&t%Gq~][[?} &\wޓO.;IJL�Oڑښ^Q:O�.:'mg1mmEY#}AO5^}7&"q]SSr->ӨSSr n`Isrj:r~ig"cg"jȲDȚy+$Ag'Dcg'暶r~k$AjȲD䦭cg'暶r~k$Aj:r~ig'Dcg'ǜ.�& VO5lH[9?4ճY" ulVOd1ճM[9?5 VO5lH[9?4ճY" ulVOd1ճM[9HE;d-Eлd-b�E~MP?b " O�7#TxԮi ~]WOIB0`�̻R~&tE)&jx[R䆼=\cߋWE3UU,-\"^}ь|aS+VS( C@ozvRiqX4KXֵA؟snm1|i94�a{`�M|~#+&{()>`fmq{kl1kP3]nIAhl%�I4?=0oO�UFE=*nQNA1 Y#C2nd_ah eQ0:!tt96x  �i94 :�_ä›K@kY ^Wf77x0?Y]??fs7�]vbUcҾ[h\֌ /Ļm]*:jΔ<(4P Or޴P Orހ /Q}T (( " d\}^??EM'}J fB:z )>Jz .rUsnOYoDUsnOY2UsnOYHDUsnOY2UsnOYHDUsnOY5u\R|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[|;L|;[Gf]IY """ """ """ """ ""_y5B/(<W4WSIRd~6";2w#j-V▨j-V▨j-V[1v_�AU<�<�ڋU<�&ha|s4A!" """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ ""_y5B/(<W4WSIRd~8l-+-S텵U67G(I qgwCnA$ 12^mf8`M"wjɴPH7n۵ 0(r^H& w٭p<g6}#ÑnvwMRbTq#{CH7/SXˆ$Η4/7xYfGVpzysrk o=H,\-4�OS ZG55Lԙlnn}RZ=<D0-scaTlpMFTl{ sn o^{8.H9 9M|^5!�g}ӿBsXn�uxSN \Ĺ@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@P?bXEAc'}J*i<W4W30- ZSt{oD5St~MT!߄|AU7HwMGoD5St~XVNَOB4j#C-Fn> )7F8YhA}KDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DD (*j_yQ2xԮi#T+tU1Fk2Y*&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oTgSЙSu= *&oTOBfAhu= ;gSЙPZ"OBfN&oT/Q}V&oUz L6$��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/docs/fp-note-panel.jpg�����������������������������������������������������������0000644�0001750�0000144�00000132536�12574421673�021020� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000�������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���Created with GIMP�C��C�D"������������   �b��� �� S 15QVWsw!478qrAa#$2"&U3BRuv%'69:FXbt���������������E����!"Aa123BSUq#4u5Qr$sCRDb� ��?�% rӓ�/��A1}ӓy e%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0ur<I~F<Ø%W#ėc91=\_0` f;sȇ sc-p� g}/MmtMv}5]uvmՍu3?w#^J�G!6*4gZbN2J <U\ܗs)>r׺͍'prOW? -u[ (YVը3;`HQtcL| H0ǑL`.GKZإ+8 -@V5RءNisq0u6aʚ{ʾ� l7?dWU#<M[خW,ݕ!yκ5 j:VWguرV=srs##9S)G NDֲ'umZYuJ$v=nty䷪G**|I{4z=OcV{> <xZUik}1![MVbG2 }2Yh:yRNʔzEbq!{)R;lmphUg3RnqOp\xZ[J`|f#ՔJe>3,x>G^3R7Egz:4Iݒ3]&-r*'B&7:4g&<P慙ū7g+nVnZᑽ:F _\aHއ@yӜ\i.KkcWPL 8;ûzE;UmC7$BnCWtu'<fYvytU=VU31Zk6X} �Pz6Cb_mP- _9|NHipf;Y H1\\ tѯ ],~*:md*Lj.kuP#> Ʀ#MzqhsSo$FkݲK']P +S"Vw>e4 MZ E B}r{| 䕁(E m{)7+c6́'UqB{ɪ<hն|ꮡvf얿Ҩ{�f<3vo_RN]Q-+ON^θMƈ_ *aUrۊR U.Q=NKMnьȉh59hՒ ;SQY3ތNr2[Uw R^`)3z=lg [rck]9I[ޱ)M龏3Kڎۓm <J" oOT'r\, :t1lt窄Z$l Z:#PZgH[ ksۋ$ ETֈܧ^~x' J ƨNAO+l {~0kNZeơ8KŽա&ֽ)'@UH։D^n݂x"{]D٘mw5Zx4mtvm �CdlfON]^.l ͥ+.1`xHŽܡwRnN_T@AY EK}2sB�rK�៼9+p�x?\ 4MTWr2Z[o]ٙ9˖lGUd~ uXO1nW"܍ɮȥgIn3>+W{㊂je m 7sAQHvoYm!�._̻R** /^!{KDVa'MZ{KrҒr7o 4=g9e2jdV|k'}f cR*dzDkۻ%(l/B NF't8Jsz-$H $Bu-)a*ŢHJ7]\'F=rơ@}7v9z@rR {km<^< k*E56aeз%XPu(Zeaf(-ٕ#)gh`<6z˙g| K6佭\]ƳU1,vo&|Qz^ewi9x|q8ozNnnDCsTmveԕc# _{eRLQYu+^ $BGYV)R`* T,0#"2ӟug*7yO /x,@=s.BE*$˝&M%]Eϲ#QO/n]̍RmFOSl@zR%P~啷u.檕4p _I$ya8^hViMU9ē< 6'8pϮͶbޝE7*/I\U܃jrh}HKt#&k8wIۓ\#~&?rsm\jeQ׏r1Ԧ+dD-F3^TRi4cM#nKн kB:?Zݯ ,'B2닜w4r), QhWObwPjGl SUWuzEiE(02tx#g:9jčwe;٠L.xd $R9R\bB8|ZsBL0UIt)al\`.sӵ{RsKHc,ljN FS])jODzGw{hCgwgV0tװwkݗX%wB t!}]#Q/$]'^*aLtK8;LBO)D-(ْ'mƇ m Жj30y]sI;R E+G9Df9*dLft^쨵!2-BMʷ¯T+MrjdnBKI<j7O=-hڳI@˃XU/8ܐ7~MKۂ{(:1dZlk54vT4jս:ҜIg^k4NIz~N?trc 'T؅`L?t%ATncrVmPZdYY(uAXz|8n"<"Sϛg9%q$\8NaBű5ORӚt۫K]j`X9x㻺KzQJ- #�%t}ilUM*dH #w)V3+)*P0{ z/;|Q-0E^wK9Jk1+H 9[դ FFk!o[Tܙs3V\Z{_tS\vW!w_nϊ/]LJ/[uRuUBJVtvUљBv}MT6L)eE3fWUbzH@iWE6U2@dC+H'28Įw67-9́Ktn9i*j3deEk&G=pn>lr f!m$\6esq_#W+/CR"iLiiX2RLVIړ7+Ǣ1܏!.o+N}WSJcډ*z432=mxL֔X�)Pb%weS0bG*n5,<a4ϵώk~Joem4EK~ >^?^Q</N6"H$=ݫlYA^S, u6MR3 /\qЄU*iE\@);df7&YNݜQJr#86G<fh>kM0EܞtDCc`(Iƀ*9^,'Z&zh4=EvY&&DXȟ czl2șTwB~萕ue*H%A^Qfk]Gj�MZ#k!2=m͝y\lBUTUzP=Yq۵ڢ0c^up g!C;0^Y����c���0���c���0���c���0���c���0���c1Lkt� D8Lkt� Ck�c<rzIux̿9!<H^ΙqutB ѷ,0?_yvo?ؽ| !::*v~%3hMhsٲ29a&{KRM{mVm71A;~g^WiS;8XSu_qHڪ1#J+Y1ͳi auvHF,6,-$1#awbنٟvoP.,D nPBJ%BsK47>P>uy>E<_ 6gׇն +Т/D3ו]Qn<Ԍ[Ç? -<yq6|4Y>V>k-1QTRmډuWÊ=KרD[Pssi�R1L^)Z\9adKo{eFM2NK%K*^߷kO2s]AǮaЗlIQP CȚU:0ɫX ) D I-rbPV \0};tg3,sNC؟#Ps$y6bXrfsV/u5)\m;ɾ?]4-k7aNJgFF1ռT_^<|I3 3kV36NAŅ"P5+dLјl- \I)[Rd$OH$R'G%dr}fq2q0K=TV2FmY _4@䘥prF7/*Z_Z[]Psu/:Vc"Gz;t,3,[I|͑ޣXeG*[[z;S{ĽKqvZR4\#n}Ti,:C7ͧP*4LxwH f8xf0fq{)*}xyW+d:ɠbkqF;k+|y|IrG=`O3϶όHLpt jc}(5ksfoTa{uU(i9+kٴ&ڦ ]qު58r&vg3RLFBJv;^Jٶe 7B=A~*M*y kqtʙam|}!ם]f;0rEԸp}k L(&ƪg:ΑjRr.^X/ǥܵSsprIk:%=nLsKVVĪ|ӚO=B_S<=kzG`4*76ǙnOxO_f=:�3إu5Ѕ+x9s3OלR}&AZ�{m:_GGx^K*Fk&QL*{L[U� DeOԵa4Ӄ4<yBR^ <� :YLO"GF]q~Fr,:řu1jL?dRcP0ڷM|U�i�~>:j bz9y$j;<^{�nG�22֥+hw@( v)�R3tȗi�UH\M\Yn#%h0הg}^Td Κd6o6R;`1q$F?β9ѐ]Vat};Ѽ:,1ccpϕ\CGUUܰ{QVJKVȢ{%nnhy.Ka$-Nܢ$\Fw6Nu-6iF݇~锠�4Zw BvjZ¶>�sę=I5,O$s%~`=2^[j/oiS%˥CzGc=v5I I%1gV6gHY-\I Jbf%Pn5''@wKo3sI>I49H&4^y1K6jv-`8':`=w/j<ːxt -[svzdad?G\ox%P[Sk3׸F|<ޡx=~?^m(=q)y%)CKjhF")sRNd镻Dak8jFF4i.&Ottù}JSX.*oGߦ҇xIGO"ah1f˜Tޓ-ꏵ㏩;vk,ijl N†i6Gȋvjčyhw96;u0Ŵ3)%LZ%.mcR5yd1ѩC#3mJUlڡ %Qnhj[WYܿo)Ȕ:\~ikaDqM#Ŭ୵DvajkZlr*Џrf-Fite3m<-V)iJݕӐ'6O(&ٮMPf5 ƒ 92 MxLjw$yT+;{g(Ĺ0r)QxW#Lf!>5j4.rgB\2ވ_ЉV 4V iuL.mhTfE4Mv.6ɑ.sW+UӨ\fy耟Y~�39iTRǩueeVNrCGm2uȤ*B׷MdWԉj?T7*U� mQa|y}5[Fj{kegkUDBM}Fy:OЍ;1ւxtuc,]<jU{oM(ơxrr)!^WCȱCslqѦ_js9Vvxݳux"t7(޽ J8dW<[cl\щc&dBf׶?2M@֩UNLɝ1>Z Q.JTPFשwM& 9"عnPb$[ThjBB l<MZfeɊkMC)țKlp~)y5׻ěS2~Ij?q.oo.BSg4޴rTJe5?&J!]^dlQ/iꈀogU V<)]GV{ԷCXs1pZ*[$'wc#-PgtLxY8ޜWn$'iڙ$Uhlts?@ӗ - rKm P%HFB4ڔVӕE^릸>.~Fԭn5a(}zMUկR:ؘd.ؠ[rw}m.EO!ґ^nM&T˥Sl nDM:K'`ڻd17%eZYKE9ʌt)Y(/$y-6MMP�j($JQWgO_B~}skj^̺w6t3tʺJY'5ͪ6%rA4G&$)B".Oш|J%5<!էRҾ.l>BU֘1K[̉+Rqް,ܖʖ:9ʋU#:dɲ=-*3)-Y:Vojb@j N),Zk܃S)w$nz_/dZ"TgYnqȚc0Mw]sx@I5<|+IOVm:~u^dx0jɔZ=}.וK$S̵ v JeraqIb?*R%Po܉JBvO;Yl/hc2Lf#$W)l{]P-@fkghgLO΍DNYdíG4oOrT1n1G/o'nqMd-8A}-. ~TjnB̍CTv^so#WDQGEKHܻj4oZJmR7kbW+'7 NRk"TbGm,B ry7=Y-C˗T`~CMyQ=(ݚm~SCJΣm gR]Ay&w"|r;sCDv }v/#],pg08)K _fV [ RpN l,Y n%+5 #s(�I4ۥnJJ[ yQl&B]3acImr&&oo5;<mvoо_%꣋OQ4l1jprfl9 / m*K8G>kYȜj1Wܭni5UCӖ\LЩ͙Ƌ*i\m%"\bVPZ˹窊ƗO~KuѿM�eky*Q+UmWkֺi X^OV$WsSsziҥ!O#93e_SԴG{2=ccw1Ռ{XǴ34oGk[Õt͜N2u[.Ѹ2=k:47%PJ4'.q(VTyvܞtgS#mɏ˛ >Eja[Ú tgQ'F)HWiS[3' c[qy͡nXe3+~GcM%rj.A:y^gmy=}Zl}UQ])&97}vR_Gc|nO1nGn�=yC38v'J'N$_!ZtBibܢLhzW]6 `qR?U7gM kEeʘ-bRI-+U Q5r񩧖н+i=v-joBGU_G\]jֶʣt6ə&Jͳs$-Y4c/.N^pr'TSgrVX-cB¶ U9Z[җV6(K2-KONyJ3:mNt]uʂ,6ns4ˏ5iWԜy(7Ey�LRF :62il�ru- cb&jSbȼu;j#2!mTj3zc7O铝9c+|^1yZܧ%i8yWܬ~Λtu2Gc]~ײfk6ӬdFuWR>������1� `�����1� `�����1� `�����1� `�c\'!c\'\�//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ//( dwܾH;m1?J"//(r!"OҀHG{m1?JܾH1 r!"OҀ e2&5ϺraO"&5ϺraO!�1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `���c>A<p>A<2���2m+#(ů?L {bC6w B[H/;|}ɮG$ZVgw <gFXj Nؼ@ab\ +}Lu%k#O]R VGwn_OHOr(<?MZ~;՜n7Z )} ?B;d8~o;j.w6Yq3J2~7E,Pfq[MGK%3[% Wn}VSƨ֫ked?-J0Ԅ:>tF#/mk'|\sI1([z=w+٬EޑtLvd<3Rl@z.:nL;|gu :kHPe'[Nva; Y%Sy98j\Щ:5e>/�oUrNrmR1oy02UMZ9몵]1K!|񋈼?9gT:ھ{63)':htkj4lr(ֆz=gvVn%MTvn#ҖcJ^ք:Qf6]Eizz.|ޔ݄i QGmIέLWo6^4Ln/#0ꡕ)\$s"jDͦ$/Y4}yr$5gR;Asf51$oOϺ5r fi!9Ƥ)Yy' ڷ*t'vO*boȯX a.D9-7 qνEz|uV)Csm$JmktIZ#7@O0:[.1Li:9GVw,Y&n<'m&BU#JFӬYylU*)A^BtJ+6:n:FS }�2x����1� `�����1� `�����1� `�����1� `��P? ~o?2>qC?r>7F<^/nqZ^IK<>/ogtW<Ov?�#gkGƛ3Ě3G/y&E's`nٍ@s}<:ʟgՉa׼^fQuaMg㬓z`׎]$Y%NcukY$9fMϹC>j+}.u'd=WrTsn!tM}fVÄH_1\5<RՎbeٵ͠tF5 H[%E{Owm.J B6.iZ@ӟuTDd}Q+ UJ]>ѵ鶌ڲ׮^u^TBVZ0V{OddmKMik[K7e%V+6oF`4niRVg_u"Q VγX:Îe@i {nA%HaW$9BJв3CXՍW^洳'8*hKyTe#k[~XFSHjU#zBk jYQBiںGO6VG-Ii:"] ,<-uXz͑/QԮƵUuVU6}�HoHu_XFhĖ×R"ui:wct*YZ[K3~#%jP;.&ԈZ8+ )܁x^\*^+ԲKZvNYuuͅwX-d9jvsm% \u�io:vH3مZ KteA,F�g#uͮ4DyoEYGApsN$4*N>õ|1MsYCϋ\zԌ[gmi!y=LSVzq#M3O/8{ӊou)-g#4i &sF+1Ħ#; j$?g\:jq;@ܶcҎ8z ^ׄO]UJQF/)ʈ5X(Vƞ<Iz':3{ҍYYiIwe7ֽw4A^ZlS0` ![C6?Beǝw&6#^\vUˈgFȱ!$B%:>-l*SjKegH#]\Fd*lp+K&C!&ytWVN+kW ʺI+-i;*ͯV::M}u;x$kӕN( ԏe$)y5v'>5hXT6o^NBF[w" jBjL[+Wz rBwlD^=f=SGR!v Ygx,I=$lLҳg*3tYo8 mq`LnV]kS_b-ZDM/9]0G크]$_jv%JFVIԪ;I#2ܽf@�+0���c���3ƹNO ?CƹNO ?1�3orTq nKTliV7JL5ΆnmF:L kB>:8wE|qk0ՓvԮFaF9׾=$$s*i-b*[D a7YoT:3l\ӞCsy%2m6h[#Flxk nM6bXF˶@e7>Ul&OLNt�cqoɪr(=Eij�N%֧}9~Go�S`}Ev|[ig(E>^'$?E]%{eIZYTVDaeBչ*"cVbd9la1v[u:zx\gv3=-mv+KZhAZqdF,['ֵME'hgT/##I!C_ZT65^`0+Te+ OJ;݉m3Q\X\�JU*gdig}[&eTZNnjV lSͯcgkk^p]h' + %q%9]VgMwr辟txLwmn;Sf'{egEYjv]vV>u#Tc:KG]NHą{Ru|Z t7*1Z҈Z !(IA[Y통Y�~Jյ#H" JPDsIK7ɺk^.k*+q=q4!G(O7]&$(p-~:Q{-!!edw'riѱ_hӖG'">F 8d)LsIgiŴ8uK 3m5c>R⸎_pYo ]ٲo;}VQ]٩JS]%՞Ke`S6! Ǜ>e<!њKt!ZNEٓ6( gI\J\$IE:t|LcK+g+It3["hΏ<KkfEk;3ϗgm_N(WNMj h2%N o&l۲u0ʊ$UP* ӡX\7dghD(-Nݜ<d7mIEGd ->ueLC0iGNTn54He/B C M8c-Wccj5U͵ԑM5֪*GFgZ[w{v5؆*Dy8B{h"9,~Y;<t8t"g="G;n/or4wͷ3(T?ZhQZhYEe^BM4\c]t\c]uƸ1cimlQ]y_b՜XΔgI)AVURڑ+cXUjNjR:  A>O��5c���0���c���0���c���0���c���0���cűkĸ#ꈦw% tS֬c]�SFbv)Mf׍+=Zk{Ǫ/qKޤGyiaaW2*^Ռk'*+ܞ[sZx#$4+wOmW +/l*vfiRruNk܎{[٪w̠%? t?(KveNbS.;䵢%cS~9iBg5-/bh� p*}fqMH|:9믧DMdv㣋%giCSێ?&FYƱ;ԷE_ 8e(^>U#Y%Eʔ*U!7MmÖf\gN0wVMgkf#tr B3M!jjQ/?=(܉HyӉu(㵥A\j<ƶZCEӞ*;jutw 2+J[neEm# =xnrUHmjJUy fO7d'l |nGѼ?XdT܉-Y.*UnrNlXH=ʮws:S9FbGl>VWfn/_.0T~w몘O&-q]8Ǯ33P{R<AxF>jb˳8^Rhi'Z3RI:8%3O%\L_gwxq}pXNrwƎ'U 6ʅ.NVQ �޵sq{[Ə! 5ǕFΪ,Y˴%W1~OSVtoa~7GEaն##ukH}UU{՝7_tUpH'ɵ ,%#b,oPYdzx1xc8elrMgHIH;bD %NSNIzY$VQE뮅i51 DQS MU6YV Ey5GX'gtFЫTzU 7 1 5h^^馚릚i5M55]uƺcc1cy|ޏ{tӇzp+XOv",2>m>?sZگJMl+%٦4ӮOq.;NLFTEf{d޵-^iX\K 5鱳*WS"5IadXRx[:φܟX.âx>/>$XPNҐk}Z5YwDV@n*hBRQymPɺ-Ud'qG} ZͲjUP8]yV'TjXԲZH|enB!J3tiRE)؃0G�Eb2ϑtum�j 7q.zi6Kz:Z-Jޞwi(65J Eh@ Տilytr#Nri,01!^zT^֧5:"ʇ7 h,47D=911*XZbډ}Ӭ&L{Y/.rpR8:ecԽn,\TV(zijBhQ;(o6>L=>HP[*uZCyoBɛsNY]jfai*&F7G4(dR.\V)2RVԺ#&XppRWq4^֬]6gDKMmiԻ rPfʐk%ѹ- y-ou姬ْ1e|F>K_ZVǰHLrvAneklJCt'Lb/^Ntt[|KA=_r[Lv47{Jv@{B/D"u/,:L)ĆC43\z^&o+!|".9NLЭb*z*PzӌhM?)ON(*ҹGl$n8+dm-&`+՝:B[0ZoZ.[&W{>Zb-;!ֈ<JȲM$, Lx\4.yUMZQujvVdM@}mp֕Mu'ftUZ@!D͛vW|-k&j4۳3:%KܥM,-np平mn`opZT :2Y4EL'x}7F2kkgqeVVQzjYe4н45M4]5]u11c|fOV݆Z*Za+zYh~A_,z]I bRa.b �kf��1� `���c>A<p>A<2���hA̮A-XL'7,ý9[iSvtG*vWw].Gf|}g;X#<Ev/ԥPwGYplXnsV FfU#|HnPrUݪS`>ǎ"sK4׮+xpu=4n3ce)tO=vnly2mHj*,)qu%)jV6)ՒF̊~Yn]8Ū,-xV$RفҠufjD۔v-qaz+S}YX]힑f](ӳatm OyoY*89< #lnsJCeMw$^W 9;PKL#lQˊ3,(LȬKk)fcM2:bdSBU]�,K-YNX7˓IGT˲+V:_1+OyjfRV,|pWU6’:-l Rߴ+qלge[2anxN(r$ڞu>Ȟ̋N!hRa anҙzNpDKPJ|ո~짇Z(6dXg-F!)e~kSnf]&D*(Om{e�<&2lHU,)qֵuu;Inç3Y.pfD%kS6nh7(#|khit}s{\gҧ}b& 6>2Lw}RQwt9j^J<=./4eSmT n/۶ȖǛBwV֛lU|~beې@9}C{^:,/=ƀw6g;Aj2o;}tS[lljKD B%ҕȔMx'F^f֛\oO%}t(?ZWb_(o3K-=F{RˡneF"1뮔<$ͪ.SժTu Ʈ܃$VRSͺǜR\*omjv!7{f"Sգ{n@N,駖<.['"5%O3_/1oxϺJ%6ەoG9Mާې\_#[Ff(9@ȮWNq;[dqJ$zg?Sr^T l5+%Ȩhhce߳^Z#+nm U(,5JM+Pr#HQnx;O JlYw|O(%yȩuW)Uy>V[ڪkW.7Z "'9e]?X S~nel3)IEQ>Eɗ8 ׏H.%qL[I+dRE6$&TuqU3PGâ_̭pYKSޕImil;(e:!ɿb*FY imj}uu%}w𝨏O n$MNE7֜Dni=|Xtk u]N ,c(9bqlpqfM窱@oij5̜aɜe:cN5^JRORvRzW4E)Y&˫)'Z#]CZwQQZq%htl$id1JBnb:(:kqOv iϕ}j=GKՇsޭ]]�67\iDO-qpqJGe펋N;(yV$E:糩393fm1nK)<*S@_g5څ fCG,ynzkUK]>;uɔ.Aj֟ d fNk^qk$Zʜ[zTؽrPvo�s�V"ᶞ;wigWq5rtsq̶R6;U6:~  X|9#bd y[2`wE)^v%{ ;hrkJVKb9H|^`pLǑ5UՐTT^[OIbۆ.kgEV\4Y]5;c@Kk5D)/ ;E%MQ6ScПBݢ#Sb4S1_$l-]}\#`'X(D*[d.{r}b*i~f}Q!ҀcW׷/' |-�9{e=yU7ɫc37_l1-z7Opg(O$N4Y=^�_q%f(_w\mum?Tף]dTwC^7|(nΖӏlI65k3n,9w^7DgѶ[kYrYU؎0Gx[3|u_cu1ur)ѣV$iz)'|Ȩ+F3#1n+nIBr6N5g$,JNvdk#0.=Jl]fV!U<ނ%BE֨U#�کU@Dn\*5RE7FV,yp!=^uuHPw #٭r^}""AW"+յSci!S2OyKdqXR_>In!d?H#ȣUr2&3F-$y"R<hSL ɼھo>inGgWaB'}nB؍TmR;jڃdmD<ˆ)Y5]b6!ꙨI};H2a`;)i5`\ ]]1?(b3Ğ$j.9\k2ij(-cқU^iQǔZ'GEjݒvʍܤuIk$ܙC-}}^oۋ *|ֲ͚ ZrP5ՠe}m=\CcJsY| jAPЎ ӷ U%9DՊʥ绐#5b#+CTخ)i)X=xf= tuUUJ9%vQگ < |I&iNTh;yw"dMJc|yzJS,{]sO*|o4,ʷwiYjWۿ/QyxCoaf}azv8 ϻN,iKŧ/t.;CXtYʻ%/穎 +'3隊&ȅu:2UiyfO1vyiщ)[Z7OR-Sk[7 X52؟zM#6+q|mtYO$SB׭KZ PG4,=kTiv7zu `]fLt)B#nijŠkqKLlvd;/ev!)ДS͇t p5L,{rYd6*q|~CR0nqݕ"܉֧91V] h6hU;YY2vˣc&*kx}9k}♍lZN67jt/ul1'S_n!<XNKU곖յ<TiuLؒD[lq\w&!L*%E^"ʛyWT8u/]W4TIcj)bDDY,mȒ4OQ~d#1g}, wu̫/U˥e/k^@"MY'C-H/̹]fзݩٮ4,&_0[/5<RgKvv2-gԉf]ΕNU*f.߶ҌTݏku#ԧo@4/yӐUt){Us"]g:ßA m *³PCkk8R|ds6,"̽jٽcKT|k Kthq5MjѱeKW<6x1B]S>9\FWmj c4wxG`nZW ma\*?^E=^h‹/o_RT K*xOz`1}<G8֚k[SFy/)7a($EJ䭝CիԞ}5EqS\M w#|2>M-Vi*S*:E,es5E"0gP+955IaqiJyxlM^"Z�wܼu{U<Yum]}Ӑ]6'T䫶~2֧}O '( {6(_bX|49vJK]-Jĭ׫w XG,H6aCEhKzv)nb= #5FZܦ{UJ#yQ65lYU{DfuZ�UgO[z.ڑ}jp��>2P|\;s.9BĴ>߇6 O]0Y̋f$>c%Wǀ-cnHwvum&=w5TK0mh=4п`x!{QچK*iGEhǿYn󱴥nZr3s�3xSǠL~Hf"E,8#ɶ&6B6yϨue#nY}Rrx$k6ttP&ƸQ6XGA7f+;-%]ӱo[r|GS~Oՠ->v[kN{n37&myؐjxOOkr5؉NbCIvx{*X)==k]Xd&2ȕjkmݜeg5jtI{.Z}j8%Hr(/#ƙC3eG%+)TcV*K&%')-v +s_vJ6iM;vrȽר%]ً6UxXQHE8͞}3 r6 .W{>mW_VW<C[9bVˢʢիtYh^+(~R9b][ӱsɪ氨 xO\[58u5r6 + ꬆH)1rmۛhoG,MM)E%}|H7$즙:!iMsnvrkM_l�#5MQܿ[Jw+^=u]J2;ڶ<GsVՒO Y)橴YzE]s6äu.ȓ^v[iwJhT&ZS9Ԋ6D�8xB2"dL$\s# wij@B6RzU`)~P#}ghq:Je34*)ZvةI4VұOIi1̷"ܒUs\]==ˣl{VV4ȑJz>-8ԯk2>ܝG:k$#r#"*et^Av[ipZ;L-Bo39ŸVo1><ueL-~[h�)X3wo.A>j M&ȣ^+Fv&3J2WU`Nʿ_`O[fQ3O(Wl 4Rr紥7.+Y<y)d:$TfڲLCI-c {-5vU02.lrz<d泑V@IG}JʔvjBW+8ì3Rbr/q%(E2Wa�[Е4Q9!fU|Q :we̪͝κ:d(-q |!-ݣ9͉"ӭ@+îU5"lwmHK̦)eH ,ۯIyb,Nr2<T<C~Xۭ%R\c_9XA dx aIJ%#Q&\\慖 {drw hO`GYsz$|5`$6MkFcQ=Hl gfV"999{ f HF^yΛٞ3� NhN6qXZ,9,mF Iq&MYɚM(=ʷsr9H #Ge#/QIIuWZ!!]s NnN˒Ocl%m'bڐT꫏vu7w䷸>>:uT}{s#hYwvA c}ʓq)_ u8 MzM)F[·g � ��1� `�c\'!c\'\�EgT:fvɳS͕oi3˜$>]l}JP-�ZJ�ԪLrٮL kjI)m&P:Y[@Z/|Wd[T!(2�`֨X7dfIY}r,&=(R/0 vs+EA"m+9*~{~VZl4x]g\$iY4{5zsk.mY5oR;uRFNigc SQic-<ɺHX3'Q9;`5:l5ڲ߽}ymA Mt1.5dqݿmP0:yzvtg~XV<i!*ToD4x.kK o%>q_ O÷,{}5Ґc"xJ3Br䵽<ֲUnaC_=d>[!CI~tTbIg\G+JVd$E,m ˨芙i*K:|iJՔi؛mPvo5,il=ʫKSwlM9n-gfEhS]uf,&MSg7Rۄ`$U5rWf3O0dz"%ٞ]6Nz9ȶV7)K'{Hq.oCefHFcj q5Rvf2H؟Ե-}eny1>HZ^0vnLnJYXIƷ#ܜ<vUX)8|׸!$iCIY2{HgJ{$}偾H:IZݴ^cj5kFIW|hgrEmU^Ko,E+x T-6LuQ,v`aėWkWwVS۵YM֮a0]yvQ[OO] .{qMZ:f #.Zt S'k3?oks[Pm]V s�nq#3뫄D 5Ygzeh=d�G7'&\ʙf~`lb9u_2RWi YSzIClkgeiiG^]qyuYcqNQ荌˵ mh+|'\4 sNU<$'c-b[c6EF�~PK7{@Fy 즾| RWe Yö֫ 2ux(4d{X&mj;QSr I꾵c 6dC6#g8008OM {'?M#*MS λ덱LS!EjD"xfba[>D#5jxaZiّZ֨!<|@ %}i+m=:uHT>ϭ $zJum?,Sz]ER6ۜm֧*5+a{9dTe\m|SNjSrqyZmVjnWC-ҙJ r4 H!u_>LMNnŲY;9l+eY<(ѧxj{%PtZNy4jZ 'ZJ؛T}̻&Eɔ&bU\2u7$5*oPģxd ybgna-s JÑ9z=F�LgWXC%\@qV|yҦ1x?vZʭ͕6T֡RcMoI3Ҕoj1zٯFֳ&iڳ,zNI)F3Pג ԰!zlG_["ZhJ9Gi ":l\ o Vs$%EvWAE}].V1Ű[IK(/\J6ě8 eمވ 0{EGl;n33X " PBf�z1Aj4w1'd  HTP~/stUW%|B[PM*7(|yrY ?&3ꛍ%Tɴf7D~ver҃訚A[sSuR 1mUE-5* &5)E&0L+tN5 ( ;{v=c=bӧjyJG@c9ȎU>`ް3 FA=H3hqU7o]y]4ːFki*XI;3s%'1unZv\jWiyRmQfYRT0C5-QZV֖*ںŠ }r 4{wӳ\rV;gkDG`S\7.P=K%r\M@NӪ/Z_jҖc$_PUH ox>L|yf +a )dpF^#[j6 \9,pI~rPhnE^A bL ѲN;:Zߡ 5Dzcۺ+M9nN@* Ae)ꕲ^P h޾xu>#=nnJuob`щ:BܢܑJQ&_Fn^ #Ejf58Pd|mWPN>-TV�Ntne3kK{+bD:0Ƣhtq36v|v>�Od5zM_* 2uRэ zǯ_hEy+m%W^2ԕCʵGhBQ`[rjnZb*3fב{8Rm1lS76y{}Jr^5ɛdS⼵ a6eCNkJcOJb[?]NO ؓuq3PHj ;;ڀ;0YbK E C"Eݪ^�z~"ī[X<u! 92bzTֵ/cr\GXUF*Li7&CG!mј}-g#GH-%@aw/ms݀fbK1%$gw1'fiF'^;P��� ��UU�z� ̦)멱+[eWf2 65^h܂RmzLQJu/m9릔 d.9ؔI=r'hҸJWB6OsH r)Y+tIy+앲)_dB-P0d@@.$NO3OJSSvYtngRRA<`grVhdZ[<bfvDfĎc-Z6 LuM3#M}-1 #kI  A l09LF7! 'v P Ue��U Mg}u԰v6*sԆVBJ7S܅bRD#4Us("=$Ȥ;db*bVlr6̼.edY/d:-91G\e>ʗn[&|!i=Ԗ&VvR\LR4)I+.wt$w5YzU'=KԢ;z(NԘe/� L;Q(f �cֲֿiqḟgfʭF(S^9q x\Wko 9ok۬̉Cco] "B͝RBELCPnbuOCEAF|jMĤ.kr|>O�NBiPlZ >h{UR]O{өvs8JL?JϧBQNSt3Z"21Ʀhx́,9V5vkVS$y{6]iVJFc]}^)h?G@; .'x*G M,`ԕώm2_؛\zoͰ`EsOHTZ~*[OjV6JJF@褯DdRL2"u/F24%#&OHFcqSۢ5 jCQVH1)bLM9;Y{ks N>VouM׏2Rgh5a 9șZdϫ;%NQD'np5BBI(']4\\Z7Ojս<:ӥ(;^u* "2(T" Q �AaYRT* 7QV*) ]P +㞚l^/ -DMUkt=Fo38͞�2I=:{UPu$DPШ**����Nij1�6f%Y$I8�MYX` +Ld!>#,W0pT.U%߻3Kr3*5b{*Rw*ee 7  6*YS#Rz*fA B h]Hã�ǭ>T)c8@<[ZB᭍ElK[tRP{!q H.F[lZrl=/Nm*ꧭ?esm g 2Wf{ JVvd/.g2n,=JRu.׸zzl:=)l;fҤ"btڽ$<9ɢӧbEHUd017/D,2{ K$xbyJ&&ZvMvΙθ*3ŅPe<iJ5R&4yoep:*dsf#W3P1ǷS$0s@�U!PCbX}'%ORK/BIɆaA A>ϊ+�"ӧNP�2׏DvT¸lh)a2D_dDأMf&j ,2kMҽ[E�^6tzS%\7W(1OυF`f]F\V` *v{Bi3#3c2PFa}g.WE}DZUzEW�0V/NLcOZTl+XA"uY/Rr൲(҉R쓦eY~K]2g}1O:NuEj/:E+_?^|GC`iD \N2K;[(I%҄ܒ];"v7ҽiP�It;\ 15z޼YV$Y^ϖ<2l&H#KWK 6rhbgZ)9&⃢ EKTc*s+tL~S c,j^AS8q^ffIeX+%PPД!U:(�(*X uVOҬGBLU |LWli9)t48H:#*LmM"ۛ}BQ ]@Gji�񷎲ntA CVAq]hiiOhF͍rVym 1t;{zӭ-6wNխ)ZҊCu[{^sI)hxiONLuO{Ƴɷhu]!=2.1nɔ8'x׼dn5U^otC'Nda$3hX`>&Ri.ҖM1Hٷ1<VNZPuy u Cjhޝ~V%qڽ�:YtD"TQT{*1|J&tDZ/-U,tR24Kb6 <lBd(9N&'M"iJmrjZɾyCُU%މ# ڋC''*t5?zNI}٠0=}9x#gCB=i/V>O �fO7(-x?^'׻׀� `�����1&5ϺraO"&5ϺraO!fmw1o?JP:u@Y@3r<MEzJ ۲:nPgx}u+f'"L֣ 3X;o^Y ճ~>]>9T.HOY{oꔕu_fFHK_b{$LcTqill&kc�{C͈gmxpvM} g +-tcj˚۝(տdy`tZb@=5ѳԲJVһi٩q~�M#XHPJDG랯,J"[<#K1427 Y$D{Mlebɱ[Y9,l:a$.*2cge<Ivk/e{­>e PaxDE/NF$V;U:oqW=nwǩ4ԉ{Oh{SM>RJEɻG rSV;.SLw6>5ɜ"/OXL!6`yo՚J硌kw3T(\vPE/G ЋU]SZ𬵍r._WJkg2]G.<Ԗe!nJDEx|/N�Hv[J0ٙax[pa|-k;iiFH< yNHMWt=A}jlSQ/]YKU8ZQH~R4q#1\yM 4e+.u3)l[Lř#ڗH 2N5xDE-n~CѬ>ٮvv*} By9YZ} Q$Lu'RKԓԛNN5xDE#=�_wӚ?w�{;S^x|D^?_+!=�_w9}~_;NN5xDE {u~/Ӛ?w�{;S^x|D^?_+!=�_w9}~_;NN5xDE {u~/Ӛ?w�{;S^x|D^?_+!=�_w9}~_;NN5xDE {u~/Ӛ?w�{;S^x|D^?_+!=�_w9}~_;NN5xDE {u~/Ӛ?w�{E>E}sן^;߶&rV_[}~νͽu@�:�؇'BΊzz�?�6cGsX���c���0���c��U"4#�x&yKj>q/of-6O}FvD߳QE-+sm&_w5`4R[Vo<o^6RfQ+9;25rSt1ƒ%ʰXF᫳]{hcg@k SL-U*Ŵۦ+&pJ$ůCWgf(Zp_oM mh7izjGjq}(j7 jX-{v3&HcaO']iFX[k.d'L-&7ԒwFg| !6<}s .WVŧwsQHK9g;9H#42: b<Ŷd_xԞOz-Q\ɩidQ./G/k=͇\/;/LQ6pVuv|725<6%Q]л65<:=I,.0ϫI PRycԮNLBzָ?w,9]y"ioI ᚦqF{vK7Wխӳ&zovDZҾu^]7b;uem6kz~c 1.i ZhQ긃X8lP45jZs+7Mկ-hMjkʼIfӚ'tΣe)q<Fy3&YaeG NمL5\.'< !s:G]�Ɠ"4n}N9S&fMV2Wg-ڣPtۿErVU\iꯍ;Y1-cV6uţĕ2a16FTE娙tm7QӅ;TbVԖ5 ZK_Qׅfո20P1~T?."vɒ\lRCBˣu01t޲dʬ?DN*٥ZȞ/?FUO\uuo0آ2vHombʧonچtՓ $jfK){%^&)d Y Rt1Ҝv5Z}ku>8wٰ8"뭦U>uM]d~HZ-F*Y=Q6EuZ{/|2-Ѡ/2>e,dő( N^1#&DpWJ;Yd&t :d(ØlfQa|&8okOեkGneZW֛PVkIηbhٶT]wm.Ai-YmlAo<UAimEVH}Ry[ lr6}UkPSD/E7m<*r_:<Ir_ uJ",2L_G'rI䅂G71$iۋ)<?y;ҩP=Ꚗ c+^ [;V\;lɉs֧ȝ]88!KQ|Emʈ*jSc !@eƗY{\miiIW=ZdD;=b~@@<!8-|ViQ0zR)s:^+x!}AK-L:?" QQR|)Ka 7Z�YrI M8SKr*($ɣƺS.-:6FIFPQ*k$uO8Gc3fa YO2F;2DeմɮmS`–4Z°#khRzBb8S61k#]mZdq><=qadG'԰]2.jtb$҃ k`6֔lV#4m1=RӢ=|óIO9әA2$ſjNφ-vNF d+nKv:`zN:)=mYNZlXFViq4rb= xV&bҔgnMTOct v !g[.Q)~obMiL&RfV&0}eKѤNVTq=zIFxE?k-'nhq5qHwEOl3%ܶM Sxkn 4T9i/q t馘\],A;ze{"ۏ2Hۗ3f#_WgltKsG7F庲F慪V+IٓV n=ʆ:-c-r _T͎`p w|gZ''˔ifIq[ ư>'[^(eCv=*Jw|eXr箐jyKDBךTwxxYm3]<-q9"9M 8_KFK{#ͶEf{FISw`8@UIsZ)冮kX0faeZwCBէ޺(Sli,s~M+\sú~˷Aآ,5] wC0]K08{pg,U]X&ӕ_&DUf KRyRJFØ]kZ[1N-= Vʉw\IuvSH*5Wm({KL »EM@a[Ixryegk=%H ٗ0Y\.ܬI6e_ЎV&bO(FVAOugM}˒^N<֗!~P%^=2Y*DgU&m%c  a>ekCxr2rN"cX\y Ԯegf3'|bҒ:Hн375289{nݤ2ҘVj=ʑv.r\Dx_(eۜOgC8_I>9œVޣQ2VF-ݬgJk"` 7ÚXV8G]p45[[ì5ơLQ4946MTR!]}֥b2A>Pс^CgVZI>��c1� `���c>A<p>A<2k5_T퍳{��B)?J?_�,=߼uxdފ^G_?g/vYOB?ӧ�\vWplȤV&w5o-i\zTTJɝ1=:} $4ߋH»E$yplqogH#së%Y]+/oW9Fui&;w4jAV Dy~ֲE9')"$ %xM!lѬ{k<Sf{l߅C{D9h/Fq\(ٜ=Co^.+5ٛ`(Uq<7/z:{pj g_&3d?NZ@.ڝ}\1qH4icCޱ; +Yő fQɄ!L&IّN 1Jl'U4oF:-*ie0EY$к5'c#S@FbN=*v< -v\cgVIsw#Vn{|ʊr�Ne:[]/781QqS N؞oYCT-EPŕ'NZ@.ڝ}\(?$ɈUF{nL`Š3M {o_b==23DZ{%)JZdl,P�o Ԧ'k.<w5oSǞ/o\."_'9^VbJ:6*1RaT+<^N'LoՠGP%e܋;+�T6QR;S/˃v~- _c㿗 A5*K cJ)Q! 8U< #%ɧW6^SjL]&Էu;&.'vb5hkc)Y?Q^znmo`#һ\9L uTyY7аBݝFk+"@gp;HէpOqSQ, ANLwt=tVGjw>;p~Ť |wGrΗui4k%b#e:9,n !qp#rؑkx\:IUe[DcN]Uw0d$ij&[b*[4u[֯bѸHNT eNİm_Lrbk M%ffWGmRF>o2&G x#M<cSHEdtu~% ͒�;i?Gjw>;pJjgDD z-kU=ZXJGYȎ_\ȹ֕Ĩ'f:iZ<)-iW6Mݠi%;$91DpT7*{ej-~0ݩ<g nSԙDSbscҴ%B7Xx3V^ɉC9hCqN/ڝ}\;iV_Էu;&.'vb5hkc)Y?Q^znmo`#һ\9L uTyQFX$J0yܬ 8rV%nzUF؉ x# *k:4V$73(Xór;*מMPE'JpNʹ<'qEuZ$#ժ^9YE%y$nN!@+_||Jᑄ= 29+KoYܽQ}qBD)TO};S/ˆJ2ARbo~)oGl b)MngC_=,dҦv%BE.h)9N71 Bܯ*ಆ hn5B)&Rh=:'^'=FRJ#UBת(ڝ}\;i^ #k~S3N/ O|(ڝ}\;i^ 7?|N/ O|(ڝ}\;i^ 7?|N/ O|(ڝ}\;i^ 7?|N/ O|(ڝ}\;i^ 7?|N/ O|(ޝg�H?VCa LCTwX#*L؍zz$$DȵV(Ly{{YY1 $7uw{%3�P{㖆ԇڽ(kPH � �+9kkF(;褩=:-s1�SF{tkU(}�C=dYת����W`�����1� `�����1� `�����1� `�����1� `�����1&5ϺraO"&5ϺraO! j�.~MX;}�&q/�m�ƹ6cO\eKE"ߡIZI)aic#TFcMNvؽz-.jY^vݾfQ1jY#α`VޥVIEqƨԝPA:A nۍsjPCrףS{fz=h#PApO OJ+АD5e 2GzEA_+bue YV諌?D^DFbI ͭŒW:Xΐ9OLhfCLˮ^cM nn&1SWԕרƥ:E U'LJyRuk4EYv.{˟w6/M|W{u#* uAz v'hͧT, a<fX\ 1DHcnxIT/8iXL$׫HG'MKޅ;MW*zOF,hJx)Ҹ4) jI\T}֧NA;zqwUy[V *[k=\׻kfkz(j3i2S]�I/~^x'R *YbZGh[cɮ\sҪ2uUsĖ3Lk$ v!ZE&i)ͱg;d2)GbI+4oJ&-ngX~`э;iKcl ڤR4+LQrRukOB} (}**=:CԌ^=p� ȳn4>n`AE'yatJ6zlNp[`8=_^`,n:`|uuT#*DW-ZomV}7nܧN:"tukJFG$lK@؈!+%n͢ETg!Y:�2iNHNS쳔bتX\Pg$4z RĒU^rգ*v_1<ҷvBVeֲj:=إː=.e[.yCNI&5=<Xl؞8HS cYɈSV0i գZVPseJCz1AIQj�S�.Ka X_Զ]/D3D*G>A?*1($f"QXJ5M&fRId2>[Y&tcN{fR1BG;T n~ܔ[c\6> C4PY`|rsYrUdhd[IڹiaM[[vHѮ8Pv 2ɃuĦ,ؽ$I=IT UE#j{l#،ZTnepMbV N#O#j'F#,gsirqrP%rp�L7N,G_igbZG,Y0�zz( TtTUU U@�� fp���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY5b~ok??pO؏�8��nU7pq vU7pq y[�U8?^_$p�L��c���0���c���0���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY5b~ok??pO؏�8��nU7pq vU7pq y[�U8?^_$p�L��c���0���c���0���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY5b~ok??pO؏�8��nU7pq vU7pq y[�U8?^_$p�L��c���0���c���0���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY5b~ok??pO؏�8��nU7pq vU7pq y[�U8?^_$p�L��c���0���c���0���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY5b~ok??pO؏�8��nU7pq vU7pq y[�U8?^_$p�L��c���0���c���0���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY5b~ok??pO؏�8��nU7pq vU7pq y[�U8?^_$p�L��c���0���c���0���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY5b~ok??pO؏�8��nU7pq vU7pq y[�U8?^_$p�L��c���0���c���0���c���3埸c�FNgg'-Q^_5O\O�E`6ӏKGN>yz OW��*˰���c���0���c���0���c���0���c���0���c��w9?0'9?0'Z{YY9bIGs? ꒛5{�?{ {f �ש�lҪJ0�nۍQZFEsbG00=Ȥm iWU)wX9afmdw6k_Q�/JOi:r;:&ˣёEYYHee$0 AṎ&\G*rt>;Ftk#Ѫ]Xe` rSw6k_Qý-Z~f9(?|~/OG-?z[fu<;5ۨaNkS |G7�|Sw6k_Qý-Z~f(?|~/OG-?z[fu<;5ۨaNkS |G7�|Sw6k_Qý-Z~f(?|~/OG-?z[fu<;5ۨaNkS |G7�|Sw6k_Qý-Z~f(?|~/OG-?z[fu<;5ۨaNkS |G7�|Sw6k_Qý-Z~f(?|~/OG-?z[fu<;5ۨaNkS |G7�|Sw6k_Qý-Z~f(?|~/OG-׻9'fkrxVS[9*%S9>=8Q[h{gAz[fut/6'G&v5dkֶ2ۗ{i~Kj~+,E^{e= ~Q!|/_J֘kG.;) J?fWkg( 1΁XkպV $7uw{%1�XjPpKe�y7zggv_a[ ˻#zDLJb8�B1Z4Q _[[RFi듙ҮgrS#Cn&w/N9khj/1M[fz"v�B�T4Y[f7D,$UԎ`ю]=Zj>=b}1~>�G#'$:MN�����0���c���0���c���0���c���0���c���0�q1}ӓy1}ӓy e>Sgx��?x/}�uD0e=Q.l Lmحss3~�}E5s�`3FjI]M)JʅQhQdunIte} 0Tr4ͶemAӟ35 p��c{?˦s)Q(I=I*>�/vkt�)K~}$l�o羒 =9}~*}~./vkt�)K~}$=rqLE8.iuatt;-gpcIJN!i/yRyev9}~'?~>}߯vk<9/s>s>7�~}�OGïhFNC/r1cw1czsOA~t|:_ʚvk<9/s>s>7�~}�OGïhFNC/r1cw1czsOA~t|:_ʚvk<9/s>s>7�~}�OGïhFNC/r1cw1czsOA~t|:_ʚvk<9/s>s>7�~}�OGïhFNC/r1cw1czsOA~t|:_ʚvk<9/s>s>7�~}�OGïhFNC/r1cw1czsOA~t|:_ʠ"G�g~o=oF(\g1�?OWǽ5/m*:}_L؇5V=`~GgMq?@Dz� `�����1� `�����1� `�����1� `�����1� `�����1&5ϺraO"&5ϺraO!qs! G  >�ޟ_%\@MX,RmV65&?H#j.-F(E'CM3>lLF�:�Z$ m8`jdY JwAUm "eu-,>N㫻vıCC"ؓW:ll<6jdyFtWfU*I!#(B~r6`jVj([\Y d]j͗6c}ZL8H'Wd{I͑DD -t\=y(w޿k8KUNJmhZq;qڑR&Ʈ%46^c%Vܙ0ǣ ÓCX6>b:n[zPñg'"VRΡRuu$0Emj(W3|e8ʥ.Z8,GItrDʇ(*gmȥ {+N3Nmo 5p#)$B[9&2C^cĕLea#~hO^ƯhUdU5Mޭr6dޅ]6 OwAͿiQ"ۧӋSuo_|n(]Or^; W#b~g; dK.͋K<ȢOLd]JsL jg9q9O�xF-P::d@`,pJ]̭*h'Nj9_FjܙbS2Q{̙Y)\�NK� lXxP.H#fvz=sEBGRI- ""VX1Ov35������1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1&5ϺraO"&5ϺraO! gbM=`s�c0 :+魅*fK5,Ds %y=)/VF L4wld}> � h? Jf޻r�?c� f <3}h�c}\\mV$m7-qB0e<"̔]Z;Ke{]\LNeT]Wf#X�YK/N*g{'0XL%7!lfXgћ.댡tBb5۾ENY^c/g]}&=]];38x?Vp,Zigvcrhj7uGn{ -/&Tv5)5N7)|yXN} u;U_ ot̐2a^RFc+}VGj*o\Uۘ{t\tPdnY> NQ5�v;����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�c\'!c\'\���o^מBCϐ,N4:/l|/=5Cr6+35"qr7V΍tC1̥EYQܷjKn)Wl(C#% ]Stfݸ%dmZܚW]r[ǣE���1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `���c>A<2����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�����1� `�������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/�������������������������������������������������������������������������0000755�0001750�0000144�00000000000�12624225533�016333� 5����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/main.py������������������������������������������������������������������0000644�0001750�0000144�00000000307�12574421673�017640� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������from app import app, db from auth import * from admin import admin from api import api from models import * from views import * admin.setup() api.setup() if __name__ == '__main__': app.run() �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/requirements.txt���������������������������������������������������������0000644�0001750�0000144�00000000060�12574421673�021622� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask werkzeug jinja2 peewee wtforms wtf-peewee ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/api.py�������������������������������������������������������������������0000644�0001750�0000144�00000001675�12574421673�017476� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������from flask_peewee.rest import RestAPI, RestResource, UserAuthentication, AdminAuthentication, RestrictOwnerResource from app import app from auth import auth from models import User, Message, Relationship user_auth = UserAuthentication(auth) admin_auth = AdminAuthentication(auth) # instantiate our api wrapper api = RestAPI(app, default_auth=user_auth) class UserResource(RestResource): exclude = ('password', 'email',) class MessageResource(RestrictOwnerResource): owner_field = 'user' include_resources = {'user': UserResource} class RelationshipResource(RestrictOwnerResource): owner_field = 'from_user' include_resources = { 'from_user': UserResource, 'to_user': UserResource, } paginate_by = None # register our models so they are exposed via /api/<model>/ api.register(User, UserResource, auth=admin_auth) api.register(Relationship, RelationshipResource) api.register(Message, MessageResource) �������������������������������������������������������������������flask-peewee-0.6.7/example/admin.py�����������������������������������������������������������������0000644�0001750�0000144�00000003654�12574421673�020014� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������import datetime from flask import request, redirect from flask_peewee.admin import Admin, ModelAdmin, AdminPanel from flask_peewee.filters import QueryFilter from app import app, db from auth import auth from models import User, Message, Note, Relationship class NotePanel(AdminPanel): template_name = 'admin/notes.html' def get_urls(self): return ( ('/create/', self.create), ) def create(self): if request.method == 'POST': if request.form.get('message'): Note.create( user=auth.get_logged_in_user(), message=request.form['message'], ) next = request.form.get('next') or self.dashboard_url() return redirect(next) def get_context(self): return { 'note_list': Note.select().order_by(Note.created_date.desc()).paginate(1, 3) } class UserStatsPanel(AdminPanel): template_name = 'admin/user_stats.html' def get_context(self): last_week = datetime.datetime.now() - datetime.timedelta(days=7) signups_this_week = User.select().where(User.join_date > last_week).count() messages_this_week = Message.select().where(Message.pub_date > last_week).count() return { 'signups': signups_this_week, 'messages': messages_this_week, } admin = Admin(app, auth, branding='Example Site') class MessageAdmin(ModelAdmin): columns = ('user', 'content', 'pub_date',) foreign_key_lookups = {'user': 'username'} filter_fields = ('user', 'content', 'pub_date', 'user__username') class NoteAdmin(ModelAdmin): columns = ('user', 'message', 'created_date',) exclude = ('created_date',) auth.register_admin(admin) admin.register(Relationship) admin.register(Message, MessageAdmin) admin.register(Note, NoteAdmin) admin.register_panel('Notes', NotePanel) admin.register_panel('User stats', UserStatsPanel) ������������������������������������������������������������������������������������flask-peewee-0.6.7/example/config.py����������������������������������������������������������������0000644�0001750�0000144�00000000325�12574421673�020161� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# config class Configuration(object): DATABASE = { 'name': 'example.db', 'engine': 'peewee.SqliteDatabase', 'check_same_thread': False, } DEBUG = True SECRET_KEY = 'shhhh' �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/app.py�������������������������������������������������������������������0000644�0001750�0000144�00000000653�12574421673�017500� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������from flask import Flask # flask-peewee bindings from flask_peewee.db import Database app = Flask(__name__) app.config.from_object('config.Configuration') db = Database(app) def create_tables(): User.create_table() Relationship.create_table() Message.create_table() Note.create_table() @app.template_filter('is_following') def is_following(from_user, to_user): return from_user.is_following(to_user) �������������������������������������������������������������������������������������flask-peewee-0.6.7/example/models.py����������������������������������������������������������������0000644�0001750�0000144�00000003527�12574421673�020206� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������from hashlib import md5 import datetime from flask_peewee.auth import BaseUser from peewee import * from app import db class User(db.Model, BaseUser): username = CharField() password = CharField() email = CharField() join_date = DateTimeField(default=datetime.datetime.now) active = BooleanField(default=True) admin = BooleanField(default=False) def __unicode__(self): return self.username def following(self): return User.select().join( Relationship, on=Relationship.to_user ).where(Relationship.from_user==self).order_by(User.username) def followers(self): return User.select().join( Relationship, on=Relationship.from_user ).where(Relationship.to_user==self).order_by(User.username) def is_following(self, user): return Relationship.select().where( Relationship.from_user==self, Relationship.to_user==user ).exists() def gravatar_url(self, size=80): return 'http://www.gravatar.com/avatar/%s?d=identicon&s=%d' % \ (md5(self.email.strip().lower().encode('utf-8')).hexdigest(), size) class Relationship(db.Model): from_user = ForeignKeyField(User, related_name='relationships') to_user = ForeignKeyField(User, related_name='related_to') def __unicode__(self): return 'Relationship from %s to %s' % (self.from_user, self.to_user) class Message(db.Model): user = ForeignKeyField(User) content = TextField() pub_date = DateTimeField(default=datetime.datetime.now) def __unicode__(self): return '%s: %s' % (self.user, self.content) class Note(db.Model): user = ForeignKeyField(User) message = TextField() status = IntegerField(choices=((1, 'live'), (2, 'deleted')), null=True) created_date = DateTimeField(default=datetime.datetime.now) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/templates/���������������������������������������������������������������0000755�0001750�0000144�00000000000�12624225533�020331� 5����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/templates/user_following.html��������������������������������������������0000644�0001750�0000144�00000000516�12574421673�024266� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{% extends "base.html" %} {% block content_title %}Following{% endblock %} {% block content %} <ul> {% for person in user.following() %} <li><a href="{{ url_for('user_detail', username=person.username) }}">{{ person.username }}</a></li> {% endfor %} </ul> {% include "includes/pagination.html" %} {% endblock %} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������flask-peewee-0.6.7/example/templates/base.html������������������������������������������������������0000644�0001750�0000144�00000001370�12574421673�022141� 0����������������������������������������������������������������������������������������������������ustar �charles�������������������������users���������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!doctype html> <title>Tweepee

Tweepee

{% if not session.logged_in %} log in join {% else %} public timeline create log out {% endif %}
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}

{% block content_title %}{% endblock %}

{% block content %}{% endblock %}
flask-peewee-0.6.7/example/templates/join.html0000644000175000001440000000100612574421673022162 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Join{% endblock %} {% block content %}
Username:
Password:
Email:

(used for gravatar)

{% endblock %} flask-peewee-0.6.7/example/templates/private_messages.html0000644000175000001440000000043512574421673024571 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Private Timeline{% endblock %} {% block content %}
    {% for message in message_list %}
  • {% include "includes/message.html" %}
  • {% endfor %}
{% include "includes/pagination.html" %} {% endblock %} flask-peewee-0.6.7/example/templates/user_list.html0000644000175000001440000000050312574421673023235 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Users{% endblock %} {% block content %} {% include "includes/pagination.html" %} {% endblock %} flask-peewee-0.6.7/example/templates/edit.html0000644000175000001440000000056012574421673022154 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Edit message{% endblock %} {% block content %}
Message:
{% endblock %} flask-peewee-0.6.7/example/templates/create.html0000644000175000001440000000050212574421673022466 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Create{% endblock %} {% block content %}
Message:
{% endblock %} flask-peewee-0.6.7/example/templates/public_messages.html0000644000175000001440000000043412574421673024374 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Public Timeline{% endblock %} {% block content %}
    {% for message in message_list %}
  • {% include "includes/message.html" %}
  • {% endfor %}
{% include "includes/pagination.html" %} {% endblock %} flask-peewee-0.6.7/example/templates/admin/0000755000175000001440000000000012624225533021421 5ustar charlesusers00000000000000flask-peewee-0.6.7/example/templates/admin/notes.html0000644000175000001440000000066612574421673023456 0ustar charlesusers00000000000000{% extends "admin/panels/default.html" %} {% block panel_content %} {% for note in note_list %}

{{ note.user.username }}: {{ note.message }}

{% endfor %}

{% endblock %} flask-peewee-0.6.7/example/templates/admin/user_stats.html0000644000175000001440000000025412574421673024513 0ustar charlesusers00000000000000{% extends "admin/panels/default.html" %} {% block panel_content %}

New users this week: {{ signups }}

Messages this week: {{ messages }}

{% endblock %} flask-peewee-0.6.7/example/templates/homepage.html0000644000175000001440000000021112574421673023005 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Home{% endblock %} {% block content %}

Welcome to the site!

{% endblock %} flask-peewee-0.6.7/example/templates/includes/0000755000175000001440000000000012624225533022137 5ustar charlesusers00000000000000flask-peewee-0.6.7/example/templates/includes/pagination.html0000644000175000001440000000031312574421673025162 0ustar charlesusers00000000000000{% if page > 1 %} {% endif %} {% if pagination.get_pages() > page %} {% endif %} flask-peewee-0.6.7/example/templates/includes/message.html0000644000175000001440000000051412574421673024460 0ustar charlesusers00000000000000{% if user and message.user == user %}edit{% endif %}

{{ message.content|urlize }}

flask-peewee-0.6.7/example/templates/user_detail.html0000644000175000001440000000160212574421673023525 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Message from {{ person.username }}{% endblock %} {% block content %} {% if user %} {% if person.username != user.username %} {% if user|is_following(person) %}
{% else %}
{% endif %} {% endif %} {% else %}

Log-in to follow

{% endif %}
    {% for message in message_list %}
  • {% include "includes/message.html" %}
  • {% endfor %}
{% include "includes/pagination.html" %} {% endblock %} flask-peewee-0.6.7/example/templates/user_followers.html0000644000175000001440000000051612574421673024302 0ustar charlesusers00000000000000{% extends "base.html" %} {% block content_title %}Followers{% endblock %} {% block content %} {% include "includes/pagination.html" %} {% endblock %} flask-peewee-0.6.7/example/views.py0000644000175000001440000001011612574421673020050 0ustar charlesusers00000000000000import datetime from flask import request, redirect, url_for, render_template, flash from flask_peewee.utils import get_object_or_404, object_list from app import app from auth import auth from models import User, Message, Relationship @app.route('/') def homepage(): if auth.get_logged_in_user(): return private_timeline() else: return public_timeline() @app.route('/private/') @auth.login_required def private_timeline(): user = auth.get_logged_in_user() messages = Message.select().where( Message.user << user.following() ).order_by(Message.pub_date.desc()) return object_list('private_messages.html', messages, 'message_list') @app.route('/public/') def public_timeline(): messages = Message.select().order_by(Message.pub_date.desc()) return object_list('public_messages.html', messages, 'message_list') @app.route('/join/', methods=['GET', 'POST']) def join(): if request.method == 'POST' and request.form['username']: try: user = User.select().where(User.username==request.form['username']).get() flash('That username is already taken') except User.DoesNotExist: user = User( username=request.form['username'], email=request.form['email'], join_date=datetime.datetime.now() ) user.set_password(request.form['password']) user.save() auth.login_user(user) return redirect(url_for('homepage')) return render_template('join.html') @app.route('/following/') @auth.login_required def following(): user = auth.get_logged_in_user() return object_list('user_following.html', user.following(), 'user_list') @app.route('/followers/') @auth.login_required def followers(): user = auth.get_logged_in_user() return object_list('user_followers.html', user.followers(), 'user_list') @app.route('/users/') def user_list(): users = User.select().order_by(User.username) return object_list('user_list.html', users, 'user_list') @app.route('/users//') def user_detail(username): user = get_object_or_404(User, User.username==username) messages = user.message_set.order_by(Message.pub_date.desc()) return object_list('user_detail.html', messages, 'message_list', person=user) @app.route('/users//follow/', methods=['POST']) @auth.login_required def user_follow(username): user = get_object_or_404(User, User.username==username) Relationship.get_or_create( from_user=auth.get_logged_in_user(), to_user=user, ) flash('You are now following %s' % user.username) return redirect(url_for('user_detail', username=user.username)) @app.route('/users//unfollow/', methods=['POST']) @auth.login_required def user_unfollow(username): user = get_object_or_404(User, User.username==username) Relationship.delete().where( Relationship.from_user==auth.get_logged_in_user(), Relationship.to_user==user, ).execute() flash('You are no longer following %s' % user.username) return redirect(url_for('user_detail', username=user.username)) @app.route('/create/', methods=['GET', 'POST']) @auth.login_required def create(): user = auth.get_logged_in_user() if request.method == 'POST' and request.form['content']: message = Message.create( user=user, content=request.form['content'], ) flash('Your message has been created') return redirect(url_for('user_detail', username=user.username)) return render_template('create.html') @app.route('/edit//', methods=['GET', 'POST']) @auth.login_required def edit(message_id): user = auth.get_logged_in_user() message = get_object_or_404(Message, Message.user==user, Message.id==message_id) if request.method == 'POST' and request.form['content']: message.content = request.form['content'] message.save() flash('Your changes were saved') return redirect(url_for('user_detail', username=user.username)) return render_template('edit.html', message=message) flask-peewee-0.6.7/example/__init__.py0000644000175000001440000000000012574421673020441 0ustar charlesusers00000000000000flask-peewee-0.6.7/example/run_example.py0000755000175000001440000000012712574421673021236 0ustar charlesusers00000000000000#!/usr/bin/env python import sys sys.path.insert(0, '..') import main main.app.run() flask-peewee-0.6.7/example/example.db0000644000175000001440000004200012574421673020300 0ustar charlesusers00000000000000SQLite format 3@ : :-$   R|vpjd^XR          AA?KAI'm an admin on this crazy site2011-09-16 18:47:17.0458847;AHey, I'm just some user2011-09-16 18:46:59.670759CSAflask and peewee, together at last!2011-09-16 18:36:15.668596 .uMtableuseruserCREATE TABLE user (username VARCHAR(255) NOT NULL, admin SMALLINT NOT NULL, id INTEGER NOT NULL PRIMARY KEY, join_date DATETIME NOT NULL, active SMALLINT NOT NULL, password VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL)>[indexuser_iduserCREATE UNIQUE INDEX user_id ON user(id)F%%OtablerelationshiprelationshipCREATE TABLE relationship (from_user_id INTEGER NOT NULL REFERENCES user (id), to_user_id INTEGER NOT NULL REFERENCES user (id), id INTEGER NOT NULL PRIMARY KEY)v?%indexrelationship_from_user_idrelationshipCREATE INDEX relationship_from_user_id ON relationship(from_user_id)p;% indexrelationship_to_user_idrelationshipCREATE INDEX relationship_to_user_id ON relationship(to_user_id)^+%{indexrelationship_idrelationshipCREATE UNIQUE INDEX relationship_id ON relationship(id) __ix3=tablemessagemessageCREATE TABLE message (content TEXT NOT NULL, pub_date DATETIME NOT NULL, user_id INTEGER NOT NULL REFERENCES user (id), id INTEGER NOT NULL PRIMARY KEY)R+mindexmessage_user_idmessage CREATE INDEX message_user_id ON message(user_id)J !gindexmessage_idmessage CREATE UNIQUE INDEX message_id ON message(id)@ ctablenotenote CREATE TABLE note (message TEXT NOT NULL, user_id INTEGER NOT NULL REFERENCES user (id), id INTEGER NOT NULL PRIMARY KEY, created_date DATETIME NOT NULL, "status" INTEGER)F %aindexnote_user_idnoteCREATE INDEX note_user_id ON note(user_id)> [indexnote_idnoteCREATE UNIQUE INDEX note_id ON note(id)   qZ}Ahey everyone, keep an eye on "coleifer", may be spam bot2011-09-16 18:35:36.06774433AHere's another note2011-10-29 17:48:11.911884Z   RFb6 Z.~R*A OOOOOO2012-03-13 02:49:31.992156*A NNNNNN2012-03-13 02:49:31.990125*A MMMMMM2012-03-13 02:49:31.987221*A LLLLLL2012-03-13 02:49:31.984260*A KKKKKK2012-03-13 02:49:31.981245* A JJJJJJ2012-03-13 02:49:31.979428* A IIIIII2012-03-13 02:49:31.977035* A HHHHHH2012-03-13 02:49:31.972886* A GGGGGG2012-03-13 02:49:31.970255* A FFFFFF2012-03-13 02:49:31.967091*A EEEEEE2012-03-13 02:49:31.963988*A DDDDDD2012-03-13 02:49:31.961231*A CCCCCC2012-03-13 02:49:31.958624*A BBBBBB2012-03-13 02:49:31.955460*A AAAAAA2012-03-13 02:49:31.950733]3i)user2011-09-16 18:46:49778f7$4093f52a85615a6450eb538ea799587df8eb0b97user@user.usere3i1coleifer2011-09-16 18:35:56e1ef7$dd4949985c4b168136b45a84d5d9770da8951243coleifer@gmail.comP3i admin2011-09-16 18:34:493af90$5e3bc2fc0348f13a4866556a1cbac20e222e8610 |P$tH*A ZZZZZZ2012-03-13 02:49:32.030799*A YYYYYY2012-03-13 02:49:32.027586*A XXXXXX2012-03-13 02:49:32.024213*A WWWWWW2012-03-13 02:49:32.021126*A VVVVVV2012-03-13 02:49:32.015616*A UUUUUU2012-03-13 02:49:32.013264*A TTTTTT2012-03-13 02:49:32.010231*A SSSSSS2012-03-13 02:49:32.007132*A RRRRRR2012-03-13 02:49:32.004115*A QQQQQQ2012-03-13 02:49:32.001454*A PPPPPP2012-03-13 02:49:31.998571flask-peewee-0.6.7/example/auth.py0000644000175000001440000000017412574421673017657 0ustar charlesusers00000000000000from flask_peewee.auth import Auth from app import app, db from models import User auth = Auth(app, db, user_model=User) flask-peewee-0.6.7/example/static/0000755000175000001440000000000012624225533017622 5ustar charlesusers00000000000000flask-peewee-0.6.7/example/static/style.css0000644000175000001440000000152112574421673021502 0ustar charlesusers00000000000000body { font-family: sans-serif; background: #eee; } a, h1, h2 { color: #377BA8; } h1, h2 { font-family: 'Georgia', serif; margin: 0; } h1 { border-bottom: 2px solid #eee; } h2 { font-size: 1.2em; } .page { margin: 2em auto; width: 35em; border: 5px solid #ccc; padding: 0.8em; background: white; } .page ul { list-style-type: none; } .page li { clear: both; } .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; margin-bottom: 1em; background: #fafafa; } .flash { background: #CEE5F5; padding: 0.5em; border: 1px solid #AACBE2; } .avatar { display: block; float: left; margin: 0 10px 0 0; } .message-content { min-height: 80px; } .message-edit { float: right; font-size: 0.6em; } flask-peewee-0.6.7/README.rst0000644000175000001440000000605212574421673016401 0ustar charlesusers00000000000000This package is in maintenance-only mode! ========================================= I'm sorry to announce that flask-peewee will now be in maintenance-only mode. This decision is motivated by a number of factors: * `Flask-Admin `_ provides a superior admin interface and has support for peewee models. * `Flask-Security `_ and `Flask-Login `_ both provide authentication functionality, and work well with Peewee. * Most importantly, though, I do not find myself wanting to work on flask-peewee. I plan on rewriting the ``Database`` and ``REST API`` portions of flask-peewee and repackaging them as a new library, but flask-peewee as it stands currently will be in maintenance-only mode. flask-peewee ============ provides a layer of integration between the `flask `_ web framework and the `peewee orm `_. batteries included: * admin interface * authentication * rest api requirements: * `flask `_ * `peewee `_ * `wtforms `_ * `wtf-peewee `_ * python 2.5 or greater check out the `documentation `_. admin interface --------------- influenced heavily by the `django `_ admin, provides easy create/edit/delete functionality for your project's models. .. image:: http://i.imgur.com/EtzdO.jpg rest api -------- influenced by `tastypie `_, provides a way to expose a RESTful interface for your project's models. :: curl localhost:5000/api/user/ { "meta": { "model": "user", "next": "", "page": 1, "previous": "" }, "objects": [ { "username": "admin", "admin": true, "email": "", "join_date": "2011-09-16 18:34:49", "active": true, "id": 1 }, { "username": "coleifer", "admin": false, "email": "coleifer@gmail.com", "join_date": "2011-09-16 18:35:56", "active": true, "id": 2 } ] } installing ---------- I recommend installing in a virtualenv. to get started:: # create a new virtualenv virtualenv --no-site-packages project cd project/ source bin/activate # install this project (will install dependencies as well) pip install flask-peewee example app ----------- the project ships with an example app, which is a silly twitter clone. to start the example app, ``cd`` into the "example" directory and execute the ``run_example.py`` script:: cd example/ python run_example.py if you would like to test out the admin area, log in as "admin/admin" and navigate to: http://127.0.0.1:5000/admin/ you can check out the REST api at the following url: http://127.0.0.1:5000/api/message/ flask-peewee-0.6.7/flask_peewee.egg-info/0000755000175000001440000000000012624225533021024 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee.egg-info/not-zip-safe0000644000175000001440000000000112624225533023252 0ustar charlesusers00000000000000 flask-peewee-0.6.7/flask_peewee.egg-info/dependency_links.txt0000644000175000001440000000000112624225533025072 0ustar charlesusers00000000000000 flask-peewee-0.6.7/flask_peewee.egg-info/requires.txt0000644000175000001440000000006712624225533023427 0ustar charlesusers00000000000000Flask werkzeug jinja2 peewee>=2.7.3 wtforms wtf-peewee flask-peewee-0.6.7/flask_peewee.egg-info/top_level.txt0000644000175000001440000000002512624225533023553 0ustar charlesusers00000000000000example flask_peewee flask-peewee-0.6.7/flask_peewee.egg-info/SOURCES.txt0000644000175000001440000001111012624225533022702 0ustar charlesusers00000000000000LICENSE MANIFEST.in README.rst setup.py docs/Makefile docs/admin.rst docs/api.rst docs/auth.rst docs/conf.py docs/database.rst docs/example.rst docs/fp-admin-btn-form.png docs/fp-admin-btn.png docs/fp-admin-filter.png docs/fp-admin-modal.png docs/fp-admin.jpg docs/fp-app.jpg docs/fp-getting-started.jpg docs/fp-message-admin-2.jpg docs/fp-message-admin.jpg docs/fp-model-admin.jpg docs/fp-note-admin-2.jpg docs/fp-note-admin.jpg docs/fp-note-panel-2.jpg docs/fp-note-panel.jpg docs/fp-panels.jpg docs/getting-started.rst docs/gevent.rst docs/index.rst docs/installation.rst docs/rest-api.rst docs/utils.rst docs/_static/peewee.jpg docs/_themes/flask/layout.html docs/_themes/flask/relations.html docs/_themes/flask/theme.conf docs/_themes/flask/static/flasky.css_t docs/_themes/flask/static/small_flask.css example/__init__.py example/admin.py example/api.py example/app.py example/auth.py example/config.py example/example.db example/main.py example/models.py example/requirements.txt example/run_example.py example/views.py example/static/style.css example/templates/base.html example/templates/create.html example/templates/edit.html example/templates/homepage.html example/templates/join.html example/templates/private_messages.html example/templates/public_messages.html example/templates/user_detail.html example/templates/user_followers.html example/templates/user_following.html example/templates/user_list.html example/templates/admin/notes.html example/templates/admin/user_stats.html example/templates/includes/message.html example/templates/includes/pagination.html flask_peewee/__init__.py flask_peewee/__init__.pyc flask_peewee/_compat.py flask_peewee/_compat.pyc flask_peewee/admin.py flask_peewee/admin.pyc flask_peewee/auth.py flask_peewee/auth.pyc flask_peewee/db.py flask_peewee/db.pyc flask_peewee/exceptions.py flask_peewee/exceptions.pyc flask_peewee/filters.py flask_peewee/filters.pyc flask_peewee/forms.py flask_peewee/forms.pyc flask_peewee/rest.py flask_peewee/rest.pyc flask_peewee/serializer.py flask_peewee/serializer.pyc flask_peewee/utils.py flask_peewee/utils.pyc flask_peewee.egg-info/PKG-INFO flask_peewee.egg-info/SOURCES.txt flask_peewee.egg-info/dependency_links.txt flask_peewee.egg-info/not-zip-safe flask_peewee.egg-info/requires.txt flask_peewee.egg-info/top_level.txt flask_peewee/static/css/admin.css flask_peewee/static/css/bootstrap-responsive.css flask_peewee/static/css/bootstrap-responsive.min.css flask_peewee/static/css/bootstrap.css flask_peewee/static/css/bootstrap.min.css flask_peewee/static/css/bootstrap.min.responsive.css flask_peewee/static/css/chosen-sprite.png flask_peewee/static/css/chosen.css flask_peewee/static/css/datepicker.css flask_peewee/static/img/glyphicons-halflings-white.png flask_peewee/static/img/glyphicons-halflings.png flask_peewee/static/js/admin.js flask_peewee/static/js/ajax-chosen.min.js flask_peewee/static/js/bootstrap-datepicker.js flask_peewee/static/js/bootstrap.js flask_peewee/static/js/bootstrap.min.js flask_peewee/static/js/chosen.jquery.min.js flask_peewee/static/js/events.js flask_peewee/static/js/jquery.min.js flask_peewee/static/js/modernizr-1.5.min.js flask_peewee/templates/base.html flask_peewee/templates/admin/base.html flask_peewee/templates/admin/index.html flask_peewee/templates/admin/includes/filter_dropdown.html flask_peewee/templates/admin/includes/filter_widgets.html flask_peewee/templates/admin/includes/form_raw_id.html flask_peewee/templates/admin/includes/pagination.html flask_peewee/templates/admin/models/add.html flask_peewee/templates/admin/models/base.html flask_peewee/templates/admin/models/base_filters.html flask_peewee/templates/admin/models/base_forms.html flask_peewee/templates/admin/models/delete.html flask_peewee/templates/admin/models/edit.html flask_peewee/templates/admin/models/export.html flask_peewee/templates/admin/models/index.html flask_peewee/templates/admin/panels/base.html flask_peewee/templates/admin/panels/default.html flask_peewee/templates/auth/login.html flask_peewee/templates/macros/forms.html flask_peewee/tests/__init__.py flask_peewee/tests/__init__.pyc flask_peewee/tests/admin.py flask_peewee/tests/admin.pyc flask_peewee/tests/auth.py flask_peewee/tests/auth.pyc flask_peewee/tests/base.py flask_peewee/tests/base.pyc flask_peewee/tests/rest.py flask_peewee/tests/rest.pyc flask_peewee/tests/serializer.py flask_peewee/tests/serializer.pyc flask_peewee/tests/test_app.py flask_peewee/tests/test_app.pyc flask_peewee/tests/test_config.py flask_peewee/tests/test_config.pyc flask_peewee/tests/utils.py flask_peewee/tests/utils.pyc flask_peewee/tests/templates/base.html flask_peewee/tests/templates/admin/notes.htmlflask-peewee-0.6.7/flask_peewee.egg-info/PKG-INFO0000644000175000001440000000114412624225533022121 0ustar charlesusers00000000000000Metadata-Version: 1.1 Name: flask-peewee Version: 0.6.7 Summary: Peewee integration for flask Home-page: http://github.com/coleifer/flask-peewee/ Author: Charles Leifer Author-email: coleifer@gmail.com License: BSD Description: UNKNOWN Platform: any Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules flask-peewee-0.6.7/setup.cfg0000644000175000001440000000007312624225533016521 0ustar charlesusers00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 flask-peewee-0.6.7/flask_peewee/0000755000175000001440000000000012624225533017332 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/rest.py0000644000175000001440000004171712624225413020670 0ustar charlesusers00000000000000import functools import operator try: import simplejson as json except ImportError: import json from flask import Blueprint from flask import Response from flask import abort from flask import g from flask import redirect from flask import request from flask import session from flask import url_for from peewee import * from peewee import DJANGO_MAP from flask_peewee.filters import make_field_tree from flask_peewee.serializer import Deserializer from flask_peewee.serializer import Serializer from flask_peewee.utils import PaginatedQuery from flask_peewee.utils import get_object_or_404 from flask_peewee.utils import slugify from flask_peewee._compat import reduce class Authentication(object): def __init__(self, protected_methods=None): if protected_methods is None: protected_methods = ['POST', 'PUT', 'DELETE'] self.protected_methods = protected_methods def authorize(self): if request.method in self.protected_methods: return False return True class APIKeyAuthentication(Authentication): """ Requires a model that has at least two fields, "key" and "secret", which will be searched for when authing a request. """ key_field = 'key' secret_field = 'secret' def __init__(self, model, protected_methods=None): super(APIKeyAuthentication, self).__init__(protected_methods) self.model = model self._key_field = model._meta.fields[self.key_field] self._secret_field = model._meta.fields[self.secret_field] def get_query(self): return self.model.select() def get_key(self, k, s): try: return self.get_query().where( self._key_field==k, self._secret_field==s ).get() except self.model.DoesNotExist: pass def get_key_secret(self): for search in [request.args, request.headers, request.form]: if 'key' in search and 'secret' in search: return search['key'], search['secret'] return None, None def authorize(self): g.api_key = None if request.method not in self.protected_methods: return True key, secret = self.get_key_secret() if key or secret: g.api_key = self.get_key(key, secret) return g.api_key class UserAuthentication(Authentication): def __init__(self, auth, protected_methods=None): super(UserAuthentication, self).__init__(protected_methods) self.auth = auth def authorize(self): g.user = None if request.method not in self.protected_methods: return True basic_auth = request.authorization if not basic_auth: return False g.user = self.auth.authenticate(basic_auth.username, basic_auth.password) return g.user class AdminAuthentication(UserAuthentication): def verify_user(self, user): return user.admin def authorize(self): res = super(AdminAuthentication, self).authorize() if res and g.user: return self.verify_user(g.user) return res class RestResource(object): paginate_by = 20 # serializing: dictionary of model -> field names to restrict output fields = None exclude = None # exclude certian fields from being exposed as filters -- for related fields # use "__" notation, e.g. user__password filter_exclude = None filter_fields = None filter_recursive = True # mapping of field name to resource class include_resources = None # delete behavior delete_recursive = True def __init__(self, rest_api, model, authentication, allowed_methods=None): self.api = rest_api self.model = model self.pk = model._meta.primary_key self.authentication = authentication self.allowed_methods = allowed_methods or ['GET', 'POST', 'PUT', 'DELETE'] self._fields = {self.model: self.fields or self.model._meta.sorted_field_names} if self.exclude: self._exclude = {self.model: self.exclude} else: self._exclude = {} self._filter_fields = self.filter_fields or list(self.model._meta.sorted_field_names) self._filter_exclude = self.filter_exclude or [] self._resources = {} # recurse into nested resources if self.include_resources: for field_name, resource in self.include_resources.items(): field_obj = self.model._meta.fields[field_name] resource_obj = resource(self.api, field_obj.rel_model, self.authentication, self.allowed_methods) self._resources[field_name] = resource_obj self._fields.update(resource_obj._fields) self._exclude.update(resource_obj._exclude) self._filter_fields.extend(['%s__%s' % (field_name, ff) for ff in resource_obj._filter_fields]) self._filter_exclude.extend(['%s__%s' % (field_name, ff) for ff in resource_obj._filter_exclude]) self._include_foreign_keys = False else: self._include_foreign_keys = True self._field_tree = make_field_tree(self.model, self._filter_fields, self._filter_exclude, self.filter_recursive) def authorize(self): return self.authentication.authorize() def get_api_name(self): return slugify(self.model.__name__) def get_url_name(self, name): return '%s.%s_%s' % ( self.api.blueprint.name, self.get_api_name(), name, ) def get_query(self): return self.model.select() def process_query(self, query): raw_filters = {} # clean and normalize the request parameters for key in request.args: orig_key = key if key.startswith('-'): negated = True key = key[1:] else: negated = False if '__' in key: expr, op = key.rsplit('__', 1) if op not in DJANGO_MAP: expr = key op = 'eq' else: expr = key op = 'eq' raw_filters.setdefault(expr, []) raw_filters[expr].append((op, request.args.getlist(orig_key), negated)) # do a breadth first search across the field tree created by filter_fields, # searching for matching keys in the request parameters -- when found, # filter the query accordingly queue = [(self._field_tree, '')] while queue: node, prefix = queue.pop(0) for field in node.fields: filter_expr = '%s%s' % (prefix, field.name) if filter_expr in raw_filters: for op, arg_list, negated in raw_filters[filter_expr]: query = self.apply_filter(query, filter_expr, op, arg_list, negated) for child_prefix, child_node in node.children.items(): queue.append((child_node, prefix + child_prefix + '__')) return query def apply_filter(self, query, expr, op, arg_list, negated): query_expr = '%s__%s' % (expr, op) constructor = lambda kwargs: negated and ~DQ(**kwargs) or DQ(**kwargs) if op == 'in': # in gives us a string format list '1,2,3,4' # we have to turn it into a list before passing to # the filter. arg_list = [i.strip() for i in arg_list[0].split(',')] return query.filter(constructor({query_expr: arg_list})) elif len(arg_list) == 1: return query.filter(constructor({query_expr: arg_list[0]})) else: query_clauses = [ constructor({query_expr: val}) for val in arg_list] return query.filter(reduce(operator.or_, query_clauses)) def get_serializer(self): return Serializer() def get_deserializer(self): return Deserializer() def prepare_data(self, obj, data): """ Hook for modifying outgoing data """ return data def serialize_object(self, obj): s = self.get_serializer() return self.prepare_data( obj, s.serialize_object(obj, self._fields, self._exclude) ) def serialize_query(self, query): s = self.get_serializer() return [ self.prepare_data(obj, s.serialize_object(obj, self._fields, self._exclude)) \ for obj in query ] def deserialize_object(self, data, instance): d = self.get_deserializer() return d.deserialize_object(instance, data) def response_forbidden(self): return Response('Forbidden', 403) def response_bad_method(self): return Response('Unsupported method "%s"' % (request.method), 405) def response_bad_request(self): return Response('Bad request', 400) def response(self, data): kwargs = {} if request.is_xhr else {'indent': 2} return Response(json.dumps(data, **kwargs), mimetype='application/json') def require_method(self, func, methods): @functools.wraps(func) def inner(*args, **kwargs): if request.method not in methods: return self.response_bad_method() return func(*args, **kwargs) return inner def get_urls(self): return ( ('/', self.require_method(self.api_list, ['GET', 'POST'])), ('//', self.require_method(self.api_detail, ['GET', 'POST', 'PUT', 'DELETE'])), ('//delete/', self.require_method(self.post_delete, ['POST', 'DELETE'])), ) def check_get(self, obj=None): return True def check_post(self, obj=None): return True def check_put(self, obj): return True def check_delete(self, obj): return True def save_object(self, instance, raw_data): instance.save() return instance def api_list(self): if not getattr(self, 'check_%s' % request.method.lower())(): return self.response_forbidden() if request.method == 'GET': return self.object_list() elif request.method == 'POST': return self.create() def api_detail(self, pk, method=None): obj = get_object_or_404(self.get_query(), self.pk==pk) method = method or request.method if not getattr(self, 'check_%s' % method.lower())(obj): return self.response_forbidden() if method == 'GET': return self.object_detail(obj) elif method in ('PUT', 'POST'): return self.edit(obj) elif method == 'DELETE': return self.delete(obj) def post_delete(self, pk): return self.api_detail(pk, 'DELETE') def apply_ordering(self, query): ordering = request.args.get('ordering') or '' if ordering: desc, column = ordering.startswith('-'), ordering.lstrip('-') if column in self.model._meta.fields: field = self.model._meta.fields[column] query = query.order_by(field.asc() if not desc else field.desc()) return query def get_request_metadata(self, paginated_query): var = paginated_query.page_var request_arguments = request.args.copy() current_page = paginated_query.get_page() next = previous = '' if current_page > 1: request_arguments[var] = current_page - 1 previous = url_for(self.get_url_name('api_list'), **request_arguments) if current_page < paginated_query.get_pages(): request_arguments[var] = current_page + 1 next = url_for(self.get_url_name('api_list'), **request_arguments) return { 'model': self.get_api_name(), 'page': current_page, 'previous': previous, 'next': next, } def get_paginate_by(self): try: paginate_by = int(request.args.get('limit', self.paginate_by)) except ValueError: paginate_by = self.paginate_by else: if self.paginate_by: paginate_by = min(paginate_by, self.paginate_by) # restrict return paginate_by def paginated_object_list(self, filtered_query): paginate_by = self.get_paginate_by() pq = PaginatedQuery(filtered_query, paginate_by) meta_data = self.get_request_metadata(pq) query_dict = self.serialize_query(pq.get_list()) return self.response({ 'meta': meta_data, 'objects': query_dict, }) def object_list(self): query = self.get_query() query = self.apply_ordering(query) # process any filters query = self.process_query(query) if self.paginate_by or 'limit' in request.args: return self.paginated_object_list(query) return self.response(self.serialize_query(query)) def object_detail(self, obj): return self.response(self.serialize_object(obj)) def save_related_objects(self, instance, data): for k, v in data.items(): if k in self._resources and isinstance(v, dict): rel_resource = self._resources[k] rel_obj, rel_models = rel_resource.deserialize_object(v, getattr(instance, k)) rel_resource.save_related_objects(rel_obj, v) setattr(instance, k, rel_resource.save_object(rel_obj, v)) def read_request_data(self): data = request.data or request.form.get('data') or '' return json.loads(data.decode('utf8')) def create(self): try: data = self.read_request_data() except ValueError: return self.response_bad_request() obj, models = self.deserialize_object(data, self.model()) self.save_related_objects(obj, data) obj = self.save_object(obj, data) return self.response(self.serialize_object(obj)) def edit(self, obj): try: data = self.read_request_data() except ValueError: return self.response_bad_request() obj, models = self.deserialize_object(data, obj) self.save_related_objects(obj, data) obj = self.save_object(obj, data) return self.response(self.serialize_object(obj)) def delete(self, obj): res = obj.delete_instance(recursive=self.delete_recursive) return self.response({'deleted': res}) class RestrictOwnerResource(RestResource): # restrict PUT/DELETE to owner of an object, likewise apply owner to any # incoming POSTs owner_field = 'user' def validate_owner(self, user, obj): return user == getattr(obj, self.owner_field) def set_owner(self, obj, user): setattr(obj, self.owner_field, user) def check_put(self, obj): return self.validate_owner(g.user, obj) def check_delete(self, obj): return self.validate_owner(g.user, obj) def save_object(self, instance, raw_data): self.set_owner(instance, g.user) return super(RestrictOwnerResource, self).save_object(instance, raw_data) class RestAPI(object): def __init__(self, app, prefix='/api', default_auth=None, name='api'): self.app = app self._registry = {} self.url_prefix = prefix self.blueprint = self.get_blueprint(name) self.default_auth = default_auth or Authentication() def register(self, model, provider=RestResource, auth=None, allowed_methods=None): self._registry[model] = provider(self, model, auth or self.default_auth, allowed_methods) def unregister(self, model): del(self._registry[model]) def is_registered(self, model): return self._registry.get(model) def response_auth_failed(self): return Response('Authentication failed', 401, { 'WWW-Authenticate': 'Basic realm="Login Required"' }) def auth_wrapper(self, func, provider): @functools.wraps(func) def inner(*args, **kwargs): if not provider.authorize(): return self.response_auth_failed() return func(*args, **kwargs) return inner def get_blueprint(self, blueprint_name): return Blueprint(blueprint_name, __name__) def get_urls(self): return () def configure_routes(self): for url, callback in self.get_urls(): self.blueprint.route(url)(callback) for provider in self._registry.values(): api_name = provider.get_api_name() for url, callback in provider.get_urls(): full_url = '/%s%s' % (api_name, url) self.blueprint.add_url_rule( full_url, '%s_%s' % (api_name, callback.__name__), self.auth_wrapper(callback, provider), methods=provider.allowed_methods, ) def register_blueprint(self, **kwargs): self.app.register_blueprint(self.blueprint, url_prefix=self.url_prefix, **kwargs) def setup(self): self.configure_routes() self.register_blueprint() flask-peewee-0.6.7/flask_peewee/exceptions.py0000644000175000001440000000006012574421673022070 0ustar charlesusers00000000000000class ImproperlyConfigured(Exception): pass flask-peewee-0.6.7/flask_peewee/filters.pyc0000644000175000001440000004461312624225311021521 0ustar charlesusers00000000000000 *QVc@s4ddlZddlZddlmZddlmZddlmZddlTddl m Z ddl m Z ddl m Z dd l m Z d efd YZd efd YZdefdYZdefdYZdefdYZdefdYZdefdYZdefdYZdefdYZdefdYZdefdYZd efd!YZd"efd#YZd$efd%YZd&efd'YZedd(Z d)e j!fd*YZ"d+efd,YZ#d-efd.YZ$dS(/iN(trequest(tBaseModelConverter(treduce(t*(tfields(tform(t validators(twidgetst QueryFiltercBs5eZdZddZdZdZdZRS(s Basic class representing a named field (with or without a list of options) and an operation against a given value cCs||_||_||_dS(N(tfieldtnametoptions(tselfR R R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyt__init__s  cCs tdS(N(tNotImplementedError(R tvalue((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pytqueryscCs tdS(N(R(R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyt operationscCs|jS(N(R (R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyt get_optionssN(t__name__t __module__t__doc__tNoneR RRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRs    tEqualQueryFiltercBseZdZdZRS(cCs |j|kS(N(R (R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR#scCsdS(Nsequal to((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR&s(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR"s tNotEqualQueryFiltercBseZdZdZRS(cCs |j|kS(N(R (R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR+scCsdS(Ns not equal to((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR.s(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR*s tLessThanQueryFiltercBseZdZdZRS(cCs |j|kS(N(R (R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR3scCsdS(Ns less than((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR6s(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR2s tLessThanEqualToQueryFiltercBseZdZdZRS(cCs |j|kS(N(R (R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR;scCsdS(Nsless than or equal to((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR>s(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR:s tGreaterThanQueryFiltercBseZdZdZRS(cCs |j|kS(N(R (R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRCscCsdS(Ns greater than((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRFs(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRBs tGreaterThanEqualToQueryFiltercBseZdZdZRS(cCs |j|kS(N(R (R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRKscCsdS(Nsgreater than or equal to((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRNs(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRJs tStartsWithQueryFiltercBseZdZdZRS(cCs1tjtj|jdt||jkS(Ni(tfntLowertSubstrR tlentlower(R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRSscCsdS(Ns starts with((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRVs(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRRs tContainsQueryFiltercBseZdZdZRS(cCs|jd|S(Ns%%%s%%(R (R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR[scCsdS(Ntcontains((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR^s(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR#Zs t YearFiltercBseZdZdZRS(cCst|}|jj|kS(N(tintR tyear(R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRcs cCsdS(Ns year equals((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRgs(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR%bs t MonthFiltercBseZdZdZRS(cCst|}|jj|kS(N(R&R tmonth(R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRls cCsdS(Ns month equals((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRps(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR(ks tWithinDaysAgoFiltercBseZdZdZRS(cCs2t|}|jtjjtjd|kS(Ntdays(R&R tdatetimetdatettodayt timedelta(R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRus cCsdS(Nswithin X days ago((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRzs(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR*ts tOlderThanDaysAgoFiltercBseZdZdZRS(cCs2t|}|jtjjtjd|kS(NR+(R&R R,R-R.R/(R R((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRs cCsdS(Nsolder than X days ago((R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRs(RRRR(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR0~s t FilterMappingcBseZdZeeeefZeeee e e fZ e e eeefZeefZeefZdZdZdZdZdZdZdZRS(sL Map a peewee field to a list of valid query filters for that field cCs_i dt6dt6dt6dt6dt6dt6dt6dt6dt6dt 6dt 6dt 6dt 6S(Ntstringt datetime_datetnumerictbooleant foreign_key( t CharFieldt TextFieldt DateTimeFieldt DateFieldt TimeFieldt IntegerFieldtBigIntegerFieldt FloatFieldt DoubleFieldt DecimalFieldt BooleanFieldtPrimaryKeyFieldtForeignKeyField(R ((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pytget_field_typesscCs`|j}xDt|jD]3}||krt|d||}||SqW|j|S(Ns convert_%s(RDttypet__mro__tgetattrtconvert_numeric(R R tmappingtklasst mapping_fn((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pytconverts   cCs,g|jD]}|||j|j^q S(N(R2t verbose_nametchoices(R R tf((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pytconvert_stringscCs,g|jD]}|||j|j^q S(N(R4RMRN(R R RO((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRHscCs,g|jD]}|||j|j^q S(N(R3RMRN(R R RO((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pytconvert_datetime_datescCs2dg}g|jD]}|||j|^qS(NtTruet1tFalset(sTrueRSsFalseRU(R5RM(R R tboolean_choicesRO((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pytconvert_booleans cCs,g|jD]}|||j|j^q S(N(R6RMRN(R R RO((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pytconvert_foreign_keys(RRRRRRR#R2RRRRR4R*R0R%R(R3R6R5RDRLRPRHRQRWRX(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR1s"           t FieldTreeNodecBseZddZRS(cCs%||_||_|pi|_dS(N(tmodelRtchildren(R RZRR[((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyR s  N(RRRR (((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/filters.pyRYsc Cs|dk}|r!|jj}n|p*g}|p9t}g}i}x>|jjD]0}|j|ksU||kr|qUn|j|kr|j|nt|trU|j ||rd} nXg|D]5} | j d|jr| j d|jd^q} | r|rd} ng|D]5} | j d|jr%| j d|jd^q%} t |j | | ||||js8       =&flask-peewee-0.6.7/flask_peewee/db.py0000644000175000001440000000350412574421673020302 0ustar charlesusers00000000000000import peewee from peewee import * from flask_peewee.exceptions import ImproperlyConfigured from flask_peewee.utils import load_class class Database(object): def __init__(self, app, database=None): self.app = app self.database = database if self.database is None: self.load_database() self.register_handlers() self.Model = self.get_model_class() def load_database(self): self.database_config = dict(self.app.config['DATABASE']) try: self.database_name = self.database_config.pop('name') self.database_engine = self.database_config.pop('engine') except KeyError: raise ImproperlyConfigured('Please specify a "name" and "engine" for your database') try: self.database_class = load_class(self.database_engine) assert issubclass(self.database_class, peewee.Database) except ImportError: raise ImproperlyConfigured('Unable to import: "%s"' % self.database_engine) except AttributeError: raise ImproperlyConfigured('Database engine not found: "%s"' % self.database_engine) except AssertionError: raise ImproperlyConfigured('Database engine not a subclass of peewee.Database: "%s"' % self.database_engine) self.database = self.database_class(self.database_name, **self.database_config) def get_model_class(self): class BaseModel(Model): class Meta: database = self.database return BaseModel def connect_db(self): self.database.connect() def close_db(self, exc): if not self.database.is_closed(): self.database.close() def register_handlers(self): self.app.before_request(self.connect_db) self.app.teardown_request(self.close_db) flask-peewee-0.6.7/flask_peewee/admin.pyc0000644000175000001440000006751512624225233021152 0ustar charlesusers00000000000000 *QVc@sddlZddlZddlZddlZyddlZWnek r_ddlZnXddlmZddlm Z ddlm Z ddlm Z ddlm Z ddlm Z ddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlm Z ddlm!Z!ddlm"Z"ddlm#Z#ddlm$Z$ddl%m&Z&ddl'm(Z(ddl'm)Z)ddl*m+Z+ddl*m,Z,ddl*m-Z-dd l.m/Z/ej0j1e2Z3d!efd"YZ4d#efd$YZ5d%e6fd&YZ7d'e6fd(YZ8d)e6fd*YZ9d+e6fd,YZ:d-e6fd.YZ;dS(/iN(t Blueprint(tResponse(tabort(tflash(tredirect(trender_template(trequest(turl_for(t FilterForm(t FilterMapping(tFilterModelConverter(tBaseModelConverter(tChosenAjaxSelectWidget(tLimitedModelSelectField(t Serializer(tPaginatedQuery(tget_next(tpath_to_models(tslugify(t BooleanField(t DateField(t DateTimeField(tForeignKeyField(t TextField(tHeaders(tfields(twidgets(tModelHiddenField(tModelSelectField(tModelSelectMultipleField(t model_formtAdminModelConvertercBseZddZdZRS(cCs#tt|j|||_dS(N(tsuperRt__init__t model_admin(tselfR"t additional((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR!/scKsk|jrt|ds t ModelAdmincBseZdZdZdZd(Zd(Zd(Zd(Z d(Z e Z d(Z eZeZeZeZidd6dd6dd6d d 6d d 6Zd ZdZdZdZdZedZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%edZ&dZ'dZ(dZ)d Z*d!Z+d"Z,d#Z-d$Z.d(d%Z/d&Z0d'Z1RS()sR ModelAdmin provides create/edit/delete functionality for a peewee Model. iisadmin/models/index.htmltindexsadmin/models/add.htmltaddsadmin/models/edit.htmlteditsadmin/models/delete.htmltdeletesadmin/models/export.htmltexportcCs_||_||_|jj|_|jjj|_t|j|_ |j j |j dS(N( tadminR&t_metatdatabasetdbt primary_keytpktdicttbase_templatest templatestupdatetget_template_overrides(R#R>R&((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR!vs   cCsiS(N((R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyRHscCs d|jjj|j|fS(Ns%s.%s_%s(R>t blueprintR)tget_admin_name(R#R)((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR6s  cCs.t|j|j||j|j|jS(N(RR&tfilter_convertertfilter_mappingt filter_fieldstfilter_exclude(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_filter_forms   cCs7|j}|j|\}}}||||jfS(N(ROtprocess_requestt _field_tree(R#tqueryt filter_formtformtcleaned((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytprocess_filterss c CsJ|o|jjj }t|jd|d|jd|jd|j|S(Ntallow_pktonlytexcludet converter(R&R?tauto_incrementRRRYtform_converter(R#taddingRW((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_forms    cCs|jdtS(NR](R^R((R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt get_add_formscCs |jS(N(R^(R#tinstance((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt get_edit_formscCs |jjS(N(R&tselect(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt get_queryscCs"|jj|j|kjS(N(RctwhereRCtget(R#RC((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt get_objectscCsLd|jfd|jfd|jfd|jfd|jfd|jffS(Nt/s/add/s/delete/s/export/s//s/_ajax/(R9R:R<R=R;R4(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_urlss      cCs |jjjS(N(R&R?tsorted_field_names(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt get_columnsscCs||jjjkS(N(R&R?R(R#tcol((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytcolumn_is_sortablescCs |jjS(N(R&R0(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_display_namescCst|jjS(N(RR&R0(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyRJscCs!|j||jd||S(Nt force_insert(t populate_objtsave(R#R`RTR]((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt save_models cCsx|rt|jd|jd}}|j|rt|jjj|}|j|s_|jn |j}qtn|S(Nt-( t startswithtlstripRlR&R?Rtorder_bytasctdesc(R#RRtorderingRwtcolumnR,((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytapply_orderings -cCsiS(N((R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_extra_contextscCs|j}tjjdp!d}|j||}|j|\}}}}t||j}tjdkrtj j d}tj ddkrt t |j dd|St t |j dd|Snt|jdd |d |d|d |d |d ||jS(NRxttPOSTtidtactionR<R=R9R"RRRSt field_treetactive_filters(RcRtargsReRzRVRt paginate_bytmethodRTtgetlistRRR6RRFR{(R#RRRxRSRURtpqtid_list((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR9s$ "cCsydtjkr(tt|jdSdtjkrPtt|jdStt|jdd|jSdS(NRpR9tsave_addR:R;RC(RRTRRR6tget_id(R#R`((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytdispatch_save_redirects c Cs|j}|j}tjdkr~|tj}|jr|j||t}td|j d|j |Sn |}t |j dd|d|d||j S(NR}sNew %s saved successfullytsuccessR:R"RTR`(R_R&RRRTtvalidateRqR(RRmRRRFR{(R#tFormR`RT((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR:s    c Csy|j|}Wn!|jjk r6tdnX|j|}tjdkr|tjd|}|jr|j ||t t d|j d|j |Sn|d|}t|jdd|d|d ||jS( NiR}tobjs Changes to %s saved successfullyRR;R"R`RT(RfR&t DoesNotExistRRaRRRTRRqtFalseRRmRRRFR{(R#RCR`RRT((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR; s" c Cs|j}g}x|jD]w\}}|js|jjj|}g|jjD] }|^q_}|r|jd|j|fqqqWt|ddS(NitkeycSs|d|djfS(Nii(R0(ti((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt0s( t dependenciesR't model_classRbRdtexecutetiteratortappendtsorted( R#RtdepstobjectsRRtfktsqtrel_objt collected((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytcollect_objects%s  %#c CsJtjdkr$tjjd}ntjjd}|jjj|j|>}tjdkri}|j rx*|D]}|j |||j }ntj dkrtj jd}t |||} | jd|jSt|jdd|d |jd |d |d |d |d|d|j|jS(NRxR|R~R}Rsexport-%s.jsonR=R"R&RRRSRRtrelated_fieldstsql(RcRRReRzRVRR&RRdRCRRTtExportt json_responseRJRRFRRR{( R#RRRxRSRURtrelatedRt raw_fieldsR=((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR=\s,   cCstjjd}d}d}yt|j|}Wntk rMg}nAX|jjj|}|j}|jj|j |}|j j |} tjjd} | r| j |d| } nt | |j} | j} | dkr| d}n| | jkr!| d}ng}|jrN|jidd6dd 6n|jg| jD]&} i| jd6t| d 6^qatji|d 6|d 6|d 6}t|d dS(NR,iRRs%%%s%%it__NoneR~R2treprt prev_paget next_paget object_listtmimetypesapplication/json(RRReRR&tAttributeErrorR?RtpopR*RbRuRdRtfilter_paginate_bytget_paget get_pagesR'Rtextendtget_listRtunicodetjsontdumpsR(R#t field_nameRRtmodelstdataR,R+t rel_fieldRRt query_stringRt current_pageRt json_data((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR4|s4        @$N(2R0R1t__doc__RRR2tcolumnsRNRMRYRRR\R*R(RRR RLR3RKRER!RHR6RORVRR^R_RaRcRfRhRjRlRmRJRqRzR{R9RR:R;RR<RR=R4(((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR8Ms^                    t AdminPanelcBsMeZdZdZdZdZdZdZdZdZ RS(sadmin/panels/default.htmlcCs(||_||_t|j|_dS(N(R>ttitleRtslug(R#R>R((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR!s  cCstd|jjjS(Ns%s.index(RR>RIR)(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt dashboard_urlscCsdS(N(((R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyRhscCsd|jjj|j|fS(Ns%s.panel_%s_%s(R>RIR)R(R#R)((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR6s cCs|jS(N(t template_name(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_template_namescCsiS(N((R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt get_contextscCst|jd||jS(Ntpanel(RRR(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytrenders( R0R1RR!RRhR6RRR(((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyRs      tAdminTemplateHelpercBsqeZdZdZdZdZdZdZdZdZ dZ d d d Z d Z RS( cCs||_|jj|_dS(N(R>tapp(R#R>((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR!s cCs&t||}t|r"|S|S(N(tgetattrtcallable(R#R&R,tattr((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_model_fields cCs t||S(N(R(R#RTR((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_form_fieldscCs|jddjS(Nt_t (treplaceR(R#ts((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytfix_underscoresscCs]|sd||fStjd|d|jdjd}d|||fjdSdS(Ns%s=%ss%s(?:[^&]+)?&?R|tutf8t&s%s&%s=%s(tretsubtdecodetrstripRt(R#t querystringRtval((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytupdate_querystrings+cCs=y|jj|}Wntk r1|j|SX|jSdS(N(R?RtKeyErrorRt verbose_name(R#R&t column_nameR,((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_verbose_names  cCs!i|jjd6|jjd6S(Nt model_adminstbranding(R>tget_model_adminsR(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyRscCsA|jjt|}|r=t|jdd|jSdS(NR;RC(R>t get_admin_forttypeRR6R(R#RR"((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt get_admin_urlscCs)|jj|}|r"|jS|jS(N(R>RRmR0(R#RR"((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytget_model_names tfr_RrcCsRg}x%|D]}|jd||fq W|jd||f|j|S(Ns%s%s(RR(R#Rt prefix_accumt field_prefixt rel_prefixtrel_sepRtprefix((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt apply_prefixs  cCs|jjdj|j|j|jjjd<|j|jjjd<|j |jjjd<|j |jjj d<|j |jjjd<|j |jjjd<|j|jjjd<|j|jjj ds flask-peeweecCsq||_||_i|_i|_i|_|j||_||_|||_|jj ||_ dS(N( Rtautht _admin_modelst _registryt_panelst get_blueprintRIt url_prefixttemplate_helperRR(R#RRR RR)R((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR!s       cs%tjfd}|S(Ncsjjj}|sAtdjjjdt}t|Sj|s]tdn||S(Ns%s.logintnexti( Rtget_logged_in_userRRIR)RRtcheck_user_permissionR(RR-tusert login_url(tfuncR#(s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytinners"  (t functoolstwraps(R#RR((RR#s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt auth_requireds! cCs|jS(N(R>(R#R((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR$scCsd|j|jffS(NRg(RR9(R#((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyRh'scCs ||jkS(N(R (R#titem((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt __contains__,scCs |j|S(N(R (R#R((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt __getitem__/scCs,|||}|j}||j|R#s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyt prepare_querys     s export.jsoncst|jix;jD]0}j|jg|jj|jq%Wfd}t}|jdd|jdd|t |ddd|d t S( Nc3scj}dVxFD]>}|d8}tjj|V|dkrdVqqWdVdS(Ns[ iis, s ](RRRtserialize_object(RR(t field_dicttprepared_queryt serializer(s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pytgenerates     s Content-Typesapplication/javascriptsContent-Dispositionsattachment; filename=%sRstext/javascripttheaderstdirect_passthrough( RRBR@RRRR)RR:RR((R#tfilenameR,RGRH((RDRERFs=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyRs   (R0R1R!RBR(((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyR~s  $(<RtoperatorR)Rt simplejsonRt ImportErrortflaskRRRRRRRRtflask_peewee.filtersRR R tflask_peewee.formsR R R tflask_peewee.serializerRtflask_peewee.utilsRRRRtpeeweeRRRRRtwerkzeugRtwtformsRRtwtfpeewee.fieldsRRRt wtfpeewee.ormRRtdirnamet__file__R*RR3tobjectR8RRRR(((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/admin.pyts^     UC{flask-peewee-0.6.7/flask_peewee/_compat.py0000644000175000001440000000037512574421673021342 0ustar charlesusers00000000000000import sys PY2 = sys.version_info[0] == 2 if PY2: text_type = unicode string_types = (str, unicode) unichr = unichr reduce = reduce else: text_type = str string_types = (str,) unichr = chr from functools import reduce flask-peewee-0.6.7/flask_peewee/admin.py0000644000175000001440000005663312624225413021006 0ustar charlesusers00000000000000import functools import operator import os import re try: import simplejson as json except ImportError: import json from flask import Blueprint from flask import Response from flask import abort from flask import flash from flask import redirect from flask import render_template from flask import request from flask import session from flask import url_for from flask_peewee.filters import FilterForm from flask_peewee.filters import FilterMapping from flask_peewee.filters import FilterModelConverter from flask_peewee.forms import BaseModelConverter from flask_peewee.forms import ChosenAjaxSelectWidget from flask_peewee.forms import LimitedModelSelectField from flask_peewee.serializer import Serializer from flask_peewee.utils import PaginatedQuery from flask_peewee.utils import get_next from flask_peewee.utils import path_to_models from flask_peewee.utils import slugify from peewee import BooleanField from peewee import DateField from peewee import DateTimeField from peewee import ForeignKeyField from peewee import TextField from werkzeug import Headers from wtforms import fields from wtforms import widgets from wtfpeewee.fields import ModelHiddenField from wtfpeewee.fields import ModelSelectField from wtfpeewee.fields import ModelSelectMultipleField from wtfpeewee.orm import model_form current_dir = os.path.dirname(__file__) class AdminModelConverter(BaseModelConverter): def __init__(self, model_admin, additional=None): super(AdminModelConverter, self).__init__(additional) self.model_admin = model_admin def handle_foreign_key(self, model, field, **kwargs): if field.null: kwargs['allow_blank'] = True if field.name in (self.model_admin.foreign_key_lookups or ()): form_field = ModelHiddenField(model=field.rel_model, **kwargs) else: form_field = ModelSelectField(model=field.rel_model, **kwargs) return field.name, form_field class AdminFilterModelConverter(FilterModelConverter): def __init__(self, model_admin, additional=None): super(AdminFilterModelConverter, self).__init__(additional) self.model_admin = model_admin def handle_foreign_key(self, model, field, **kwargs): if field.name in (self.model_admin.foreign_key_lookups or ()): data_source = url_for(self.model_admin.get_url_name('ajax_list')) widget = ChosenAjaxSelectWidget(data_source, field.name) form_field = LimitedModelSelectField(model=field.rel_model, widget=widget, **kwargs) else: form_field = ModelSelectField(model=field.rel_model, **kwargs) return field.name, form_field class ModelAdmin(object): """ ModelAdmin provides create/edit/delete functionality for a peewee Model. """ paginate_by = 20 filter_paginate_by = 15 # columns to display in the list index - can be field names or callables on # a model instance, though in the latter case they will not be sortable columns = None # exclude certian fields from being exposed as filters -- for related fields # use "__" notation, e.g. user__password filter_exclude = None filter_fields = None # form parameters, lists of fields exclude = None fields = None form_converter = AdminModelConverter # foreign_key_field --> related field to search on, e.g. {'user': 'username'} foreign_key_lookups = None # delete behavior delete_collect_objects = True delete_recursive = True filter_mapping = FilterMapping filter_converter = AdminFilterModelConverter # templates, to override see get_template_overrides() base_templates = { 'index': 'admin/models/index.html', 'add': 'admin/models/add.html', 'edit': 'admin/models/edit.html', 'delete': 'admin/models/delete.html', 'export': 'admin/models/export.html', } def __init__(self, admin, model): self.admin = admin self.model = model self.db = model._meta.database self.pk = self.model._meta.primary_key self.templates = dict(self.base_templates) self.templates.update(self.get_template_overrides()) def get_template_overrides(self): return {} def get_url_name(self, name): return '%s.%s_%s' % ( self.admin.blueprint.name, self.get_admin_name(), name, ) def get_filter_form(self): return FilterForm( self.model, self.filter_converter(self), self.filter_mapping(), self.filter_fields, self.filter_exclude, ) def process_filters(self, query): filter_form = self.get_filter_form() form, query, cleaned = filter_form.process_request(query) return form, query, cleaned, filter_form._field_tree def get_form(self, adding=False): allow_pk = adding and not self.model._meta.auto_increment return model_form(self.model, allow_pk=allow_pk, only=self.fields, exclude=self.exclude, converter=self.form_converter(self), ) def get_add_form(self): return self.get_form(adding=True) def get_edit_form(self, instance): return self.get_form() def get_query(self): return self.model.select() def get_object(self, pk): return self.get_query().where(self.pk==pk).get() def get_urls(self): return ( ('/', self.index), ('/add/', self.add), ('/delete/', self.delete), ('/export/', self.export), ('//', self.edit), ('/_ajax/', self.ajax_list), ) def get_columns(self): return self.model._meta.sorted_field_names def column_is_sortable(self, col): return col in self.model._meta.fields def get_display_name(self): return self.model.__name__ def get_admin_name(self): return slugify(self.model.__name__) def save_model(self, instance, form, adding=False): form.populate_obj(instance) instance.save(force_insert=adding) return instance def apply_ordering(self, query, ordering): if ordering: desc, column = ordering.startswith('-'), ordering.lstrip('-') if self.column_is_sortable(column): field = self.model._meta.fields[column] query = query.order_by(field.asc() if not desc else field.desc()) return query def get_extra_context(self): return {} def index(self): session['%s.index' % self.get_admin_name()] = request.url query = self.get_query() ordering = request.args.get('ordering') or '' query = self.apply_ordering(query, ordering) # process the filters from the request filter_form, query, cleaned, field_tree = self.process_filters(query) # create a paginated query out of our filtered results pq = PaginatedQuery(query, self.paginate_by) if request.method == 'POST': id_list = request.form.getlist('id') if request.form['action'] == 'delete': return redirect(url_for(self.get_url_name('delete'), id=id_list)) else: return redirect(url_for(self.get_url_name('export'), id=id_list)) return render_template(self.templates['index'], model_admin=self, query=pq, ordering=ordering, filter_form=filter_form, field_tree=field_tree, active_filters=cleaned, **self.get_extra_context() ) def dispatch_save_redirect(self, instance): if 'save' in request.form: url = (session.get('%s.index' % self.get_admin_name()) or url_for(self.get_url_name('index'))) return redirect(url) elif 'save_add' in request.form: return redirect(url_for(self.get_url_name('add'))) else: return redirect( url_for(self.get_url_name('edit'), pk=instance.get_id()) ) def add(self): Form = self.get_add_form() instance = self.model() if request.method == 'POST': form = Form(request.form) if form.validate(): instance = self.save_model(instance, form, True) flash('New %s saved successfully' % self.get_display_name(), 'success') return self.dispatch_save_redirect(instance) else: form = Form() return render_template(self.templates['add'], model_admin=self, form=form, instance=instance, **self.get_extra_context() ) def edit(self, pk): try: instance = self.get_object(pk) except self.model.DoesNotExist: abort(404) Form = self.get_edit_form(instance) if request.method == 'POST': form = Form(request.form, obj=instance) if form.validate(): self.save_model(instance, form, False) flash('Changes to %s saved successfully' % self.get_display_name(), 'success') return self.dispatch_save_redirect(instance) else: form = Form(obj=instance) return render_template(self.templates['edit'], model_admin=self, instance=instance, form=form, **self.get_extra_context() ) def collect_objects(self, obj): deps = obj.dependencies() objects = [] for query, fk in obj.dependencies(): if not fk.null: sq = fk.model_class.select().where(query) collected = [rel_obj for rel_obj in sq.execute().iterator()] if collected: objects.append((0, fk.model_class, collected)) return sorted(objects, key=lambda i: (i[0], i[1].__name__)) def delete(self): if request.method == 'GET': id_list = request.args.getlist('id') else: id_list = request.form.getlist('id') query = self.model.select().where(self.pk << id_list) if request.method == 'GET': collected = {} if self.delete_collect_objects: for obj in query: collected[obj.get_id()] = self.collect_objects(obj) elif request.method == 'POST': count = query.count() for obj in query: obj.delete_instance(recursive=self.delete_recursive) flash('Successfully deleted %s %ss' % (count, self.get_display_name()), 'success') url = (session.get('%s.index' % self.get_admin_name()) or url_for(self.get_url_name('index'))) return redirect(url) return render_template(self.templates['delete'], **dict( model_admin=self, query=query, collected=collected, **self.get_extra_context() )) def collect_related_fields(self, model, accum, path, seen=None): seen = seen or set() path_str = '__'.join(path) for field in model._meta.sorted_fields: if isinstance(field, ForeignKeyField) and field not in seen: seen.add(field) self.collect_related_fields(field.rel_model, accum, path + [field.name], seen) elif model != self.model: accum.setdefault((model, path_str), []) accum[(model, path_str)].append(field) return accum def export(self): query = self.get_query() ordering = request.args.get('ordering') or '' query = self.apply_ordering(query, ordering) # process the filters from the request filter_form, query, cleaned, field_tree = self.process_filters(query) related = self.collect_related_fields(self.model, {}, []) # check for raw id id_list = request.args.getlist('id') if id_list: query = query.where(self.pk << id_list) if request.method == 'POST': raw_fields = request.form.getlist('fields') export = Export(query, related, raw_fields) return export.json_response('export-%s.json' % self.get_admin_name()) return render_template(self.templates['export'], model_admin=self, model=query.model_class, query=query, filter_form=filter_form, field_tree=field_tree, active_filters=cleaned, related_fields=related, sql=query.sql(), **self.get_extra_context() ) def ajax_list(self): field_name = request.args.get('field') prev_page = 0 next_page = 0 try: models = path_to_models(self.model, field_name) except AttributeError: data = [] else: field = self.model._meta.fields[field_name] rel_model = models.pop() rel_field = rel_model._meta.fields[self.foreign_key_lookups[field_name]] query = rel_model.select().order_by(rel_field) query_string = request.args.get('query') if query_string: query = query.where(rel_field ** ('%%%s%%' % query_string)) pq = PaginatedQuery(query, self.filter_paginate_by) current_page = pq.get_page() if current_page > 1: prev_page = current_page - 1 if current_page < pq.get_pages(): next_page = current_page + 1 data = [] # if the field is nullable, include the "None" option at the top of the list if field.null: data.append({'id': '__None', 'repr': 'None'}) data.extend([{'id': obj.get_id(), 'repr': unicode(obj)} for obj in pq.get_list()]) json_data = json.dumps({'prev_page': prev_page, 'next_page': next_page, 'object_list': data}) return Response(json_data, mimetype='application/json') class AdminPanel(object): template_name = 'admin/panels/default.html' def __init__(self, admin, title): self.admin = admin self.title = title self.slug = slugify(self.title) def dashboard_url(self): return url_for('%s.index' % (self.admin.blueprint.name)) def get_urls(self): return () def get_url_name(self, name): return '%s.panel_%s_%s' % ( self.admin.blueprint.name, self.slug, name, ) def get_template_name(self): return self.template_name def get_context(self): return {} def render(self): return render_template(self.get_template_name(), panel=self, **self.get_context()) class AdminTemplateHelper(object): def __init__(self, admin): self.admin = admin self.app = self.admin.app def get_model_field(self, model, field): try: attr = getattr(model, field) except AttributeError: model_admin = self.admin[type(model)] try: attr = getattr(model_admin, field) except AttributeError: raise AttributeError('Could not find attribute or method ' 'named "%s".' % field) else: return attr(model) else: if callable(attr): attr = attr() return attr def get_form_field(self, form, field_name): return getattr(form, field_name) def fix_underscores(self, s): return s.replace('_', ' ').title() def update_querystring(self, querystring, key, val): if not querystring: return '%s=%s' % (key, val) else: querystring = re.sub('%s(?:[^&]+)?&?' % key, '', querystring.decode('utf8')).rstrip('&') return ('%s&%s=%s' % (querystring, key, val)).lstrip('&') def get_verbose_name(self, model, column_name): try: field = model._meta.fields[column_name] except KeyError: return self.fix_underscores(column_name) else: return field.verbose_name def get_model_admins(self): return {'model_admins': self.admin.get_model_admins(), 'branding': self.admin.branding} def get_admin_url(self, obj): model_admin = self.admin.get_admin_for(type(obj)) if model_admin: return url_for(model_admin.get_url_name('edit'), pk=obj.get_id()) def get_model_name(self, model_class): model_admin = self.admin.get_admin_for(model_class) if model_admin: return model_admin.get_display_name() return model_class.__name__ def apply_prefix(self, field_name, prefix_accum, field_prefix, rel_prefix='fr_', rel_sep='-'): accum = [] for prefix in prefix_accum: accum.append('%s%s' % (rel_prefix, prefix)) accum.append('%s%s' % (field_prefix, field_name)) return rel_sep.join(accum) def prepare_environment(self): self.app.template_context_processors[None].append(self.get_model_admins) self.app.jinja_env.globals['get_model_field'] = self.get_model_field self.app.jinja_env.globals['get_form_field'] = self.get_form_field self.app.jinja_env.globals['get_verbose_name'] = self.get_verbose_name self.app.jinja_env.filters['fix_underscores'] = self.fix_underscores self.app.jinja_env.globals['update_querystring'] = self.update_querystring self.app.jinja_env.globals['get_admin_url'] = self.get_admin_url self.app.jinja_env.globals['get_model_name'] = self.get_model_name self.app.jinja_env.filters['apply_prefix'] = self.apply_prefix class Admin(object): def __init__(self, app, auth, template_helper=AdminTemplateHelper, prefix='/admin', name='admin', branding='flask-peewee'): self.app = app self.auth = auth self._admin_models = {} self._registry = {} self._panels = {} self.blueprint = self.get_blueprint(name) self.url_prefix = prefix self.template_helper = template_helper(self) self.template_helper.prepare_environment() self.branding = branding def auth_required(self, func): @functools.wraps(func) def inner(*args, **kwargs): user = self.auth.get_logged_in_user() if not user: login_url = url_for('%s.login' % self.auth.blueprint.name, next=get_next()) return redirect(login_url) if not self.check_user_permission(user): abort(403) return func(*args, **kwargs) return inner def check_user_permission(self, user): return user.admin def get_urls(self): return ( ('/', self.auth_required(self.index)), ) def __contains__(self, item): return item in self._registry def __getitem__(self, item): return self._registry[item] def register(self, model, admin_class=ModelAdmin): model_admin = admin_class(self, model) admin_name = model_admin.get_admin_name() self._registry[model] = model_admin def unregister(self, model): del(self._registry[model]) def register_panel(self, title, panel): panel_instance = panel(self, title) self._panels[title] = panel_instance def unregister_panel(self, title): del(self._panels[title]) def get_admin_for(self, model): return self._registry.get(model) def get_model_admins(self): return sorted(self._registry.values(), key=lambda o: o.get_admin_name()) def get_panels(self): return sorted(self._panels.values(), key=lambda o: o.slug) def index(self): return render_template('admin/index.html', model_admins=self.get_model_admins(), panels=self.get_panels(), ) def get_blueprint(self, blueprint_name): return Blueprint( blueprint_name, __name__, static_folder=os.path.join(current_dir, 'static'), template_folder=os.path.join(current_dir, 'templates'), ) def register_blueprint(self, **kwargs): self.app.register_blueprint( self.blueprint, url_prefix=self.url_prefix, **kwargs ) def configure_routes(self): for url, callback in self.get_urls(): self.blueprint.route(url, methods=['GET', 'POST'])(callback) for model_admin in self._registry.values(): admin_name = model_admin.get_admin_name() for url, callback in model_admin.get_urls(): full_url = '/%s%s' % (admin_name, url) self.blueprint.add_url_rule( full_url, '%s_%s' % (admin_name, callback.__name__), self.auth_required(callback), methods=['GET', 'POST'], ) for panel in self._panels.values(): for url, callback in panel.get_urls(): full_url = '/%s%s' % (panel.slug, url) self.blueprint.add_url_rule( full_url, 'panel_%s_%s' % (panel.slug, callback.__name__), self.auth_required(callback), methods=['GET', 'POST'], ) def setup(self): self.configure_routes() self.register_blueprint() class Export(object): def __init__(self, query, related, fields): self.query = query self.related = related self.fields = fields self.alias_to_model = dict([(k[1], k[0]) for k in self.related.keys()]) def prepare_query(self): clone = self.query.clone() select = [] joined = set() def ensure_join(query, m, p): if m not in joined: if '__' not in p: next_model = query.model_class else: next, _ = p.rsplit('__', 1) next_model = self.alias_to_model[next] query = ensure_join(query, next_model, next) joined.add(m) return query.switch(next_model).join(m) else: return query for lookup in self.fields: # lookup may be something like "content" or "user__user_name" if '__' in lookup: path, column = lookup.rsplit('__', 1) model = self.alias_to_model[path] clone = ensure_join(clone, model, path) else: model = self.query.model_class column = lookup field = model._meta.fields[column] select.append(field) clone._select = select return clone def json_response(self, filename='export.json'): serializer = Serializer() prepared_query = self.prepare_query() field_dict = {} for field in prepared_query._select: field_dict.setdefault(field.model_class, []) field_dict[field.model_class].append(field.name) def generate(): i = prepared_query.count() yield '[\n' for obj in prepared_query: i -= 1 yield json.dumps(serializer.serialize_object(obj, field_dict)) if i > 0: yield ',\n' yield '\n]' headers = Headers() headers.add('Content-Type', 'application/javascript') headers.add('Content-Disposition', 'attachment; filename=%s' % filename) return Response(generate(), mimetype='text/javascript', headers=headers, direct_passthrough=True) flask-peewee-0.6.7/flask_peewee/serializer.py0000644000175000001440000000260312574421673022065 0ustar charlesusers00000000000000import datetime import sys from peewee import Model from flask_peewee.utils import get_dictionary_from_model from flask_peewee.utils import get_model_from_dictionary class Serializer(object): date_format = '%Y-%m-%d' time_format = '%H:%M:%S' datetime_format = ' '.join([date_format, time_format]) def convert_value(self, value): if isinstance(value, datetime.datetime): return value.strftime(self.datetime_format) elif isinstance(value, datetime.date): return value.strftime(self.date_format) elif isinstance(value, datetime.time): return value.strftime(self.time_format) elif isinstance(value, Model): return value.get_id() else: return value def clean_data(self, data): for key, value in data.items(): if isinstance(value, dict): self.clean_data(value) elif isinstance(value, (list, tuple)): data[key] = map(self.clean_data, value) else: data[key] = self.convert_value(value) return data def serialize_object(self, obj, fields=None, exclude=None): data = get_dictionary_from_model(obj, fields, exclude) return self.clean_data(data) class Deserializer(object): def deserialize_object(self, model, data): return get_model_from_dictionary(model, data) flask-peewee-0.6.7/flask_peewee/utils.pyc0000644000175000001440000001413312624225233021206 0ustar charlesusers00000000000000 *QVc@sFddlZddlZddlZddlZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddl m Z dd l mZdd lmZd Zd d ZdefdYZdZdZdZdddZdZdZdZdZdZdS(iN(tsha1(tabort(trender_template(trequest(t DoesNotExist(tForeignKeyField(tModel(t SelectQuery(t text_typecGsWt|ts|j}ny|j|jSWntk rRtdnXdS(Ni(t isinstanceRtselecttwheretgetRR(tquery_or_modeltquery((s=/home/charles/Dropbox/code/flask-peewee/flask_peewee/utils.pytget_object_or_404s  t object_listcKsJt||jdd}|j||s0             flask-peewee-0.6.7/flask_peewee/tests/0000755000175000001440000000000012624225533020474 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/tests/rest.py0000644000175000001440000011754712574421673022051 0ustar charlesusers00000000000000from __future__ import with_statement try: import simplejson as json except ImportError: import json import base64 import datetime import unittest from flask import g from flask_peewee.rest import Authentication from flask_peewee.rest import RestAPI from flask_peewee.rest import RestResource from flask_peewee.rest import UserAuthentication from flask_peewee.tests.base import FlaskPeeweeTestCase from flask_peewee.tests.test_app import AModel from flask_peewee.tests.test_app import APIKey from flask_peewee.tests.test_app import BModel from flask_peewee.tests.test_app import CModel from flask_peewee.tests.test_app import EModel from flask_peewee.tests.test_app import FModel from flask_peewee.tests.test_app import Message from flask_peewee.tests.test_app import Note from flask_peewee.tests.test_app import TestModel from flask_peewee.tests.test_app import User from flask_peewee.utils import check_password from flask_peewee.utils import get_next from flask_peewee.utils import make_password class RestApiTestCase(FlaskPeeweeTestCase): def setUp(self): super(RestApiTestCase, self).setUp() TestModel.drop_table(True) APIKey.drop_table(True) APIKey.create_table() TestModel.create_table() def response_json(self, response): return json.loads(response.data.decode('utf8')) def auth_headers(self, username, password): data = '%s:%s' % (username, password) return {'Authorization': 'Basic %s' % base64.b64encode(data.encode('utf8')).decode('utf8')} def conv_date(self, dt): return dt.strftime('%Y-%m-%d %H:%M:%S') def assertAPIResponse(self, resp_json, body): self.assertEqual(body, resp_json['objects']) def assertAPIMeta(self, resp_json, meta): self.assertEqual(meta, resp_json['meta']) def assertAPIUser(self, json_data, user): self.assertEqual(json_data, { 'username': user.username, 'active': user.active, 'join_date': self.conv_date(user.join_date), 'admin': user.admin, 'id': user.id, }) def assertAPIUsers(self, json_data, users): for json_item, user in zip(json_data['objects'], users): self.assertAPIUser(json_item, user) def assertAPINote(self, json_data, note): self.assertEqual(json_data, { 'user': note.user.id, 'message': note.message, 'created_date': self.conv_date(note.created_date), 'id': note.id, }) def assertAPINotes(self, json_data, notes): for json_item, note in zip(json_data['objects'], notes): self.assertAPINote(json_item, note) def assertAPIMessage(self, json_data, message): self.assertEqual(json_data, { 'user': message.user.id, 'content': message.content, 'pub_date': self.conv_date(message.pub_date), 'id': message.id, }) def assertAPIMessages(self, json_data, messages): for json_item, message in zip(json_data['objects'], messages): self.assertAPIMessage(json_item, message) def assertAPITestModel(self, json_data, tm): self.assertEqual(json_data, { 'data': tm.data, 'id': tm.id, }) def assertAPITestModels(self, json_data, tms): for json_item, tm in zip(json_data['objects'], tms): self.assertAPITestModel(json_item, tm) class RestApiResourceTestCase(RestApiTestCase): def setUp(self): super(RestApiResourceTestCase, self).setUp() FModel.delete().execute() EModel.delete().execute() CModel.delete().execute() BModel.delete().execute() AModel.delete().execute() def create_test_models(self): self.a1 = AModel.create(a_field='a1') self.a2 = AModel.create(a_field='a2') self.b1 = BModel.create(b_field='b1', a=self.a1) self.b2 = BModel.create(b_field='b2', a=self.a2) self.c1 = CModel.create(c_field='c1', b=self.b1) self.c2 = CModel.create(c_field='c2', b=self.b2) self.e1 = EModel.create(e_field='e1') self.e2 = EModel.create(e_field='e2') self.f1 = FModel.create(f_field='f1', e=self.e1) self.f2 = FModel.create(f_field='f2') def test_resources_list_detail(self): self.create_test_models() # amodel resp = self.app.get('/api/amodel/?ordering=id') resp_json = self.response_json(resp) self.assertEqual(resp_json['objects'], [ {'id': self.a1.id, 'a_field': 'a1'}, {'id': self.a2.id, 'a_field': 'a2'}, ]) resp = self.app.get('/api/amodel/%s/' % self.a2.id) resp_json = self.response_json(resp) self.assertEqual(resp_json, { 'id': self.a2.id, 'a_field': 'a2', }) # bmodel resp = self.app.get('/api/bmodel/?ordering=id') resp_json = self.response_json(resp) self.assertEqual(resp_json['objects'], [ {'id': self.b1.id, 'b_field': 'b1', 'a': {'id': self.a1.id, 'a_field': 'a1'}}, {'id': self.b2.id, 'b_field': 'b2', 'a': {'id': self.a2.id, 'a_field': 'a2'}}, ]) resp = self.app.get('/api/bmodel/%s/' % self.b2.id) resp_json = self.response_json(resp) self.assertEqual(resp_json, { 'id': self.b2.id, 'b_field': 'b2', 'a': {'id': self.a2.id, 'a_field': 'a2'}, }) # cmodel resp = self.app.get('/api/cmodel/?ordering=id') resp_json = self.response_json(resp) self.assertEqual(resp_json['objects'], [ {'id': self.c1.id, 'c_field': 'c1', 'b': {'id': self.b1.id, 'b_field': 'b1', 'a': {'id': self.a1.id, 'a_field': 'a1'}}}, {'id': self.c2.id, 'c_field': 'c2', 'b': {'id': self.b2.id, 'b_field': 'b2', 'a': {'id': self.a2.id, 'a_field': 'a2'}}}, ]) resp = self.app.get('/api/cmodel/%s/' % self.c2.id) resp_json = self.response_json(resp) self.assertEqual(resp_json, { 'id': self.c2.id, 'c_field': 'c2', 'b': {'id': self.b2.id, 'b_field': 'b2', 'a': {'id': self.a2.id, 'a_field': 'a2'}}, }) # fmodel resp = self.app.get('/api/fmodel/?ordering=id') resp_json = self.response_json(resp) self.assertEqual(resp_json['objects'], [ {'id': self.f1.id, 'f_field': 'f1', 'e': {'id': self.e1.id, 'e_field': 'e1'}}, {'id': self.f2.id, 'f_field': 'f2', 'e': None}, ]) resp = self.app.get('/api/fmodel/%s/' % self.f1.id) resp_json = self.response_json(resp) self.assertEqual(resp_json, { 'id': self.f1.id, 'f_field': 'f1', 'e': {'id': self.e1.id, 'e_field': 'e1'}, }) resp = self.app.get('/api/fmodel/%s/' % self.f2.id) resp_json = self.response_json(resp) self.assertEqual(resp_json, { 'id': self.f2.id, 'f_field': 'f2', 'e': None, }) def post_to(self, url, data): return self.app.post(url, data=json.dumps(data)) def test_resources_create(self): # a model resp = self.post_to('/api/amodel/', {'a_field': 'ax'}) self.assertEqual(resp.status_code, 200) self.assertEqual(AModel.select().count(), 1) a_obj = AModel.get(a_field='ax') self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': a_obj.id, 'a_field': 'ax', }) # b model resp = self.post_to('/api/bmodel/', {'b_field': 'by', 'a': {'a_field': 'ay'}}) self.assertEqual(resp.status_code, 200) self.assertEqual(BModel.select().count(), 1) self.assertEqual(AModel.select().count(), 2) b_obj = BModel.get(b_field='by') a_obj = AModel.get(a_field='ay') self.assertEqual(b_obj.a, a_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': b_obj.id, 'b_field': 'by', 'a': { 'id': a_obj.id, 'a_field': 'ay', }, }) # c model resp = self.post_to('/api/cmodel/', {'c_field': 'cz', 'b': {'b_field': 'bz', 'a': {'a_field': 'az'}}}) self.assertEqual(resp.status_code, 200) self.assertEqual(CModel.select().count(), 1) self.assertEqual(BModel.select().count(), 2) self.assertEqual(AModel.select().count(), 3) c_obj = CModel.get(c_field='cz') b_obj = BModel.get(b_field='bz') a_obj = AModel.get(a_field='az') self.assertEqual(c_obj.b, b_obj) self.assertEqual(b_obj.a, a_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': c_obj.id, 'c_field': 'cz', 'b': { 'id': b_obj.id, 'b_field': 'bz', 'a': { 'id': a_obj.id, 'a_field': 'az', }, }, }) # f model resp = self.post_to('/api/fmodel/', {'f_field': 'fy', 'e': {'e_field': 'ey'}}) self.assertEqual(resp.status_code, 200) self.assertEqual(FModel.select().count(), 1) self.assertEqual(EModel.select().count(), 1) f_obj = FModel.get(f_field='fy') e_obj = EModel.get(e_field='ey') self.assertEqual(f_obj.e, e_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': f_obj.id, 'f_field': 'fy', 'e': { 'id': e_obj.id, 'e_field': 'ey', }, }) resp = self.post_to('/api/fmodel/', {'f_field': 'fz'}) self.assertEqual(resp.status_code, 200) self.assertEqual(FModel.select().count(), 2) self.assertEqual(EModel.select().count(), 1) f_obj = FModel.get(f_field='fz') self.assertEqual(f_obj.e, None) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': f_obj.id, 'f_field': 'fz', 'e': None, }) def test_resources_edit(self): self.create_test_models() # a resp = self.post_to('/api/amodel/%s/' % self.a2.id, {'a_field': 'a2-xxx'}) self.assertEqual(resp.status_code, 200) self.assertEqual(AModel.select().count(), 2) a_obj = AModel.get(id=self.a2.id) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': self.a2.id, 'a_field': 'a2-xxx', }) # b resp = self.post_to('/api/bmodel/%s/' % self.b2.id, {'b_field': 'b2-yyy', 'a': {'a_field': 'a2-yyy'}}) self.assertEqual(resp.status_code, 200) self.assertEqual(BModel.select().count(), 2) self.assertEqual(AModel.select().count(), 2) b_obj = BModel.get(id=self.b2.id) a_obj = AModel.get(id=self.a2.id) self.assertEqual(b_obj.a, a_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': b_obj.id, 'b_field': 'b2-yyy', 'a': { 'id': a_obj.id, 'a_field': 'a2-yyy', }, }) # c resp = self.post_to('/api/cmodel/%s/' % self.c2.id, {'c_field': 'c2-zzz', 'b': {'b_field': 'b2-zzz', 'a': {'a_field': 'a2-zzz'}}}) self.assertEqual(resp.status_code, 200) self.assertEqual(CModel.select().count(), 2) self.assertEqual(BModel.select().count(), 2) self.assertEqual(AModel.select().count(), 2) c_obj = CModel.get(id=self.c2.id) b_obj = BModel.get(id=self.b2.id) a_obj = AModel.get(id=self.a2.id) self.assertEqual(c_obj.b, b_obj) self.assertEqual(b_obj.a, a_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': c_obj.id, 'c_field': 'c2-zzz', 'b': { 'id': b_obj.id, 'b_field': 'b2-zzz', 'a': { 'id': a_obj.id, 'a_field': 'a2-zzz', }, }, }) # f resp = self.post_to('/api/fmodel/%s/' % self.f1.id, {'f_field': 'f1-yyy', 'e': {'e_field': 'e1-yyy'}}) self.assertEqual(resp.status_code, 200) self.assertEqual(FModel.select().count(), 2) self.assertEqual(EModel.select().count(), 2) f_obj = FModel.get(id=self.f1.id) e_obj = EModel.get(id=self.e1.id) self.assertEqual(f_obj.e, e_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': f_obj.id, 'f_field': 'f1-yyy', 'e': { 'id': e_obj.id, 'e_field': 'e1-yyy', }, }) resp = self.post_to('/api/fmodel/%s/' % self.f2.id, {'f_field': 'f2-yyy'}) self.assertEqual(resp.status_code, 200) self.assertEqual(FModel.select().count(), 2) self.assertEqual(EModel.select().count(), 2) f_obj = FModel.get(id=self.f2.id) self.assertEqual(f_obj.e, None) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': f_obj.id, 'f_field': 'f2-yyy', 'e': None, }) def test_resource_edit_partial(self): self.create_test_models() # b model resp = self.post_to('/api/bmodel/%s/' % self.b2.id, {'b_field': 'b2-yyy'}) self.assertEqual(resp.status_code, 200) self.assertEqual(BModel.select().count(), 2) self.assertEqual(AModel.select().count(), 2) b_obj = BModel.get(id=self.b2.id) a_obj = AModel.get(id=self.a2.id) self.assertEqual(b_obj.a, a_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': b_obj.id, 'b_field': 'b2-yyy', 'a': { 'id': a_obj.id, 'a_field': 'a2', }, }) # f model resp = self.post_to('/api/fmodel/%s/' % self.f1.id, {'f_field': 'f1-zzz'}) self.assertEqual(resp.status_code, 200) self.assertEqual(FModel.select().count(), 2) self.assertEqual(EModel.select().count(), 2) f_obj = FModel.get(id=self.f1.id) e_obj = EModel.get(id=self.e1.id) self.assertEqual(f_obj.e, e_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': f_obj.id, 'f_field': 'f1-zzz', 'e': { 'id': e_obj.id, 'e_field': 'e1', }, }) def test_resource_edit_by_fk(self): self.create_test_models() # b model resp = self.post_to('/api/bmodel/%s/' % self.b2.id, {'a': self.a1.id}) self.assertEqual(resp.status_code, 200) self.assertEqual(BModel.select().count(), 2) self.assertEqual(AModel.select().count(), 2) b_obj = BModel.get(id=self.b2.id) a_obj = AModel.get(id=self.a1.id) self.assertEqual(b_obj.a, a_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': b_obj.id, 'b_field': 'b2', 'a': { 'id': a_obj.id, 'a_field': 'a1', }, }) # f model resp = self.post_to('/api/fmodel/%s/' % self.f2.id, {'e': self.e2.id}) self.assertEqual(resp.status_code, 200) self.assertEqual(BModel.select().count(), 2) self.assertEqual(AModel.select().count(), 2) f_obj = FModel.get(id=self.f2.id) e_obj = EModel.get(id=self.e2.id) self.assertEqual(f_obj.e, e_obj) self.assertEqual(json.loads(resp.data.decode('utf8')), { 'id': f_obj.id, 'f_field': 'f2', 'e': { 'id': e_obj.id, 'e_field': 'e2', }, }) def test_delete(self): self.create_test_models() resp = self.post_to('/api/cmodel/%s/delete/' % self.c2.id, {}) self.assertEqual(json.loads(resp.data.decode('utf8')), {'deleted': 1}) self.assertEqual(CModel.select().count(), 1) self.assertEqual(BModel.select().count(), 2) self.assertEqual(AModel.select().count(), 2) resp = self.post_to('/api/amodel/%s/delete/' % self.a1.id, {}) self.assertEqual(json.loads(resp.data.decode('utf8')), {'deleted': 1}) self.assertEqual(CModel.select().count(), 0) self.assertEqual(BModel.select().count(), 1) self.assertEqual(AModel.select().count(), 1) resp = self.post_to('/api/emodel/%s/delete/' % self.e1.id, {}) self.assertEqual(json.loads(resp.data.decode('utf8')), {'deleted': 1}) self.assertEqual(EModel.select().count(), 1) self.assertEqual(FModel.select().count(), 2) f_obj = FModel.get(id=self.f1.id) self.assertEqual(f_obj.e, None) class RestApiBasicTestCase(RestApiTestCase): def get_users_and_notes(self): users = self.create_users() notes = [] for i in range(10): for user in users: notes.append(Note.create(user=user, message='%s-%s' % (user.username, i))) return users, notes def test_pagination(self): users, notes = self.get_users_and_notes() # do a simple list of the first 20 items resp = self.app.get('/api/note/?ordering=id') resp_json = self.response_json(resp) # verify we have page and link to next page self.assertEqual(resp_json['meta']['model'], 'note') self.assertEqual(resp_json['meta']['previous'], '') self.assertEqual(resp_json['meta']['page'], 1) self.assertTrue('page=2' in resp_json['meta']['next']) # verify response objects are paginated properly self.assertAPINotes(resp_json, notes[:20]) # do a list of first 10 items resp = self.app.get('/api/note/?ordering=id&limit=10') resp_json = self.response_json(resp) self.assertEqual(resp_json['meta']['model'], 'note') self.assertEqual(resp_json['meta']['previous'], '') self.assertEqual(resp_json['meta']['page'], 1) self.assertTrue('page=2' in resp_json['meta']['next']) # verify response objects are paginated properly self.assertAPINotes(resp_json, notes[:10]) # grab the second page resp = self.app.get(resp_json['meta']['next']) resp_json = self.response_json(resp) self.assertEqual(resp_json['meta']['model'], 'note') self.assertEqual(resp_json['meta']['page'], 2) self.assertTrue('page=1' in resp_json['meta']['previous']) self.assertTrue('page=3' in resp_json['meta']['next']) # verify response objects are paginated properly self.assertAPINotes(resp_json, notes[10:20]) # grab the last page resp = self.app.get(resp_json['meta']['next']) resp_json = self.response_json(resp) self.assertEqual(resp_json['meta']['model'], 'note') self.assertEqual(resp_json['meta']['next'], '') self.assertEqual(resp_json['meta']['page'], 3) self.assertTrue('page=2' in resp_json['meta']['previous']) # verify response objects are paginated properly self.assertAPINotes(resp_json, notes[20:]) def test_filtering(self): users, notes = self.get_users_and_notes() # do a simple filter on a related model resp = self.app.get('/api/note/?user=%s&ordering=id' % self.normal.id) resp_json = self.response_json(resp) self.assertAPIMeta(resp_json, { 'model': 'note', 'previous': '', 'next': '', 'page': 1, }) self.assertAPINotes(resp_json, self.normal.note_set.order_by(Note.id)) # do a filter following a join resp = self.app.get('/api/note/?user__username=admin&ordering=id') resp_json = self.response_json(resp) self.assertAPIMeta(resp_json, { 'model': 'note', 'previous': '', 'next': '', 'page': 1, }) self.assertAPINotes(resp_json, self.admin.note_set.order_by(Note.id)) # filter multiple fields notes = list(self.admin.note_set.order_by(Note.id)) third_id = notes[3].id resp = self.app.get('/api/note/?user__username=admin&id__lt=%s&ordering=id' % third_id) resp_json = self.response_json(resp) self.assertAPINotes(resp_json, notes[:3]) # do a filter using multiple values resp = self.app.get('/api/note/?user__username=admin&user__username=inactive&ordering=id') resp_json = self.response_json(resp) self.assertAPIMeta(resp_json, { 'model': 'note', 'previous': '', 'next': '', 'page': 1, }) self.assertAPINotes(resp_json, Note.filter(user__in=[self.admin, self.inactive]).order_by(Note.id)) # do a filter with a negation resp = self.app.get('/api/note/?-user__username=admin&ordering=id') resp_json = self.response_json(resp) self.assertAPINotes(resp_json, Note.filter(user__in=[ self.normal, self.inactive]).order_by(Note.id)) # do a filter with an IN operator and multiple IDs # https://github.com/coleifer/flask-peewee/issues/112 resp = self.app.get('/api/note/?id__in=1,2,5') resp_json = self.response_json(resp) self.assertAPINotes(resp_json, Note.filter(id__in=[1,2,5]).order_by(Note.id)) # also test that the IN operator works with list of strings resp = self.app.get('/api/user/?username__in=admin,normal') resp_json = self.response_json(resp) self.assertAPIUsers(resp_json, User.filter(username__in=['admin', 'normal']).order_by(User.id)) def test_filter_with_pagination(self): users, notes = self.get_users_and_notes() notes = list(self.admin.note_set.order_by(Note.id)) # do a simple filter on a related model resp = self.app.get('/api/note/?user__username=admin&limit=4&ordering=id') resp_json = self.response_json(resp) self.assertAPINotes(resp_json, notes[:4]) next_url = resp_json['meta']['next'] resp = self.app.get(next_url) resp_json = self.response_json(resp) self.assertAPINotes(resp_json, notes[4:8]) next_url = resp_json['meta']['next'] resp = self.app.get(next_url) resp_json = self.response_json(resp) self.assertEqual(resp_json['meta']['next'], '') self.assertAPINotes(resp_json, notes[8:]) prev_url = resp_json['meta']['previous'] resp = self.app.get(prev_url) resp_json = self.response_json(resp) self.assertAPINotes(resp_json, notes[4:8]) prev_url = resp_json['meta']['previous'] resp = self.app.get(prev_url) resp_json = self.response_json(resp) self.assertEqual(resp_json['meta']['previous'], '') self.assertAPINotes(resp_json, notes[:4]) class RestApiUserAuthTestCase(RestApiTestCase): def setUp(self): super(RestApiUserAuthTestCase, self).setUp() self.create_users() def create_notes(self): notes = [ Note.create(user=self.admin, message='admin'), Note.create(user=self.normal, message='normal'), ] self.admin_note, self.normal_note = notes return notes def test_list_get(self): resp = self.app.get('/api/note/') resp_json = self.response_json(resp) self.assertAPIResponse(resp_json, []) self.assertAPIMeta(resp_json, {'model': 'note', 'next': '', 'page': 1, 'previous': ''}) self.create_notes() resp = self.app.get('/api/note/?ordering=id') resp_json = self.response_json(resp) self.assertAPINotes(resp_json, [ self.admin_note, self.normal_note, ]) def test_detail_get(self): resp = self.app.get('/api/note/1/') self.assertEqual(resp.status_code, 404) self.create_notes() resp = self.app.get('/api/note/%s/' % self.normal_note.id) resp_json = self.response_json(resp) self.assertAPINote(resp_json, self.normal_note) def test_auth_create(self): note_data = {'message': 'test', 'user': self.inactive.id} serialized = json.dumps(note_data) # this request is not authorized resp = self.app.post('/api/note/', data=serialized) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.post('/api/note/', data=serialized, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database resp = self.app.post('/api/note/', data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) def test_create(self): note_data = {'message': 'test', 'user': self.inactive.id} serialized = json.dumps(note_data) # authorized as an admin resp = self.app.post('/api/note/', data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) new_note = Note.get(message='test') self.assertEqual(new_note.user, self.inactive) resp_json = self.response_json(resp) self.assertAPINote(resp_json, new_note) def test_auth_edit(self): self.create_notes() note_data = {'message': 'edited'} serialized = json.dumps(note_data) url = '/api/note/%s/' % self.admin_note.id # this request is not authorized resp = self.app.put(url, data=serialized) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.put(url, data=serialized, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database resp = self.app.put(url, data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) def test_edit(self): self.create_notes() note_data = {'message': 'edited'} serialized = json.dumps(note_data) url = '/api/note/%s/' % self.admin_note.id # authorized as an admin resp = self.app.put(url, data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) note = Note.get(id=self.admin_note.id) self.assertEqual(note.message, 'edited') resp_json = self.response_json(resp) self.assertAPINote(resp_json, note) def test_auth_delete(self): self.create_notes() url = '/api/note/%s/' % self.admin_note.id # this request is not authorized resp = self.app.delete(url) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.delete(url, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database resp = self.app.delete(url, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) def test_delete(self): self.create_notes() url = '/api/note/%s/' % self.admin_note.id # authorized as an admin resp = self.app.delete(url, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) self.assertEqual(Note.select().count(), 1) resp_json = self.response_json(resp) self.assertEqual(resp_json, {'deleted': 1}) class RestApiOwnerAuthTestCase(RestApiTestCase): def setUp(self): super(RestApiOwnerAuthTestCase, self).setUp() self.create_users() def create_messages(self): messages = [ Message.create(user=self.admin, content='admin'), Message.create(user=self.normal, content='normal'), ] self.admin_message, self.normal_message = messages return messages def test_list_get(self): resp = self.app.get('/api/message/') resp_json = self.response_json(resp) self.assertAPIResponse(resp_json, []) self.assertAPIMeta(resp_json, {'model': 'message', 'next': '', 'page': 1, 'previous': ''}) self.create_messages() resp = self.app.get('/api/message/?ordering=id') resp_json = self.response_json(resp) self.assertAPIMessages(resp_json, [ self.admin_message, self.normal_message, ]) def test_detail_get(self): resp = self.app.get('/api/message/1/') self.assertEqual(resp.status_code, 404) self.create_messages() resp = self.app.get('/api/message/%s/' % self.normal_message.id) resp_json = self.response_json(resp) self.assertAPIMessage(resp_json, self.normal_message) def test_auth_create(self): message_data = {'content': 'test'} serialized = json.dumps(message_data) # this request is not authorized resp = self.app.post('/api/message/', data=serialized) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.post('/api/message/', data=serialized, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database resp = self.app.post('/api/message/', data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) def test_create(self): message_data = {'content': 'test'} serialized = json.dumps(message_data) # authorized as an admin resp = self.app.post('/api/message/', data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) new_message = Message.get(content='test') self.assertEqual(new_message.user, self.normal) resp_json = self.response_json(resp) self.assertAPIMessage(resp_json, new_message) def test_auth_edit(self): self.create_messages() message_data = {'content': 'edited'} serialized = json.dumps(message_data) url = '/api/message/%s/' % self.normal_message.id # this request is not authorized resp = self.app.put(url, data=serialized) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.put(url, data=serialized, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database, but not owner resp = self.app.put(url, data=serialized, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 403) # authorized, user in database, is owner resp = self.app.put(url, data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) obj = Message.get(id=self.normal_message.id) self.assertEqual(obj.content, 'edited') def test_edit(self): self.create_messages() message_data = {'content': 'edited'} serialized = json.dumps(message_data) url = '/api/message/%s/' % self.normal_message.id # authorized as normal resp = self.app.put(url, data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) message = Message.get(id=self.normal_message.id) self.assertEqual(message.content, 'edited') resp_json = self.response_json(resp) self.assertAPIMessage(resp_json, message) def test_auth_delete(self): self.create_messages() url = '/api/message/%s/' % self.normal_message.id # this request is not authorized resp = self.app.delete(url) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.delete(url, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database, not owner resp = self.app.delete(url, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 403) # authorized, user in database, is owner resp = self.app.delete(url, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) def test_delete(self): self.create_messages() url = '/api/message/%s/' % self.normal_message.id # authorized as an admin resp = self.app.delete(url, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 200) self.assertEqual(Message.select().count(), 1) resp_json = self.response_json(resp) self.assertEqual(resp_json, {'deleted': 1}) class RestApiAdminAuthTestCase(RestApiTestCase): def test_list_get(self): resp = self.app.get('/api/user/') resp_json = self.response_json(resp) self.assertAPIResponse(resp_json, []) self.assertAPIMeta(resp_json, {'model': 'user', 'next': '', 'page': 1, 'previous': ''}) self.create_users() resp = self.app.get('/api/user/?ordering=id') resp_json = self.response_json(resp) self.assertAPIUsers(resp_json, [ self.admin, self.normal, ]) def test_detail_get(self): resp = self.app.get('/api/user/1/') self.assertEqual(resp.status_code, 404) self.create_users() resp = self.app.get('/api/user/%s/' % self.normal.id) resp_json = self.response_json(resp) self.assertAPIUser(resp_json, self.normal) resp = self.app.get('/api/user/%s/' % self.inactive.id) self.assertEqual(resp.status_code, 404) def test_auth_create(self): self.create_users() new_pass = make_password('test') user_data = {'username': 'test', 'password': new_pass, 'email': ''} serialized = json.dumps(user_data) # this request is not authorized resp = self.app.post('/api/user/', data=serialized) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.post('/api/user/', data=serialized, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database, but not an administrator resp = self.app.post('/api/user/', data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 401) # authorized as an admin resp = self.app.post('/api/user/', data=serialized, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 200) def test_create(self): self.create_users() new_pass = make_password('test') user_data = {'username': 'test', 'password': new_pass, 'email': ''} serialized = json.dumps(user_data) # authorized as an admin resp = self.app.post('/api/user/', data=serialized, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 200) new_user = User.get(username='test') self.assertTrue(check_password('test', new_user.password)) resp_json = self.response_json(resp) self.assertAPIUser(resp_json, new_user) def test_auth_edit(self): self.create_users() user_data = {'username': 'edited'} serialized = json.dumps(user_data) url = '/api/user/%s/' % self.normal.id # this request is not authorized resp = self.app.put(url, data=serialized) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.put(url, data=serialized, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database, but not an administrator resp = self.app.put(url, data=serialized, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 401) # authorized as an admin resp = self.app.put(url, data=serialized, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 200) def test_edit(self): self.create_users() user_data = {'username': 'edited'} serialized = json.dumps(user_data) url = '/api/user/%s/' % self.normal.id # authorized as an admin resp = self.app.put(url, data=serialized, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 200) user = User.get(id=self.normal.id) self.assertEqual(user.username, 'edited') resp_json = self.response_json(resp) self.assertAPIUser(resp_json, user) def test_auth_delete(self): self.create_users() url = '/api/user/%s/' % self.normal.id # this request is not authorized resp = self.app.delete(url) self.assertEqual(resp.status_code, 401) # authorized, but user does not exist in database resp = self.app.delete(url, headers=self.auth_headers('xxx', 'xxx')) self.assertEqual(resp.status_code, 401) # authorized, user in database, but not an administrator resp = self.app.delete(url, headers=self.auth_headers('normal', 'normal')) self.assertEqual(resp.status_code, 401) # authorized as an admin resp = self.app.delete(url, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 200) def test_delete(self): self.create_users() url = '/api/user/%s/' % self.normal.id # authorized as an admin resp = self.app.delete(url, headers=self.auth_headers('admin', 'admin')) self.assertEqual(resp.status_code, 200) self.assertEqual(User.select().count(), 2) resp_json = self.response_json(resp) self.assertEqual(resp_json, {'deleted': 1}) class RestApiKeyAuthTestCase(RestApiTestCase): def setUp(self): super(RestApiKeyAuthTestCase, self).setUp() self.tm1 = TestModel.create(data='test1') self.tm2 = TestModel.create(data='test2') self.k1 = APIKey.create(key='k', secret='s') self.k2 = APIKey.create(key='k2', secret='s2') def test_list_get(self): with self.flask_app.test_client() as c: resp = c.get('/api/testmodel/') self.assertEqual(resp.status_code, 401) self.assertEqual(g.api_key, None) resp = c.get('/api/testmodel/?key=k&secret=s2') self.assertEqual(resp.status_code, 401) self.assertEqual(g.api_key, None) resp = c.get('/api/testmodel/?key=k&secret=s') self.assertEqual(g.api_key, self.k1) resp_json = self.response_json(resp) self.assertAPITestModels(resp_json, [ self.tm1, self.tm2, ]) self.assertAPIMeta(resp_json, {'model': 'testmodel', 'next': '', 'page': 1, 'previous': ''}) def test_auth_headers(self): with self.flask_app.test_client() as c: resp = c.get('/api/testmodel/', headers={'key': 'k', 'secret': 'foo'}) self.assertEqual(resp.status_code, 401) self.assertEqual(g.api_key, None) resp = c.get('/api/testmodel/', headers={'key': 'k', 'secret': 's'}) self.assertEqual(resp.status_code, 200) self.assertEqual(g.api_key, self.k1) def test_create(self): with self.flask_app.test_client() as c: test_data = {'data': 't3'} serialized = json.dumps(test_data) resp = c.post('/api/testmodel/', data=serialized) self.assertEqual(resp.status_code, 401) self.assertEqual(g.api_key, None) resp = c.post('/api/testmodel/?key=k&secret=s2', data=serialized) self.assertEqual(resp.status_code, 401) self.assertEqual(g.api_key, None) # test passing in via get args resp = c.post('/api/testmodel/?key=k&secret=s', data=serialized) self.assertEqual(g.api_key, self.k1) resp_json = self.response_json(resp) self.assertEqual(TestModel.select().count(), 3) self.assertEqual(resp_json['data'], 't3') flask-peewee-0.6.7/flask_peewee/tests/admin.pyc0000644000175000001440000005307612574421713022316 0ustar charlesusers00000000000000 #Uc@sddlmZddlZddlmZddlmZddlmZddlmZddlm Z ddlm Z dd l m Z dd l mZdd l mZdd l mZdd l mZddl mZddl mZddl mZddl mZddl mZddlmZddlmZddlmZddlmZddlmZde fdYZdefdYZ defdYZ!de fdYZ"dS( i(twith_statementN(tg(trequest(tsession(turl_for(t AdminPanel(t ModelAdmin(tFlaskPeeweeTestCase(tAModel(tBDetails(tBModel(tCModel(tDModel(tMessage(tNote(tUser(tadmin(tcheck_password(tget_next(t make_password(t text_type(t model_formtBaseAdminTestCasecBs eZddZddZRS(cCs4|p |j}|jddidd6dd6dS(Ns/accounts/login/tdataRtusernametpassword(tapptpost(tselftcontext((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pytloginscCs |p |j}|jddS(Ns/accounts/logout/(RR(RR((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pytlogout&sN(t__name__t __module__tNoneRR(((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyRs t AdminTestCasecBskeZdZdZdZdZdZdZdZdZ dZ d Z d Z RS( cCsT|j|jjd}|j|jd|j|jdd|jjddidd6dd 6dd 6}|j|jd|j|jdd |jjd}|j|jd |jjd }|jjddidd6dd 6dd 6}|j|jd|j|jdd |jjd}|j|jddS(Ns/admin/i.tlocations1http://localhost/accounts/login/?next=%2Fadmin%2Fs/accounts/login/RtnormalRRtnextshttp://localhost/admin/is/accounts/logout/Ri(t create_usersRtgett assertEqualt status_codetheadersR(Rtresp((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_admin_auth,s*   c Cs|jjd|jtdd|jtdd|jtdd|jtdd d d |jtd d |jtddWdQXdS(Nt/s admin.indexs/admin/sadmin.user_indexs /admin/user/sadmin.user_adds/admin/user/add/sadmin.user_edittpkis/admin/user/1/sadmin.user_deletes/admin/user/delete/sadmin.panel_notes_creates/admin/notes/create/(t flask_appttest_request_contextR)R(R((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_url_resolutionOsc Cs|j|j|jjd}|j|jd|jd|j|jdtjt tjt tjt tjt tjt tjttjttjtg|jdtjdgdS(Ns/admin/itusert model_adminstpanelstNotes(R'RRR(R)R*t assertContextRt _registryRR R R R R RRt_panels(RR,((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_index_view^s            c Cs|j|jtjjd|jjo}|j||jd}|j|j d|j d|j |j dt j t|j d|jjk|jjd}|jt|jjddd d d d g|jdd idd 6dd 6dd6dd 6dd 6}|j|j d|jtjjd|jd}|j|jidgd 6dgd 6|jdd idd 6dd 6dd6dd 6dd6dd6}|j|j d|jtjjdtjd d}|j|jt|j|j t|j|jd|j|jtjddd|j td|j|j |jdjd|jWdQXdS(Nis/admin/user/add/iR3t model_admintformtactiveRtemailt join_dateRRRttxxxt1s2011-01-01 00:00:00sThis field is required.tnews new@new.news 2011-01-01sjoin_date-dates00:00:00sjoin_date-timei.iiiR$s/admin/user/%d/( R'R)RtselecttcountR0t test_clientRR(R*R7RR8t assertTruet_template_contexttsortedt_fieldstkeysRt get_contextterrorsR=tTruetFalseR>R?tdatetimeRRR+tendswithtid(RtcR,tfrmR3((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_model_admin_addvsZ      "c Cs~|j}|jtjjdgtddD]$}tjd|js8|^q8d}|jj }|j ||j d|}|j|j d|j d|j j}|j|j d|jd |j|jd tjt|jd |jjk|jjd }|jt|jjd d ddddg|j|jidd6|jjd6dd6td 6td 6|jjd6|jd|j jdidd6dd6dd 6dd6dd6dd6}|j|j d|jtjjdtj d|j j}|j|jd|jd }|j|jidgd6dgd6|jd|j jdidd6dd6dd 6dd6dd6dd6}|j|j d|jtjjdtj dd}|j|j|j j|jt d|j|j|j!t|j|jt|j|j"d|j|jt#j#ddd|j|j$d j%d|j|jd|jdid!d6|jd6dd 6dd6dd6dd6}|j|j d|jtjjdtj dd!}|j|j|j j|jt d|jWdQXdS("NiiiRRis/admin/user/%d/iiR3R;R<R=RR>R?RRR%R@RRBs fap@fap.faps 2011-01-01sjoin_date-dates00:00:00sjoin_date-timesThis field is required.teditedsx@x.xi.iR$tedited2(&R'R)RRDREtrangetfiltertexistsR0RFRR(R*R%RRR7RR8RGRHRIRJRKRRRORNR?RRRLRMRR=R>RPR+RQ( Rtuserstxt unused_idRSR,RTR%R3((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_model_admin_edits >      "$  c Csm|j|jjN}|j||jd}|j|jd|jd|j|jdtj t |j d}|jt |g|jd|j j}|j|jd|j d}|jt ||j g|jt jjd|jddi|j jd 6}|j|jd |jt jjd |jt jt jd |j j|j|jd jd |jd|jj|jjf}|j|jd|j d}|jt ||j|jg|jddi|jj|jjgd 6}|j|jd |jt jjdWdQXdS(Ns/admin/user/delete/iR3R;tquerys/admin/user/delete/?id=%diRRRi.iR$s /admin/user/s/admin/user/delete/?id=%d&id=%di(R'R0RFRR(R)R*R7RR8RRLtlistR%RRRDRERt assertRaisest DoesNotExistRGR+RQtinactive(RRSR,R_((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_model_admin_delete0s4  ""%".c Cs|jtjd|jdd}tjd|jdd}tjd|jdd}tjd|jdd}tjd|jdd}tjd|jdd}tjdd}tjdd }tjd d d |} tjd d d |} tjd| } tjd| } t jddd| } t jddd| }t jddd| }t jddd|}|j j +}|j ||jd|j}|j|jd|jd}|j|idt| gfdt| gfdt | gfdt |gfg|j6|jddi|jd6}|j|jd|jtjjd|jtjjd|jtjjd|jt jjd|jt jjd|jd|jj}|j|jd|jd }|jt||jg|jd}|jt|d||jj}|jt|d!|j|dt||gfdt||gfg|jd"di|jjd6}|j|jd|jtjjd!|jtjjd|jtjjd|jd#|jj|jjf}|j|jd|jd}|jt|d!||jj}|jt|d!|j|dt|gfdt|gfg||jj}|jt|d|jd"di|jj|jjgd6}|j|jd|jtjjd|jtjjd|jtjjdWdQXdS($NR3tcontentttest1ttest2ttest3tmessageta_fieldta1ta2tb_fieldtb1tatb2tbtc_fieldtc1tc2td_fieldtd1RStd2s/admin/amodel/delete/?id=%dit collectedis/admin/amodel/delete/RRRi.is/admin/user/delete/?id=%dR_is/admin/user/delete/s/admin/user/delete/?id=%d&id=%d(R'R tcreateR%RRRR R R R R0RFRR(RRR)R*RLRRDRER`tlenRRc(Rtm1tm2tm3tn1tn2tn3RkRlRnRptbd1tbd2RsRtRvRwRSR,RxR_tu_k((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyt!test_model_admin_recursive_deleteas    "% .c Cs|j|jj}|j||jd}|j|jd|jd|j|jdtj t |jdd|j d}|j|g|j d}|jt |j |j|j|jg|j|jd |j|jd WdQXdS( Ns/admin/user/?ordering=usernameiR3R;torderingRtactive_filtersR_i(R'R0RFRR(R)R*R7RR8RRLR`tget_listRcR%tget_paget get_pages(RRSR,RR_((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_model_admin_indexs"   c Cs|j}i}xG|D]?}gtdD]"}tjd|dd|^q,||/admin/user/?fo_username=2&fv_username=norm&ordering=-usernames!/admin/note/?fo_user=0&fv_user=%ds6/admin/note/?fo_user=0&fv_user=%d&fo_user=0&fv_user=%d(R'RXRRyt create_userR0RFRR(R)R*R7RR8RRLR`RR%RR( RR[tnotesR3titnorm2RSR,R_texpected_notes((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_model_admin_index_filterssL  =    #%c Cs |j}i}xG|D]?}gtdD]"}tjd|dd|^q,||s  ( R R!R-R2R:RUR^RdRRRRR(((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyR#+s #   G s 1 `  @ #tAdminFilterTestCasecBs5eZdZdZdZdZdZRS(cCstt|jtjttjttjttjtt jtt j tj tj tj tj dS(N( tsuperRtsetUpR t drop_tableRNR R R Rt create_table(R((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyRQs         cCsxtddD]}tjdd|}tjdd|d|}tjdd |d |}tjd d |d |}|ddkrtjd |}qqWdS(NiiRjsa%dRmsb%dRoRrsc%dRqRusd%dRSii(RXRRyR R R R (RRRoRqRStdtbd((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyt create_models^scCs&|j}|j|jj}|j||jd}|jd}|jg|jD]}|j ^qfdg|jd}|jd}|jg|jD]}|j ^qdg|jd}|jd}|jg|jD]}|j ^qdgWdQXdS(NsG/admin/dmodel/?fr_c-fr_b-fr_a-fo_a_field=0&fr_c-fr_b-fr_a-fv_a_field=a1R_RvsG/admin/dmodel/?fr_c-fr_b-fr_a-fo_a_field=0&fr_c-fr_b-fr_a-fv_a_field=a3td3s0/admin/dmodel/?fr_c-fr_b-fo_a=0&fr_c-fr_b-fv_a=2Rw( R'RR0RFRR(RLR)RRu(RR[RSR,R_to((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyt test_filtersgs   //cCs|jd}i}|g}xU|ru|jd}g|jD]}|j^q@||j<|j|jjq!W|j||dS(Nt field_treei( RLtpoptfieldstnametmodeltextendtchildrentvaluesR)(RtexpectedRt field_dicttqueuetnodetf((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pytassertFieldTree}s  &c Cs9|j}|jj}|j||jd}|jiddgt6|jd}|jiddgt6dddgt6|jd}|jiddgt6dddgt6ddd gt6|jd }|jiddgt6dddgt6ddd gt6dd d gt 6WdQXdS( Ns/admin/amodel/RRRjs/admin/bmodel/RoRms/admin/cmodel/RqRrs/admin/dmodel/RSRu( R'R0RFRR(RRR R R (RR[RSR,((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyt test_lookupss*         (R R!RRRRR(((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyRPs   tTemplateHelperTestCasecBsGeZdZdZdZdZdZdZdZRS(cCsftt|j|j|j|jd|j|jd|j|jdtj|_dS(Ns admin messagesadmin message 2snormal message( RRRR'tcreate_messageRR%ttemplate_helpertth(R((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyRs  cCsg|j|jj|jdd|j|jj|jdd|jt|jj|jddS(NRRt message_countit missing_attr(R)Rtget_model_fieldRRatAttributeError(R((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_get_model_fields""cCs`ttd|j}|j|jj|d|j|j|jj|djddS(NtobjRR(RRRR)Rtget_form_fieldRR(RR<((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_get_form_fields"cCs<|j|jjdd|j|jjdddS(Nt some_models Some ModelttesttTest(R)Rtfix_underscores(R((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_fix_underscoresscCsd}|j|jj|dddd|j|jj|dddd|j|jj|dddd |j|jj|d ddd |j|jj|d ddd |j|jj|d ddd dS(NcSst|jdS(Ntutf8(Rtencode(tt((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pytsR@tpageispage=1ispage=2ssession=3&page=1ssession=3&page=2spage=1&session=3ssession=3&page=1&ordering=idssession=3&ordering=id&page=2ssession=3&ordering=id(R)Rtupdate_querystring(Rtqs((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_update_querystrings (((((cCs|j|jjtdd|j|jjtdd|j|jjtdd|j|jjtdddS( NRtUsernameR?s Join DateRsCan access admint some_fields Some Field(R)Rtget_verbose_nameR(R((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_get_verbose_namesc Cs{|j|jjitjttjttjttjttjt tjt tjt tjt gd6dd6dS(NR4s flask-peeweetbranding( R)Rtget_model_adminsRR8RR R R R R RR(R((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyttest_get_model_adminss       ( R R!RRRRRRR(((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyRs    (#t __future__RRPtflaskRRRRtflask_peewee.adminRRtflask_peewee.tests.baseRtflask_peewee.tests.test_appRR R R R R RRRtflask_peewee.utilsRRRtflask_peewee._compatRt wtfpeewee.ormRRR#RR(((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/admin.pyts8  '[flask-peewee-0.6.7/flask_peewee/tests/admin.py0000644000175000001440000006561212574421673022157 0ustar charlesusers00000000000000from __future__ import with_statement import datetime from flask import g from flask import request from flask import session from flask import url_for from flask_peewee.admin import AdminPanel from flask_peewee.admin import ModelAdmin from flask_peewee.tests.base import FlaskPeeweeTestCase from flask_peewee.tests.test_app import AModel from flask_peewee.tests.test_app import BDetails from flask_peewee.tests.test_app import BModel from flask_peewee.tests.test_app import CModel from flask_peewee.tests.test_app import DModel from flask_peewee.tests.test_app import Message from flask_peewee.tests.test_app import Note from flask_peewee.tests.test_app import User from flask_peewee.tests.test_app import admin from flask_peewee.utils import check_password from flask_peewee.utils import get_next from flask_peewee.utils import make_password from flask_peewee._compat import text_type from wtfpeewee.orm import model_form class BaseAdminTestCase(FlaskPeeweeTestCase): def login(self, context=None): context = context or self.app context.post('/accounts/login/', data={ 'username': 'admin', 'password': 'admin', }) def logout(self, context=None): context = context or self.app context.post('/accounts/logout/') class AdminTestCase(BaseAdminTestCase): def test_admin_auth(self): self.create_users() # check login redirect resp = self.app.get('/admin/') self.assertEqual(resp.status_code, 302) self.assertEqual(resp.headers['location'], 'http://localhost/accounts/login/?next=%2Fadmin%2F') # try logging in as a normal user, get a 403 forbidden resp = self.app.post('/accounts/login/', data={ 'username': 'normal', 'password': 'normal', 'next': '/admin/', }) self.assertEqual(resp.status_code, 302) self.assertEqual(resp.headers['location'], 'http://localhost/admin/') resp = self.app.get('/admin/') self.assertEqual(resp.status_code, 403) # log out from normal user resp = self.app.get('/accounts/logout/') # try logging in as an admin and get a 200 resp = self.app.post('/accounts/login/', data={ 'username': 'admin', 'password': 'admin', 'next': '/admin/', }) self.assertEqual(resp.status_code, 302) self.assertEqual(resp.headers['location'], 'http://localhost/admin/') resp = self.app.get('/admin/') self.assertEqual(resp.status_code, 200) def test_url_resolution(self): # need to be in a 'request' context to use ``url_for`` with self.flask_app.test_request_context('/'): # admin urls self.assertEqual(url_for('admin.index'), '/admin/') # modeladmin urls self.assertEqual(url_for('admin.user_index'), '/admin/user/') self.assertEqual(url_for('admin.user_add'), '/admin/user/add/') self.assertEqual(url_for('admin.user_edit', pk=1), '/admin/user/1/') self.assertEqual(url_for('admin.user_delete'), '/admin/user/delete/') # panel urls self.assertEqual(url_for('admin.panel_notes_create'), '/admin/notes/create/') def test_index_view(self): self.create_users() self.login() # check for context in the index view resp = self.app.get('/admin/') self.assertEqual(resp.status_code, 200) # check that we have the stuff from the auth module and the index view self.assertContext('user', self.admin) self.assertContext('model_admins', [ admin._registry[AModel], admin._registry[BDetails], admin._registry[BModel], admin._registry[CModel], admin._registry[DModel], admin._registry[Message], admin._registry[Note], admin._registry[User], ]) self.assertContext('panels', [ admin._panels['Notes'], ]) def test_model_admin_add(self): self.create_users() self.assertEqual(User.select().count(), 3) with self.flask_app.test_client() as c: self.login(c) # the add url returns a 200 resp = c.get('/admin/user/add/') self.assertEqual(resp.status_code, 200) # ensure the user, model_admin and form are correct in the context self.assertContext('user', self.admin) self.assertContext('model_admin', admin._registry[User]) self.assertTrue('form' in self.flask_app._template_context) frm = self.flask_app._template_context['form'] self.assertEqual(sorted(frm._fields.keys()), [ 'active', 'admin', 'email', 'join_date', 'password', 'username', ]) # make an incomplete post and get a 200 with errors resp = c.post('/admin/user/add/', data={ 'username': '', 'password': 'xxx', 'active': '1', 'email': '', 'join_date': '2011-01-01 00:00:00', }) self.assertEqual(resp.status_code, 200) # no new user created self.assertEqual(User.select().count(), 3) # check the form for errors frm = self.get_context('form') self.assertEqual(frm.errors, { 'username': ['This field is required.'], 'email': ['This field is required.'], }) # make a complete post and get a 302 to the edit page resp = c.post('/admin/user/add/', data={ 'username': 'new', 'password': 'new', 'active': '1', 'email': 'new@new.new', 'join_date-date': '2011-01-01', 'join_date-time': '00:00:00', }) self.assertEqual(resp.status_code, 302) # new user was created self.assertEqual(User.select().count(), 4) # check they have the correct data on the new instance user = User.get(username='new') self.assertEqual(user.active, True) self.assertEqual(user.admin, False) self.assertEqual(user.email, 'new@new.new') self.assertEqual(user.join_date, datetime.datetime(2011, 1, 1)) self.assertTrue(check_password('new', user.password)) # check the redirect was correct self.assertTrue(resp.headers['location'].endswith('/admin/user/%d/' % user.id)) def test_model_admin_edit(self): users = self.create_users() self.assertEqual(User.select().count(), 3) # grab an id so we can test a 404 on non-existent user unused_id = [x for x in range(1, 5) if not User.filter(id=x).exists()][0] with self.flask_app.test_client() as c: self.login(c) # nonexistant user 404s resp = c.get('/admin/user/%d/' % unused_id) self.assertEqual(resp.status_code, 404) # edit page returns a 200 resp = c.get('/admin/user/%d/' % self.normal.id) self.assertEqual(resp.status_code, 200) # check the user, model_admin and form are correct in the context self.assertContext('user', self.admin) self.assertContext('model_admin', admin._registry[User]) self.assertTrue('form' in self.flask_app._template_context) frm = self.flask_app._template_context['form'] self.assertEqual(sorted(frm._fields.keys()), [ 'active', 'admin', 'email', 'join_date', 'password', 'username', ]) # check the form pulled the right data off the model self.assertEqual(frm.data, { 'username': 'normal', 'password': frm.password.data, # skip this 'email': '', 'admin': False, 'active': True, 'join_date': frm.join_date.data, # microseconds...bleh }) # make an incomplete post to update the user and get a 200 w/errors resp = c.post('/admin/user/%d/' % self.normal.id, data={ 'username': '', 'password': '', 'active': '1', 'email': 'fap@fap.fap', 'join_date-date': '2011-01-01', 'join_date-time': '00:00:00', }) self.assertEqual(resp.status_code, 200) # no new user created self.assertEqual(User.select().count(), 3) # refresh database content normal = User.get(id=self.normal.id) self.assertEqual(normal.username, 'normal') # was not saved # check the form for errors frm = self.get_context('form') self.assertEqual(frm.errors, { 'username': ['This field is required.'], 'password': ['This field is required.'], }) # make a complete post resp = c.post('/admin/user/%d/' % self.normal.id, data={ 'username': 'edited', 'password': 'edited', 'active': '1', 'email': 'x@x.x', 'join_date-date': '2011-01-01', 'join_date-time': '00:00:00', }) self.assertEqual(resp.status_code, 302) # no new user was created self.assertEqual(User.select().count(), 3) # grab from the database user = User.get(username='edited') self.assertEqual(user.id, self.normal.id) # it is the same user self.assertTrue(check_password('edited', user.password)) self.assertEqual(user.active, True) self.assertEqual(user.admin, False) self.assertEqual(user.email, 'x@x.x') self.assertEqual(user.join_date, datetime.datetime(2011, 1, 1)) self.assertTrue(resp.headers['location'].endswith('/admin/user/%d/' % user.id)) # make another post without modifying the password, should stay same resp = c.post('/admin/user/%d/' % user.id, data={ 'username': 'edited2', 'password': user.password, 'active': '1', 'email': 'x@x.x', 'join_date-date': '2011-01-01', 'join_date-time': '00:00:00', }) self.assertEqual(resp.status_code, 302) # no new user was created self.assertEqual(User.select().count(), 3) # grab from the database user = User.get(username='edited2') self.assertEqual(user.id, self.normal.id) # it is the same user # the password has not changed self.assertTrue(check_password('edited', user.password)) def test_model_admin_delete(self): self.create_users() with self.flask_app.test_client() as c: self.login(c) # do a basic get, nothing much going on resp = c.get('/admin/user/delete/') self.assertEqual(resp.status_code, 200) self.assertContext('user', self.admin) self.assertContext('model_admin', admin._registry[User]) query = self.get_context('query') self.assertEqual(list(query), []) # send it a single id resp = c.get('/admin/user/delete/?id=%d' % (self.normal.id)) self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query), [self.normal]) # ensure nothing was deleted self.assertEqual(User.select().count(), 3) # post to it, get a redirect on success resp = c.post('/admin/user/delete/', data={'id': self.normal.id}) self.assertEqual(resp.status_code, 302) # ensure the user was deleted self.assertEqual(User.select().count(), 2) self.assertRaises(User.DoesNotExist, User.get, id=self.normal.id) self.assertTrue(resp.headers['location'].endswith('/admin/user/')) # do a multi-delete resp = c.get('/admin/user/delete/?id=%d&id=%d' % (self.admin.id, self.inactive.id)) self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query), [self.admin, self.inactive]) # post to it and check both deleted resp = c.post('/admin/user/delete/', data={'id': [self.admin.id, self.inactive.id]}) self.assertEqual(resp.status_code, 302) self.assertEqual(User.select().count(), 0) def test_model_admin_recursive_delete(self): self.create_users() m1 = Message.create(user=self.normal, content='test1') m2 = Message.create(user=self.normal, content='test2') m3 = Message.create(user=self.admin, content='test3') n1 = Note.create(user=self.normal, message='test1') n2 = Note.create(user=self.normal, message='test2') n3 = Note.create(user=self.admin, message='test3') a1 = AModel.create(a_field='a1') a2 = AModel.create(a_field='a2') b1 = BModel.create(b_field='b1', a=a1) b2 = BModel.create(b_field='b2', a=a2) bd1= BDetails.create(b=b1) bd2= BDetails.create(b=b2) c1 = CModel.create(c_field='c1', b=b1) c2 = CModel.create(c_field='c2', b=b2) d1 = DModel.create(d_field='d1', c=c1) d2 = DModel.create(d_field='d2', c=c2) with self.flask_app.test_client() as c: self.login(c) resp = c.get('/admin/amodel/delete/?id=%d' % (a1.id)) self.assertEqual(resp.status_code, 200) collected = self.get_context('collected') self.assertEqual(collected, { a1.id: [ (0, BDetails, [bd1]), (0, BModel, [b1]), (0, CModel, [c1]), (0, DModel, [d1]), ] }) resp = c.post('/admin/amodel/delete/', data={'id': a1.id}) self.assertEqual(resp.status_code, 302) self.assertEqual(AModel.select().count(), 1) self.assertEqual(BModel.select().count(), 1) self.assertEqual(BDetails.select().count(), 1) self.assertEqual(CModel.select().count(), 1) self.assertEqual(DModel.select().count(), 1) # send it a single id resp = c.get('/admin/user/delete/?id=%d' % (self.normal.id)) self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query), [self.normal]) collected = self.get_context('collected') self.assertEqual(len(collected), 1) u_k = collected[self.normal.id] self.assertEqual(len(u_k), 2) self.assertEqual(u_k, [ (0, Message, [m1, m2]), (0, Note, [n1, n2]), ]) # post to it, get a redirect on success resp = c.post('/admin/user/delete/', data={'id': self.normal.id}) self.assertEqual(resp.status_code, 302) self.assertEqual(User.select().count(), 2) self.assertEqual(Message.select().count(), 1) self.assertEqual(Note.select().count(), 1) resp = c.get('/admin/user/delete/?id=%d&id=%d' % (self.admin.id, self.inactive.id)) self.assertEqual(resp.status_code, 200) collected = self.get_context('collected') self.assertEqual(len(collected), 2) u_k = collected[self.admin.id] self.assertEqual(len(u_k), 2) self.assertEqual(u_k, [ (0, Message, [m3]), (0, Note, [n3]), ]) u_k = collected[self.inactive.id] self.assertEqual(len(u_k), 0) # post to it, get a redirect on success resp = c.post('/admin/user/delete/', data={'id': [self.admin.id, self.inactive.id]}) self.assertEqual(resp.status_code, 302) self.assertEqual(User.select().count(), 0) self.assertEqual(Message.select().count(), 0) self.assertEqual(Note.select().count(), 0) def test_model_admin_index(self): self.create_users() with self.flask_app.test_client() as c: self.login(c) resp = c.get('/admin/user/?ordering=username') self.assertEqual(resp.status_code, 200) self.assertContext('user', self.admin) self.assertContext('model_admin', admin._registry[User]) self.assertContext('ordering', 'username') active_filters = self.get_context('active_filters') self.assertEqual(active_filters, []) query = self.get_context('query') self.assertEqual(list(query.get_list()), [ self.admin, self.inactive, self.normal, ]) self.assertEqual(query.get_page(), 1) self.assertEqual(query.get_pages(), 1) def test_model_admin_index_filters(self): users = self.create_users() notes = {} for user in users: notes[user] = [Note.create(user=user, message='test-%d' % i) for i in range(3)] norm2 = self.create_user('normal2', 'normal2') with self.flask_app.test_client() as c: self.login(c) # test a simple lookup resp = c.get('/admin/user/?fo_username=0&fv_username=admin') self.assertEqual(resp.status_code, 200) self.assertContext('user', self.admin) self.assertContext('model_admin', admin._registry[User]) self.assertContext('ordering', '') query = self.get_context('query') self.assertEqual(list(query.get_list()), [ self.admin, ]) # test a lookup using multiple values joined with "eq" resp = c.get('/admin/user/?fo_username=0&fv_username=admin&fo_username=0&fv_username=normal&ordering=-username') self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query.get_list()), [ self.normal, self.admin, ]) # test a lookup using partial string (startswith) resp = c.get('/admin/user/?fo_username=2&fv_username=norm&ordering=-username') self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query.get_list()), [ norm2, self.normal, ]) # test a lookup spanning a relation resp = c.get('/admin/note/?fo_user=0&fv_user=%d' % self.normal.id) self.assertEqual(resp.status_code, 200) self.assertContext('model_admin', admin._registry[Note]) query = self.get_context('query') self.assertEqual(list(query.get_list()), notes[self.normal]) # test a multi-value lookup spanning a relation resp = c.get('/admin/note/?fo_user=0&fv_user=%d&fo_user=0&fv_user=%d' % (self.normal.id, self.admin.id)) self.assertEqual(resp.status_code, 200) self.assertContext('model_admin', admin._registry[Note]) query = self.get_context('query') expected_notes = notes[self.admin] + notes[self.normal] self.assertEqual(list(query.get_list()), expected_notes) def test_model_admin_index_pagination(self): users = self.create_users() notes = {} for user in users: notes[user] = [Note.create(user=user, message='test-%d' % i) for i in range(20)] with self.flask_app.test_client() as c: self.login(c) # test a simple lookup resp = c.get('/admin/note/?ordering=id') self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query.get_list()), notes[users[0]]) resp = c.get('/admin/note/?ordering=id&page=2') self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query.get_list()), notes[users[1]]) resp = c.get('/admin/note/?ordering=id&page=1&fo_user=0&fv_user=%d&fo_user=0&fv_user=%d' % (users[1].id, users[2].id)) self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query.get_list()), notes[users[1]]) resp = c.get('/admin/note/?ordering=id&page=2&fo_user=0&fv_user=%d&fo_user=0&fv_user=%d' % (users[1].id, users[2].id)) self.assertEqual(resp.status_code, 200) query = self.get_context('query') self.assertEqual(list(query.get_list()), notes[users[2]]) def test_panel_simple(self): users = self.create_users() with self.flask_app.test_client() as c: self.login(c) self.assertEqual(Note.select().count(), 0) resp = c.post('/admin/notes/create/', data={'message': 'testing'}) self.assertEqual(resp.status_code, 302) self.assertTrue(resp.headers['location'].endswith('/admin/')) self.assertEqual(Note.select().count(), 1) note = Note.get(user=self.admin) self.assertEqual(note.message, 'testing') class AdminFilterTestCase(BaseAdminTestCase): def setUp(self): super(AdminFilterTestCase, self).setUp() BDetails.drop_table(True) DModel.drop_table(True) CModel.drop_table(True) BModel.drop_table(True) AModel.drop_table(True) AModel.create_table() BModel.create_table() CModel.create_table() DModel.create_table() BDetails.create_table() def create_models(self): for i in range(1, 4): a = AModel.create(a_field='a%d' % i) b = BModel.create(b_field='b%d' % i, a=a) c = CModel.create(c_field='c%d' % i, b=b) d = DModel.create(d_field='d%d' % i, c=c) if i % 2 == 0: bd = BDetails.create(b=b) def test_filters(self): users = self.create_users() self.create_models() with self.flask_app.test_client() as c: self.login(c) resp = c.get('/admin/dmodel/?fr_c-fr_b-fr_a-fo_a_field=0&fr_c-fr_b-fr_a-fv_a_field=a1') query = self.get_context('query') self.assertEqual([o.d_field for o in query.get_list()], ['d1']) resp = c.get('/admin/dmodel/?fr_c-fr_b-fr_a-fo_a_field=0&fr_c-fr_b-fr_a-fv_a_field=a3') query = self.get_context('query') self.assertEqual([o.d_field for o in query.get_list()], ['d3']) resp = c.get('/admin/dmodel/?fr_c-fr_b-fo_a=0&fr_c-fr_b-fv_a=2') query = self.get_context('query') self.assertEqual([o.d_field for o in query.get_list()], ['d2']) def assertFieldTree(self, expected): field_tree = self.get_context('field_tree') # convert to dict field_dict = {} queue = [field_tree] while queue: node = queue.pop(0) field_dict[node.model] = [f.name for f in node.fields] queue.extend(node.children.values()) self.assertEqual(field_dict, expected) def test_lookups(self): users = self.create_users() with self.flask_app.test_client() as c: self.login(c) resp = c.get('/admin/amodel/') self.assertFieldTree({ AModel: ['id', 'a_field'], }) resp = c.get('/admin/bmodel/') self.assertFieldTree({ AModel: ['id', 'a_field'], BModel: ['id', 'a', 'b_field'], }) resp = c.get('/admin/cmodel/') self.assertFieldTree({ AModel: ['id', 'a_field'], BModel: ['id', 'a', 'b_field'], CModel: ['id', 'b', 'c_field'], }) resp = c.get('/admin/dmodel/') self.assertFieldTree({ AModel: ['id', 'a_field'], BModel: ['id', 'a', 'b_field'], CModel: ['id', 'b', 'c_field'], DModel: ['id', 'c', 'd_field'], }) class TemplateHelperTestCase(FlaskPeeweeTestCase): def setUp(self): super(TemplateHelperTestCase, self).setUp() self.create_users() self.create_message(self.admin, 'admin message') self.create_message(self.admin, 'admin message 2') self.create_message(self.normal, 'normal message') self.th = admin.template_helper def test_get_model_field(self): self.assertEqual(self.th.get_model_field(self.admin, 'username'), 'admin') self.assertEqual(self.th.get_model_field(self.admin, 'message_count'), 2) self.assertRaises(AttributeError, self.th.get_model_field, self.admin, 'missing_attr') def test_get_form_field(self): form = model_form(User)(obj=self.admin) self.assertEqual(self.th.get_form_field(form, 'username'), form.username) self.assertEqual(self.th.get_form_field(form, 'username').data, 'admin') def test_fix_underscores(self): self.assertEqual(self.th.fix_underscores('some_model'), 'Some Model') self.assertEqual(self.th.fix_underscores('test'), 'Test') def test_update_querystring(self): qs = lambda t: text_type(t).encode('utf8') self.assertEqual(self.th.update_querystring(qs(''), 'page', 1), 'page=1') self.assertEqual(self.th.update_querystring(qs('page=1'), 'page', 2), 'page=2') self.assertEqual(self.th.update_querystring(qs('session=3&page=1'), 'page', 2), 'session=3&page=2') self.assertEqual(self.th.update_querystring(qs('page=1&session=3'), 'page', 2), 'session=3&page=2') self.assertEqual(self.th.update_querystring(qs('session=3&page=1&ordering=id'), 'page', 2), 'session=3&ordering=id&page=2') self.assertEqual(self.th.update_querystring(qs('session=3&ordering=id'), 'page', 2), 'session=3&ordering=id&page=2') def test_get_verbose_name(self): self.assertEqual(self.th.get_verbose_name(User, 'username'), 'Username') self.assertEqual(self.th.get_verbose_name(User, 'join_date'), 'Join Date') self.assertEqual(self.th.get_verbose_name(User, 'admin'), 'Can access admin') self.assertEqual(self.th.get_verbose_name(User, 'some_field'), 'Some Field') def test_get_model_admins(self): self.assertEqual(self.th.get_model_admins(), {'model_admins': [ admin._registry[AModel], admin._registry[BDetails], admin._registry[BModel], admin._registry[CModel], admin._registry[DModel], admin._registry[Message], admin._registry[Note], admin._registry[User], ], 'branding': 'flask-peewee'}) flask-peewee-0.6.7/flask_peewee/tests/serializer.py0000644000175000001440000000604212574421673023230 0ustar charlesusers00000000000000import datetime from flask_peewee.serializer import Deserializer from flask_peewee.serializer import Serializer from flask_peewee.tests.base import FlaskPeeweeTestCase from flask_peewee.tests.test_app import Message from flask_peewee.tests.test_app import Note from flask_peewee.tests.test_app import User class SerializerTestCase(FlaskPeeweeTestCase): def setUp(self): super(SerializerTestCase, self).setUp() self.s = Serializer() self.d = Deserializer() def test_serializer(self): users = self.create_users() serialized = self.s.serialize_object(self.admin) self.assertEqual(serialized, { 'id': self.admin.id, 'username': 'admin', 'password': self.admin.password, 'join_date': self.admin.join_date.strftime('%Y-%m-%d %H:%M:%S'), 'active': True, 'admin': True, 'email': '', }) serialized = self.s.serialize_object(self.admin, fields={User: ['id', 'username']}) self.assertEqual(serialized, { 'id': self.admin.id, 'username': 'admin', }) serialized = self.s.serialize_object(self.admin, exclude={User: ['password', 'join_date']}) self.assertEqual(serialized, { 'id': self.admin.id, 'username': 'admin', 'active': True, 'admin': True, 'email': '', }) def test_deserializer(self): users = self.create_users() deserialized, models = self.d.deserialize_object(User(), { 'id': self.admin.id, 'username': 'admin', 'password': self.admin.password, 'join_date': self.admin.join_date.strftime('%Y-%m-%d %H:%M:%S'), 'active': True, 'admin': True, }) for attr in ['id', 'username', 'password', 'active', 'admin']: self.assertEqual( getattr(deserialized, attr), getattr(self.admin, attr), ) self.assertEqual( deserialized.join_date.strftime('%Y-%m-%d %H:%M:%S'), self.admin.join_date.strftime('%Y-%m-%d %H:%M:%S'), ) admin_pk = self.admin.id deserialized, models = self.d.deserialize_object(self.admin, { 'username': 'edited', 'active': False, 'admin': False, }) self.assertEqual(deserialized.username, 'edited') self.assertEqual(deserialized.admin, False) self.assertEqual(deserialized.active, False) self.assertEqual(deserialized.id, admin_pk) deserialized.save() self.assertEqual(User.select().count(), 3) edited = User.get(username='edited') self.assertEqual(edited.id, admin_pk) def test_s_and_d(self): self.create_users() s = self.s.serialize_object(self.admin) d, model_list = self.d.deserialize_object(User(), s) self.assertEqual(d, self.admin) flask-peewee-0.6.7/flask_peewee/tests/test_config.pyc0000644000175000001440000000107012624224541023511 0ustar charlesusers00000000000000 #Uc@sdefdYZdS(t ConfigurationcBs.eZidd6dd6ZeZdZeZRS(stest.dbtnamespeewee.SqliteDatabasetenginetshhhh(t__name__t __module__tDATABASEtTruetDEBUGt SECRET_KEYtTESTING(((sI/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_config.pyRs  N(tobjectR(((sI/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_config.pytsflask-peewee-0.6.7/flask_peewee/tests/utils.pyc0000644000175000001440000000436112624224624022355 0ustar charlesusers00000000000000 #Uc@syddlZWnek r/ddlZnXddlZddlmZddlmZddlm Z ddlm Z ddlm Z ddl m Z ddlmZdd lmZdd lmZdd lmZd e fd YZdS(iN(trequest(tNotFound(tcheck_password(tget_object_or_404(t make_password(tFlaskPeeweeTestCase(tMessage(tNote(tUser(tappt UtilsTestCasecBs#eZdZdZdZRS(cCstt|jdS(N(tsuperR tsetUp(tself((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/utils.pyR scCs|jdd}|jttttjdk|j|tttjdktjjtj t k}tjjtj t k}|jtt|tjdk|jtt|tjdk|j|t|tjdkdS(Nttestsnot-here( t create_usert assertRaisesRRRtusernamet assertEqualtselecttwheretactivetTruetFalse(R tuserRtinactive((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/utils.pyttest_get_object_or_404s"cCstd}|jtd||jtd||jtd||jtd|td}|j||kdS(Nttestingstesting tTestingt(Rt assertTrueRt assertFalse(R tptp2((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/utils.pyttest_passwords's  (t__name__t __module__R RR"(((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/utils.pyR s  (t simplejsontjsont ImportErrortdatetimetflaskRtwerkzeug.exceptionsRtflask_peewee.utilsRRRtflask_peewee.tests.baseRtflask_peewee.tests.test_appRRRR t flask_appR (((sC/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/utils.pyts  flask-peewee-0.6.7/flask_peewee/tests/templates/0000755000175000001440000000000012624225533022472 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/tests/templates/base.html0000644000175000001440000000002712574421673024300 0ustar charlesusers00000000000000{# needed for tests #} flask-peewee-0.6.7/flask_peewee/tests/templates/admin/0000755000175000001440000000000012624225533023562 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/tests/templates/admin/notes.html0000644000175000001440000000000012574421673025575 0ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/tests/serializer.pyc0000644000175000001440000000600112624224624023357 0ustar charlesusers00000000000000 #Uc@sddlZddlmZddlmZddlmZddlmZddlmZddlm Z defd YZ dS( iN(t Deserializer(t Serializer(tFlaskPeeweeTestCase(tMessage(tNote(tUsertSerializerTestCasecBs,eZdZdZdZdZRS(cCs/tt|jt|_t|_dS(N(tsuperRtsetUpRtsRtd(tself((sH/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/serializer.pyR s cCs.|j}|jj|j}|j|i|jjd6dd6|jjd6|jjjdd6t d6t d6dd 6|jj|jd iddgt 6}|j|i|jjd6dd6|jj|jd iddgt 6}|j|i|jjd6dd6t d6t d6dd 6dS( Ntidtadmintusernametpasswords%Y-%m-%d %H:%M:%St join_datetactivettemailtfieldstexclude( t create_usersR tserialize_objectR t assertEqualR RRtstrftimetTrueR(R tuserst serialized((sH/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/serializer.pyttest_serializers*     (   (  cCs|j}|jjti|jjd6dd6|jjd6|jjjdd6t d6t d6\}}xBdddddgD]+}|j t ||t |j|qW|j |jjd|jjjd|jj}|jj|jidd6t d6t d6\}}|j |j d|j |jt |j |jt |j |j||j|j tjjd tjdd}|j |j|dS( NR R RRs%Y-%m-%d %H:%M:%SRRteditedi(RR tdeserialize_objectRR R RRRRRtgetattrtFalseRRtsavetselecttcounttget(R Rt deserializedtmodelstattrtadmin_pkR((sH/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/serializer.pyttest_deserializer-s8      cCsT|j|jj|j}|jjt|\}}|j||jdS(N(RR RR R RRR(R R R t model_list((sH/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/serializer.pyt test_s_and_dWs (t__name__t __module__RRR*R,(((sH/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/serializer.pyR s   *( tdatetimetflask_peewee.serializerRRtflask_peewee.tests.baseRtflask_peewee.tests.test_appRRRR(((sH/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/serializer.pyts flask-peewee-0.6.7/flask_peewee/tests/test_app.pyc0000644000175000001440000003031312624224541023026 0ustar charlesusers00000000000000 #Uc@skddlZddlmZddlmZddlmZddlmZddlmZddlmZddlmZdd lm Z dd l Tdd l m Z dd l m Z dd l mZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlm Z ddlm!Z!defdYZ"e"e#Z$e$j%j&dee$Z'e$j(dZ)d e'j*efd!YZ+d"e'j*fd#YZ,d$e'j*fd%YZ-d&e'j*fd'YZ.d(e'j*fd)YZ/d*e'j*fd+YZ0d,e'j*fd-YZ1d.e'j*fd/YZ2d0e'j*fd1YZ3d2e'j*fd3YZ4d4e'j*fd5YZ5d6e'j*fd7YZ6d8e fd9YZ7ee$e'd:e+Z8e e$e8Z9d;efd<YZ:d=efd>YZ;d?efd@YZ<dAefdBYZ=dCefdDYZ>dEefdFYZ?e8j@e9e9jAe/e:e9jAe0e;e9jAe1e<e9jAe2e=e9jAe3e9jAe,e>e9jAe-e?e9jBdGe7dHefdIYZCdJefdKYZDdLefdMYZEdNefdOYZFdPefdQYZGdRefdSYZHedTgZIee8ZJee8ZKee6dUdVdWdXgZLee$dYeJZMeMjAe,eeMjAe+eCdZeKeMjAe-eMjAe.dZeLeMjAe/eDdZeIeMjAe0eEdZeIeMjAe1eFdZeIeMjAe4eGdZeIeMjAe5eHdZeIe$jNd[d\ZOe$jNd]e8jPd^ZQe$jNd_e8jRd`ZSe9jTeMjTdS(aiN(tFlask(tResponse(tflash(tg(tredirect(trender_template(trequest(turl_for(t*(tAdmin(t AdminPanel(t ModelAdmin(tAuth(tBaseUser(tDatabase(t QueryFilter(tAPIKeyAuthentication(tAdminAuthentication(tAuthentication(tRestAPI(t RestResource(tRestrictOwnerResource(tUserAuthentication(tget_object_or_404(t make_password(t object_listt TestFlaskcBseZdZRS(cCs,tt|j|}|jj||S(N(tsuperRtupdate_template_contextt_template_contexttupdate(tselftcontexttret((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR#s(t__name__t __module__R(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR"ss,flask_peewee.tests.test_config.ConfigurationcCs it_dS(N(tappR(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyt clear_context.stUsercBsweZeZeZeZedejjZ e de Z e de ddZdZdZdZRS(tdefaultt verbose_namesCan access admincCs|jS(N(tusername(R((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyt __unicode__;scCs t|jS(N(thashR)(R((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyt__hash__>scCs |jjS(N(t message_settcount(R((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyt message_countAs(R"R#t CharFieldR)tpasswordtemailt DateTimeFieldtdatetimetnowt join_datet BooleanFieldtTruetactivetFalsetadminR*R,R/(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR&3s     tMessagecBs;eZeeZeZedejj Z dZ RS(R'cCsd|j|jfS(Ns%s: %s(tusertcontent(R((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR*Js( R"R#tForeignKeyFieldR&R=t TextFieldR>R3R4R5tpub_dateR*(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR<Es  tNotecBs2eZeeZeZedejj Z RS(R'( R"R#R?R&R=R@tmessageR3R4R5t created_date(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRBNs  t TestModelcBs$eZeZdddYZRS(tMetacBseZdZRS(tid(sid(R"R#torder_by(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRFWs((R"R#R@tdataRF(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRETs tAModelcBseZeZRS((R"R#R0ta_field(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRJ[stBModelcBseZeeZeZRS((R"R#R?RJtaR0tb_field(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRL^s tCModelcBseZeeZeZRS((R"R#R?RLtbR0tc_field(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRObs tDModelcBseZeeZeZRS((R"R#R?ROtcR0td_field(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRRfs tBDetailscBseZeeZRS((R"R#R?RLRP(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRUjstEModelcBseZeZRS((R"R#R0te_field(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRVnstFModelcBs#eZeedeZeZRS(tnull(R"R#R?RVR8teR0tf_field(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRXqstAPIKeycBseZeZeZRS((R"R#R0tkeytsecret(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR\vs t NotePanelcBs)eZdZdZdZdZRS(sadmin/notes.htmlcCsd|jffS(Ns/create/(tcreate(R((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pytget_urls~scCsrtjdkrJtjjdrJtjdtjdtjdqJntjjdpe|j}t |S(NtPOSTRCR=tnext( RtmethodtformtgetRBR`tauthtget_logged_in_usert dashboard_urlR(RRc((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR`s  cCs&itjjdjddd6S(NRDtdesciit note_list(s created_datesdesc(RBtselectRHtpaginate(R((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyt get_contexts(R"R#t template_nameRaR`Rn(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR_{s  t user_modeltAAdmincBseZdZRS(RK(sa_field(R"R#tcolumns(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRqstBAdmincBseZdZidd6ZRS(RMRNRK(RMsb_field(R"R#Rrtinclude_foreign_keys(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRsstCAdmincBseZdZidd6ZRS(RPRQRN(RPsc_field(R"R#RrRt(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRustDAdmincBseZdZidd6ZRS(RSRTRQ(RSsd_field(R"R#RrRt(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRvst MessageAdmincBseZdZRS(R=R>RA(suserscontentspub_date(R"R#Rr(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRwst NoteAdmincBseZdZRS(R=RCRD(susersmessages created_date(R"R#Rr(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRxstNotest UserResourcecBseZdZdZRS(R1R2cCstjjtjtkS(N(R&RltwhereR9R8(R((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyt get_querys(spasswordsemail(R"R#texcludeR|(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRzst AResourcecBseZRS((R"R#(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyR~st BResourcecBseZied6ZRS(RM(R"R#R~tinclude_resources(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRst CResourcecBseZied6ZRS(RP(R"R#RR(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRst EResourcecBseZRS((R"R#(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRst FResourcecBseZied6ZRS(RZ(R"R#RR(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyRstprotected_methodstGETRbtPUTtDELETEt default_authRgt/cCstS(N(R(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pythomepagess /private/cCstS(N(R(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pytprivate_timeliness/secret/cCstS(N(R(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyt secret_areas(UR4tflaskRRRRRRRRtpeeweetflask_peewee.adminR R R tflask_peewee.authR R tflask_peewee.dbRtflask_peewee.filtersRtflask_peewee.restRRRRRRRtflask_peewee.utilsRRRRR"R$tconfigt from_objecttdbtbefore_requestR%tModelR&R<RBRERJRLRORRRURVRXR\R_RgR;RqRsRuRvRwRxtregister_admintregistertregister_panelRzR~RRRRt dummy_autht user_autht admin_autht api_key_authtapitrouteRtlogin_requiredRtadmin_requiredRtsetup(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/test_app.pyts             flask-peewee-0.6.7/flask_peewee/tests/rest.pyc0000644000175000001440000010615212624224624022173 0ustar charlesusers00000000000000 #Uc@s2ddlmZyddlZWnek r?ddlZnXddlZddlZddlZddlm Z ddl m Z ddl m Z ddl m Z ddl mZddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZdefdYZ de fdYZ!de fdYZ"de fdYZ#de fdYZ$d e fd!YZ%d"e fd#YZ&dS($i(twith_statementN(tg(tAuthentication(tRestAPI(t RestResource(tUserAuthentication(tFlaskPeeweeTestCase(tAModel(tAPIKey(tBModel(tCModel(tEModel(tFModel(tMessage(tNote(t TestModel(tUser(tcheck_password(tget_next(t make_passwordtRestApiTestCasecBseZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZRS(cCsEtt|jtjttjttjtjdS(N(tsuperRtsetUpRt drop_tabletTrueRt create_table(tself((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR#s    cCstj|jjdS(Ntutf8(tjsontloadstdatatdecode(Rtresponse((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt response_json*scCs:d||f}idtj|jdjdd6S(Ns%s:%ssBasic %sRt Authorization(tbase64t b64encodetencodeR(RtusernametpasswordR((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt auth_headers-scCs |jdS(Ns%Y-%m-%d %H:%M:%S(tstrftime(Rtdt((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt conv_date1scCs|j||ddS(Ntobjects(t assertEqual(Rt resp_jsontbody((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytassertAPIResponse4scCs|j||ddS(Ntmeta(R-(RR.R1((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt assertAPIMeta7scCsO|j|i|jd6|jd6|j|jd6|jd6|jd6dS(NR&tactivet join_datetadmintid(R-R&R3R+R4R5R6(Rt json_datatuser((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt assertAPIUser:s     cCs8x1t|d|D]\}}|j||qWdS(NR,(tzipR9(RR7tuserst json_itemR8((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytassertAPIUsersCs cCsH|j|i|jjd6|jd6|j|jd6|jd6dS(NR8tmessaget created_dateR6(R-R8R6R>R+R?(RR7tnote((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt assertAPINoteGs    cCs8x1t|d|D]\}}|j||qWdS(NR,(R:RA(RR7tnotesR<R@((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytassertAPINotesOs cCsH|j|i|jjd6|jd6|j|jd6|jd6dS(NR8tcontenttpub_dateR6(R-R8R6RDR+RE(RR7R>((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytassertAPIMessageSs    cCs8x1t|d|D]\}}|j||qWdS(NR,(R:RF(RR7tmessagesR<R>((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytassertAPIMessages[s cCs(|j|i|jd6|jd6dS(NRR6(R-RR6(RR7ttm((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytassertAPITestModel_s  cCs8x1t|d|D]\}}|j||qWdS(NR,(R:RJ(RR7ttmsR<RI((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytassertAPITestModelses (t__name__t __module__RR!R(R+R0R2R9R=RARCRFRHRJRL(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR"s            tRestApiResourceTestCasecBsYeZdZdZdZdZdZdZdZdZ dZ RS( cCsgtt|jtjjtjjtjjtjjt jjdS(N( RRORR tdeletetexecuteR R R R(R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRks cCstjdd|_tjdd|_tjddd|j|_tjddd|j|_tjdd d |j|_tjdd d |j|_ t jd d |_ t jd d|_ t jddd|j |_t jdd|_dS(Nta_fieldta1ta2tb_fieldtb1tatb2tc_fieldtc1tbtc2te_fieldte1te2tf_fieldtf1tetf2(RtcreateRSRTR RVRXR RZR\R R^R_R RaRc(R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytcreate_test_modelssscCs\|j|jjd}|j|}|j|di|jjd6dd6i|jjd6dd6g|jjd|jj}|j|}|j|i|jjd6dd6|jjd}|j|}|j|di|jjd6d d 6i|jjd6dd6d 6i|j jd6d d 6i|jjd6dd6d 6g|jjd |j j}|j|}|j|i|j jd6d d 6i|jjd6dd6d 6|jjd}|j|}|j|di|j jd6dd6i|jjd6d d 6i|jjd6dd6d 6d6i|j jd6dd6i|j jd6d d 6i|jjd6dd6d 6d6g|jjd|j j}|j|}|j|i|j jd6dd6i|j jd6d d 6i|jjd6dd6d 6d6|jjd}|j|}|j|di|j jd6dd6i|j jd6dd6d6i|jjd6dd6dd6g|jjd|j j}|j|}|j|i|j jd6dd6i|j jd6dd6d6|jjd|jj}|j|}|j|i|jjd6dd6dd6dS(Ns/api/amodel/?ordering=idR,R6RSRRRTs/api/amodel/%s/s/api/bmodel/?ordering=idRVRURWRXs/api/bmodel/%s/s/api/cmodel/?ordering=idRZRYR[R\s/api/cmodel/%s/s/api/fmodel/?ordering=idRaR`R^R]RbRcs/api/fmodel/%s/(RetapptgetR!R-RSR6RTRVRXRZR\RaR^RctNone(RtrespR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_resources_list_detailsd      29   MT  : 2%    cCs|jj|dtj|S(NR(RftpostRtdumps(RturlR((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytpost_toscCs|jdidd6}|j|jd|jtjjdtjdd}|jtj|j j di|j d6dd6|jdid d 6id d6d 6}|j|jd|jt jjd|jtjjd t jd d }tjdd }|j|j ||jtj|j j di|j d6d d 6i|j d6d d6d 6|jdidd6idd 6idd6d 6d6}|j|jd|jtjjd|jt jjd |jtjjdtjdd}t jd d}tjdd}|j|j||j|j ||jtj|j j di|j d6dd6i|j d6dd 6i|j d6dd6d 6d6|jdidd6idd6d6}|j|jd|jtjjd|jtjjdtjdd}tjdd}|j|j||jtj|j j di|j d6dd6i|j d6dd6d6|jdidd6}|j|jd|jtjjd |jtjjdtjdd}|j|jd|jtj|j j di|j d6dd6dd6dS(Ns /api/amodel/taxRRiiRR6s /api/bmodel/tbyRUtayRWis /api/cmodel/tczRYtbztazR[is /api/fmodel/tfyR`teyR]Rbtfz(RnR-t status_codeRtselecttcountRgRRRRR6R RWR R[R R RbRh(RRita_objtb_objtc_objtf_objte_obj((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_resources_creates|!  '!  5!   '!  ! cCs|j|jd|jjidd6}|j|jd|jtjjdtj d|jj}|jt j |j j di|jjd6dd6|jd|jjid d 6id d6d 6}|j|jd|jtjjd|jtjjdtj d|jj}tj d|jj}|j|j||jt j |j j di|jd6d d 6i|jd6d d6d 6|jd |jjidd6idd 6idd6d 6d6}|j|jd|jtjjd|jtjjd|jtjjdtj d|jj}tj d|jj}tj d|jj}|j|j||j|j||jt j |j j di|jd6dd6i|jd6dd 6i|jd6dd6d 6d6|jd|jjidd6idd6d6}|j|jd|jtjjd|jtjjdtj d|jj}tj d|jj}|j|j||jt j |j j di|jd6dd6i|jd6dd6d6|jd|jjidd6}|j|jd|jtjjd|jtjjdtj d|jj}|j|jd|jt j |j j di|jd6dd6dd6dS(Ns/api/amodel/%s/sa2-xxxRRiiR6Rs/api/bmodel/%s/sb2-yyyRUsa2-yyyRWs/api/cmodel/%s/sc2-zzzRYsb2-zzzsa2-zzzR[s/api/fmodel/%s/sf1-yyyR`se1-yyyR]Rbsf2-yyy(ReRnRTR6R-RxRRyRzRgRRRRRXR RWR\R R[RaR R R^RbRcRh(RRiR{R|R}R~R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_resources_edit's~ #!  1!  ?!   1!  #! cCs |j|jd|jjidd6}|j|jd|jtjjd|jt jjdtj d|jj}t j d|j j}|j|j ||jt j|jjdi|jd6dd6i|jd6dd 6d 6|jd |jjid d 6}|j|jd|jtjjd|jtjjdtj d|jj}tj d|jj}|j|j||jt j|jjdi|jd6d d 6i|jd6dd6d6dS(Ns/api/bmodel/%s/sb2-yyyRUiiR6RRTRRRWs/api/fmodel/%s/sf1-zzzR`R^R]Rb(ReRnRXR6R-RxR RyRzRRgRTRWRRRRRaR R R^Rb(RRiR|R{R~R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_resource_edit_partials6 #!  #!  cCs|j|jd|jji|jjd6}|j|jd|jtjj d|jt jj dtj d|jj}t j d|jj}|j|j ||jt j|jjdi|jd6dd6i|jd6d d 6d6|jd |jji|jjd 6}|j|jd|jtjj d|jt jj dtj d|jj}tj d|jj}|j|j||jt j|jjdi|jd6d d6i|jd6dd6d 6dS(Ns/api/bmodel/%s/RWiiR6RRXRURSRRs/api/fmodel/%s/RbRcR`R_R](ReRnRXR6RSR-RxR RyRzRRgRWRRRRRcR_R R Rb(RRiR|R{R~R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_resource_edit_by_fks6 )!  )!  cCs|j|jd|jji}|jtj|jjdidd6|jt j j d|jt j j d|jt j j d|jd|jji}|jtj|jjdidd6|jt j j d|jt j j d|jt j j d|jd|jji}|jtj|jjdidd6|jtj j d|jtj j dtjd |jj}|j|jddS( Ns/api/cmodel/%s/delete/Ritdeletedis/api/amodel/%s/delete/is/api/emodel/%s/delete/R6(ReRnR\R6R-RRRRR RyRzR RRSR^R R RgRaRbRh(RRiR~((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt test_deletes" ,,,( RMRNRReRjRnRRRRR(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyROjs  J  Z ] ) )tRestApiBasicTestCasecBs,eZdZdZdZdZRS(c Csp|j}g}xQtdD]C}x:|D]2}|jtjd|dd|j|fq,WqW||fS(Ni R8R>s%s-%s(t create_userstrangetappendRRdR&(RR;RBtiR8((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytget_users_and_notess   4cCs|j\}}|jjd}|j|}|j|ddd|j|ddd|j|ddd|jd |dd k|j||d |jjd }|j|}|j|ddd|j|ddd|j|ddd|jd |dd k|j||d |jj|dd }|j|}|j|ddd|j|ddd|jd|ddk|jd|dd k|j||d d !|jj|dd }|j|}|j|ddd|j|dd d|j|ddd|jd |ddk|j||d dS(Ns/api/note/?ordering=idR1tmodelR@tpreviousttpageispage=2tnextis/api/note/?ordering=id&limit=10i ispage=1spage=3i(RRfRgR!R-t assertTrueRC(RR;RBRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_paginations:cCs|j\}}|jjd|jj}|j|}|j|idd6dd6dd6dd6|j||jjj t j|jjd }|j|}|j|idd6dd6dd6dd6|j||j jj t jt |j jj t j}|d j}|jjd |}|j|}|j||d |jjd }|j|}|j|idd6dd6dd6dd6|j|t j d |j |jgj t j|jjd}|j|}|j|t j d |j|jgj t j|jjd}|j|}|j|t j ddddgj t j|jjd}|j|}|j|tj dddgj tjdS(Ns/api/note/?user=%s&ordering=idR@RRRRiRs+/api/note/?user__username=admin&ordering=idis5/api/note/?user__username=admin&id__lt=%s&ordering=idsC/api/note/?user__username=admin&user__username=inactive&ordering=idtuser__ins,/api/note/?-user__username=admin&ordering=ids/api/note/?id__in=1,2,5tid__iniis$/api/user/?username__in=admin,normalt username__inR5tnormal(RRfRgRR6R!R2RCtnote_settorder_byRR5tlisttfiltertinactiveR=R(RR;RBRiR.tthird_id((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_filtering/sP  "  "   4"1cCs|j\}}t|jjjtj}|jjd}|j |}|j ||d |dd}|jj|}|j |}|j ||dd!|dd}|jj|}|j |}|j |ddd|j ||d|dd}|jj|}|j |}|j ||dd!|dd}|jj|}|j |}|j |ddd|j ||d dS(Ns3/api/note/?user__username=admin&limit=4&ordering=idiR1RiRR( RRR5RRRR6RfRgR!RCR-(RR;RBRiR.tnext_urltprev_url((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_filter_with_paginationps.(RMRNRRRR(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs 4 AtRestApiUserAuthTestCasecBsbeZdZdZdZdZdZdZdZdZ dZ d Z RS( cCs!tt|j|jdS(N(RRRR(R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRscCsLtjd|jddtjd|jddg}|\|_|_|S(NR8R>R5R(RRdR5Rt admin_notet normal_note(RRB((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt create_notesscCs|jjd}|j|}|j|g|j|idd6dd6dd6dd6|j|jjd }|j|}|j||j|jgdS( Ns /api/note/R@RRRiRRs/api/note/?ordering=id( RfRgR!R0R2RRCRR(RRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt test_list_gets,  cCsq|jjd}|j|jd|j|jjd|jj}|j|}|j||jdS(Ns /api/note/1/is /api/note/%s/( RfRgR-RxRRR6R!RA(RRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_detail_gets  cCsidd6|jjd6}tj|}|jjdd|}|j|jd|jjdd|d|jdd}|j|jd|jjdd|d|jd d }|j|jd dS( NttestR>R8s /api/note/RitheaderstxxxRi( RR6RRlRfRkR-RxR((Rt note_datat serializedRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_auth_creates**cCsidd6|jjd6}tj|}|jjdd|d|jdd}|j|jdt j dd}|j|j |j|j |}|j ||dS( NRR>R8s /api/note/RRRi(RR6RRlRfRkR(R-RxRRgR8R!RA(RRRRitnew_noteR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt test_creates*cCs|jidd6}tj|}d|jj}|jj|d|}|j|jd|jj|d|d|j dd}|j|jd|jj|d|d|j dd}|j|jd dS( NteditedR>s /api/note/%s/RiRRRi( RRRlRR6RftputR-RxR((RRRRmRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_auth_edits  **cCs|jidd6}tj|}d|jj}|jj|d|d|jdd}|j|j dt j d|jj}|j|j d|j |}|j||dS( NRR>s /api/note/%s/RRRiR6(RRRlRR6RfRR(R-RxRRgR>R!RA(RRRRmRiR@R.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyt test_edits  *cCs|jd|jj}|jj|}|j|jd|jj|d|jdd}|j|jd|jj|d|jdd}|j|jddS(Ns /api/note/%s/iRRRi(RRR6RfRPR-RxR((RRmRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_auth_deletes $$cCs|jd|jj}|jj|d|jdd}|j|jd|jtj j d|j |}|j|idd6dS(Ns /api/note/%s/RRiiR( RRR6RfRPR(R-RxRRyRzR!(RRmRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs $( RMRNRRRRRRRRRR(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs        tRestApiOwnerAuthTestCasecBsbeZdZdZdZdZdZdZdZdZ dZ d Z RS( cCs!tt|j|jdS(N(RRRR(R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR"scCsLtjd|jddtjd|jddg}|\|_|_|S(NR8RDR5R(R RdR5Rt admin_messagetnormal_message(RRG((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytcreate_messages&scCs|jjd}|j|}|j|g|j|idd6dd6dd6dd6|j|jjd }|j|}|j||j|jgdS( Ns /api/message/R>RRRiRRs/api/message/?ordering=id( RfRgR!R0R2RRHRR(RRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR.s,  cCsq|jjd}|j|jd|j|jjd|jj}|j|}|j||jdS(Ns/api/message/1/is/api/message/%s/( RfRgR-RxRRR6R!RF(RRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR?s  cCsidd6}tj|}|jjdd|}|j|jd|jjdd|d|jdd}|j|jd|jjdd|d|jdd}|j|jd dS( NRRDs /api/message/RiRRRi(RRlRfRkR-RxR((Rt message_dataRRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRIs **cCsidd6}tj|}|jjdd|d|jdd}|j|jdtjdd}|j|j |j |j |}|j ||dS(NRRDs /api/message/RRRi( RRlRfRkR(R-RxR RgR8RR!RF(RRRRit new_messageR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRYs *cCsG|jidd6}tj|}d|jj}|jj|d|}|j|jd|jj|d|d|j dd}|j|jd|jj|d|d|j dd}|j|jd |jj|d|d|j d d }|j|jd t j d |jj}|j|j ddS( NRRDs/api/message/%s/RiRRR5iRiR6( RRRlRR6RfRR-RxR(R RgRD(RRRRmRitobj((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRgs  ***cCs|jidd6}tj|}d|jj}|jj|d|d|jdd}|j|j dt j d|jj}|j|j d|j |}|j||dS( NRRDs/api/message/%s/RRRiR6(RRRlRR6RfRR(R-RxR RgRDR!RF(RRRRmRiR>R.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs  *cCs|jd|jj}|jj|}|j|jd|jj|d|jdd}|j|jd|jj|d|jdd}|j|jd|jj|d|jdd}|j|jddS( Ns/api/message/%s/iRRR5iRi(RRR6RfRPR-RxR((RRmRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs $$$cCs|jd|jj}|jj|d|jdd}|j|jd|jtj j d|j |}|j|idd6dS(Ns/api/message/%s/RRiiR( RRR6RfRPR(R-RxR RyRzR!(RRmRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs $( RMRNRRRRRRRRRR(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR!s        tRestApiAdminAuthTestCasecBsPeZdZdZdZdZdZdZdZdZ RS(cCs|jjd}|j|}|j|g|j|idd6dd6dd6dd6|j|jjd }|j|}|j||j|jgdS( Ns /api/user/R8RRRiRRs/api/user/?ordering=id( RfRgR!R0R2RR=R5R(RRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs,  cCs|jjd}|j|jd|j|jjd|jj}|j|}|j||j|jjd|j j}|j|jddS(Ns /api/user/1/is /api/user/%s/( RfRgR-RxRRR6R!R9R(RRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs cCs&|jtd}idd6|d6dd6}tj|}|jjdd|}|j|jd|jjdd|d |jd d }|j|jd|jjdd|d |jd d }|j|jd|jjdd|d |jd d }|j|jd dS(NRR&R'Rtemails /api/user/RiRRRR5i( RRRRlRfRkR-RxR((Rtnew_passt user_dataRRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs  ***cCs|jtd}idd6|d6dd6}tj|}|jjdd|d|jd d }|j|jd t j dd}|j t d|j |j|}|j||dS( NRR&R'RRs /api/user/RRR5i(RRRRlRfRkR(R-RxRRgRRR'R!R9(RRRRRitnew_userR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs  *cCs|jidd6}tj|}d|jj}|jj|d|}|j|jd|jj|d|d|j dd}|j|jd|jj|d|d|j dd}|j|jd|jj|d|d|j d d }|j|jd dS( NRR&s /api/user/%s/RiRRRR5i( RRRlRR6RfRR-RxR((RRRRmRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs  ***cCs|jidd6}tj|}d|jj}|jj|d|d|jdd}|j|j dt j d|jj}|j|j d|j |}|j||dS( NRR&s /api/user/%s/RRR5iR6(RRRlRR6RfRR(R-RxRRgR&R!R9(RRRRmRiR8R.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs  *cCs|jd|jj}|jj|}|j|jd|jj|d|jdd}|j|jd|jj|d|jdd}|j|jd|jj|d|jdd}|j|jddS(Ns /api/user/%s/iRRRR5i(RRR6RfRPR-RxR((RRmRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR+s $$$cCs|jd|jj}|jj|d|jdd}|j|jd|jtj j d|j |}|j|idd6dS(Ns /api/user/%s/RR5iiiR( RRR6RfRPR(R-RxRRyRzR!(RRmRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyR@s $( RMRNRRRRRRRR(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRs      tRestApiKeyAuthTestCasecBs,eZdZdZdZdZRS(cCswtt|jtjdd|_tjdd|_tjdddd|_tjdddd |_ dS( NRttest1ttest2tkeytktsecrettstk2ts2( RRRRRdttm1ttm2Rtk1R(R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRPs c Cs|jj}|jd}|j|jd|jtjd|jd}|j|jd|jtjd|jd}|jtj|j|j |}|j ||j |j g|j |idd6dd6d d 6dd 6WdQXdS( Ns/api/testmodel/is/api/testmodel/?key=k&secret=s2s/api/testmodel/?key=k&secret=st testmodelRRRiRR(t flask_appt test_clientRgR-RxRtapi_keyRhRR!RLRRR2(RtcRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRYs  c Cs|jj}|jddidd6dd6}|j|jd|jtjd|jddidd6dd6}|j|jd |jtj|jWdQXdS( Ns/api/testmodel/RRRtfooRiRi( RRRgR-RxRRRhR(RRRi((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyttest_auth_headersms##cCs|jj}idd6}tj|}|jdd|}|j|jd|jtjd|jdd|}|j|jd|jtjd|jdd|}|jtj|j |j |}|jt j jd|j|ddWdQXdS(Ntt3Rs/api/testmodel/is/api/testmodel/?key=k&secret=s2s/api/testmodel/?key=k&secret=si(RRRRlRkR-RxRRRhRR!RRyRz(RRt test_dataRRiR.((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyRws (RMRNRRRR(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pyROs  ('t __future__Rt simplejsonRt ImportErrorR#tdatetimetunittesttflaskRtflask_peewee.restRRRRtflask_peewee.tests.baseRtflask_peewee.tests.test_appRRR R R R R RRRtflask_peewee.utilsRRRRRORRRRR(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/rest.pytsD    Hflask-peewee-0.6.7/flask_peewee/tests/base.py0000644000175000001440000000377012574421673021776 0ustar charlesusers00000000000000import unittest from flask_peewee.tests import test_app from flask_peewee.tests.test_app import AModel from flask_peewee.tests.test_app import BDetails from flask_peewee.tests.test_app import BModel from flask_peewee.tests.test_app import CModel from flask_peewee.tests.test_app import DModel from flask_peewee.tests.test_app import EModel from flask_peewee.tests.test_app import FModel from flask_peewee.tests.test_app import Message from flask_peewee.tests.test_app import Note from flask_peewee.tests.test_app import User class FlaskPeeweeTestCase(unittest.TestCase): def setUp(self): Note.drop_table(True) Message.drop_table(True) User.drop_table(True) User.create_table() Message.create_table() Note.create_table() FModel.drop_table(True) EModel.drop_table(True) EModel.create_table() FModel.create_table() self.flask_app = test_app.app self.flask_app._template_context = {} self.app = test_app.app.test_client() def create_user(self, username, password, **kwargs): user = User(username=username, email=kwargs.pop('email', ''), **kwargs) user.set_password(password) user.save() return user def create_message(self, user, content, **kwargs): return Message.create(user=user, content=content, **kwargs) def create_users(self): users = [ self.create_user('admin', 'admin', admin=True), self.create_user('normal', 'normal'), self.create_user('inactive', 'inactive', active=False), ] self.admin, self.normal, self.inactive = users return users def get_context(self, var_name): if var_name not in self.flask_app._template_context: raise KeyError('%s not in template context' % var_name) return self.flask_app._template_context[var_name] def assertContext(self, key, value): self.assertEqual(self.get_context(key), value) flask-peewee-0.6.7/flask_peewee/tests/base.pyc0000644000175000001440000000544512624224541022131 0ustar charlesusers00000000000000 #Uc@sddlZddlmZddlmZddlmZddlmZddlmZddlmZddlm Z dd lm Z dd lm Z dd lm Z dd lm Z d ejfdYZdS(iN(ttest_app(tAModel(tBDetails(tBModel(tCModel(tDModel(tEModel(tFModel(tMessage(tNote(tUsertFlaskPeeweeTestCasecBs>eZdZdZdZdZdZdZRS(cCstjttjttjttjtjtjtjttjttjtjtj |_ i|j _ tj j |_ dS(N( R t drop_tabletTrueRR t create_tableRRRtappt flask_appt_template_contextt test_client(tself((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pytsetUps            cKs?td|d|jdd|}|j||j|S(Ntusernametemailt(R tpopt set_passwordtsave(RRtpasswordtkwargstuser((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pyt create_user#s$  cKstjd|d||S(NRtcontent(Rtcreate(RRRR((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pytcreate_message)scCs[|jdddt|jdd|jdddtg}|\|_|_|_|S(Ntadmintnormaltinactivetactive(RR tFalseR"R#R$(Rtusers((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pyt create_users,s cCs3||jjkr%td|n|jj|S(Ns%s not in template context(RRtKeyError(Rtvar_name((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pyt get_context5scCs|j|j||dS(N(t assertEqualR+(Rtkeytvalue((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pyt assertContext:s(t__name__t __module__RRR!R(R+R/(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pyR s     (tunittesttflask_peewee.testsRtflask_peewee.tests.test_appRRRRRRRRR R tTestCaseR (((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/base.pyts flask-peewee-0.6.7/flask_peewee/tests/auth.pyc0000644000175000001440000001661112624224624022157 0ustar charlesusers00000000000000 #Uc@s0ddlmZddlZyddlZWn!ek rOddlmZnXddlmZddlm Z ddlm Z ddlm Z ddl m Z dd l mZdd lmZdd lmZdd lmZdd lmZddlmZde fdYZdefdYZdS(i(twith_statementN(tparse(tget_flashed_messages(trequest(tsession(turl_for(tAuth(t LoginForm(tFlaskPeeweeTestCase(tUser(tapp(tauth(tdbtTestAuthcBseZdZRS(cCsdS(N((tself((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pytsetups(t__name__t __module__R(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyR st AuthTestCasecBsweZdZddd dZd dZdZdZdZdZ dZ d Z d Z d Z RS( cCs)tt|jttt|_dS(N(tsuperRtsetUpR R R t test_auth(R((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyRstadmincCs0|p |j}|jddi|d6|d6S(Ns/accounts/login/tdatatusernametpassword(R tpost(RRRtcontext((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pytlogin"scCs|p |j}|jdS(Ns/accounts/logout/(R R(RR((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pytlogout)scCsN|j|jjjjdtttdd}|j|jjjddS(Ntusertdb_tablet peewee_users(t assertEqualRR t_metaRR R R (Rt fake_auth((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyt test_table-sc CsO|j|jj0}|jd}|j|jd|jdd|jd}|j t |t |j|j idd6dd6|j ddidd6d d6}|j|jd|jd}|j|jid gd6|jd tk|jtjd|j ddid d6d d6}|j|jd|j d tkt}|j|dg|jtjd|j ddidd6dd6}|j|jd|jdd|jtjd|j ddid d6d d6}|j|jd|jtj|jWdQXdS(Ns/accounts/login/iRtformRRRttxxxuThis field is required.t_flashestnormaltbazsIncorrect username or passwordtinactivei.(t create_userst flask_appt test_clienttgetR!t status_codet assertContexttNonet get_contextt assertTruet isinstanceRRRterrorst assertFalseRR tget_logged_in_userRR)(Rtctresptfrmtmessages((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyttest_login_view3sH !       c Csc|j|jjD}|jd}|j}tj|}tj|j}|j|idgd6|j dd}|j|}|j|j dd|j ddidd6d d 6dd6}|j|j d |j|j dd|j ddidd6dd 6dd6}|j|j d |j |jd jdWdQXdS(Ns/admin/tnextshttp://localhostR&s/accounts/login/RR)Rsincorrect-passwordRii.tlocation(R,R-R.R/R?turlparsetparse_qstqueryR!treplaceR3RR0R4theaderstendswith(RR9R:R?tparsedt querystring((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyttest_login_redirect_in_depth|s,    c Cs|j|jjb}|jddidd6dd6}|j|jd|jjdd}|j|d WdQXdS( Ns/accounts/login/RR)RRi.shttp://localhostR&t/( R,R-R.RR!R0R?RCR4(RR9R:R?((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyttest_login_default_redirects  c Cs|j|jja}|jddidd6dd6dd6}|j|jd|j|jd jdWdQXdS( Ns/accounts/login/RR)RRs /foo-baz/R>i.R?( R,R-R.RR!R0R4RDRE(RR9R:((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyttest_login_redirects  c Cs|j|jj}|jddidd6dd6}|jtj|j|jd}|jtjd|jddidd6dd6}|jtj|j |jddidd6dd6}|jtj|jWdQXdS(Ns/accounts/login/RR)RRs/accounts/logout/R( R,R-R.RR!R R8R)R2R(RR9R:((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyttest_login_logouts     cCs|j|jj}|jd}|j|jd|j|jdjd|j dd||jd}|j|jd|jt j |j |j dd||jd}|j|jd|jt j |j WdQXdS(Ns /private/i.R?s#/accounts/login/?next=%2Fprivate%2FR)iR(R,R-R.R/R!R0R4RDRERR R8R)R(RR9R:((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyttest_login_requireds cCs|j|jj}|jd}|j|jd|j|jdjd|j dd||jd}|j|jd|j|jdjd|jt j |j |j dd||jd}|j|jd|jt j |j WdQXdS(Ns/secret/i.R?s"/accounts/login/?next=%2Fsecret%2FR)Ri(R,R-R.R/R!R0R4RDRERR R8R)R(RR9R:((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyttest_admin_requireds N(RRRR2RRR$R=RHRJRKRLRMRN(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyRs    I  (t __future__RtdatetimeR@t ImportErrorturllibRtflaskRRRRtflask_peewee.authRRtflask_peewee.tests.baseRtflask_peewee.tests.test_appR R R R R R(((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/auth.pyts$  flask-peewee-0.6.7/flask_peewee/tests/test_app.py0000644000175000001440000001340512574421673022677 0ustar charlesusers00000000000000import datetime from flask import Flask from flask import Response from flask import flash from flask import g from flask import redirect from flask import render_template from flask import request from flask import url_for from peewee import * # flask-peewee bindings from flask_peewee.admin import Admin from flask_peewee.admin import AdminPanel from flask_peewee.admin import ModelAdmin from flask_peewee.auth import Auth from flask_peewee.auth import BaseUser from flask_peewee.db import Database from flask_peewee.filters import QueryFilter from flask_peewee.rest import APIKeyAuthentication from flask_peewee.rest import AdminAuthentication from flask_peewee.rest import Authentication from flask_peewee.rest import RestAPI from flask_peewee.rest import RestResource from flask_peewee.rest import RestrictOwnerResource from flask_peewee.rest import UserAuthentication from flask_peewee.utils import get_object_or_404 from flask_peewee.utils import make_password from flask_peewee.utils import object_list class TestFlask(Flask): def update_template_context(self, context): ret = super(TestFlask, self).update_template_context(context) self._template_context.update(context) return ret app = TestFlask(__name__) app.config.from_object('flask_peewee.tests.test_config.Configuration') db = Database(app) @app.before_request def clear_context(): app._template_context = {} class User(db.Model, BaseUser): username = CharField() password = CharField() email = CharField() join_date = DateTimeField(default=datetime.datetime.now) active = BooleanField(default=True) admin = BooleanField(default=False, verbose_name='Can access admin') def __unicode__(self): return self.username def __hash__(self): return hash(self.username) def message_count(self): return self.message_set.count() class Message(db.Model): user = ForeignKeyField(User) content = TextField() pub_date = DateTimeField(default=datetime.datetime.now) def __unicode__(self): return '%s: %s' % (self.user, self.content) class Note(db.Model): user = ForeignKeyField(User) message = TextField() created_date = DateTimeField(default=datetime.datetime.now) class TestModel(db.Model): data = TextField() class Meta: order_by = ('id',) class AModel(db.Model): a_field = CharField() class BModel(db.Model): a = ForeignKeyField(AModel) b_field = CharField() class CModel(db.Model): b = ForeignKeyField(BModel) c_field = CharField() class DModel(db.Model): c = ForeignKeyField(CModel) d_field = CharField() class BDetails(db.Model): b = ForeignKeyField(BModel) class EModel(db.Model): e_field = CharField() class FModel(db.Model): e = ForeignKeyField(EModel, null=True) f_field = CharField() class APIKey(db.Model): key = CharField() secret = CharField() class NotePanel(AdminPanel): template_name = 'admin/notes.html' def get_urls(self): return ( ('/create/', self.create), ) def create(self): if request.method == 'POST': if request.form.get('message'): Note.create( user=auth.get_logged_in_user(), message=request.form['message'], ) next = request.form.get('next') or self.dashboard_url() return redirect(next) def get_context(self): return { 'note_list': Note.select().order_by(('created_date', 'desc')).paginate(1, 3) } auth = Auth(app, db, user_model=User) admin = Admin(app, auth) class AAdmin(ModelAdmin): columns = ('a_field',) class BAdmin(ModelAdmin): columns = ('a', 'b_field',) include_foreign_keys = {'a': 'a_field'} class CAdmin(ModelAdmin): columns = ('b', 'c_field',) include_foreign_keys = {'b': 'b_field'} class DAdmin(ModelAdmin): columns = ('c', 'd_field',) include_foreign_keys = {'c': 'c_field'} class MessageAdmin(ModelAdmin): columns = ('user', 'content', 'pub_date',) class NoteAdmin(ModelAdmin): columns = ('user', 'message', 'created_date',) auth.register_admin(admin) admin.register(AModel, AAdmin) admin.register(BModel, BAdmin) admin.register(CModel, CAdmin) admin.register(DModel, DAdmin) admin.register(BDetails) admin.register(Message, MessageAdmin) admin.register(Note, NoteAdmin) admin.register_panel('Notes', NotePanel) class UserResource(RestResource): exclude = ('password', 'email',) def get_query(self): return User.select().where(User.active==True) class AResource(RestResource): pass class BResource(RestResource): include_resources = {'a': AResource} class CResource(RestResource): include_resources = {'b': BResource} class EResource(RestResource): pass class FResource(RestResource): include_resources = {'e': EResource} # rest api stuff dummy_auth = Authentication(protected_methods=[]) user_auth = UserAuthentication(auth) admin_auth = AdminAuthentication(auth) api_key_auth = APIKeyAuthentication(APIKey, ['GET', 'POST', 'PUT', 'DELETE']) api = RestAPI(app, default_auth=user_auth) api.register(Message, RestrictOwnerResource) api.register(User, UserResource, auth=admin_auth) api.register(Note) api.register(TestModel, auth=api_key_auth) api.register(AModel, AResource, auth=dummy_auth) api.register(BModel, BResource, auth=dummy_auth) api.register(CModel, CResource, auth=dummy_auth) api.register(EModel, EResource, auth=dummy_auth) api.register(FModel, FResource, auth=dummy_auth) # views @app.route('/') def homepage(): return Response() @app.route('/private/') @auth.login_required def private_timeline(): return Response() @app.route('/secret/') @auth.admin_required def secret_area(): return Response() admin.setup() api.setup() flask-peewee-0.6.7/flask_peewee/tests/__init__.pyc0000644000175000001440000000057312574421713022757 0ustar charlesusers00000000000000 #Uc@s6ddlTddlTddlTddlTddlTdS(i(t*N(tflask_peewee.tests.admintflask_peewee.tests.authtflask_peewee.tests.resttflask_peewee.tests.serializertflask_peewee.tests.utils(((sF/home/charles/Dropbox/code/flask-peewee/flask_peewee/tests/__init__.pyts    flask-peewee-0.6.7/flask_peewee/tests/test_config.py0000644000175000001440000000030112574421673023353 0ustar charlesusers00000000000000# config class Configuration(object): DATABASE = { 'name': 'test.db', 'engine': 'peewee.SqliteDatabase', } DEBUG = True SECRET_KEY = 'shhhh' TESTING = True flask-peewee-0.6.7/flask_peewee/tests/utils.py0000644000175000001440000000332612574421673022221 0ustar charlesusers00000000000000try: import simplejson as json except ImportError: import json import datetime from flask import request from werkzeug.exceptions import NotFound from flask_peewee.utils import check_password from flask_peewee.utils import get_object_or_404 from flask_peewee.utils import make_password from flask_peewee.tests.base import FlaskPeeweeTestCase from flask_peewee.tests.test_app import Message from flask_peewee.tests.test_app import Note from flask_peewee.tests.test_app import User from flask_peewee.tests.test_app import app as flask_app class UtilsTestCase(FlaskPeeweeTestCase): def setUp(self): super(UtilsTestCase, self).setUp() def test_get_object_or_404(self): user = self.create_user('test', 'test') # test with model as first arg self.assertRaises(NotFound, get_object_or_404, User, User.username=='not-here') self.assertEqual(user, get_object_or_404(User, User.username=='test')) # test with query as first arg active = User.select().where(User.active==True) inactive = User.select().where(User.active==False) self.assertRaises(NotFound, get_object_or_404, active, User.username=='not-here') self.assertRaises(NotFound, get_object_or_404, inactive, User.username=='test') self.assertEqual(user, get_object_or_404(active, User.username=='test')) def test_passwords(self): p = make_password('testing') self.assertTrue(check_password('testing', p)) self.assertFalse(check_password('testing ', p)) self.assertFalse(check_password('Testing', p)) self.assertFalse(check_password('', p)) p2 = make_password('Testing') self.assertFalse(p == p2) flask-peewee-0.6.7/flask_peewee/tests/__init__.py0000644000175000001440000000030612574421673022613 0ustar charlesusers00000000000000from flask_peewee.tests.admin import * from flask_peewee.tests.auth import * from flask_peewee.tests.rest import * from flask_peewee.tests.serializer import * from flask_peewee.tests.utils import * flask-peewee-0.6.7/flask_peewee/tests/auth.py0000644000175000001440000002064512574421673022025 0ustar charlesusers00000000000000from __future__ import with_statement import datetime try: import urlparse except ImportError: from urllib import parse as urlparse from flask import get_flashed_messages from flask import request from flask import session from flask import url_for from flask_peewee.auth import Auth from flask_peewee.auth import LoginForm from flask_peewee.tests.base import FlaskPeeweeTestCase from flask_peewee.tests.test_app import User from flask_peewee.tests.test_app import app from flask_peewee.tests.test_app import auth from flask_peewee.tests.test_app import db class TestAuth(Auth): def setup(self): pass class AuthTestCase(FlaskPeeweeTestCase): def setUp(self): super(AuthTestCase, self).setUp() self.test_auth = TestAuth(app, db) def login(self, username='admin', password='admin', context=None): context = context or self.app return context.post('/accounts/login/', data={ 'username': username, 'password': password, }) def logout(self, context=None): context = context or self.app return context.post('/accounts/logout/') def test_table(self): self.assertEqual(self.test_auth.User._meta.db_table, 'user') fake_auth = TestAuth(app, db, db_table='peewee_users') self.assertEqual(fake_auth.User._meta.db_table, 'peewee_users') def test_login_view(self): self.create_users() with self.flask_app.test_client() as c: resp = c.get('/accounts/login/') self.assertEqual(resp.status_code, 200) # check that we have no logged-in user self.assertContext('user', None) frm = self.get_context('form') self.assertTrue(isinstance(frm, LoginForm)) self.assertEqual(frm.data, {'username': None, 'password': None}) # make a post missing the username resp = c.post('/accounts/login/', data={ 'username': '', 'password': 'xxx', }) self.assertEqual(resp.status_code, 200) # check form for errors frm = self.get_context('form') self.assertEqual(frm.errors, {'username': [u'This field is required.']}) # check that no messages were generated self.assertFalse('_flashes' in session) # check that the auth API does not indicate a logged-in user self.assertEqual(auth.get_logged_in_user(), None) # make a post with a bad username/password combo resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'baz', }) self.assertEqual(resp.status_code, 200) # both fields were present so no form errors, but flash the user # indicating bad username/password combo self.assertTrue('_flashes' in session) messages = get_flashed_messages() self.assertEqual(messages, [ 'Incorrect username or password', ]) # check that the auth API does not indicate a logged-in user self.assertEqual(auth.get_logged_in_user(), None) # make a post with an inactive user resp = c.post('/accounts/login/', data={ 'username': 'inactive', 'password': 'inactive', }) self.assertEqual(resp.status_code, 200) # still no logged-in user self.assertContext('user', None) # check that the auth API does not indicate a logged-in user self.assertEqual(auth.get_logged_in_user(), None) # finally post as a known good user resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'normal', }) self.assertEqual(resp.status_code, 302) # check that we now have a logged-in user self.assertEqual(auth.get_logged_in_user(), self.normal) def test_login_redirect_in_depth(self): self.create_users() with self.flask_app.test_client() as c: resp = c.get('/admin/') location = resp.location parsed = urlparse.urlparse(location) querystring = urlparse.parse_qs(parsed.query) self.assertEqual(querystring, {'next': ['/admin/']}) # Following the redirect, the next url is passed to context. location = location.replace('http://localhost', '') resp = c.get(location) self.assertEqual(self.get_context('next'), '/admin/') # Simulate incorrect password. resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'incorrect-password', 'next': '/admin/', }) self.assertEqual(resp.status_code, 200) self.assertEqual(self.get_context('next'), '/admin/') resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'normal', 'next': '/admin/', }) self.assertEqual(resp.status_code, 302) self.assertTrue(resp.headers['location'].endswith('/admin/')) def test_login_default_redirect(self): self.create_users() with self.flask_app.test_client() as c: resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'normal', }) self.assertEqual(resp.status_code, 302) location = resp.location.replace('http://localhost', '') self.assertTrue(location, '/') def test_login_redirect(self): self.create_users() with self.flask_app.test_client() as c: resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'normal', 'next': '/foo-baz/', }) self.assertEqual(resp.status_code, 302) self.assertTrue(resp.headers['location'].endswith('/foo-baz/')) def test_login_logout(self): self.create_users() with self.flask_app.test_client() as c: resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'normal', }) self.assertEqual(auth.get_logged_in_user(), self.normal) resp = c.post('/accounts/logout/') self.assertEqual(auth.get_logged_in_user(), None) resp = c.post('/accounts/login/', data={ 'username': 'admin', 'password': 'admin', }) self.assertEqual(auth.get_logged_in_user(), self.admin) # log back in without logging out resp = c.post('/accounts/login/', data={ 'username': 'normal', 'password': 'normal', }) self.assertEqual(auth.get_logged_in_user(), self.normal) def test_login_required(self): self.create_users() with self.flask_app.test_client() as c: resp = c.get('/private/') self.assertEqual(resp.status_code, 302) self.assertTrue(resp.headers['location'].endswith('/accounts/login/?next=%2Fprivate%2F')) self.login('normal', 'normal', c) resp = c.get('/private/') self.assertEqual(resp.status_code, 200) self.assertEqual(auth.get_logged_in_user(), self.normal) self.login('admin', 'admin', c) resp = c.get('/private/') self.assertEqual(resp.status_code, 200) self.assertEqual(auth.get_logged_in_user(), self.admin) def test_admin_required(self): self.create_users() with self.flask_app.test_client() as c: resp = c.get('/secret/') self.assertEqual(resp.status_code, 302) self.assertTrue(resp.headers['location'].endswith('/accounts/login/?next=%2Fsecret%2F')) self.login('normal', 'normal', c) resp = c.get('/secret/') self.assertEqual(resp.status_code, 302) self.assertTrue(resp.headers['location'].endswith('/accounts/login/?next=%2Fsecret%2F')) self.assertEqual(auth.get_logged_in_user(), self.normal) self.login('admin', 'admin', c) resp = c.get('/secret/') self.assertEqual(resp.status_code, 200) self.assertEqual(auth.get_logged_in_user(), self.admin) flask-peewee-0.6.7/flask_peewee/templates/0000755000175000001440000000000012624225533021330 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/templates/macros/0000755000175000001440000000000012624225533022614 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/templates/macros/forms.html0000644000175000001440000000215612574421673024643 0ustar charlesusers00000000000000{% macro with_errors(field) %} {% if field.errors %} {% set css_class = 'invalid ' + kwargs.pop('class', '') %} {{ field(class=css_class, **kwargs) }} {% if field.description %}{{ field.description|safe() }}{% endif %}
    {% for error in field.errors %}
  • {{ error|e }}
  • {% endfor %}
{% else %} {{ field(**kwargs) }} {% if field.description %}{{ field.description|safe() }}{% endif %} {% endif %} {% endmacro %} {% macro admin_field(field) %}
{{ field.label(class="control-label") }}
{% set css_class = 'span8 ' + kwargs.pop('class', '') %} {% if field.errors %} {% set css_class = 'error ' + css_class %} {% endif %} {{ field(class=css_class, **kwargs) }} {% if field.description %}{{ field.description|safe() }}{% endif %} {% for error in field.errors %}{{ error|e }}{% endfor %}
{% endmacro %} flask-peewee-0.6.7/flask_peewee/templates/base.html0000644000175000001440000000043612574421673023142 0ustar charlesusers00000000000000 {% block title %}Title here{% endblock %}
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}

{% block content_title %}{% endblock %}

{% block content %}{% endblock %}
flask-peewee-0.6.7/flask_peewee/templates/admin/0000755000175000001440000000000012624225533022420 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/templates/admin/base.html0000644000175000001440000000716112574421673024234 0ustar charlesusers00000000000000 {% block title %}{% endblock %}{% block title_branding %} | {{ branding }}{% endblock %} {% block extra_script %}{% endblock %}
{% for category, message in get_flashed_messages(with_categories=true) %}
×

{{ message }}

{% endfor %} {% block pre_content %}{% endblock %} {% block content %}{% endblock %}

{% block footer %}Site administration{% endblock %}

flask-peewee-0.6.7/flask_peewee/templates/admin/index.html0000644000175000001440000000226612574421673024432 0ustar charlesusers00000000000000{% extends "admin/base.html" %} {% block title %}Admin Dashboard{% endblock %} {% block content_title %}Admin Dashboard{% endblock %} {% block content %} {% if panels %}
{% for panel in panels %} {{ panel.render()|safe() }} {% endfor %}
{% endif %} {% for iter_admin in model_admins %} {% endfor %}
Model name Records
{% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/0000755000175000001440000000000012624225533023703 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/templates/admin/models/base.html0000644000175000001440000000224512574421673025515 0ustar charlesusers00000000000000{% extends "admin/base.html" %} {% from 'macros/forms.html' import admin_field %} {% block body_class %}{{ super() }} model-admin{% endblock %} {% block title %}{{ model_admin.get_display_name()|fix_underscores }} Admin{% endblock %} {% block content_title %}{{ model_admin.get_display_name()|fix_underscores }} Admin{% endblock %} {% block breadcrumbs %}
  • / {{ model_admin.get_display_name()|fix_underscores }}
  • {% endblock %} {% block pre_content %} {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/base_filters.html0000644000175000001440000000076512574421673027252 0ustar charlesusers00000000000000{% extends "admin/models/base.html" %} {% block extra_script %} {{ super() }} {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/index.html0000644000175000001440000000607712624225413025707 0ustar charlesusers00000000000000{% extends "admin/models/base_filters.html" %} {% block tab_index_class %}active{% endblock %} {% block extra_tabs %} {% include "admin/includes/filter_dropdown.html" %} {% endblock %} {% block content %} {% include "admin/includes/filter_widgets.html" %}
    {% if csrf_token %}{# Support for flask-seasurf #}{% endif %} {% if model_admin.columns %} {% for column in model_admin.columns %} {% if ordering == column %} {% set sort_by = '-'+column %} {% else %} {% set sort_by = column %} {% endif %} {% endfor %} {% else %} {% endif %} {% for object in query.get_list() %} {% if model_admin.columns %} {% for column in model_admin.columns %} {% if loop.index == 1 %} {% else %} {% endif %} {% endfor %} {% else %} {% endif %} {% endfor %}
    {% if model_admin.column_is_sortable(column) %}{% endif %}{{ get_verbose_name(model_admin.model, column) }}{% if model_admin.column_is_sortable(column) %}{% endif %}{{ model_admin.get_display_name() }}
    {{ get_model_field(object, column) }}{{ get_model_field(object, column) }}{{ object }}
    {% include "admin/includes/pagination.html" %} {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/edit.html0000644000175000001440000000277112574421673025534 0ustar charlesusers00000000000000{% extends "admin/models/base_forms.html" %} {% block breadcrumbs %} {{ super() }}
  • / Editing
  • {% endblock %} {% block extra_tabs %}
  • Editing
  • {% endblock %} {% block content %} {% include "admin/includes/form_raw_id.html" %} {% if form.errors %}
    ×

    There were errors with your form submission

    {% endif %}
    {% if csrf_token %}{# Support for flask-seasurf #}{% endif %} Edit {{ model_admin.get_display_name() }} {% for field in form %} {{ admin_field(field) }} {% endfor %} {% block extra_form %}{% endblock %}
    Cancel Delete
    {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/export.html0000644000175000001440000000431212624225413026107 0ustar charlesusers00000000000000{% extends "admin/models/base_filters.html" %} {% block breadcrumbs %} {{ super() }}
  • / Export
  • {% endblock %} {% block tab_export_class %}active{% endblock %} {% block extra_tabs %} {% include "admin/includes/filter_dropdown.html" %} {% endblock %} {% block content %} {% include "admin/includes/filter_widgets.html" %}

    Currently {{ query.count() }} records are scheduled for export details

    {% if csrf_token %}{# Support for flask-seasurf #}{% endif %} Select fields to export
    {% for field in model._meta.sorted_fields %} {% endfor %}
    {% for (model, path), fields in related_fields.items() %} Select related fields to export
    {% for field in fields %} {% endfor %}
    {% endfor %}
    Cancel
    {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/add.html0000644000175000001440000000251412574421673025332 0ustar charlesusers00000000000000{% extends "admin/models/base_forms.html" %} {% block breadcrumbs %} {{ super() }}
  • / Add new
  • {% endblock %} {% block tab_add_class %}active{% endblock %} {% block content %} {% include "admin/includes/form_raw_id.html" %} {% if form.errors %}
    ×

    There were errors with your form submission

    {% endif %}
    {% if csrf_token %}{# Support for flask-seasurf #}{% endif %} Add a new {{ model_admin.get_display_name() }} {% for field in form %} {{ admin_field(field) }} {% endfor %} {% block extra_form %}{% endblock %}
    Cancel
    {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/base_forms.html0000644000175000001440000000114512574421673026721 0ustar charlesusers00000000000000{% extends "admin/models/base.html" %} {% block extra_script %} {{ super() }} {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/models/delete.html0000644000175000001440000000353012574421673026043 0ustar charlesusers00000000000000{% extends "admin/models/base.html" %} {% block breadcrumbs %} {{ super() }}
  • / Delete
  • {% endblock %} {% block extra_tabs %}
  • Delete
  • {% endblock %} {% block content %}
    {% for object in query %}{% endfor %}
    {% if csrf_token %}{# Support for flask-seasurf #}{% endif %} Confirm delete
      {% for object in query %}
    • {% if get_admin_url(object) %} {{ object }} {% else %} {{ object }} {% endif %} {% if collected and object.get_id() in collected %}
        {% for depth, model, collected_objects in collected[object.get_id()] %} {% for sub_object in collected_objects %}
      • {{ get_model_name(model) }}: {% if get_admin_url(sub_object) %} {{ sub_object }} {% else %} {{ sub_object }} {% endif %}
      • {% endfor %} {% endfor %}
      {% endif %}
    • {% endfor %}
    Cancel
    {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/panels/0000755000175000001440000000000012624225533023702 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/templates/admin/panels/base.html0000644000175000001440000000025312574421673025511 0ustar charlesusers00000000000000

    {% block panel_title %}{% endblock %}

    {% block panel_content %}{% endblock %}
    flask-peewee-0.6.7/flask_peewee/templates/admin/panels/default.html0000644000175000001440000000021212574421673026216 0ustar charlesusers00000000000000{% extends "admin/panels/base.html" %} {% block panel_title %}{{ panel.title }}{% endblock %} {% block panel_content %} {% endblock %} flask-peewee-0.6.7/flask_peewee/templates/admin/includes/0000755000175000001440000000000012624225533024226 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/templates/admin/includes/filter_dropdown.html0000644000175000001440000000150712574421673030327 0ustar charlesusers00000000000000{% macro list_fields(node, prefix) %} {% for field in node.fields %}
  • {% if prefix %}{{ ' / '.join(prefix) }} / {% endif %}{{ field.name }}
  • {% endfor %} {% for child_prefix, child in node.children.items() %} {{ list_fields(child, prefix + [child_prefix]) }} {% endfor %} {% endmacro %} flask-peewee-0.6.7/flask_peewee/templates/admin/includes/pagination.html0000644000175000001440000000107312574421673027255 0ustar charlesusers00000000000000 flask-peewee-0.6.7/flask_peewee/templates/admin/includes/form_raw_id.html0000644000175000001440000000136012574421673027413 0ustar charlesusers00000000000000{% if model_admin.foreign_key_lookups %} {% for field_name, search in model_admin.foreign_key_lookups.items() %} {% endfor %} {% endif %} flask-peewee-0.6.7/flask_peewee/templates/admin/includes/filter_widgets.html0000644000175000001440000000120712574421673030136 0ustar charlesusers00000000000000 flask-peewee-0.6.7/flask_peewee/templates/auth/0000755000175000001440000000000012624225533022271 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/templates/auth/login.html0000644000175000001440000000210312574421673024272 0ustar charlesusers00000000000000{% extends "base.html" %} {% from 'macros/forms.html' import with_errors %} {% block content_title %}Log in{% endblock %} {% block content %}
    {% if csrf_token %}{# Support for flask-seasurf #}{% endif %} {% for field in form %}
    {{ field.label }}
    {% set css_class = 'span6 ' %} {% if field.errors %} {% set css_class = 'error ' + css_class %} {% endif %} {{ field(class=css_class) }} {% if field.description %}{{ field.description|safe() }}{% endif %} {% for error in field.errors %}{{ error }}{% endfor %}
    {% endfor %}
    {% endblock %} flask-peewee-0.6.7/flask_peewee/forms.pyc0000644000175000001440000000506112574421713021201 0ustar charlesusers00000000000000 #Uc@sddlmZddlmZddlmZddlmZddlmZdefdYZ dej fd YZ d efd YZ d S( i(t BooleanField(twidgets(tBooleanSelectField(tModelSelectField(tModelConvertertBaseModelConvertercBseZdZdZRS(cOs-tt|j|||j|jts flask-peewee-0.6.7/flask_peewee/_compat.pyc0000644000175000001440000000065612624224541021476 0ustar charlesusers00000000000000 #Uc@soddlZejddkZerFeZeefZeZeZn%eZefZe Zddl mZdS(iNii(treduce( tsyst version_infotPY2tunicodet text_typetstrt string_typestunichrRtchrt functools(((s?/home/charles/Dropbox/code/flask-peewee/flask_peewee/_compat.pyts    flask-peewee-0.6.7/flask_peewee/serializer.pyc0000644000175000001440000000426012624224541022220 0ustar charlesusers00000000000000 #Uc@sxddlZddlZddlmZddlmZddlmZdefdYZdefdYZ dS( iN(tModel(tget_dictionary_from_model(tget_model_from_dictionaryt SerializercBsJeZdZdZdjeegZdZdZdddZ RS(s%Y-%m-%ds%H:%M:%St cCst|tjr"|j|jSt|tjrD|j|jSt|tjrf|j|jSt|tr|j S|SdS(N( t isinstancetdatetimetstrftimetdatetime_formattdatet date_formatttimet time_formatRtget_id(tselftvalue((sB/home/charles/Dropbox/code/flask-peewee/flask_peewee/serializer.pyt convert_values cCsxz|jD]l\}}t|tr8|j|q t|ttfrft|j|||s   flask-peewee-0.6.7/flask_peewee/rest.pyc0000644000175000001440000005451012624225311021023 0ustar charlesusers00000000000000 *QVc@sddlZddlZyddlZWnek rGddlZnXddlmZddlmZddlmZddlm Z ddlm Z ddlm Z ddlm Z dd lm Z dd lTdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddlmZdefdYZdefdYZdefdYZdefdYZdefdYZ de fdYZ!defd YZ"dS(!iN(t Blueprint(tResponse(tabort(tg(tredirect(trequest(tsession(turl_for(t*(t DJANGO_MAP(tmake_field_tree(t Deserializer(t Serializer(tPaginatedQuery(tget_object_or_404(tslugify(treducetAuthenticationcBseZddZdZRS(cCs+|dkrdddg}n||_dS(NtPOSTtPUTtDELETE(tNonetprotected_methods(tselfR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt__init__s cCstj|jkrtStS(N(RtmethodRtFalsetTrue(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt authorize#sN(t__name__t __module__RRR(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs tAPIKeyAuthenticationcBsJeZdZdZdZddZdZdZdZ dZ RS( s Requires a model that has at least two fields, "key" and "secret", which will be searched for when authing a request. tkeytsecretcCsOtt|j|||_|jj|j|_|jj|j|_ dS(N( tsuperRRtmodelt_metatfieldst key_fieldt _key_fieldt secret_fieldt _secret_field(RR#R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyR2s cCs |jjS(N(R#tselect(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt get_query8scCsPy2|jj|j|k|j|kjSWn|jjk rKnXdS(N(R+twhereR'R)tgetR#t DoesNotExist(Rtkts((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytget_key;s   cCsQxJtjtjtjgD]0}d|krd|kr|d|dfSqWdS(NR R!(NN(RtargstheaderstformR(Rtsearch((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytget_key_secretDscCs\dt_tj|jkrtS|j\}}|s=|rU|j||t_ntjS(N( RRtapi_keyRRRRR6R1(RR R!((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRJs  N( RRt__doc__R&R(RRR+R1R6R(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyR*s   tUserAuthenticationcBseZddZdZRS(cCs#tt|j|||_dS(N(R"R9Rtauth(RR:R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRXscCsWdt_tj|jkrtStj}|s2tS|j j |j |j t_tjS(N( RRtuserRRRRt authorizationRR:t authenticatetusernametpassword(Rt basic_auth((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyR\s  N(RRRRR(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyR9Ws tAdminAuthenticationcBseZdZdZRS(cCs|jS(N(tadmin(RR;((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt verify_userkscCs8tt|j}|r4tjr4|jtjS|S(N(R"RARRR;RC(Rtres((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRns(RRRCR(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRAjs t RestResourcecBseZdZd'Zd'Zd'Zd'ZeZ d'Z eZ d'dZ dZ dZdZdZdZdZdZd Zd Zd Zd Zd ZdZdZdZdZdZdZd'dZd'dZ dZ!dZ"dZ#dZ$d'dZ%dZ&dZ'dZ(dZ)dZ*d Z+d!Z,d"Z-d#Z.d$Z/d%Z0d&Z1RS((ic Cs||_||_|jj|_||_|p?ddddg|_i|jp]|jjj|j6|_ |j ri|j |j6|_ n i|_ |j pt |jjj|_|jpg|_i|_|jrx|jjD]\}}|jjj|}||j|j|j|j}||j|<|j j|j |j j|j |jjg|jD]} d|| f^qp|jjg|jD]} d|| f^qqWt|_n t|_t|j|j|j|j|_dS(NtGETRRRs%s__%s(tapiR#R$t primary_keytpktauthenticationtallowed_methodsR%tsorted_field_namest_fieldstexcludet_excludet filter_fieldstlistt_filter_fieldstfilter_excludet_filter_excludet _resourcestinclude_resourcestitemst rel_modeltupdatetextendRt_include_foreign_keysRR tfilter_recursivet _field_tree( Rtrest_apiR#RJRKt field_nametresourcet field_objt resource_objtff((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs0   %  !  ! 04  cCs |jjS(N(RJR(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRscCst|jjS(N(RR#R(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt get_api_namescCs d|jjj|j|fS(Ns%s.%s_%s(RGt blueprinttnameRd(RRf((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt get_url_names  cCs |jjS(N(R#R*(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyR+scCsi}xtjD]}|}|jdr>t}|d}nt}d|kr|jdd\}}|tkr|}d}qn |}d}|j|g||j|tjj ||fqW|j dfg}x|r|j d\} } xl| j D]a} d| | j f} | |krx9|| D]*\}} }|j|| || |}q6WqqWx8| jjD]'\}}|j|| |dfq{WqW|S(Nt-it__teqtis%s%s(RR2t startswithRRtrsplitR t setdefaulttappendtgetlistR]tpopR%Rft apply_filtertchildrenRW(Rtqueryt raw_filtersR torig_keytnegatedtexprtoptqueuetnodetprefixtfieldt filter_exprtarg_listt child_prefixt child_node((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt process_querys6    *  &#c sd||f}fd}|dkrqg|djdD]}|j^q?}|j|i||6St|dkr|j|i|d|6Sg|D]} |i| |6^q} |jttj| SdS(Ns%s__%scsrt|pt|S(N(tDQ(tkwargs(Rw(s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytstinit,i(tsplittstriptfiltertlenRtoperatortor_( RRtRxRyRRwt query_exprt constructortitvalt query_clauses((Rws</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRrs ,&cCstS(N(R (R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytget_serializerscCstS(N(R (R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytget_deserializerscCs|S(s2 Hook for modifying outgoing data ((Rtobjtdata((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt prepare_datascCs1|j}|j||j||j|jS(N(RRtserialize_objectRMRO(RRR0((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs cCsD|j}g|D]-}|j||j||j|j^qS(N(RRRRMRO(RRtR0R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytserialize_querys cCs|j}|j||S(N(Rtdeserialize_object(RRtinstancetd((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs cCs tddS(Nt Forbiddeni(R(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytresponse_forbiddenscCstdtjdS(NsUnsupported method "%s"i(RRR(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytresponse_bad_methodscCs tddS(Ns Bad requesti(R(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytresponse_bad_requestscCs8tjrin idd6}ttj||ddS(Nitindenttmimetypesapplication/json(Rtis_xhrRtjsontdumps(RRR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytresponsescs(tjfd}|S(Ncs&tjkrjS||S(N(RRR(R2R(tfunctmethodsR(s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytinner s (t functoolstwraps(RRRR((RRRs</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytrequire_methods$cCsdd|j|jddgfd|j|jddddgfd|j|jddgffS(Nt/RFRs//RRs //delete/(Rtapi_listt api_detailt post_delete(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytget_urls's$cCstS(N(R(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt check_get.scCstS(N(R(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt check_post1scCstS(N(R(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt check_put4scCstS(N(R(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt check_delete7scCs|j|S(N(tsave(RRtraw_data((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt save_object:s cCs_t|dtjjs)|jStjdkrB|jStjdkr[|jSdS(Nscheck_%sRFR(tgetattrRRtlowerRt object_listtcreate(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyR>s   cCst|j|j|k}|p*tj}t|d|j|sV|jS|dkro|j|S|dkr|j |S|dkr|j |SdS(Nscheck_%sRFRRR(sPUTsPOST( RR+RIRRRRRt object_detailtedittdelete(RRIRR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRGs      cCs|j|dS(NR(R(RRI((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRVscCstjjdpd}|r|jd|jd}}||jjjkr|jjj|}|j|s}|j n |j }qn|S(NtorderingRkRh( RR2R-RltlstripR#R$R%torder_bytasctdesc(RRtRRtcolumnR}((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytapply_orderingYs-cCs|j}tjj}|j}d}}|dkrc|d|||j}nX|jr]t||j}n|S(Ntlimit(tintRR2R-t paginate_byt ValueErrortmin(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytget_paginate_byxs"   cCsZ|j}t||}|j|}|j|j}|ji|d6|d6S(Ntmetatobjects(RR RRtget_listR(Rtfiltered_queryRtpqt meta_datat query_dict((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytpaginated_object_lists  cCse|j}|j|}|j|}|jsBdtjkrO|j|S|j|j|S(NR( R+RRRRR2RRR(RRt((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs   cCs|j|j|S(N(RR(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRscCsx|jD]\}}||jkr t|tr |j|}|j|t||\}}|j||t|||j||q q WdS(N( RWRUt isinstancetdictRRtsave_related_objectstsetattrR(RRRR/tvt rel_resourcetrel_objt rel_models((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs  !cCs7tjptjjdpd}tj|jdS(NRRktutf8(RRR4R-Rtloadstdecode(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytread_request_datas!cCsy|j}Wntk r*|jSX|j||j\}}|j|||j||}|j|j|S(N( RRRRR#RRRR(RRRtmodels((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs  cCs{y|j}Wntk r*|jSX|j||\}}|j|||j||}|j|j|S(N(RRRRRRRR(RRRR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs  cCs)|jd|j}|ji|d6S(Nt recursivetdeleted(tdelete_instancetdelete_recursiveR(RRRD((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRsN(2RRRRR%RNRSRPRR\RVRRRRdRgR+RRrRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyREvs\ %     '                         tRestrictOwnerResourcecBs;eZdZdZdZdZdZdZRS(R;cCs|t||jkS(N(Rt owner_field(RR;R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pytvalidate_ownerscCst||j|dS(N(RR(RRR;((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyt set_ownerscCs|jtj|S(N(RRR;(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRscCs|jtj|S(N(RRR;(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRscCs,|j|tjtt|j||S(N(RRR;R"RR(RRR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs(RRRRRRRR(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs     tRestAPIcBs}eZdd ddZed d dZdZdZdZdZ dZ d Z d Z d Z d ZRS(s/apiRGcCsC||_i|_||_|j||_|p9t|_dS(N(tappt _registryt url_prefixt get_blueprintReRt default_auth(RRR|RRf((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/rest.pyRs    cCs)||||p|j||j|s<    - Sflask-peewee-0.6.7/flask_peewee/auth.pyc0000644000175000001440000002546512624224541021022 0ustar charlesusers00000000000000 #Uc@szddlZddlZddlmZddlmZddlmZddlmZddlmZddlmZddlm Z dd lm Z dd lm Z dd l Tdd l mZdd l mZddl mZddl mZddlmZddlmZddlmZejjeZdefdYZdefdYZdefdYZdS(iN(t Blueprint(tabort(tflash(tg(tredirect(trender_template(trequest(tsession(turl_for(t*(tForm(t PasswordField(t TextField(t validators(tcheck_password(tget_next(t make_passwordt LoginFormcBs>eZeddejgZeddejgZRS(tUsernameR tPassword(t__name__t __module__R R tRequiredtusernameR tpassword(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyRstBaseUsercBseZdZdZRS(cCst||_dS(N(RR(tselfR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyt set_password"scCst||jS(N(RR(RR((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyR%s(RRRR(((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyR!s tAuthcBseZdddedddZdZdZddZddZd Z d Z d Z d Z d Z dZdZdZdZdZdZdZdZdZdZdZdZdZRS(s /accountstautht/tuserc Csk||_||_||_|p*|j|_|j||_||_||_||_ |j dS(N( tapptdbtdb_tabletget_user_modeltUsert get_blueprintt blueprintt url_prefixt clear_sessiontdefault_next_urltsetup( RR R!t user_modeltprefixtnameR(R)R"((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyt__init__*s      cCsi|jd6S(NR(tget_logged_in_user(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytget_context_user:scs)djjtffdY}|S(NR$csieZedeZeZedeZeZede Z dZ ddfdYZ RS(tuniquetdefaultcSs|jS(N(R(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyt __unicode__EstMetacseZjZRS((RRR"((R(s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyR4Hs(( RRt CharFieldtTrueRRtemailt BooleanFieldtactivetFalsetadminR3R4((R(s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyR$>s   (R!tModelR(RR$((Rs</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyR#=s% csHdkr%ddlm}|ndffdYS(Ni(t ModelAdmint UserAdmincs;eZedp$ddddgZefdZRS(tcolumnsRR7R9R;cs]|j}t|j|||}||jjkrY|j|jj|jn|S(N(Rtsupert save_modeltdataRtsave(Rtinstancetformtaddingt orig_passwordR(R>(s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyRAVs   (RRtgetattrR?R:RA((R>t model_admin(s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyR>Rs(tNonetflask_peewee.adminR=(RRIR=((R>RIs</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytget_model_adminMs   cCs |j|j|j|dS(N(tregisterR$RL(Rt admin_siteRI((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytregister_admindsc Cs7t|tdtjjtddtjjtdS(Nt static_foldertstaticttemplate_foldert templates(RRtostpathtjoint current_dir(Rtblueprint_name((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyR%gs cCsd|jfd|jffS(Ns/logout/s/login/(tlogouttlogin(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytget_urlsos cCstS(N(R(R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytget_login_formuscsfd}|S(Ncs(tjfd}|S(NcsVj}| s | rItdjjdt}t|S||S(Ns%s.logintnext(R/RR&R-RR(targstkwargsRt login_url(tfnRttest_fn(s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytinnerzs   (t functoolstwraps(RaRc(RRb(Ras</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyt decoratorys$((RRbRf((RRbs</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyt test_userxs cCs|jd|S(NcSstS(N(R6(tu((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyts(Rg(Rtfunc((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytlogin_requiredscCs|jd|S(NcSs|jS(N(R;(Rh((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyRis(Rg(RRj((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pytadmin_requiredscCs{|jjj|jjtk}y%|j|jj|kj}Wn|jjk rctSX|j |swtS|S(N( R$tselecttwhereR9R6Rtgett DoesNotExistR:R(RRRR9R((s</home/charles/Dropbox/code/flask-peewee/flask_peewee/auth.pyt authenticates$%cCsAttd<|jtds,   flask-peewee-0.6.7/flask_peewee/__init__.pyc0000644000175000001440000000026712574421713021615 0ustar charlesusers00000000000000 #Uc@s dZdS(s0.6.5N(t __version__(((s@/home/charles/Dropbox/code/flask-peewee/flask_peewee/__init__.pytsflask-peewee-0.6.7/flask_peewee/filters.py0000644000175000001440000003045212624225413021355 0ustar charlesusers00000000000000import datetime import operator from flask import request from flask_peewee.forms import BaseModelConverter from flask_peewee._compat import reduce from peewee import * from wtforms import fields from wtforms import form from wtforms import validators from wtforms import widgets class QueryFilter(object): """ Basic class representing a named field (with or without a list of options) and an operation against a given value """ def __init__(self, field, name, options=None): self.field = field self.name = name self.options = options def query(self, value): raise NotImplementedError def operation(self): raise NotImplementedError def get_options(self): return self.options class EqualQueryFilter(QueryFilter): def query(self, value): return self.field == value def operation(self): return 'equal to' class NotEqualQueryFilter(QueryFilter): def query(self, value): return self.field != value def operation(self): return 'not equal to' class LessThanQueryFilter(QueryFilter): def query(self, value): return self.field < value def operation(self): return 'less than' class LessThanEqualToQueryFilter(QueryFilter): def query(self, value): return self.field <= value def operation(self): return 'less than or equal to' class GreaterThanQueryFilter(QueryFilter): def query(self, value): return self.field > value def operation(self): return 'greater than' class GreaterThanEqualToQueryFilter(QueryFilter): def query(self, value): return self.field >= value def operation(self): return 'greater than or equal to' class StartsWithQueryFilter(QueryFilter): def query(self, value): return fn.Lower(fn.Substr(self.field, 1, len(value))) == value.lower() def operation(self): return 'starts with' class ContainsQueryFilter(QueryFilter): def query(self, value): return self.field ** ('%%%s%%' % value) def operation(self): return 'contains' class YearFilter(QueryFilter): def query(self, value): value = int(value) return self.field.year == value def operation(self): return 'year equals' class MonthFilter(QueryFilter): def query(self, value): value = int(value) return self.field.month == value def operation(self): return 'month equals' class WithinDaysAgoFilter(QueryFilter): def query(self, value): value = int(value) return self.field >= ( datetime.date.today() - datetime.timedelta(days=value)) def operation(self): return 'within X days ago' class OlderThanDaysAgoFilter(QueryFilter): def query(self, value): value = int(value) return self.field < ( datetime.date.today() - datetime.timedelta(days=value)) def operation(self): return 'older than X days ago' class FilterMapping(object): """ Map a peewee field to a list of valid query filters for that field """ string = ( EqualQueryFilter, NotEqualQueryFilter, StartsWithQueryFilter, ContainsQueryFilter) numeric = ( EqualQueryFilter, NotEqualQueryFilter, LessThanQueryFilter, GreaterThanQueryFilter, LessThanEqualToQueryFilter, GreaterThanEqualToQueryFilter) datetime_date = (numeric + ( WithinDaysAgoFilter, OlderThanDaysAgoFilter, YearFilter, MonthFilter)) foreign_key = (EqualQueryFilter, NotEqualQueryFilter) boolean = (EqualQueryFilter, NotEqualQueryFilter) def get_field_types(self): return { CharField: 'string', TextField: 'string', DateTimeField: 'datetime_date', DateField: 'datetime_date', TimeField: 'numeric', IntegerField: 'numeric', BigIntegerField: 'numeric', FloatField: 'numeric', DoubleField: 'numeric', DecimalField: 'numeric', BooleanField: 'boolean', PrimaryKeyField: 'numeric', ForeignKeyField: 'foreign_key', } def convert(self, field): mapping = self.get_field_types() for klass in type(field).__mro__: if klass in mapping: mapping_fn = getattr(self, 'convert_%s' % mapping[klass]) return mapping_fn(field) # fall back to numeric return self.convert_numeric(field) def convert_string(self, field): return [f(field, field.verbose_name, field.choices) for f in self.string] def convert_numeric(self, field): return [f(field, field.verbose_name, field.choices) for f in self.numeric] def convert_datetime_date(self, field): return [f(field, field.verbose_name, field.choices) for f in self.datetime_date] def convert_boolean(self, field): boolean_choices = [('True', '1', 'False', '')] return [f(field, field.verbose_name, boolean_choices) for f in self.boolean] def convert_foreign_key(self, field): return [f(field, field.verbose_name, field.choices) for f in self.foreign_key] class FieldTreeNode(object): def __init__(self, model, fields, children=None): self.model = model self.fields = fields self.children = children or {} def make_field_tree(model, fields, exclude, force_recursion=False, seen=None): no_explicit_fields = fields is None # assume we want all of them if no_explicit_fields: fields = model._meta.sorted_field_names exclude = exclude or [] seen = seen or set() model_fields = [] children = {} for field_obj in model._meta.sorted_fields: if field_obj.name in exclude or field_obj in seen: continue if field_obj.name in fields: model_fields.append(field_obj) if isinstance(field_obj, ForeignKeyField): seen.add(field_obj) if no_explicit_fields: rel_fields = None else: rel_fields = [ rf.replace('%s__' % field_obj.name, '') \ for rf in fields if rf.startswith('%s__' % field_obj.name) ] if not rel_fields and force_recursion: rel_fields = None rel_exclude = [ rx.replace('%s__' % field_obj.name, '') \ for rx in exclude if rx.startswith('%s__' % field_obj.name) ] children[field_obj.name] = make_field_tree(field_obj.rel_model, rel_fields, rel_exclude, force_recursion, seen) return FieldTreeNode(model, model_fields, children) class SmallSelectWidget(widgets.Select): def __call__(self, field, **kwargs): kwargs['class'] = 'span2' return super(SmallSelectWidget, self).__call__(field, **kwargs) class FilterForm(object): base_class = form.Form separator = '-' field_operation_prefix = 'fo_' field_value_prefix = 'fv_' field_relation_prefix = 'fr_' def __init__(self, model, model_converter, filter_mapping, fields=None, exclude=None): self.model = model self.model_converter = model_converter self.filter_mapping = filter_mapping # convert fields and exclude into a tree self._field_tree = make_field_tree(model, fields, exclude) self._query_filters = self.load_query_filters() def load_query_filters(self): query_filters = {} queue = [self._field_tree] while queue: curr = queue.pop(0) for field in curr.fields: query_filters[field] = self.filter_mapping.convert(field) queue.extend(curr.children.values()) return query_filters def get_operation_field(self, field): choices = [] for i, query_filter in enumerate(self._query_filters[field]): choices.append((str(i), query_filter.operation())) return fields.SelectField(choices=choices, validators=[validators.Optional()], widget=SmallSelectWidget()) def get_field_default(self, field): if isinstance(field, DateTimeField): return datetime.datetime.now() elif isinstance(field, DateField): return datetime.date.today() elif isinstance(field, TimeField): return datetime.time(0, 0) return field.default def get_value_field(self, field): field_name, form_field = self.model_converter.convert(field.model_class, field, None) form_field.kwargs['default'] = self.get_field_default(field) form_field.kwargs['validators'] = [validators.Optional()] return form_field def get_field_dict(self, node=None, prefix=None): field_dict = {} node = node or self._field_tree for field in node.fields: op_field = self.get_operation_field(field) val_field = self.get_value_field(field) field_dict['%s%s' % (self.field_operation_prefix, field.name)] = op_field field_dict['%s%s' % (self.field_value_prefix, field.name)] = val_field for prefix, node in node.children.items(): child_fd = self.get_field_dict(node, prefix) field_dict['%s%s' % (self.field_relation_prefix, prefix)] = fields.FormField( self.get_form(child_fd), separator=self.separator, ) return field_dict def get_form(self, field_dict): return type( self.model.__name__ + 'FilterForm', (self.base_class, ), field_dict, ) def parse_query_filters(self): # reconstruct the "select" and "value" fields we are searching for in the # arguments from the request by depth-first searching the field tree -- # basically what we should have at the end is the field we're querying, # the type of query (QueryFilter), the value requested, and the path we # took to get there (joins) accum = {} def _dfs(node, prefix, models, join_columns): for field in node.fields: qf_select = self.field_operation_prefix.join((prefix, field.name)) qf_value = self.field_value_prefix.join((prefix, field.name)) if qf_select in request.args and qf_value in request.args: accum.setdefault(field, []) accum[field].append(( request.args.getlist(qf_select), request.args.getlist(qf_value), models, join_columns, qf_select, qf_value, )) for child_prefix, child in node.children.items(): new_prefix = prefix + self.field_relation_prefix + child_prefix + self.separator model_copy = list(models) + [child.model] join_copy = list(join_columns) + [child_prefix] _dfs(child, new_prefix, model_copy, join_copy) _dfs(self._field_tree, '', [], []) return accum def process_request(self, query): field_dict = self.get_field_dict() FormClass = self.get_form(field_dict) form = FormClass(request.args) query_filters = self.parse_query_filters() cleaned = [] for field, filters in query_filters.items(): for (filter_idx_list, filter_value_list, path, join_path, qf_s, qf_v) in filters: query = query.switch(self.model) for join, model in zip(join_path, path): query = query.join(model, on=join) q_objects = [] for filter_idx, filter_value in zip(filter_idx_list, filter_value_list): idx = int(filter_idx) cleaned.append((qf_s, idx, qf_v, filter_value)) query_filter = self._query_filters[field][idx] q_objects.append(query_filter.query(field.db_value(filter_value))) query = query.where(reduce(operator.or_, q_objects)) return form, query, cleaned class FilterModelConverter(BaseModelConverter): def __init__(self, *args, **kwargs): super(FilterModelConverter, self).__init__(*args, **kwargs) self.defaults = dict(self.defaults) self.defaults[TextField] = fields.TextField self.defaults[DateTimeField] = fields.DateTimeField flask-peewee-0.6.7/flask_peewee/utils.py0000644000175000001440000001110012624225413021032 0ustar charlesusers00000000000000import math import random import re import sys from hashlib import sha1 from flask import abort from flask import render_template from flask import request from peewee import DoesNotExist from peewee import ForeignKeyField from peewee import Model from peewee import SelectQuery from flask_peewee._compat import text_type def get_object_or_404(query_or_model, *query): if not isinstance(query_or_model, SelectQuery): query_or_model = query_or_model.select() try: return query_or_model.where(*query).get() except DoesNotExist: abort(404) def object_list(template_name, qr, var_name='object_list', **kwargs): pq = PaginatedQuery(qr, kwargs.pop('paginate_by', 20)) kwargs[var_name] = pq.get_list() return render_template(template_name, pagination=pq, page=pq.get_page(), **kwargs) class PaginatedQuery(object): page_var = 'page' def __init__(self, query_or_model, paginate_by): self.paginate_by = paginate_by if isinstance(query_or_model, SelectQuery): self.query = query_or_model self.model = self.query.model_class else: self.model = query_or_model self.query = self.model.select() def get_page(self): curr_page = request.args.get(self.page_var) if curr_page and curr_page.isdigit(): return int(curr_page) return 1 def get_pages(self): return int(math.ceil(float(self.query.count()) / self.paginate_by)) def get_list(self): return self.query.paginate(self.get_page(), self.paginate_by) def get_next(): if not request.query_string: return request.path return '%s?%s' % (request.path, request.query_string) def slugify(s): return re.sub('[^a-z0-9_\-]+', '-', s.lower()) def load_class(s): path, klass = s.rsplit('.', 1) __import__(path) mod = sys.modules[path] return getattr(mod, klass) def get_dictionary_from_model(model, fields=None, exclude=None): model_class = type(model) data = {} fields = fields or {} exclude = exclude or {} curr_exclude = exclude.get(model_class, []) curr_fields = fields.get(model_class, model._meta.sorted_field_names) for field_name in curr_fields: if field_name in curr_exclude: continue field_obj = model_class._meta.fields[field_name] field_data = model._data.get(field_name) if isinstance(field_obj, ForeignKeyField) and field_data and field_obj.rel_model in fields: rel_obj = getattr(model, field_name) data[field_name] = get_dictionary_from_model(rel_obj, fields, exclude) else: data[field_name] = field_data return data def get_model_from_dictionary(model, field_dict): if isinstance(model, Model): model_instance = model check_fks = True else: model_instance = model() check_fks = False models = [model_instance] for field_name, value in field_dict.items(): field_obj = model._meta.fields[field_name] if isinstance(value, dict): rel_obj = field_obj.rel_model if check_fks: try: rel_obj = getattr(model, field_name) except field_obj.rel_model.DoesNotExist: pass if rel_obj is None: rel_obj = field_obj.rel_model rel_inst, rel_models = get_model_from_dictionary(rel_obj, value) models.extend(rel_models) setattr(model_instance, field_name, rel_inst) else: setattr(model_instance, field_name, field_obj.python_value(value)) return model_instance, models def path_to_models(model, path): accum = [] if '__' in path: next, path = path.split('__') else: next, path = path, '' if next in model._meta.rel: field = model._meta.rel[next] accum.append(field.rel_model) else: raise AttributeError('%s has no related field named "%s"' % (model, next)) if path: accum.extend(path_to_models(model, path)) return accum # borrowing these methods, slightly modified, from django.contrib.auth def get_hexdigest(salt, raw_password): data = salt + raw_password return sha1(data.encode('utf8')).hexdigest() def make_password(raw_password): salt = get_hexdigest(text_type(random.random()), text_type(random.random()))[:5] hsh = get_hexdigest(salt, raw_password) return '%s$%s' % (salt, hsh) def check_password(raw_password, enc_password): salt, hsh = enc_password.split('$', 1) return hsh == get_hexdigest(salt, raw_password) flask-peewee-0.6.7/flask_peewee/forms.py0000644000175000001440000000260412574421673021043 0ustar charlesusers00000000000000from peewee import BooleanField from wtforms import widgets from wtfpeewee.fields import BooleanSelectField from wtfpeewee.fields import ModelSelectField from wtfpeewee.orm import ModelConverter class BaseModelConverter(ModelConverter): def __init__(self, *args, **kwargs): super(BaseModelConverter, self).__init__(*args, **kwargs) self.converters[BooleanField] = self.handle_boolean def handle_boolean(self, model, field, **kwargs): return field.name, BooleanSelectField(**kwargs) class ChosenAjaxSelectWidget(widgets.Select): def __init__(self, data_source, data_param, *args, **kwargs): self.data_source = data_source self.data_param = data_param super(ChosenAjaxSelectWidget, self).__init__(*args, **kwargs) def __call__(self, field, **kwargs): if field.allow_blank and not self.multiple: kwargs['data-role'] = u'ajax-chosenblank' else: kwargs['data-role'] = u'ajax-chosen' kwargs['data-source'] = self.data_source kwargs['data-param'] = self.data_param kwargs['data-placeholder'] = 'Type to search...' return super(ChosenAjaxSelectWidget, self).__call__(field, **kwargs) class LimitedModelSelectField(ModelSelectField): def iter_choices(self): for obj in self.query.limit(20): yield (obj.get_id(), self.get_label(obj), obj == self.data) flask-peewee-0.6.7/flask_peewee/db.pyc0000644000175000001440000000576212624224541020444 0ustar charlesusers00000000000000 #Uc@sPddlZddlTddlmZddlmZdefdYZdS(iN(t*(tImproperlyConfigured(t load_classtDatabasecBsAeZddZdZdZdZdZdZRS(cCsK||_||_|jdkr.|jn|j|j|_dS(N(tapptdatabasetNonet load_databasetregister_handlerstget_model_classtModel(tselfRR((s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyt__init__ s     cCs$t|jjd|_y.|jjd|_|jjd|_Wntk rftdnXy1t |j|_ t |j t j stWnjtk rtd|jnGtk rtd|jn$tk rtd|jnX|j |j|j|_dS(NtDATABASEtnametengines6Please specify a "name" and "engine" for your databasesUnable to import: "%s"sDatabase engine not found: "%s"s7Database engine not a subclass of peewee.Database: "%s"(tdictRtconfigtdatabase_configtpopt database_nametdatabase_enginetKeyErrorRRtdatabase_classt issubclasstpeeweeRtAssertionErrort ImportErrortAttributeErrorR(R ((s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyRs     cs dtffdY}|S(Nt BaseModelcs!eZddfdYZRS(tMetacseZjZRS((t__name__t __module__R((R (s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyR*s((RR R((R (s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyR)s(R (R R((R s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyR (scCs|jjdS(N(Rtconnect(R ((s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyt connect_db/scCs#|jjs|jjndS(N(Rt is_closedtclose(R texc((s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pytclose_db2scCs*|jj|j|jj|jdS(N(Rtbefore_requestR"tteardown_requestR&(R ((s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyR6sN( RR RR RR R"R&R(((s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyRs     (Rtflask_peewee.exceptionsRtflask_peewee.utilsRtobjectR(((s:/home/charles/Dropbox/code/flask-peewee/flask_peewee/db.pyts  flask-peewee-0.6.7/flask_peewee/__init__.py0000644000175000001440000000002612574421673021450 0ustar charlesusers00000000000000__version__ = '0.6.5' flask-peewee-0.6.7/flask_peewee/auth.py0000644000175000001440000001553412574421673020664 0ustar charlesusers00000000000000import functools import os from flask import Blueprint from flask import abort from flask import flash from flask import g from flask import redirect from flask import render_template from flask import request from flask import session from flask import url_for from peewee import * from wtforms import Form from wtforms import PasswordField from wtforms import TextField from wtforms import validators from flask_peewee.utils import check_password from flask_peewee.utils import get_next from flask_peewee.utils import make_password current_dir = os.path.dirname(__file__) class LoginForm(Form): username = TextField('Username', validators=[validators.Required()]) password = PasswordField('Password', validators=[validators.Required()]) class BaseUser(object): def set_password(self, password): self.password = make_password(password) def check_password(self, password): return check_password(password, self.password) class Auth(object): def __init__(self, app, db, user_model=None, prefix='/accounts', name='auth', clear_session=False, default_next_url='/', db_table='user'): self.app = app self.db = db self.db_table = db_table self.User = user_model or self.get_user_model() self.blueprint = self.get_blueprint(name) self.url_prefix = prefix self.clear_session = clear_session self.default_next_url = default_next_url self.setup() def get_context_user(self): return {'user': self.get_logged_in_user()} def get_user_model(self): class User(self.db.Model, BaseUser): username = CharField(unique=True) password = CharField() email = CharField(unique=True) active = BooleanField() admin = BooleanField(default=False) def __unicode__(self): return self.username class Meta: db_table = self.db_table # Postgres reserves user as a keyword return User def get_model_admin(self, model_admin=None): if model_admin is None: from flask_peewee.admin import ModelAdmin model_admin = ModelAdmin class UserAdmin(model_admin): columns = getattr(model_admin, 'columns') or ( ['username', 'email', 'active', 'admin']) def save_model(self, instance, form, adding=False): orig_password = instance.password user = super(UserAdmin, self).save_model(instance, form, adding) if orig_password != form.password.data: user.set_password(form.password.data) user.save() return user return UserAdmin def register_admin(self, admin_site, model_admin=None): admin_site.register(self.User, self.get_model_admin(model_admin)) def get_blueprint(self, blueprint_name): return Blueprint( blueprint_name, __name__, static_folder=os.path.join(current_dir, 'static'), template_folder=os.path.join(current_dir, 'templates'), ) def get_urls(self): return ( ('/logout/', self.logout), ('/login/', self.login), ) def get_login_form(self): return LoginForm def test_user(self, test_fn): def decorator(fn): @functools.wraps(fn) def inner(*args, **kwargs): user = self.get_logged_in_user() if not user or not test_fn(user): login_url = url_for('%s.login' % self.blueprint.name, next=get_next()) return redirect(login_url) return fn(*args, **kwargs) return inner return decorator def login_required(self, func): return self.test_user(lambda u: True)(func) def admin_required(self, func): return self.test_user(lambda u: u.admin)(func) def authenticate(self, username, password): active = self.User.select().where(self.User.active==True) try: user = active.where(self.User.username==username).get() except self.User.DoesNotExist: return False else: if not user.check_password(password): return False return user def login_user(self, user): session['logged_in'] = True session['user_pk'] = user.get_id() session.permanent = True g.user = user flash('You are logged in as %s' % user, 'success') def logout_user(self): if self.clear_session: session.clear() else: session.pop('logged_in', None) g.user = None flash('You are now logged out', 'success') def get_logged_in_user(self): if session.get('logged_in'): if getattr(g, 'user', None): return g.user try: return self.User.select().where( self.User.active==True, self.User.id==session.get('user_pk') ).get() except self.User.DoesNotExist: pass def login(self): error = None Form = self.get_login_form() if request.method == 'POST': form = Form(request.form) next_url = request.form.get('next') or self.default_next_url if form.validate(): authenticated_user = self.authenticate( form.username.data, form.password.data, ) if authenticated_user: self.login_user(authenticated_user) return redirect(next_url) else: flash('Incorrect username or password') else: form = Form() next_url = request.args.get('next') return render_template( 'auth/login.html', error=error, form=form, login_url=url_for('%s.login' % self.blueprint.name), next=next_url) def logout(self): self.logout_user() return redirect(request.args.get('next') or self.default_next_url) def configure_routes(self): for url, callback in self.get_urls(): self.blueprint.route(url, methods=['GET', 'POST'])(callback) def register_blueprint(self, **kwargs): self.app.register_blueprint(self.blueprint, url_prefix=self.url_prefix, **kwargs) def load_user(self): g.user = self.get_logged_in_user() def register_handlers(self): self.app.before_request(self.load_user) def register_context_processors(self): self.app.template_context_processors[None].append(self.get_context_user) def setup(self): self.configure_routes() self.register_blueprint() self.register_handlers() self.register_context_processors() flask-peewee-0.6.7/flask_peewee/static/0000755000175000001440000000000012624225533020621 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/static/img/0000755000175000001440000000000012624225533021375 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/static/img/glyphicons-halflings.png0000644000175000001440000003300212574421673026234 0ustar charlesusers00000000000000PNG  IHDRtEXtSoftwareAdobe ImageReadyqe<iTXtXML:com.adobe.xmp glyphicons_small_dark 5k1IDATx}ol\EW^zD$|_w'CwG;4<1uij6C" Eʼ0 "=, f3o 0`snuݾT;1Kmw֭{~Uuʘ1cKά:kb10Q!8dM` \5e]OYKA*9c8 ?'M7k1c]?bѽc}x$/$Y3sOqY+*bQ8C A,VuXx XMYRژ5@4 E얌ԏ jt(JM>(=BJC71Q7% WY}dlP"oHTV-/NPάVo cqhOg6pwêkǺ _)M+I :Hz̬/ɞ{9OdnV|_xH0kt|Nn3#3u+/Ua9%XqNzg;y9y9O%~uɗ*=Ipcy}Y(o(u±$^j e\iX;X-rѲ&>>eìas??1aۤ^=765^8R6Ҩ*4|QN$*>skUqSE -?DGƯ M#۠ ֙ʟU[3HVUwd#)~@@V -s'A]Λdn 37UuSCz{v(8l-;ޙṹ[;V~ )t>7QeS)jǹOhc YCb7: X 'Y 9 Y1y=G 6`=GVB[\yQ=uo㺷c?U|gdD&tÓCv߈z&AIg)ʨuGU8G*=Wb6yhDM$?.&rvQCXԙvdrQ]olwc*-73pyNV+xU^4 YiYqD,48c~T}֙{~2dnsզS ;]ɨDuF_1glGz`cKZ>߷h{>IoURΕN'0i2qˆN԰cA$+-y6f?%xYUiJU?m}gsVYUt&qyYT u,U. Uc,w'alj"MW$)҈ʳ#i5v:}D6w}O 8sDJ,#`F^gw?ӑtxC~TWyf-̶B?WԪ-_5Tlfc%Z}h ã-oM۴t<-|sޫBD?<0ځ_9/uspƔM&xӤ=_h9`e8ki_^ gaYݫ-(x j謮1;;_W$t]=⣿.^"_^j}PV saF-+Xў/meUµq;>E4d,sdɜX| bNg(G ԉjS,}ؖ1{奪n}t ݽ.t\}p5v*ʵ^4БoR7F+V?Ooz:tzaxFp6&[R)dndKߕ@jTQg$*茲\ЃDAJRO*OX| n @;3g*NN}1υxǹ|ic˨TMF3X ֐GX#;UF;v_Ɉ[m֯wK!lT]"eߨzx-r;tݱ|Tuׇx7 *<־PJڞT>9TIx{Urp'ZU,ۜ[ iNU>=_5~p:|M>7!9ѕލGUw(sOZw/< 늝>TGQQRΪJg5t@ꁜDg蚢2S#E>;|iϛd?'?%`}Oƒ$x9SMoTMxOq==NP@ٙM0Qz5D1 uٓ YgKUe7|I9uVyZtV<`VIrB!.ySX0'>Q].\,:#?,۹>_SC#4XCU5&*SMM4SUucǨԻo#C7}.dÛtкxGgU+5tD}p>Nŝ+֝+Z9w"ͪ.x@ꍪPժz\FvivV+#*pa[Vkm:g0ܗyPUdMU]U̟ÕzaTZ>wXF+!I\h>NŝmWS>H-SݞWKfrH-Wˌ9710Y=_C!B|뱟ZKyY#ڶ8!S~ZC"s!6<E wA oo;T})C[˕_x3sI{QuDO<"6uSdFP\B__UU>X#|\nSyul^WӅڐoѹ%NyS>u%CBepʘ1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f\[im ue4hs+k)Ti&ȥȨԻdʲ%gRap:Yh۪.Pz*VrYgtH= _SQpm3"KXI|5鯳vGSշJ,g cK Od?CW.īejIFԧ*JDv5 kulMXAtI>WLA %7`)[(h6lqӻ{ݳXM _\6ea'uy]1*t*k]SS5"*xYTm{ҍ r1LtK)鞙l b*Ur*p14/#F}7~l ^RZgE"9"TrVH4t]3uG~pUunZƓ |JUlU[q,&JkXJh+'5*FBUޔZ.cKWN 7^FR֝ XP;/}(uKm#̅XȰU!ԂBRUWB7@ NomZI>>\{[|cï"QqUgYH~xV3Nx=3:V@PV6c#E*(jR&ٽSUWB_B?\$S{ުV:${UA$j@o{oے׽}V婪Kw]؊_7v]&ٽqP`-MԤ( @"$pSWeg pÓ,iJ_z{ub0`4wkWbpt/^YQgVʈWU'>(;=q1J!Bg]j(к\3tQw{-㏷b W[!yM>QD-N~BlՏ..5 ] 't{RZ)`\OOvVM+^*pq.uI~psS_W#G!j1^FToNnNlh!6 b$1(01{ zc칹䯖=< &9C;I HnAJ 838^U|T֨~!?޽ ')B[ S"i|]PZ 6N??P[~NUe7C7댔">BLZԥT->v)S,ǃl!UQ(PGmAlq*UR鶠.]rhJcxpH)g>Z}JQ5.%D`L=?1f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f ,zLga̘ KqLQdl 9CrnF*Z-)+3Vm꺜n*Cפ8D&\}MP$L>i(Hk:^cgJۅ?JʟN ש&*+epK#Bx$vj4Miuz eB|CskDXnؖSO濶)f[b,`)gv9E1NGR,^x nOJ*!Q֟a@zCvvd=QV6NX`Fqʈ!k'Oo09ޙ;jkZR})/ y,$TD}VI=|1J!Sc o<]-$:"D55VgWUUvpE֜{=JEÜ 7pqFjhI~6zrZPw`,*S3⽡{;'uo۞NUK9Z=|1?S}17NU 6/>:gz/t~EÓN3Cҥ;,7?geus$v;U>{OjY&QFBU{)T)N`)g GU}}@-S}3INTҰ8f:/kx݄x JgcK&UlmAf*aRUϪQC 5>EB$Кs^^jZo5EK;K/WuVEƭTINXSD'Qafx=#?ƪlq{|JjFp9On̆ŝY? Ɵ D߶,jߓ_%rA6Ax1vL ᮴ O[CV5kpoUg<.aPtx#=$q:簚S Jo{`?[~nR3~ [z셥%Pk~%V/nMkJ]UGIM?li[]eM΃6" aF0f)STzacPNZ;vu+.x?Yժ^XV2GԋoLR47BV5E4@M1cnFS]91cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌtuzoxҬ}(5鴦nBҺWbRiN7h:78ˈ3ԧReK ayZꂹ;zWbyɜ] "'phVJ4<_ԆWd^Ԭsq6vŜZ=f;3;NUyFe4aMDG7J( j훀ģ_ F`'Koa  = Nw; 3F\F\`K/_ADNןvh'I v*0o p#:B kN? 7GN k(M亮nZ{Prx'vNSa@@< :m/X>?:U:x!wfq5{8>N$`[{k) P.Uf_b6y庬1(ʙc#t. TpDl!5 \P߱԰睧r2:(cAZ=/N[%G_~;(+GUV{]P5 Fiuz8+,j< [$X?R[quoꢌRqj]biI⌐shR1=k`?|FBI">GTx2<!W礒rc\Jm.qDQxÓ4zj(e^KMCt~(u]M&- (p~r- ;زƓ*a  Pej5 {wGVV[{ZJ IQkƫQ-./\nv(f.7>=3ǶӲBT% >!5uD`O:ݿYGZ%ULbJ<Rg>g}=Lԃ[1Qqd i}?nǶ;RUM qrr-ۙ`bxcK T[,n)YSP,$NbuCOb8wVP-+J;UE%fՃӘLBڟ/~I\B]}VUvAP r<ŒA\xxjCUYSO;rɠ6ԙюiT{!eqK QPK ,Yd:Qx́ssQb[JB>zwr]bN7R&`>V! >t' <a*;^?F)O\HBTG383/_,qJoO})lݷ~(tzKËVʯ;;IF⢣{l5>x;Esߡ ]lQff%2sKz2I7K|2a=jמR.:T^)H{ܥUJ@Xihoi{d[|uHT:9m嚢Ō]w-tV tm)YbUn3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3fX 1`X!-4teA%v<?|ㇶ&i_qz ] eR_ |& c*kր4f,J U_h\1AeL-L\^~Phr*tqa0fT:MUp>yduUYCA>k).,+ɦ@bjE)W F+As$e6\Q9oI}4xjH}2o^՟|ϧp+P;昭?^$^)tn9VOdDTʘY #jǍvR!*]|6!~.MPxG5Ø9G6QIWGjRT|^|Y߅&g|JuKw-wS=3,7< {o-xL(Ex? OY`# ߑ ̗kTŐHgEp#Fiq3O2_NƟtOrR? ./1IE;WN˜5嘫b+Ontutu6RNѾ|:Qb[A򖘫T @܀e-8hx?tQCSC>Ho=5} n #}oU(x U< $kG/Ut^""9䮉Fv+OF8kTm:ꍇm*v0&գjep[DYq3Cӹm!HXm-Q(6]^#'vvͪ\Qؤ[CT>I1 Oʧ+"!uwϴѼJ5׽W7HTѓuevʷJzNUW}L%up&:Լ m6f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘ WYɜ$P,;AUӺJ]v낀sէ Ţ{%kwned--Yj7bɦɮ@ -/7p]b@ ];`1kٵր?*<':KU? ~;eAI:ɥ-k} !^ȯ-5١o\_]0/n xIU&XefʬdkԵ БeW$mjOl%ep~&RgĞzQNU^ OoC鰚:ϥ{f4mP#_SaD[џ nK<.d= @}N| Qs~^etkj]ܽS' vckeeM<"E:ס侹̱囫s-]^ }(#J,kܫȸw!=3B5Kԍ^j3FҬﳁrS7Q3R<'J9"]|_З%/#TcGqn"[cGQ љgƎ*iV!jT2%Тtuhc(;Mе|' RƸHge-S1 c,+j 25{zu͵cx'-i6γosw-4ΰg؞^'1 K\d@f#i0=@%5zݷut!]M|![@QDL;7U Ѿ3ՊM4!~a @1_'onҋM3BQjp&%!l"Xqr; A[<`am}43/0IPCM!6(*gK&YQGDP,`{VP-x)h7e1]W$1bzSܕcO]U;Zi'y"؆K 64Y*.v@c.};tN%DI !ZЏ5LH26 ɯ" -bE,,)ʏ B>mn6pmRO wm@V#?'CȑZ#qb|$:)/E%nRqChn%i̓}lm ?idd",`H"r.z~(bQU&)5X#EMR<*p[[%.Ọk7lIoJF lV!̡ăuH`&,zRk$|$lXbjߪdU?Σ$HW$U'HE3*խU\}( zhVk}guRk$%|T|ck獳"D_W+.Q)@ƽHbslTDR2Xm#a 3lYzj㒚#! 4J8(cvt]aT D ΅Q?^-_^$:\V $N|=(vZ'q6Z׆B5V!y3K㱿bv4xR]al!IoP@tVyL٪mlڿIUb|[*lke'*WddDӝ}\W_WߝrN?vޫ۲X%0uoui*JVƦb%}i5IYlNE-wςf_W3mI-mQ)S kTC7m<"܌bT|'$ҘR&>O p6tSN\ׯLm\r@3uT b7t.5.q3r0=8TiJ\6uF R32^'ŪxI F8O{%8kJMSȴdBEdWCYO:/ON/I_=xFE! =i:o~ y?''[͓[͓[͓[͓[ͭ.U>$PƦc%]\c:| ,eSZ,oXrX!R@Zv 0>?* <|N60;{ad2v+D^t[q!۞V}fۨϏYeॗ)Vyl|" fUq@Ǽ4Y-Y-!6aB:o%JIUQ|UKO`=\ :0x Pau@!KPdxhw1>$j΍vZdxSUA&[URd7øzk/rU^w:I.VǮc>q.!zSr&2)Wg R -iQ 8Pa\ОU%iݡU_=p Lu(N?0?Æ:]άtB%U|NsorNf ,P !v" Y6hL_@@bscqgv4||0lϟ$S9bʱj#~?o}}7sAPm:IV=n !{{hEࢪ8suoLT$;VscqD3 ༂3.DBB4&V' T `D6Ϸqyj8V*X%@s\jrN$|=5Ά 'mUiKi%CI:ssaƅ`*`=l)>u՘MeuSI_OL_}o&jzp{lu:O)s%Q@$<]f xO%PCbhr2PKpf5Në3^o]eJiB464^tuٲU֌:G4'22YpuG'/Py4?.SBP_>I 1t3ΓBɭɭɭɭVVVVVs]!67(g y@ 4>Q VF}^Xׇڼje26 L%YGh lC})< !EEPZWZV+@†R 5{@ouɐ4&H6ey V݀VťcqZޒrJyByFzFN$Hb*+jՏqэ ګkݿUXle1d0d^-B%} {Y%r*j5Ak5u",:~ҸY~ hSA~6 fulՇf{ȵQtATHZkƭ/_Sn u']b]|m`BāJ,O$du]Zs FL:aǙT4o~by?wpj滥A(x]†f~an֧/^dڲcՇ,!1i&xi_VK@ip̓9Vi%a; L?0J*Ū5U'x^6V[^ {eU|:0=0d۫o*Jq%[YN.sQLud[29I:WnmXlڃ6!lNlVէKUjV\J%UߊBLcKfb>a=b~R]aG%[js@/9MطݘU>yɲX@} Ftg^vO\Ӹwvpz3K5i!$P>ā'VƛL2r@UMKZ6tw맟¦bm1h||]}~0MjA(JJP68C&yr׉e}j_cJ?I0k>šW |Bޝ."TEXd 8!cw*E(J)![W"j_ТeX_XB;oO0~?:PC (.[!Wq%*leY)E<^KZT60.#A\5;Rmtkd/8)5~^0 #Ckgey)ͶԺ6ĥ<(?&uAVm0^h.txR*a':,H|ō l5z;8+e#b'#|}2w(|KcJ l6 w^Տoi3H R ̔9,YgPְ:N [5SR![)]i}`mN4Хv`|;f(FltL8÷Z#AO%Y)NU5YedJE3dZذݣHT1 ;8MjnʏӤqp 1h^<<>yt{?|'j)}YUU{@V/J1F+7䀉[OWO[ yUY!?BD%DWj>-Ai6xz)U R7 d@g\so)a4zf[W+> P> |qLG8vȣlj2Zt+VA6gT *ʆUz(m)CD `He/.:zN9pgo &NC׃އ>Wհ_Hj)Xe6F7pm-`'c.AZ=^e8F;{Rtn(z!S7o Iew3]bܗ85|iϠRJkʱZRO+8U&:]ZieR(JMޗ7Z@5a^\GzsρU*rMezT^:ɬͦX=>$ bi>U&XQoybbGk8 Ҙn).Սo ^MmdZi$soo*{4eLbLٳ""mx:`:mk[geTެ)'0*TB{!I ''''[͓[͓[͓[͓[]Zj Q.e '/yvQ71(Z&X?(_Z){tڀmZWϏ)-C jqn,̋"IvUL!h꛿skAcrN佚фVE40yX~4zʸV㳰%,)fqtpu~  *^0:ܲ33JO(ZB?K^ v]unlWi0p6[착C_5X#[wX3b廫R{NKAe Se|wxso>P\儔ԕ6;nVmfI$V͓J-J%֌0UwYЎSnum藮xz˗VƫIvnW_qLZ"_Xz 8]Ap?C543zw({7e*Ȳ`۰!AQ:KUnz]1yVGaCm0PY ٚUx6TT&hV9V ӬzÑ 1[XzZ9erqJND/gX*9oN6D` {I%Mz9—TQ7f\"j_3~xB'ܷY]*KЌ%"5"qxq~ƕ=jS>jV&~]2xzF1X_yD<#NRB}K/iy !V^˿eJ}/FkA7 S+.(ecJ:zWZ몖wQ~ä́p6,e5,+,tv%O^OO}ן -O7>ekC6wa_C |9*WA)UJg8=:mjUvqysܒLglC6+[FSWg9wV31A ND<$5e(s[ ۨbaF.]KIENDB`flask-peewee-0.6.7/flask_peewee/static/css/0000755000175000001440000000000012624225533021411 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/static/css/chosen-sprite.png0000644000175000001440000000105712574421673024714 0ustar charlesusers00000000000000PNG  IHDR<(IDAThMKQEZD6eh"MQwm q" " Ȭ6E-E(}8d#jq.<`dϹ@\x.o6 Ȃ+ai=澴[B\?9l QHquC0Ba*;5szl&<.<\1=`OP}DIԐ?ae)6ߙD|D))3(,8^pdd=}1P*J$}G;sUԕiFȖ8G EJzJZpez4dsALֈ/ P YQ6("91Niё Ӝ 9Qz{\x8b{y;Zs+qLsuO@JqU jMi?AXJGEʠo w(QgIENDB`flask-peewee-0.6.7/flask_peewee/static/css/chosen.css0000644000175000001440000003332412574421673023416 0ustar charlesusers00000000000000/* @group Base */ .chzn-container { font-size: 13px; position: relative; display: inline-block; zoom: 1; *display: inline; } .chzn-container .chzn-drop { background: #fff; border: 1px solid #aaa; border-top: 0; position: absolute; top: 29px; left: 0; -webkit-box-shadow: 0 4px 5px rgba(0,0,0,.15); -moz-box-shadow : 0 4px 5px rgba(0,0,0,.15); -o-box-shadow : 0 4px 5px rgba(0,0,0,.15); box-shadow : 0 4px 5px rgba(0,0,0,.15); z-index: 1010; } /* @end */ /* @group Single Chosen */ .chzn-container-single .chzn-single { background-color: #ffffff; filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0 ); background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4)); background-image: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); background-image: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); background-image: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); background-image: -ms-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); background-image: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); -webkit-border-radius: 5px; -moz-border-radius : 5px; border-radius : 5px; -moz-background-clip : padding; -webkit-background-clip: padding-box; background-clip : padding-box; border: 1px solid #aaaaaa; -webkit-box-shadow: 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); -moz-box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); display: block; overflow: hidden; white-space: nowrap; position: relative; height: 23px; line-height: 24px; padding: 0 0 0 8px; color: #444444; text-decoration: none; } .chzn-container-single .chzn-default { color: #999; } .chzn-container-single .chzn-single span { margin-right: 26px; display: block; overflow: hidden; white-space: nowrap; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis; text-overflow: ellipsis; } .chzn-container-single .chzn-single abbr { display: block; position: absolute; right: 26px; top: 6px; width: 12px; height: 13px; font-size: 1px; background: url('chosen-sprite.png') right top no-repeat; } .chzn-container-single .chzn-single abbr:hover { background-position: right -11px; } .chzn-container-single.chzn-disabled .chzn-single abbr:hover { background-position: right top; } .chzn-container-single .chzn-single div { position: absolute; right: 0; top: 0; display: block; height: 100%; width: 18px; } .chzn-container-single .chzn-single div b { background: url('chosen-sprite.png') no-repeat 0 0; display: block; width: 100%; height: 100%; } .chzn-container-single .chzn-search { padding: 3px 4px; position: relative; margin: 0; white-space: nowrap; z-index: 1010; } .chzn-container-single .chzn-search input { background: #fff url('chosen-sprite.png') no-repeat 100% -22px; background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat 100% -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat 100% -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat 100% -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat 100% -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%); margin: 1px 0; padding: 4px 20px 4px 5px; outline: 0; border: 1px solid #aaa; font-family: sans-serif; font-size: 1em; } .chzn-container-single .chzn-drop { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius : 0 0 4px 4px; border-radius : 0 0 4px 4px; -moz-background-clip : padding; -webkit-background-clip: padding-box; background-clip : padding-box; } /* @end */ .chzn-container-single-nosearch .chzn-search input { position: absolute; left: -9000px; } /* @group Multi Chosen */ .chzn-container-multi .chzn-choices { background-color: #fff; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background-image: -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background-image: linear-gradient(top, #eeeeee 1%, #ffffff 15%); border: 1px solid #aaa; margin: 0; padding: 0; cursor: text; overflow: hidden; height: auto !important; height: 1%; position: relative; } .chzn-container-multi .chzn-choices li { float: left; list-style: none; } .chzn-container-multi .chzn-choices .search-field { white-space: nowrap; margin: 0; padding: 0; } .chzn-container-multi .chzn-choices .search-field input { color: #666; background: transparent !important; border: 0 !important; font-family: sans-serif; font-size: 100%; height: 15px; padding: 5px; margin: 1px 0; outline: 0; -webkit-box-shadow: none; -moz-box-shadow : none; -o-box-shadow : none; box-shadow : none; } .chzn-container-multi .chzn-choices .search-field .default { color: #999; } .chzn-container-multi .chzn-choices .search-choice { -webkit-border-radius: 3px; -moz-border-radius : 3px; border-radius : 3px; -moz-background-clip : padding; -webkit-background-clip: padding-box; background-clip : padding-box; background-color: #e4e4e4; filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 ); background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); background-image: -ms-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); -moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); color: #333; border: 1px solid #aaaaaa; line-height: 13px; padding: 3px 20px 3px 5px; margin: 3px 0 3px 5px; position: relative; cursor: default; } .chzn-container-multi .chzn-choices .search-choice-focus { background: #d4d4d4; } .chzn-container-multi .chzn-choices .search-choice .search-choice-close { display: block; position: absolute; right: 3px; top: 4px; width: 12px; height: 13px; font-size: 1px; background: url('chosen-sprite.png') right top no-repeat; } .chzn-container-multi .chzn-choices .search-choice .search-choice-close:hover { background-position: right -11px; } .chzn-container-multi .chzn-choices .search-choice-focus .search-choice-close { background-position: right -11px; } /* @end */ /* @group Results */ .chzn-container .chzn-results { margin: 0 4px 4px 0; max-height: 240px; padding: 0 0 0 4px; position: relative; overflow-x: hidden; overflow-y: auto; -webkit-overflow-scrolling: touch; } .chzn-container-multi .chzn-results { margin: -1px 0 0; padding: 0; } .chzn-container .chzn-results li { display: none; line-height: 15px; padding: 5px 6px; margin: 0; list-style: none; } .chzn-container .chzn-results .active-result { cursor: pointer; display: list-item; } .chzn-container .chzn-results .highlighted { background-color: #3875d7; filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3875d7', endColorstr='#2a62bc', GradientType=0 ); background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc)); background-image: -webkit-linear-gradient(top, #3875d7 20%, #2a62bc 90%); background-image: -moz-linear-gradient(top, #3875d7 20%, #2a62bc 90%); background-image: -o-linear-gradient(top, #3875d7 20%, #2a62bc 90%); background-image: -ms-linear-gradient(top, #3875d7 20%, #2a62bc 90%); background-image: linear-gradient(top, #3875d7 20%, #2a62bc 90%); color: #fff; } .chzn-container .chzn-results li em { background: #feffde; font-style: normal; } .chzn-container .chzn-results .highlighted em { background: transparent; } .chzn-container .chzn-results .no-results { background: #f4f4f4; display: list-item; } .chzn-container .chzn-results .group-result { cursor: default; color: #999; font-weight: bold; } .chzn-container .chzn-results .group-option { padding-left: 15px; } .chzn-container-multi .chzn-drop .result-selected { display: none; } .chzn-container .chzn-results-scroll { background: white; margin: 0 4px; position: absolute; text-align: center; width: 321px; /* This should by dynamic with js */ z-index: 1; } .chzn-container .chzn-results-scroll span { display: inline-block; height: 17px; text-indent: -5000px; width: 9px; } .chzn-container .chzn-results-scroll-down { bottom: 0; } .chzn-container .chzn-results-scroll-down span { background: url('chosen-sprite.png') no-repeat -4px -3px; } .chzn-container .chzn-results-scroll-up span { background: url('chosen-sprite.png') no-repeat -22px -3px; } /* @end */ /* @group Active */ .chzn-container-active .chzn-single { -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); -o-box-shadow : 0 0 5px rgba(0,0,0,.3); box-shadow : 0 0 5px rgba(0,0,0,.3); border: 1px solid #5897fb; } .chzn-container-active .chzn-single-with-drop { border: 1px solid #aaa; -webkit-box-shadow: 0 1px 0 #fff inset; -moz-box-shadow : 0 1px 0 #fff inset; -o-box-shadow : 0 1px 0 #fff inset; box-shadow : 0 1px 0 #fff inset; background-color: #eee; filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0 ); background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff)); background-image: -webkit-linear-gradient(top, #eeeeee 20%, #ffffff 80%); background-image: -moz-linear-gradient(top, #eeeeee 20%, #ffffff 80%); background-image: -o-linear-gradient(top, #eeeeee 20%, #ffffff 80%); background-image: -ms-linear-gradient(top, #eeeeee 20%, #ffffff 80%); background-image: linear-gradient(top, #eeeeee 20%, #ffffff 80%); -webkit-border-bottom-left-radius : 0; -webkit-border-bottom-right-radius: 0; -moz-border-radius-bottomleft : 0; -moz-border-radius-bottomright: 0; border-bottom-left-radius : 0; border-bottom-right-radius: 0; } .chzn-container-active .chzn-single-with-drop div { background: transparent; border-left: none; } .chzn-container-active .chzn-single-with-drop div b { background-position: -18px 1px; } .chzn-container-active .chzn-choices { -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); -o-box-shadow : 0 0 5px rgba(0,0,0,.3); box-shadow : 0 0 5px rgba(0,0,0,.3); border: 1px solid #5897fb; } .chzn-container-active .chzn-choices .search-field input { color: #111 !important; } /* @end */ /* @group Disabled Support */ .chzn-disabled { cursor: default; opacity:0.5 !important; } .chzn-disabled .chzn-single { cursor: default; } .chzn-disabled .chzn-choices .search-choice .search-choice-close { cursor: default; } /* @group Right to Left */ .chzn-rtl { text-align: right; } .chzn-rtl .chzn-single { padding: 0 8px 0 0; overflow: visible; } .chzn-rtl .chzn-single span { margin-left: 26px; margin-right: 0; direction: rtl; } .chzn-rtl .chzn-single div { left: 3px; right: auto; } .chzn-rtl .chzn-single abbr { left: 26px; right: auto; } .chzn-rtl .chzn-choices .search-field input { direction: rtl; } .chzn-rtl .chzn-choices li { float: right; } .chzn-rtl .chzn-choices .search-choice { padding: 3px 5px 3px 19px; margin: 3px 5px 3px 0; } .chzn-rtl .chzn-choices .search-choice .search-choice-close { left: 4px; right: auto; background-position: right top;} .chzn-rtl.chzn-container-single .chzn-results { margin: 0 0 4px 4px; padding: 0 4px 0 0; } .chzn-rtl .chzn-results .group-option { padding-left: 0; padding-right: 15px; } .chzn-rtl.chzn-container-active .chzn-single-with-drop div { border-right: none; } .chzn-rtl .chzn-search input { background: #fff url('chosen-sprite.png') no-repeat -38px -22px; background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); background: url('chosen-sprite.png') no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%); padding: 4px 5px 4px 20px; direction: rtl; } /* @end */ flask-peewee-0.6.7/flask_peewee/static/css/bootstrap-responsive.css0000644000175000001440000002445712574421673026356 0ustar charlesusers00000000000000/*! * Bootstrap Responsive v2.0.0 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */ .hidden { display: none; visibility: hidden; } @media (max-width: 480px) { .nav-collapse { -webkit-transform: translate3d(0, 0, 0); } .page-header h1 small { display: block; line-height: 18px; } input[class*="span"], select[class*="span"], textarea[class*="span"], .uneditable-input { display: block; width: 100%; height: 28px; /* Make inputs at least the height of their button counterpart */ /* Makes inputs behave like true block-level elements */ -webkit-box-sizing: border-box; /* Older Webkit */ -moz-box-sizing: border-box; /* Older FF */ -ms-box-sizing: border-box; /* IE8 */ box-sizing: border-box; /* CSS3 spec*/ } .input-prepend input[class*="span"], .input-append input[class*="span"] { width: auto; } input[type="checkbox"], input[type="radio"] { border: 1px solid #ccc; } .form-horizontal .control-group > label { float: none; width: auto; padding-top: 0; text-align: left; } .form-horizontal .controls { margin-left: 0; } .form-horizontal .control-list { padding-top: 0; } .form-horizontal .form-actions { padding-left: 10px; padding-right: 10px; } .modal { position: absolute; top: 10px; left: 10px; right: 10px; width: auto; margin: 0; } .modal.fade.in { top: auto; } .modal-header .close { padding: 10px; margin: -10px; } .carousel-caption { position: static; } } @media (max-width: 768px) { .container { width: auto; padding: 0 20px; } .row-fluid { width: 100%; } .row { margin-left: 0; } .row > [class*="span"], .row-fluid > [class*="span"] { float: none; display: block; width: auto; margin: 0; } } @media (min-width: 768px) and (max-width: 980px) { .row { margin-left: -20px; *zoom: 1; } .row:before, .row:after { display: table; content: ""; } .row:after { clear: both; } [class*="span"] { float: left; margin-left: 20px; } .span1 { width: 42px; } .span2 { width: 104px; } .span3 { width: 166px; } .span4 { width: 228px; } .span5 { width: 290px; } .span6 { width: 352px; } .span7 { width: 414px; } .span8 { width: 476px; } .span9 { width: 538px; } .span10 { width: 600px; } .span11 { width: 662px; } .span12, .container { width: 724px; } .offset1 { margin-left: 82px; } .offset2 { margin-left: 144px; } .offset3 { margin-left: 206px; } .offset4 { margin-left: 268px; } .offset5 { margin-left: 330px; } .offset6 { margin-left: 392px; } .offset7 { margin-left: 454px; } .offset8 { margin-left: 516px; } .offset9 { margin-left: 578px; } .offset10 { margin-left: 640px; } .offset11 { margin-left: 702px; } .row-fluid { width: 100%; *zoom: 1; } .row-fluid:before, .row-fluid:after { display: table; content: ""; } .row-fluid:after { clear: both; } .row-fluid > [class*="span"] { float: left; margin-left: 2.762430939%; } .row-fluid > [class*="span"]:first-child { margin-left: 0; } .row-fluid .span1 { width: 5.801104972%; } .row-fluid .span2 { width: 14.364640883%; } .row-fluid .span3 { width: 22.928176794%; } .row-fluid .span4 { width: 31.491712705%; } .row-fluid .span5 { width: 40.055248616%; } .row-fluid .span6 { width: 48.618784527%; } .row-fluid .span7 { width: 57.182320438000005%; } .row-fluid .span8 { width: 65.74585634900001%; } .row-fluid .span9 { width: 74.30939226%; } .row-fluid .span10 { width: 82.87292817100001%; } .row-fluid .span11 { width: 91.436464082%; } .row-fluid .span12 { width: 99.999999993%; } input.span1, textarea.span1, .uneditable-input.span1 { width: 32px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 94px; } input.span3, textarea.span3, .uneditable-input.span3 { width: 156px; } input.span4, textarea.span4, .uneditable-input.span4 { width: 218px; } input.span5, textarea.span5, .uneditable-input.span5 { width: 280px; } input.span6, textarea.span6, .uneditable-input.span6 { width: 342px; } input.span7, textarea.span7, .uneditable-input.span7 { width: 404px; } input.span8, textarea.span8, .uneditable-input.span8 { width: 466px; } input.span9, textarea.span9, .uneditable-input.span9 { width: 528px; } input.span10, textarea.span10, .uneditable-input.span10 { width: 590px; } input.span11, textarea.span11, .uneditable-input.span11 { width: 652px; } input.span12, textarea.span12, .uneditable-input.span12 { width: 714px; } } @media (max-width: 980px) { body { padding-top: 0; } .navbar-fixed-top { position: static; margin-bottom: 18px; } .navbar-fixed-top .navbar-inner { padding: 5px; } .navbar .container { width: auto; padding: 0; } .navbar .brand { padding-left: 10px; padding-right: 10px; margin: 0 0 0 -5px; } .navbar .nav-collapse { clear: left; } .navbar .nav { float: none; margin: 0 0 9px; } .navbar .nav > li { float: none; } .navbar .nav > li > a { margin-bottom: 2px; } .navbar .nav > .divider-vertical { display: none; } .navbar .nav > li > a, .navbar .dropdown-menu a { padding: 6px 15px; font-weight: bold; color: #999999; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .navbar .dropdown-menu li + li a { margin-bottom: 2px; } .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { background-color: #222222; } .navbar .dropdown-menu { position: static; top: auto; left: auto; float: none; display: block; max-width: none; margin: 0 15px; padding: 0; background-color: transparent; border: none; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { display: none; } .navbar .dropdown-menu .divider { display: none; } .navbar-form, .navbar-search { float: none; padding: 9px 15px; margin: 9px 0; border-top: 1px solid #222222; border-bottom: 1px solid #222222; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); } .navbar .nav.pull-right { float: none; margin-left: 0; } .navbar-static .navbar-inner { padding-left: 10px; padding-right: 10px; } .btn-navbar { display: block; } .nav-collapse { overflow: hidden; height: 0; } } @media (min-width: 980px) { .nav-collapse.collapse { height: auto !important; } } @media (min-width: 1200px) { .row { margin-left: -30px; *zoom: 1; } .row:before, .row:after { display: table; content: ""; } .row:after { clear: both; } [class*="span"] { float: left; margin-left: 30px; } .span1 { width: 70px; } .span2 { width: 170px; } .span3 { width: 270px; } .span4 { width: 370px; } .span5 { width: 470px; } .span6 { width: 570px; } .span7 { width: 670px; } .span8 { width: 770px; } .span9 { width: 870px; } .span10 { width: 970px; } .span11 { width: 1070px; } .span12, .container { width: 1170px; } .offset1 { margin-left: 130px; } .offset2 { margin-left: 230px; } .offset3 { margin-left: 330px; } .offset4 { margin-left: 430px; } .offset5 { margin-left: 530px; } .offset6 { margin-left: 630px; } .offset7 { margin-left: 730px; } .offset8 { margin-left: 830px; } .offset9 { margin-left: 930px; } .offset10 { margin-left: 1030px; } .offset11 { margin-left: 1130px; } .row-fluid { width: 100%; *zoom: 1; } .row-fluid:before, .row-fluid:after { display: table; content: ""; } .row-fluid:after { clear: both; } .row-fluid > [class*="span"] { float: left; margin-left: 2.564102564%; } .row-fluid > [class*="span"]:first-child { margin-left: 0; } .row-fluid .span1 { width: 5.982905983%; } .row-fluid .span2 { width: 14.529914530000001%; } .row-fluid .span3 { width: 23.076923077%; } .row-fluid .span4 { width: 31.623931624%; } .row-fluid .span5 { width: 40.170940171000005%; } .row-fluid .span6 { width: 48.717948718%; } .row-fluid .span7 { width: 57.264957265%; } .row-fluid .span8 { width: 65.81196581200001%; } .row-fluid .span9 { width: 74.358974359%; } .row-fluid .span10 { width: 82.905982906%; } .row-fluid .span11 { width: 91.45299145300001%; } .row-fluid .span12 { width: 100%; } input.span1, textarea.span1, .uneditable-input.span1 { width: 60px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 160px; } input.span3, textarea.span3, .uneditable-input.span3 { width: 260px; } input.span4, textarea.span4, .uneditable-input.span4 { width: 360px; } input.span5, textarea.span5, .uneditable-input.span5 { width: 460px; } input.span6, textarea.span6, .uneditable-input.span6 { width: 560px; } input.span7, textarea.span7, .uneditable-input.span7 { width: 660px; } input.span8, textarea.span8, .uneditable-input.span8 { width: 760px; } input.span9, textarea.span9, .uneditable-input.span9 { width: 860px; } input.span10, textarea.span10, .uneditable-input.span10 { width: 960px; } input.span11, textarea.span11, .uneditable-input.span11 { width: 1060px; } input.span12, textarea.span12, .uneditable-input.span12 { width: 1160px; } .thumbnails { margin-left: -30px; } .thumbnails > li { margin-left: 30px; } } flask-peewee-0.6.7/flask_peewee/static/css/datepicker.css0000644000175000001440000001027312574421673024250 0ustar charlesusers00000000000000/*! * Datepicker for Bootstrap * * Copyright 2012 Stefan Petre * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * */ .datepicker { top: 0; left: 0; padding: 4px; margin-top: 1px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; /*.dow { border-top: 1px solid #ddd !important; }*/ } .datepicker:before { content: ''; display: inline-block; border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid #ccc; border-bottom-color: rgba(0, 0, 0, 0.2); position: absolute; top: -7px; left: 6px; } .datepicker:after { content: ''; display: inline-block; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #ffffff; position: absolute; top: -6px; left: 7px; } .datepicker > div { display: none; } .datepicker table { width: 100%; margin: 0; } .datepicker td, .datepicker th { text-align: center; width: 20px; height: 20px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td.day:hover { background: #eeeeee; cursor: pointer; } .datepicker td.old, .datepicker td.new { color: #999999; } .datepicker td.active, .datepicker td.active:hover { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td.active:hover, .datepicker td.active:hover:hover, .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active, .datepicker td.active.disabled, .datepicker td.active:hover.disabled, .datepicker td.active[disabled], .datepicker td.active:hover[disabled] { background-color: #0044cc; } .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active { background-color: #003399 \9; } .datepicker td span { display: block; width: 47px; height: 54px; line-height: 54px; float: left; margin: 2px; cursor: pointer; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td span:hover { background: #eeeeee; } .datepicker td span.active { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td span.active:hover, .datepicker td span.active:active, .datepicker td span.active.active, .datepicker td span.active.disabled, .datepicker td span.active[disabled] { background-color: #0044cc; } .datepicker td span.active:active, .datepicker td span.active.active { background-color: #003399 \9; } .datepicker td span.old { color: #999999; } .datepicker th.switch { width: 145px; } .datepicker thead tr:first-child th { cursor: pointer; } .datepicker thead tr:first-child th:hover { background: #eeeeee; } .input-append.date .add-on i, .input-prepend.date .add-on i { display: block; cursor: pointer; width: 16px; height: 16px; }flask-peewee-0.6.7/flask_peewee/static/css/bootstrap.css0000644000175000001440000026472712574421673024171 0ustar charlesusers00000000000000/*! * Bootstrap v2.0.2 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */ article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } audio:not([controls]) { display: none; } html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } a:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } a:hover, a:active { outline: 0; } sub, sup { position: relative; font-size: 75%; line-height: 0; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } img { height: auto; border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } button, input, select, textarea { margin: 0; font-size: 100%; vertical-align: middle; } button, input { *overflow: visible; line-height: normal; } button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; } button, input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } input[type="search"] { -webkit-appearance: textfield; -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; } input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; } textarea { overflow: auto; vertical-align: top; } .clearfix { *zoom: 1; } .clearfix:before, .clearfix:after { display: table; content: ""; } .clearfix:after { clear: both; } .hide-text { overflow: hidden; text-indent: 100%; white-space: nowrap; } .input-block-level { display: block; width: 100%; min-height: 28px; /* Make inputs at least the height of their button counterpart */ /* Makes inputs behave like true block-level elements */ -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; } body { margin: 0; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; line-height: 18px; color: #333333; background-color: #ffffff; } a { color: #0088cc; text-decoration: none; } a:hover { color: #005580; text-decoration: underline; } .row { margin-left: -20px; *zoom: 1; } .row:before, .row:after { display: table; content: ""; } .row:after { clear: both; } [class*="span"] { float: left; margin-left: 20px; } .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } .span12 { width: 940px; } .span11 { width: 860px; } .span10 { width: 780px; } .span9 { width: 700px; } .span8 { width: 620px; } .span7 { width: 540px; } .span6 { width: 460px; } .span5 { width: 380px; } .span4 { width: 300px; } .span3 { width: 220px; } .span2 { width: 140px; } .span1 { width: 60px; } .offset12 { margin-left: 980px; } .offset11 { margin-left: 900px; } .offset10 { margin-left: 820px; } .offset9 { margin-left: 740px; } .offset8 { margin-left: 660px; } .offset7 { margin-left: 580px; } .offset6 { margin-left: 500px; } .offset5 { margin-left: 420px; } .offset4 { margin-left: 340px; } .offset3 { margin-left: 260px; } .offset2 { margin-left: 180px; } .offset1 { margin-left: 100px; } .row-fluid { width: 100%; *zoom: 1; } .row-fluid:before, .row-fluid:after { display: table; content: ""; } .row-fluid:after { clear: both; } .row-fluid > [class*="span"] { float: left; margin-left: 2.127659574%; } .row-fluid > [class*="span"]:first-child { margin-left: 0; } .row-fluid > .span12 { width: 99.99999998999999%; } .row-fluid > .span11 { width: 91.489361693%; } .row-fluid > .span10 { width: 82.97872339599999%; } .row-fluid > .span9 { width: 74.468085099%; } .row-fluid > .span8 { width: 65.95744680199999%; } .row-fluid > .span7 { width: 57.446808505%; } .row-fluid > .span6 { width: 48.93617020799999%; } .row-fluid > .span5 { width: 40.425531911%; } .row-fluid > .span4 { width: 31.914893614%; } .row-fluid > .span3 { width: 23.404255317%; } .row-fluid > .span2 { width: 14.89361702%; } .row-fluid > .span1 { width: 6.382978723%; } .container { margin-left: auto; margin-right: auto; *zoom: 1; } .container:before, .container:after { display: table; content: ""; } .container:after { clear: both; } .container-fluid { padding-left: 20px; padding-right: 20px; *zoom: 1; } .container-fluid:before, .container-fluid:after { display: table; content: ""; } .container-fluid:after { clear: both; } p { margin: 0 0 9px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; line-height: 18px; } p small { font-size: 11px; color: #999999; } .lead { margin-bottom: 18px; font-size: 20px; font-weight: 200; line-height: 27px; } h1, h2, h3, h4, h5, h6 { margin: 0; font-family: inherit; font-weight: bold; color: inherit; text-rendering: optimizelegibility; } h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-weight: normal; color: #999999; } h1 { font-size: 30px; line-height: 36px; } h1 small { font-size: 18px; } h2 { font-size: 24px; line-height: 36px; } h2 small { font-size: 18px; } h3 { line-height: 27px; font-size: 18px; } h3 small { font-size: 14px; } h4, h5, h6 { line-height: 18px; } h4 { font-size: 14px; } h4 small { font-size: 12px; } h5 { font-size: 12px; } h6 { font-size: 11px; color: #999999; text-transform: uppercase; } .page-header { padding-bottom: 17px; margin: 18px 0; border-bottom: 1px solid #eeeeee; } .page-header h1 { line-height: 1; } ul, ol { padding: 0; margin: 0 0 9px 25px; } ul ul, ul ol, ol ol, ol ul { margin-bottom: 0; } ul { list-style: disc; } ol { list-style: decimal; } li { line-height: 18px; } ul.unstyled, ol.unstyled { margin-left: 0; list-style: none; } dl { margin-bottom: 18px; } dt, dd { line-height: 18px; } dt { font-weight: bold; line-height: 17px; } dd { margin-left: 9px; } .dl-horizontal dt { float: left; clear: left; width: 120px; text-align: right; } .dl-horizontal dd { margin-left: 130px; } hr { margin: 18px 0; border: 0; border-top: 1px solid #eeeeee; border-bottom: 1px solid #ffffff; } strong { font-weight: bold; } em { font-style: italic; } .muted { color: #999999; } abbr[title] { border-bottom: 1px dotted #ddd; cursor: help; } abbr.initialism { font-size: 90%; text-transform: uppercase; } blockquote { padding: 0 0 0 15px; margin: 0 0 18px; border-left: 5px solid #eeeeee; } blockquote p { margin-bottom: 0; font-size: 16px; font-weight: 300; line-height: 22.5px; } blockquote small { display: block; line-height: 18px; color: #999999; } blockquote small:before { content: '\2014 \00A0'; } blockquote.pull-right { float: right; padding-left: 0; padding-right: 15px; border-left: 0; border-right: 5px solid #eeeeee; } blockquote.pull-right p, blockquote.pull-right small { text-align: right; } q:before, q:after, blockquote:before, blockquote:after { content: ""; } address { display: block; margin-bottom: 18px; line-height: 18px; font-style: normal; } small { font-size: 100%; } cite { font-style: normal; } code, pre { padding: 0 3px 2px; font-family: Menlo, Monaco, "Courier New", monospace; font-size: 12px; color: #333333; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } code { padding: 2px 4px; color: #d14; background-color: #f7f7f9; border: 1px solid #e1e1e8; } pre { display: block; padding: 8.5px; margin: 0 0 9px; font-size: 12.025px; line-height: 18px; background-color: #f5f5f5; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.15); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; white-space: pre; white-space: pre-wrap; word-break: break-all; word-wrap: break-word; } pre.prettyprint { margin-bottom: 18px; } pre code { padding: 0; color: inherit; background-color: transparent; border: 0; } .pre-scrollable { max-height: 340px; overflow-y: scroll; } form { margin: 0 0 18px; } fieldset { padding: 0; margin: 0; border: 0; } legend { display: block; width: 100%; padding: 0; margin-bottom: 27px; font-size: 19.5px; line-height: 36px; color: #333333; border: 0; border-bottom: 1px solid #eee; } legend small { font-size: 13.5px; color: #999999; } label, input, button, select, textarea { font-size: 13px; font-weight: normal; line-height: 18px; } input, button, select, textarea { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } label { display: block; margin-bottom: 5px; color: #333333; } input, textarea, select, .uneditable-input { display: inline-block; width: 210px; height: 18px; padding: 4px; margin-bottom: 9px; font-size: 13px; line-height: 18px; color: #555555; border: 1px solid #cccccc; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .uneditable-textarea { width: auto; height: auto; } label input, label textarea, label select { display: block; } input[type="image"], input[type="checkbox"], input[type="radio"] { width: auto; height: auto; padding: 0; margin: 3px 0; *margin-top: 0; /* IE7 */ line-height: normal; cursor: pointer; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; border: 0 \9; /* IE9 and down */ } input[type="image"] { border: 0; } input[type="file"] { width: auto; padding: initial; line-height: initial; border: initial; background-color: #ffffff; background-color: initial; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } input[type="button"], input[type="reset"], input[type="submit"] { width: auto; height: auto; } select, input[type="file"] { height: 28px; /* In IE7, the height of the select element cannot be changed by height, only font-size */ *margin-top: 4px; /* For IE7, add top margin to align select with labels */ line-height: 28px; } input[type="file"] { line-height: 18px \9; } select { width: 220px; background-color: #ffffff; } select[multiple], select[size] { height: auto; } input[type="image"] { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } textarea { height: auto; } input[type="hidden"] { display: none; } .radio, .checkbox { padding-left: 18px; } .radio input[type="radio"], .checkbox input[type="checkbox"] { float: left; margin-left: -18px; } .controls > .radio:first-child, .controls > .checkbox:first-child { padding-top: 5px; } .radio.inline, .checkbox.inline { display: inline-block; padding-top: 5px; margin-bottom: 0; vertical-align: middle; } .radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { margin-left: 10px; } input, textarea { -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -ms-transition: border linear 0.2s, box-shadow linear 0.2s; -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; } input:focus, textarea:focus { border-color: rgba(82, 168, 236, 0.8); -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); outline: 0; outline: thin dotted \9; /* IE6-9 */ } input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus, select:focus { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .input-mini { width: 60px; } .input-small { width: 90px; } .input-medium { width: 150px; } .input-large { width: 210px; } .input-xlarge { width: 270px; } .input-xxlarge { width: 530px; } input[class*="span"], select[class*="span"], textarea[class*="span"], .uneditable-input { float: none; margin-left: 0; } input, textarea, .uneditable-input { margin-left: 0; } input.span12, textarea.span12, .uneditable-input.span12 { width: 930px; } input.span11, textarea.span11, .uneditable-input.span11 { width: 850px; } input.span10, textarea.span10, .uneditable-input.span10 { width: 770px; } input.span9, textarea.span9, .uneditable-input.span9 { width: 690px; } input.span8, textarea.span8, .uneditable-input.span8 { width: 610px; } input.span7, textarea.span7, .uneditable-input.span7 { width: 530px; } input.span6, textarea.span6, .uneditable-input.span6 { width: 450px; } input.span5, textarea.span5, .uneditable-input.span5 { width: 370px; } input.span4, textarea.span4, .uneditable-input.span4 { width: 290px; } input.span3, textarea.span3, .uneditable-input.span3 { width: 210px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 130px; } input.span1, textarea.span1, .uneditable-input.span1 { width: 50px; } input[disabled], select[disabled], textarea[disabled], input[readonly], select[readonly], textarea[readonly] { background-color: #eeeeee; border-color: #ddd; cursor: not-allowed; } .control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { color: #c09853; } .control-group.warning input, .control-group.warning select, .control-group.warning textarea { color: #c09853; border-color: #c09853; } .control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { border-color: #a47e3c; -webkit-box-shadow: 0 0 6px #dbc59e; -moz-box-shadow: 0 0 6px #dbc59e; box-shadow: 0 0 6px #dbc59e; } .control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { color: #c09853; background-color: #fcf8e3; border-color: #c09853; } .control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { color: #b94a48; } .control-group.error input, .control-group.error select, .control-group.error textarea { color: #b94a48; border-color: #b94a48; } .control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { border-color: #953b39; -webkit-box-shadow: 0 0 6px #d59392; -moz-box-shadow: 0 0 6px #d59392; box-shadow: 0 0 6px #d59392; } .control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { color: #b94a48; background-color: #f2dede; border-color: #b94a48; } .control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { color: #468847; } .control-group.success input, .control-group.success select, .control-group.success textarea { color: #468847; border-color: #468847; } .control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { border-color: #356635; -webkit-box-shadow: 0 0 6px #7aba7b; -moz-box-shadow: 0 0 6px #7aba7b; box-shadow: 0 0 6px #7aba7b; } .control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { color: #468847; background-color: #dff0d8; border-color: #468847; } input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { color: #b94a48; border-color: #ee5f5b; } input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { border-color: #e9322d; -webkit-box-shadow: 0 0 6px #f8b9b7; -moz-box-shadow: 0 0 6px #f8b9b7; box-shadow: 0 0 6px #f8b9b7; } .form-actions { padding: 17px 20px 18px; margin-top: 18px; margin-bottom: 18px; background-color: #eeeeee; border-top: 1px solid #ddd; *zoom: 1; } .form-actions:before, .form-actions:after { display: table; content: ""; } .form-actions:after { clear: both; } .uneditable-input { display: block; background-color: #ffffff; border-color: #eee; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); cursor: not-allowed; } :-moz-placeholder { color: #999999; } ::-webkit-input-placeholder { color: #999999; } .help-block, .help-inline { color: #555555; } .help-block { display: block; margin-bottom: 9px; } .help-inline { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; vertical-align: middle; padding-left: 5px; } .input-prepend, .input-append { margin-bottom: 5px; } .input-prepend input, .input-append input, .input-prepend select, .input-append select, .input-prepend .uneditable-input, .input-append .uneditable-input { *margin-left: 0; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .input-prepend input:focus, .input-append input:focus, .input-prepend select:focus, .input-append select:focus, .input-prepend .uneditable-input:focus, .input-append .uneditable-input:focus { position: relative; z-index: 2; } .input-prepend .uneditable-input, .input-append .uneditable-input { border-left-color: #ccc; } .input-prepend .add-on, .input-append .add-on { display: inline-block; width: auto; min-width: 16px; height: 18px; padding: 4px 5px; font-weight: normal; line-height: 18px; text-align: center; text-shadow: 0 1px 0 #ffffff; vertical-align: middle; background-color: #eeeeee; border: 1px solid #ccc; } .input-prepend .add-on, .input-append .add-on, .input-prepend .btn, .input-append .btn { -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-prepend .active, .input-append .active { background-color: #a9dba9; border-color: #46a546; } .input-prepend .add-on, .input-prepend .btn { margin-right: -1px; } .input-append input, .input-append select .uneditable-input { -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-append .uneditable-input { border-left-color: #eee; border-right-color: #ccc; } .input-append .add-on, .input-append .btn { margin-left: -1px; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .input-prepend.input-append input, .input-prepend.input-append select, .input-prepend.input-append .uneditable-input { -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .input-prepend.input-append .add-on:first-child, .input-prepend.input-append .btn:first-child { margin-right: -1px; -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-prepend.input-append .add-on:last-child, .input-prepend.input-append .btn:last-child { margin-left: -1px; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .search-query { padding-left: 14px; padding-right: 14px; margin-bottom: 0; -webkit-border-radius: 14px; -moz-border-radius: 14px; border-radius: 14px; } .form-search input, .form-inline input, .form-horizontal input, .form-search textarea, .form-inline textarea, .form-horizontal textarea, .form-search select, .form-inline select, .form-horizontal select, .form-search .help-inline, .form-inline .help-inline, .form-horizontal .help-inline, .form-search .uneditable-input, .form-inline .uneditable-input, .form-horizontal .uneditable-input, .form-search .input-prepend, .form-inline .input-prepend, .form-horizontal .input-prepend, .form-search .input-append, .form-inline .input-append, .form-horizontal .input-append { display: inline-block; margin-bottom: 0; } .form-search .hide, .form-inline .hide, .form-horizontal .hide { display: none; } .form-search label, .form-inline label { display: inline-block; } .form-search .input-append, .form-inline .input-append, .form-search .input-prepend, .form-inline .input-prepend { margin-bottom: 0; } .form-search .radio, .form-search .checkbox, .form-inline .radio, .form-inline .checkbox { padding-left: 0; margin-bottom: 0; vertical-align: middle; } .form-search .radio input[type="radio"], .form-search .checkbox input[type="checkbox"], .form-inline .radio input[type="radio"], .form-inline .checkbox input[type="checkbox"] { float: left; margin-left: 0; margin-right: 3px; } .control-group { margin-bottom: 9px; } legend + .control-group { margin-top: 18px; -webkit-margin-top-collapse: separate; } .form-horizontal .control-group { margin-bottom: 18px; *zoom: 1; } .form-horizontal .control-group:before, .form-horizontal .control-group:after { display: table; content: ""; } .form-horizontal .control-group:after { clear: both; } .form-horizontal .control-label { float: left; width: 140px; padding-top: 5px; text-align: right; } .form-horizontal .controls { margin-left: 160px; /* Super jank IE7 fix to ensure the inputs in .input-append and input-prepend don't inherit the margin of the parent, in this case .controls */ *display: inline-block; *margin-left: 0; *padding-left: 20px; } .form-horizontal .help-block { margin-top: 9px; margin-bottom: 0; } .form-horizontal .form-actions { padding-left: 160px; } table { max-width: 100%; border-collapse: collapse; border-spacing: 0; background-color: transparent; } .table { width: 100%; margin-bottom: 18px; } .table th, .table td { padding: 8px; line-height: 18px; text-align: left; vertical-align: top; border-top: 1px solid #dddddd; } .table th { font-weight: bold; } .table thead th { vertical-align: bottom; } .table colgroup + thead tr:first-child th, .table colgroup + thead tr:first-child td, .table thead:first-child tr:first-child th, .table thead:first-child tr:first-child td { border-top: 0; } .table tbody + tbody { border-top: 2px solid #dddddd; } .table-condensed th, .table-condensed td { padding: 4px 5px; } .table-bordered { border: 1px solid #dddddd; border-left: 0; border-collapse: separate; *border-collapse: collapsed; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .table-bordered th, .table-bordered td { border-left: 1px solid #dddddd; } .table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { border-top: 0; } .table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { -webkit-border-radius: 4px 0 0 0; -moz-border-radius: 4px 0 0 0; border-radius: 4px 0 0 0; } .table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { -webkit-border-radius: 0 4px 0 0; -moz-border-radius: 0 4px 0 0; border-radius: 0 4px 0 0; } .table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { -webkit-border-radius: 0 0 0 4px; -moz-border-radius: 0 0 0 4px; border-radius: 0 0 0 4px; } .table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { -webkit-border-radius: 0 0 4px 0; -moz-border-radius: 0 0 4px 0; border-radius: 0 0 4px 0; } .table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { background-color: #f9f9f9; } .table tbody tr:hover td, .table tbody tr:hover th { background-color: #f5f5f5; } table .span1 { float: none; width: 44px; margin-left: 0; } table .span2 { float: none; width: 124px; margin-left: 0; } table .span3 { float: none; width: 204px; margin-left: 0; } table .span4 { float: none; width: 284px; margin-left: 0; } table .span5 { float: none; width: 364px; margin-left: 0; } table .span6 { float: none; width: 444px; margin-left: 0; } table .span7 { float: none; width: 524px; margin-left: 0; } table .span8 { float: none; width: 604px; margin-left: 0; } table .span9 { float: none; width: 684px; margin-left: 0; } table .span10 { float: none; width: 764px; margin-left: 0; } table .span11 { float: none; width: 844px; margin-left: 0; } table .span12 { float: none; width: 924px; margin-left: 0; } table .span13 { float: none; width: 1004px; margin-left: 0; } table .span14 { float: none; width: 1084px; margin-left: 0; } table .span15 { float: none; width: 1164px; margin-left: 0; } table .span16 { float: none; width: 1244px; margin-left: 0; } table .span17 { float: none; width: 1324px; margin-left: 0; } table .span18 { float: none; width: 1404px; margin-left: 0; } table .span19 { float: none; width: 1484px; margin-left: 0; } table .span20 { float: none; width: 1564px; margin-left: 0; } table .span21 { float: none; width: 1644px; margin-left: 0; } table .span22 { float: none; width: 1724px; margin-left: 0; } table .span23 { float: none; width: 1804px; margin-left: 0; } table .span24 { float: none; width: 1884px; margin-left: 0; } [class^="icon-"], [class*=" icon-"] { display: inline-block; width: 14px; height: 14px; line-height: 14px; vertical-align: text-top; background-image: url("../img/glyphicons-halflings.png"); background-position: 14px 14px; background-repeat: no-repeat; *margin-right: .3em; } [class^="icon-"]:last-child, [class*=" icon-"]:last-child { *margin-left: 0; } .icon-white { background-image: url("../img/glyphicons-halflings-white.png"); } .icon-glass { background-position: 0 0; } .icon-music { background-position: -24px 0; } .icon-search { background-position: -48px 0; } .icon-envelope { background-position: -72px 0; } .icon-heart { background-position: -96px 0; } .icon-star { background-position: -120px 0; } .icon-star-empty { background-position: -144px 0; } .icon-user { background-position: -168px 0; } .icon-film { background-position: -192px 0; } .icon-th-large { background-position: -216px 0; } .icon-th { background-position: -240px 0; } .icon-th-list { background-position: -264px 0; } .icon-ok { background-position: -288px 0; } .icon-remove { background-position: -312px 0; } .icon-zoom-in { background-position: -336px 0; } .icon-zoom-out { background-position: -360px 0; } .icon-off { background-position: -384px 0; } .icon-signal { background-position: -408px 0; } .icon-cog { background-position: -432px 0; } .icon-trash { background-position: -456px 0; } .icon-home { background-position: 0 -24px; } .icon-file { background-position: -24px -24px; } .icon-time { background-position: -48px -24px; } .icon-road { background-position: -72px -24px; } .icon-download-alt { background-position: -96px -24px; } .icon-download { background-position: -120px -24px; } .icon-upload { background-position: -144px -24px; } .icon-inbox { background-position: -168px -24px; } .icon-play-circle { background-position: -192px -24px; } .icon-repeat { background-position: -216px -24px; } .icon-refresh { background-position: -240px -24px; } .icon-list-alt { background-position: -264px -24px; } .icon-lock { background-position: -287px -24px; } .icon-flag { background-position: -312px -24px; } .icon-headphones { background-position: -336px -24px; } .icon-volume-off { background-position: -360px -24px; } .icon-volume-down { background-position: -384px -24px; } .icon-volume-up { background-position: -408px -24px; } .icon-qrcode { background-position: -432px -24px; } .icon-barcode { background-position: -456px -24px; } .icon-tag { background-position: 0 -48px; } .icon-tags { background-position: -25px -48px; } .icon-book { background-position: -48px -48px; } .icon-bookmark { background-position: -72px -48px; } .icon-print { background-position: -96px -48px; } .icon-camera { background-position: -120px -48px; } .icon-font { background-position: -144px -48px; } .icon-bold { background-position: -167px -48px; } .icon-italic { background-position: -192px -48px; } .icon-text-height { background-position: -216px -48px; } .icon-text-width { background-position: -240px -48px; } .icon-align-left { background-position: -264px -48px; } .icon-align-center { background-position: -288px -48px; } .icon-align-right { background-position: -312px -48px; } .icon-align-justify { background-position: -336px -48px; } .icon-list { background-position: -360px -48px; } .icon-indent-left { background-position: -384px -48px; } .icon-indent-right { background-position: -408px -48px; } .icon-facetime-video { background-position: -432px -48px; } .icon-picture { background-position: -456px -48px; } .icon-pencil { background-position: 0 -72px; } .icon-map-marker { background-position: -24px -72px; } .icon-adjust { background-position: -48px -72px; } .icon-tint { background-position: -72px -72px; } .icon-edit { background-position: -96px -72px; } .icon-share { background-position: -120px -72px; } .icon-check { background-position: -144px -72px; } .icon-move { background-position: -168px -72px; } .icon-step-backward { background-position: -192px -72px; } .icon-fast-backward { background-position: -216px -72px; } .icon-backward { background-position: -240px -72px; } .icon-play { background-position: -264px -72px; } .icon-pause { background-position: -288px -72px; } .icon-stop { background-position: -312px -72px; } .icon-forward { background-position: -336px -72px; } .icon-fast-forward { background-position: -360px -72px; } .icon-step-forward { background-position: -384px -72px; } .icon-eject { background-position: -408px -72px; } .icon-chevron-left { background-position: -432px -72px; } .icon-chevron-right { background-position: -456px -72px; } .icon-plus-sign { background-position: 0 -96px; } .icon-minus-sign { background-position: -24px -96px; } .icon-remove-sign { background-position: -48px -96px; } .icon-ok-sign { background-position: -72px -96px; } .icon-question-sign { background-position: -96px -96px; } .icon-info-sign { background-position: -120px -96px; } .icon-screenshot { background-position: -144px -96px; } .icon-remove-circle { background-position: -168px -96px; } .icon-ok-circle { background-position: -192px -96px; } .icon-ban-circle { background-position: -216px -96px; } .icon-arrow-left { background-position: -240px -96px; } .icon-arrow-right { background-position: -264px -96px; } .icon-arrow-up { background-position: -289px -96px; } .icon-arrow-down { background-position: -312px -96px; } .icon-share-alt { background-position: -336px -96px; } .icon-resize-full { background-position: -360px -96px; } .icon-resize-small { background-position: -384px -96px; } .icon-plus { background-position: -408px -96px; } .icon-minus { background-position: -433px -96px; } .icon-asterisk { background-position: -456px -96px; } .icon-exclamation-sign { background-position: 0 -120px; } .icon-gift { background-position: -24px -120px; } .icon-leaf { background-position: -48px -120px; } .icon-fire { background-position: -72px -120px; } .icon-eye-open { background-position: -96px -120px; } .icon-eye-close { background-position: -120px -120px; } .icon-warning-sign { background-position: -144px -120px; } .icon-plane { background-position: -168px -120px; } .icon-calendar { background-position: -192px -120px; } .icon-random { background-position: -216px -120px; } .icon-comment { background-position: -240px -120px; } .icon-magnet { background-position: -264px -120px; } .icon-chevron-up { background-position: -288px -120px; } .icon-chevron-down { background-position: -313px -119px; } .icon-retweet { background-position: -336px -120px; } .icon-shopping-cart { background-position: -360px -120px; } .icon-folder-close { background-position: -384px -120px; } .icon-folder-open { background-position: -408px -120px; } .icon-resize-vertical { background-position: -432px -119px; } .icon-resize-horizontal { background-position: -456px -118px; } .dropdown { position: relative; } .dropdown-toggle { *margin-bottom: -3px; } .dropdown-toggle:active, .open .dropdown-toggle { outline: 0; } .caret { display: inline-block; width: 0; height: 0; vertical-align: top; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4px solid #000000; opacity: 0.3; filter: alpha(opacity=30); content: ""; } .dropdown .caret { margin-top: 8px; margin-left: 2px; } .dropdown:hover .caret, .open.dropdown .caret { opacity: 1; filter: alpha(opacity=100); } .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: 1000; float: left; display: none; min-width: 160px; padding: 4px 0; margin: 0; list-style: none; background-color: #ffffff; border-color: #ccc; border-color: rgba(0, 0, 0, 0.2); border-style: solid; border-width: 1px; -webkit-border-radius: 0 0 5px 5px; -moz-border-radius: 0 0 5px 5px; border-radius: 0 0 5px 5px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; *border-right-width: 2px; *border-bottom-width: 2px; } .dropdown-menu.pull-right { right: 0; left: auto; } .dropdown-menu .divider { height: 1px; margin: 8px 1px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; *width: 100%; *margin: -5px 0 5px; } .dropdown-menu a { display: block; padding: 3px 15px; clear: both; font-weight: normal; line-height: 18px; color: #333333; white-space: nowrap; } .dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { color: #ffffff; text-decoration: none; background-color: #0088cc; } .dropdown.open { *z-index: 1000; } .dropdown.open .dropdown-toggle { color: #ffffff; background: #ccc; background: rgba(0, 0, 0, 0.3); } .dropdown.open .dropdown-menu { display: block; } .pull-right .dropdown-menu { left: auto; right: 0; } .dropup .caret, .navbar-fixed-bottom .dropdown .caret { border-top: 0; border-bottom: 4px solid #000000; content: "\2191"; } .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { top: auto; bottom: 100%; margin-bottom: 1px; } .typeahead { margin-top: 2px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .well { min-height: 20px; padding: 19px; margin-bottom: 20px; background-color: #f5f5f5; border: 1px solid #eee; border: 1px solid rgba(0, 0, 0, 0.05); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); } .well blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } .well-large { padding: 24px; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .well-small { padding: 9px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .fade { -webkit-transition: opacity 0.15s linear; -moz-transition: opacity 0.15s linear; -ms-transition: opacity 0.15s linear; -o-transition: opacity 0.15s linear; transition: opacity 0.15s linear; opacity: 0; } .fade.in { opacity: 1; } .collapse { -webkit-transition: height 0.35s ease; -moz-transition: height 0.35s ease; -ms-transition: height 0.35s ease; -o-transition: height 0.35s ease; transition: height 0.35s ease; position: relative; overflow: hidden; height: 0; } .collapse.in { height: auto; } .close { float: right; font-size: 20px; font-weight: bold; line-height: 18px; color: #000000; text-shadow: 0 1px 0 #ffffff; opacity: 0.2; filter: alpha(opacity=20); } .close:hover { color: #000000; text-decoration: none; opacity: 0.4; filter: alpha(opacity=40); cursor: pointer; } .btn { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; padding: 4px 10px 4px; margin-bottom: 0; font-size: 13px; line-height: 18px; color: #333333; text-align: center; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; background-color: #f5f5f5; background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); border-color: #e6e6e6 #e6e6e6 #bfbfbf; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); border: 1px solid #cccccc; border-bottom-color: #b3b3b3; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); cursor: pointer; *margin-left: .3em; } .btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] { background-color: #e6e6e6; } .btn:active, .btn.active { background-color: #cccccc \9; } .btn:first-child { *margin-left: 0; } .btn:hover { color: #333333; text-decoration: none; background-color: #e6e6e6; background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; -ms-transition: background-position 0.1s linear; -o-transition: background-position 0.1s linear; transition: background-position 0.1s linear; } .btn:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .btn.active, .btn:active { background-image: none; -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); background-color: #e6e6e6; background-color: #d9d9d9 \9; outline: 0; } .btn.disabled, .btn[disabled] { cursor: default; background-image: none; background-color: #e6e6e6; opacity: 0.65; filter: alpha(opacity=65); -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } .btn-large { padding: 9px 14px; font-size: 15px; line-height: normal; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .btn-large [class^="icon-"] { margin-top: 1px; } .btn-small { padding: 5px 9px; font-size: 11px; line-height: 16px; } .btn-small [class^="icon-"] { margin-top: -1px; } .btn-mini { padding: 2px 6px; font-size: 11px; line-height: 14px; } .btn-primary, .btn-primary:hover, .btn-warning, .btn-warning:hover, .btn-danger, .btn-danger:hover, .btn-success, .btn-success:hover, .btn-info, .btn-info:hover, .btn-inverse, .btn-inverse:hover { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); color: #ffffff; } .btn-primary.active, .btn-warning.active, .btn-danger.active, .btn-success.active, .btn-info.active, .btn-inverse.active { color: rgba(255, 255, 255, 0.75); } .btn-primary { background-color: #0074cc; background-image: -moz-linear-gradient(top, #0088cc, #0055cc); background-image: -ms-linear-gradient(top, #0088cc, #0055cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0055cc); background-image: -o-linear-gradient(top, #0088cc, #0055cc); background-image: linear-gradient(top, #0088cc, #0055cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0); border-color: #0055cc #0055cc #003580; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] { background-color: #0055cc; } .btn-primary:active, .btn-primary.active { background-color: #004099 \9; } .btn-warning { background-color: #faa732; background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-image: -ms-linear-gradient(top, #fbb450, #f89406); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); background-image: -webkit-linear-gradient(top, #fbb450, #f89406); background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(top, #fbb450, #f89406); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); border-color: #f89406 #f89406 #ad6704; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-warning:hover, .btn-warning:active, .btn-warning.active, .btn-warning.disabled, .btn-warning[disabled] { background-color: #f89406; } .btn-warning:active, .btn-warning.active { background-color: #c67605 \9; } .btn-danger { background-color: #da4f49; background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); background-image: linear-gradient(top, #ee5f5b, #bd362f); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); border-color: #bd362f #bd362f #802420; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-danger:hover, .btn-danger:active, .btn-danger.active, .btn-danger.disabled, .btn-danger[disabled] { background-color: #bd362f; } .btn-danger:active, .btn-danger.active { background-color: #942a25 \9; } .btn-success { background-color: #5bb75b; background-image: -moz-linear-gradient(top, #62c462, #51a351); background-image: -ms-linear-gradient(top, #62c462, #51a351); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); background-image: -webkit-linear-gradient(top, #62c462, #51a351); background-image: -o-linear-gradient(top, #62c462, #51a351); background-image: linear-gradient(top, #62c462, #51a351); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); border-color: #51a351 #51a351 #387038; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-success:hover, .btn-success:active, .btn-success.active, .btn-success.disabled, .btn-success[disabled] { background-color: #51a351; } .btn-success:active, .btn-success.active { background-color: #408140 \9; } .btn-info { background-color: #49afcd; background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); background-image: linear-gradient(top, #5bc0de, #2f96b4); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); border-color: #2f96b4 #2f96b4 #1f6377; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-info:hover, .btn-info:active, .btn-info.active, .btn-info.disabled, .btn-info[disabled] { background-color: #2f96b4; } .btn-info:active, .btn-info.active { background-color: #24748c \9; } .btn-inverse { background-color: #414141; background-image: -moz-linear-gradient(top, #555555, #222222); background-image: -ms-linear-gradient(top, #555555, #222222); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); background-image: -webkit-linear-gradient(top, #555555, #222222); background-image: -o-linear-gradient(top, #555555, #222222); background-image: linear-gradient(top, #555555, #222222); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); border-color: #222222 #222222 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-inverse:hover, .btn-inverse:active, .btn-inverse.active, .btn-inverse.disabled, .btn-inverse[disabled] { background-color: #222222; } .btn-inverse:active, .btn-inverse.active { background-color: #080808 \9; } button.btn, input[type="submit"].btn { *padding-top: 2px; *padding-bottom: 2px; } button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { padding: 0; border: 0; } button.btn.btn-large, input[type="submit"].btn.btn-large { *padding-top: 7px; *padding-bottom: 7px; } button.btn.btn-small, input[type="submit"].btn.btn-small { *padding-top: 3px; *padding-bottom: 3px; } button.btn.btn-mini, input[type="submit"].btn.btn-mini { *padding-top: 1px; *padding-bottom: 1px; } .btn-group { position: relative; *zoom: 1; *margin-left: .3em; } .btn-group:before, .btn-group:after { display: table; content: ""; } .btn-group:after { clear: both; } .btn-group:first-child { *margin-left: 0; } .btn-group + .btn-group { margin-left: 5px; } .btn-toolbar { margin-top: 9px; margin-bottom: 9px; } .btn-toolbar .btn-group { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; } .btn-group .btn { position: relative; float: left; margin-left: -1px; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .btn-group .btn:first-child { margin-left: 0; -webkit-border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; border-top-left-radius: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomleft: 4px; border-bottom-left-radius: 4px; } .btn-group .btn:last-child, .btn-group .dropdown-toggle { -webkit-border-top-right-radius: 4px; -moz-border-radius-topright: 4px; border-top-right-radius: 4px; -webkit-border-bottom-right-radius: 4px; -moz-border-radius-bottomright: 4px; border-bottom-right-radius: 4px; } .btn-group .btn.large:first-child { margin-left: 0; -webkit-border-top-left-radius: 6px; -moz-border-radius-topleft: 6px; border-top-left-radius: 6px; -webkit-border-bottom-left-radius: 6px; -moz-border-radius-bottomleft: 6px; border-bottom-left-radius: 6px; } .btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { -webkit-border-top-right-radius: 6px; -moz-border-radius-topright: 6px; border-top-right-radius: 6px; -webkit-border-bottom-right-radius: 6px; -moz-border-radius-bottomright: 6px; border-bottom-right-radius: 6px; } .btn-group .btn:hover, .btn-group .btn:focus, .btn-group .btn:active, .btn-group .btn.active { z-index: 2; } .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; } .btn-group .dropdown-toggle { padding-left: 8px; padding-right: 8px; -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); *padding-top: 3px; *padding-bottom: 3px; } .btn-group .btn-mini.dropdown-toggle { padding-left: 5px; padding-right: 5px; *padding-top: 1px; *padding-bottom: 1px; } .btn-group .btn-small.dropdown-toggle { *padding-top: 4px; *padding-bottom: 4px; } .btn-group .btn-large.dropdown-toggle { padding-left: 12px; padding-right: 12px; } .btn-group.open { *z-index: 1000; } .btn-group.open .dropdown-menu { display: block; margin-top: 1px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .btn-group.open .dropdown-toggle { background-image: none; -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); } .btn .caret { margin-top: 7px; margin-left: 0; } .btn:hover .caret, .open.btn-group .caret { opacity: 1; filter: alpha(opacity=100); } .btn-mini .caret { margin-top: 5px; } .btn-small .caret { margin-top: 6px; } .btn-large .caret { margin-top: 6px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #000000; } .btn-primary .caret, .btn-warning .caret, .btn-danger .caret, .btn-info .caret, .btn-success .caret, .btn-inverse .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; opacity: 0.75; filter: alpha(opacity=75); } .alert { padding: 8px 35px 8px 14px; margin-bottom: 18px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); background-color: #fcf8e3; border: 1px solid #fbeed5; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #c09853; } .alert-heading { color: inherit; } .alert .close { position: relative; top: -2px; right: -21px; line-height: 18px; } .alert-success { background-color: #dff0d8; border-color: #d6e9c6; color: #468847; } .alert-danger, .alert-error { background-color: #f2dede; border-color: #eed3d7; color: #b94a48; } .alert-info { background-color: #d9edf7; border-color: #bce8f1; color: #3a87ad; } .alert-block { padding-top: 14px; padding-bottom: 14px; } .alert-block > p, .alert-block > ul { margin-bottom: 0; } .alert-block p + p { margin-top: 5px; } .nav { margin-left: 0; margin-bottom: 18px; list-style: none; } .nav > li > a { display: block; } .nav > li > a:hover { text-decoration: none; background-color: #eeeeee; } .nav .nav-header { display: block; padding: 3px 15px; font-size: 11px; font-weight: bold; line-height: 18px; color: #999999; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); text-transform: uppercase; } .nav li + .nav-header { margin-top: 9px; } .nav-list { padding-left: 15px; padding-right: 15px; margin-bottom: 0; } .nav-list > li > a, .nav-list .nav-header { margin-left: -15px; margin-right: -15px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); } .nav-list > li > a { padding: 3px 15px; } .nav-list > .active > a, .nav-list > .active > a:hover { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); background-color: #0088cc; } .nav-list [class^="icon-"] { margin-right: 2px; } .nav-list .divider { height: 1px; margin: 8px 1px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; *width: 100%; *margin: -5px 0 5px; } .nav-tabs, .nav-pills { *zoom: 1; } .nav-tabs:before, .nav-pills:before, .nav-tabs:after, .nav-pills:after { display: table; content: ""; } .nav-tabs:after, .nav-pills:after { clear: both; } .nav-tabs > li, .nav-pills > li { float: left; } .nav-tabs > li > a, .nav-pills > li > a { padding-right: 12px; padding-left: 12px; margin-right: 2px; line-height: 14px; } .nav-tabs { border-bottom: 1px solid #ddd; } .nav-tabs > li { margin-bottom: -1px; } .nav-tabs > li > a { padding-top: 8px; padding-bottom: 8px; line-height: 18px; border: 1px solid transparent; -webkit-border-radius: 4px 4px 0 0; -moz-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; } .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #dddddd; } .nav-tabs > .active > a, .nav-tabs > .active > a:hover { color: #555555; background-color: #ffffff; border: 1px solid #ddd; border-bottom-color: transparent; cursor: default; } .nav-pills > li > a { padding-top: 8px; padding-bottom: 8px; margin-top: 2px; margin-bottom: 2px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .nav-pills > .active > a, .nav-pills > .active > a:hover { color: #ffffff; background-color: #0088cc; } .nav-stacked > li { float: none; } .nav-stacked > li > a { margin-right: 0; } .nav-tabs.nav-stacked { border-bottom: 0; } .nav-tabs.nav-stacked > li > a { border: 1px solid #ddd; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .nav-tabs.nav-stacked > li:first-child > a { -webkit-border-radius: 4px 4px 0 0; -moz-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; } .nav-tabs.nav-stacked > li:last-child > a { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } .nav-tabs.nav-stacked > li > a:hover { border-color: #ddd; z-index: 2; } .nav-pills.nav-stacked > li > a { margin-bottom: 3px; } .nav-pills.nav-stacked > li:last-child > a { margin-bottom: 1px; } .nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { margin-top: 1px; border-width: 1px; } .nav-pills .dropdown-menu { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { border-top-color: #0088cc; border-bottom-color: #0088cc; margin-top: 6px; } .nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { border-top-color: #005580; border-bottom-color: #005580; } .nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { border-top-color: #333333; border-bottom-color: #333333; } .nav > .dropdown.active > a:hover { color: #000000; cursor: pointer; } .nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { color: #ffffff; background-color: #999999; border-color: #999999; } .nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; opacity: 1; filter: alpha(opacity=100); } .tabs-stacked .open > a:hover { border-color: #999999; } .tabbable { *zoom: 1; } .tabbable:before, .tabbable:after { display: table; content: ""; } .tabbable:after { clear: both; } .tab-content { display: table; width: 100%; } .tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { border-bottom: 0; } .tab-content > .tab-pane, .pill-content > .pill-pane { display: none; } .tab-content > .active, .pill-content > .active { display: block; } .tabs-below .nav-tabs { border-top: 1px solid #ddd; } .tabs-below .nav-tabs > li { margin-top: -1px; margin-bottom: 0; } .tabs-below .nav-tabs > li > a { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } .tabs-below .nav-tabs > li > a:hover { border-bottom-color: transparent; border-top-color: #ddd; } .tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { border-color: transparent #ddd #ddd #ddd; } .tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { float: none; } .tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { min-width: 74px; margin-right: 0; margin-bottom: 3px; } .tabs-left .nav-tabs { float: left; margin-right: 19px; border-right: 1px solid #ddd; } .tabs-left .nav-tabs > li > a { margin-right: -1px; -webkit-border-radius: 4px 0 0 4px; -moz-border-radius: 4px 0 0 4px; border-radius: 4px 0 0 4px; } .tabs-left .nav-tabs > li > a:hover { border-color: #eeeeee #dddddd #eeeeee #eeeeee; } .tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { border-color: #ddd transparent #ddd #ddd; *border-right-color: #ffffff; } .tabs-right .nav-tabs { float: right; margin-left: 19px; border-left: 1px solid #ddd; } .tabs-right .nav-tabs > li > a { margin-left: -1px; -webkit-border-radius: 0 4px 4px 0; -moz-border-radius: 0 4px 4px 0; border-radius: 0 4px 4px 0; } .tabs-right .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #eeeeee #dddddd; } .tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { border-color: #ddd #ddd #ddd transparent; *border-left-color: #ffffff; } .navbar { *position: relative; *z-index: 2; overflow: visible; margin-bottom: 18px; } .navbar-inner { padding-left: 20px; padding-right: 20px; background-color: #2c2c2c; background-image: -moz-linear-gradient(top, #333333, #222222); background-image: -ms-linear-gradient(top, #333333, #222222); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); background-image: -webkit-linear-gradient(top, #333333, #222222); background-image: -o-linear-gradient(top, #333333, #222222); background-image: linear-gradient(top, #333333, #222222); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); } .navbar .container { width: auto; } .btn-navbar { display: none; float: right; padding: 7px 10px; margin-left: 5px; margin-right: 5px; background-color: #2c2c2c; background-image: -moz-linear-gradient(top, #333333, #222222); background-image: -ms-linear-gradient(top, #333333, #222222); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); background-image: -webkit-linear-gradient(top, #333333, #222222); background-image: -o-linear-gradient(top, #333333, #222222); background-image: linear-gradient(top, #333333, #222222); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); border-color: #222222 #222222 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); } .btn-navbar:hover, .btn-navbar:active, .btn-navbar.active, .btn-navbar.disabled, .btn-navbar[disabled] { background-color: #222222; } .btn-navbar:active, .btn-navbar.active { background-color: #080808 \9; } .btn-navbar .icon-bar { display: block; width: 18px; height: 2px; background-color: #f5f5f5; -webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); } .btn-navbar .icon-bar + .icon-bar { margin-top: 3px; } .nav-collapse.collapse { height: auto; } .navbar { color: #999999; } .navbar .brand:hover { text-decoration: none; } .navbar .brand { float: left; display: block; padding: 8px 20px 12px; margin-left: -20px; font-size: 20px; font-weight: 200; line-height: 1; color: #ffffff; } .navbar .navbar-text { margin-bottom: 0; line-height: 40px; } .navbar .btn, .navbar .btn-group { margin-top: 5px; } .navbar .btn-group .btn { margin-top: 0; } .navbar-form { margin-bottom: 0; *zoom: 1; } .navbar-form:before, .navbar-form:after { display: table; content: ""; } .navbar-form:after { clear: both; } .navbar-form input, .navbar-form select, .navbar-form .radio, .navbar-form .checkbox { margin-top: 5px; } .navbar-form input, .navbar-form select { display: inline-block; margin-bottom: 0; } .navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { margin-top: 3px; } .navbar-form .input-append, .navbar-form .input-prepend { margin-top: 6px; white-space: nowrap; } .navbar-form .input-append input, .navbar-form .input-prepend input { margin-top: 0; } .navbar-search { position: relative; float: left; margin-top: 6px; margin-bottom: 0; } .navbar-search .search-query { padding: 4px 9px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; line-height: 1; color: #ffffff; background-color: #626262; border: 1px solid #151515; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none; transition: none; } .navbar-search .search-query:-moz-placeholder { color: #cccccc; } .navbar-search .search-query::-webkit-input-placeholder { color: #cccccc; } .navbar-search .search-query:focus, .navbar-search .search-query.focused { padding: 5px 10px; color: #333333; text-shadow: 0 1px 0 #ffffff; background-color: #ffffff; border: 0; -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); outline: 0; } .navbar-fixed-top, .navbar-fixed-bottom { position: fixed; right: 0; left: 0; z-index: 1030; margin-bottom: 0; } .navbar-fixed-top .navbar-inner, .navbar-fixed-bottom .navbar-inner { padding-left: 0; padding-right: 0; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } .navbar-fixed-top { top: 0; } .navbar-fixed-bottom { bottom: 0; } .navbar .nav { position: relative; left: 0; display: block; float: left; margin: 0 10px 0 0; } .navbar .nav.pull-right { float: right; } .navbar .nav > li { display: block; float: left; } .navbar .nav > li > a { float: none; padding: 10px 10px 11px; line-height: 19px; color: #999999; text-decoration: none; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .navbar .nav > li > a:hover { background-color: transparent; color: #ffffff; text-decoration: none; } .navbar .nav .active > a, .navbar .nav .active > a:hover { color: #ffffff; text-decoration: none; background-color: #222222; } .navbar .divider-vertical { height: 40px; width: 1px; margin: 0 9px; overflow: hidden; background-color: #222222; border-right: 1px solid #333333; } .navbar .nav.pull-right { margin-left: 10px; margin-right: 0; } .navbar .dropdown-menu { margin-top: 1px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .navbar .dropdown-menu:before { content: ''; display: inline-block; border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid #ccc; border-bottom-color: rgba(0, 0, 0, 0.2); position: absolute; top: -7px; left: 9px; } .navbar .dropdown-menu:after { content: ''; display: inline-block; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #ffffff; position: absolute; top: -6px; left: 10px; } .navbar-fixed-bottom .dropdown-menu:before { border-top: 7px solid #ccc; border-top-color: rgba(0, 0, 0, 0.2); border-bottom: 0; bottom: -7px; top: auto; } .navbar-fixed-bottom .dropdown-menu:after { border-top: 6px solid #ffffff; border-bottom: 0; bottom: -6px; top: auto; } .navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; } .navbar .nav .active .caret { opacity: 1; filter: alpha(opacity=100); } .navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { background-color: transparent; } .navbar .nav .active > .dropdown-toggle:hover { color: #ffffff; } .navbar .nav.pull-right .dropdown-menu, .navbar .nav .dropdown-menu.pull-right { left: auto; right: 0; } .navbar .nav.pull-right .dropdown-menu:before, .navbar .nav .dropdown-menu.pull-right:before { left: auto; right: 12px; } .navbar .nav.pull-right .dropdown-menu:after, .navbar .nav .dropdown-menu.pull-right:after { left: auto; right: 13px; } .breadcrumb { padding: 7px 14px; margin: 0 0 18px; list-style: none; background-color: #fbfbfb; background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); background-image: linear-gradient(top, #ffffff, #f5f5f5); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); border: 1px solid #ddd; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: inset 0 1px 0 #ffffff; -moz-box-shadow: inset 0 1px 0 #ffffff; box-shadow: inset 0 1px 0 #ffffff; } .breadcrumb li { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; text-shadow: 0 1px 0 #ffffff; } .breadcrumb .divider { padding: 0 5px; color: #999999; } .breadcrumb .active a { color: #333333; } .pagination { height: 36px; margin: 18px 0; } .pagination ul { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; margin-left: 0; margin-bottom: 0; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .pagination li { display: inline; } .pagination a { float: left; padding: 0 14px; line-height: 34px; text-decoration: none; border: 1px solid #ddd; border-left-width: 0; } .pagination a:hover, .pagination .active a { background-color: #f5f5f5; } .pagination .active a { color: #999999; cursor: default; } .pagination .disabled span, .pagination .disabled a, .pagination .disabled a:hover { color: #999999; background-color: transparent; cursor: default; } .pagination li:first-child a { border-left-width: 1px; -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .pagination li:last-child a { -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .pagination-centered { text-align: center; } .pagination-right { text-align: right; } .pager { margin-left: 0; margin-bottom: 18px; list-style: none; text-align: center; *zoom: 1; } .pager:before, .pager:after { display: table; content: ""; } .pager:after { clear: both; } .pager li { display: inline; } .pager a { display: inline-block; padding: 5px 14px; background-color: #fff; border: 1px solid #ddd; -webkit-border-radius: 15px; -moz-border-radius: 15px; border-radius: 15px; } .pager a:hover { text-decoration: none; background-color: #f5f5f5; } .pager .next a { float: right; } .pager .previous a { float: left; } .pager .disabled a, .pager .disabled a:hover { color: #999999; background-color: #fff; cursor: default; } .modal-open .dropdown-menu { z-index: 2050; } .modal-open .dropdown.open { *z-index: 2050; } .modal-open .popover { z-index: 2060; } .modal-open .tooltip { z-index: 2070; } .modal-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1040; background-color: #000000; } .modal-backdrop.fade { opacity: 0; } .modal-backdrop, .modal-backdrop.fade.in { opacity: 0.8; filter: alpha(opacity=80); } .modal { position: fixed; top: 50%; left: 50%; z-index: 1050; overflow: auto; width: 560px; margin: -250px 0 0 -280px; background-color: #ffffff; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.3); *border: 1px solid #999; /* IE6-7 */ -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -webkit-background-clip: padding-box; -moz-background-clip: padding-box; background-clip: padding-box; } .modal.fade { -webkit-transition: opacity .3s linear, top .3s ease-out; -moz-transition: opacity .3s linear, top .3s ease-out; -ms-transition: opacity .3s linear, top .3s ease-out; -o-transition: opacity .3s linear, top .3s ease-out; transition: opacity .3s linear, top .3s ease-out; top: -25%; } .modal.fade.in { top: 50%; } .modal-header { padding: 9px 15px; border-bottom: 1px solid #eee; } .modal-header .close { margin-top: 2px; } .modal-body { overflow-y: auto; max-height: 400px; padding: 15px; } .modal-form { margin-bottom: 0; } .modal-footer { padding: 14px 15px 15px; margin-bottom: 0; text-align: right; background-color: #f5f5f5; border-top: 1px solid #ddd; -webkit-border-radius: 0 0 6px 6px; -moz-border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px; -webkit-box-shadow: inset 0 1px 0 #ffffff; -moz-box-shadow: inset 0 1px 0 #ffffff; box-shadow: inset 0 1px 0 #ffffff; *zoom: 1; } .modal-footer:before, .modal-footer:after { display: table; content: ""; } .modal-footer:after { clear: both; } .modal-footer .btn + .btn { margin-left: 5px; margin-bottom: 0; } .modal-footer .btn-group .btn + .btn { margin-left: -1px; } .tooltip { position: absolute; z-index: 1020; display: block; visibility: visible; padding: 5px; font-size: 11px; opacity: 0; filter: alpha(opacity=0); } .tooltip.in { opacity: 0.8; filter: alpha(opacity=80); } .tooltip.top { margin-top: -2px; } .tooltip.right { margin-left: 2px; } .tooltip.bottom { margin-top: 2px; } .tooltip.left { margin-left: -2px; } .tooltip.top .tooltip-arrow { bottom: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #000000; } .tooltip.left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-left: 5px solid #000000; } .tooltip.bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 5px solid #000000; } .tooltip.right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-right: 5px solid #000000; } .tooltip-inner { max-width: 200px; padding: 3px 8px; color: #ffffff; text-align: center; text-decoration: none; background-color: #000000; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .tooltip-arrow { position: absolute; width: 0; height: 0; } .popover { position: absolute; top: 0; left: 0; z-index: 1010; display: none; padding: 5px; } .popover.top { margin-top: -5px; } .popover.right { margin-left: 5px; } .popover.bottom { margin-top: 5px; } .popover.left { margin-left: -5px; } .popover.top .arrow { bottom: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #000000; } .popover.right .arrow { top: 50%; left: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-right: 5px solid #000000; } .popover.bottom .arrow { top: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 5px solid #000000; } .popover.left .arrow { top: 50%; right: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-left: 5px solid #000000; } .popover .arrow { position: absolute; width: 0; height: 0; } .popover-inner { padding: 3px; width: 280px; overflow: hidden; background: #000000; background: rgba(0, 0, 0, 0.8); -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); } .popover-title { padding: 9px 15px; line-height: 1; background-color: #f5f5f5; border-bottom: 1px solid #eee; -webkit-border-radius: 3px 3px 0 0; -moz-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; } .popover-content { padding: 14px; background-color: #ffffff; -webkit-border-radius: 0 0 3px 3px; -moz-border-radius: 0 0 3px 3px; border-radius: 0 0 3px 3px; -webkit-background-clip: padding-box; -moz-background-clip: padding-box; background-clip: padding-box; } .popover-content p, .popover-content ul, .popover-content ol { margin-bottom: 0; } .thumbnails { margin-left: -20px; list-style: none; *zoom: 1; } .thumbnails:before, .thumbnails:after { display: table; content: ""; } .thumbnails:after { clear: both; } .thumbnails > li { float: left; margin: 0 0 18px 20px; } .thumbnail { display: block; padding: 4px; line-height: 1; border: 1px solid #ddd; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); } a.thumbnail:hover { border-color: #0088cc; -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); } .thumbnail > img { display: block; max-width: 100%; margin-left: auto; margin-right: auto; } .thumbnail .caption { padding: 9px; } .label { padding: 1px 4px 2px; font-size: 10.998px; font-weight: bold; line-height: 13px; color: #ffffff; vertical-align: middle; white-space: nowrap; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #999999; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .label:hover { color: #ffffff; text-decoration: none; } .label-important { background-color: #b94a48; } .label-important:hover { background-color: #953b39; } .label-warning { background-color: #f89406; } .label-warning:hover { background-color: #c67605; } .label-success { background-color: #468847; } .label-success:hover { background-color: #356635; } .label-info { background-color: #3a87ad; } .label-info:hover { background-color: #2d6987; } .label-inverse { background-color: #333333; } .label-inverse:hover { background-color: #1a1a1a; } .badge { padding: 1px 9px 2px; font-size: 12.025px; font-weight: bold; white-space: nowrap; color: #ffffff; background-color: #999999; -webkit-border-radius: 9px; -moz-border-radius: 9px; border-radius: 9px; } .badge:hover { color: #ffffff; text-decoration: none; cursor: pointer; } .badge-error { background-color: #b94a48; } .badge-error:hover { background-color: #953b39; } .badge-warning { background-color: #f89406; } .badge-warning:hover { background-color: #c67605; } .badge-success { background-color: #468847; } .badge-success:hover { background-color: #356635; } .badge-info { background-color: #3a87ad; } .badge-info:hover { background-color: #2d6987; } .badge-inverse { background-color: #333333; } .badge-inverse:hover { background-color: #1a1a1a; } @-webkit-keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } @-moz-keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } @-ms-keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } @keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } .progress { overflow: hidden; height: 18px; margin-bottom: 18px; background-color: #f7f7f7; background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: linear-gradient(top, #f5f5f5, #f9f9f9); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .progress .bar { width: 0%; height: 18px; color: #ffffff; font-size: 12px; text-align: center; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #0e90d2; background-image: -moz-linear-gradient(top, #149bdf, #0480be); background-image: -ms-linear-gradient(top, #149bdf, #0480be); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); background-image: -webkit-linear-gradient(top, #149bdf, #0480be); background-image: -o-linear-gradient(top, #149bdf, #0480be); background-image: linear-gradient(top, #149bdf, #0480be); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; -webkit-transition: width 0.6s ease; -moz-transition: width 0.6s ease; -ms-transition: width 0.6s ease; -o-transition: width 0.6s ease; transition: width 0.6s ease; } .progress-striped .bar { background-color: #149bdf; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -webkit-background-size: 40px 40px; -moz-background-size: 40px 40px; -o-background-size: 40px 40px; background-size: 40px 40px; } .progress.active .bar { -webkit-animation: progress-bar-stripes 2s linear infinite; -moz-animation: progress-bar-stripes 2s linear infinite; animation: progress-bar-stripes 2s linear infinite; } .progress-danger .bar { background-color: #dd514c; background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); background-image: linear-gradient(top, #ee5f5b, #c43c35); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); } .progress-danger.progress-striped .bar { background-color: #ee5f5b; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-success .bar { background-color: #5eb95e; background-image: -moz-linear-gradient(top, #62c462, #57a957); background-image: -ms-linear-gradient(top, #62c462, #57a957); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); background-image: -webkit-linear-gradient(top, #62c462, #57a957); background-image: -o-linear-gradient(top, #62c462, #57a957); background-image: linear-gradient(top, #62c462, #57a957); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); } .progress-success.progress-striped .bar { background-color: #62c462; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-info .bar { background-color: #4bb1cf; background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); background-image: -o-linear-gradient(top, #5bc0de, #339bb9); background-image: linear-gradient(top, #5bc0de, #339bb9); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); } .progress-info.progress-striped .bar { background-color: #5bc0de; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-warning .bar { background-color: #faa732; background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-image: -ms-linear-gradient(top, #fbb450, #f89406); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); background-image: -webkit-linear-gradient(top, #fbb450, #f89406); background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(top, #fbb450, #f89406); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); } .progress-warning.progress-striped .bar { background-color: #fbb450; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .accordion { margin-bottom: 18px; } .accordion-group { margin-bottom: 2px; border: 1px solid #e5e5e5; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .accordion-heading { border-bottom: 0; } .accordion-heading .accordion-toggle { display: block; padding: 8px 15px; } .accordion-inner { padding: 9px 15px; border-top: 1px solid #e5e5e5; } .carousel { position: relative; margin-bottom: 18px; line-height: 1; } .carousel-inner { overflow: hidden; width: 100%; position: relative; } .carousel .item { display: none; position: relative; -webkit-transition: 0.6s ease-in-out left; -moz-transition: 0.6s ease-in-out left; -ms-transition: 0.6s ease-in-out left; -o-transition: 0.6s ease-in-out left; transition: 0.6s ease-in-out left; } .carousel .item > img { display: block; line-height: 1; } .carousel .active, .carousel .next, .carousel .prev { display: block; } .carousel .active { left: 0; } .carousel .next, .carousel .prev { position: absolute; top: 0; width: 100%; } .carousel .next { left: 100%; } .carousel .prev { left: -100%; } .carousel .next.left, .carousel .prev.right { left: 0; } .carousel .active.left { left: -100%; } .carousel .active.right { left: 100%; } .carousel-control { position: absolute; top: 40%; left: 15px; width: 40px; height: 40px; margin-top: -20px; font-size: 60px; font-weight: 100; line-height: 30px; color: #ffffff; text-align: center; background: #222222; border: 3px solid #ffffff; -webkit-border-radius: 23px; -moz-border-radius: 23px; border-radius: 23px; opacity: 0.5; filter: alpha(opacity=50); } .carousel-control.right { left: auto; right: 15px; } .carousel-control:hover { color: #ffffff; text-decoration: none; opacity: 0.9; filter: alpha(opacity=90); } .carousel-caption { position: absolute; left: 0; right: 0; bottom: 0; padding: 10px 15px 5px; background: #333333; background: rgba(0, 0, 0, 0.75); } .carousel-caption h4, .carousel-caption p { color: #ffffff; } .hero-unit { padding: 60px; margin-bottom: 30px; background-color: #eeeeee; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .hero-unit h1 { margin-bottom: 0; font-size: 60px; line-height: 1; color: inherit; letter-spacing: -1px; } .hero-unit p { font-size: 18px; font-weight: 200; line-height: 27px; color: inherit; } .pull-right { float: right; } .pull-left { float: left; } .hide { display: none; } .show { display: block; } .invisible { visibility: hidden; } flask-peewee-0.6.7/flask_peewee/static/css/bootstrap-responsive.min.css0000644000175000001440000003627112574421673027135 0ustar charlesusers00000000000000/*! * Bootstrap Responsive v2.1.0 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#555;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} flask-peewee-0.6.7/flask_peewee/static/css/bootstrap.min.responsive.css0000644000175000001440000001700012574421673027123 0ustar charlesusers00000000000000 .hidden{display:none;visibility:hidden;} @media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:18px;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} .input-prepend input[class*="span"],.input-append input[class*="span"]{width:auto;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{position:absolute;top:10px;left:10px;right:10px;width:auto;margin:0;}.modal.fade.in{top:auto;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (max-width:768px){.container{width:auto;padding:0 20px;} .row-fluid{width:100%;} .row{margin-left:0;} .row>[class*="span"],.row-fluid>[class*="span"]{float:none;display:block;width:auto;margin:0;}}@media (min-width:768px) and (max-width:980px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .span1{width:42px;} .span2{width:104px;} .span3{width:166px;} .span4{width:228px;} .span5{width:290px;} .span6{width:352px;} .span7{width:414px;} .span8{width:476px;} .span9{width:538px;} .span10{width:600px;} .span11{width:662px;} .span12,.container{width:724px;} .offset1{margin-left:82px;} .offset2{margin-left:144px;} .offset3{margin-left:206px;} .offset4{margin-left:268px;} .offset5{margin-left:330px;} .offset6{margin-left:392px;} .offset7{margin-left:454px;} .offset8{margin-left:516px;} .offset9{margin-left:578px;} .offset10{margin-left:640px;} .offset11{margin-left:702px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.762430939%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid .span1{width:5.801104972%;} .row-fluid .span2{width:14.364640883%;} .row-fluid .span3{width:22.928176794%;} .row-fluid .span4{width:31.491712705%;} .row-fluid .span5{width:40.055248616%;} .row-fluid .span6{width:48.618784527%;} .row-fluid .span7{width:57.182320438000005%;} .row-fluid .span8{width:65.74585634900001%;} .row-fluid .span9{width:74.30939226%;} .row-fluid .span10{width:82.87292817100001%;} .row-fluid .span11{width:91.436464082%;} .row-fluid .span12{width:99.999999993%;} input.span1,textarea.span1,.uneditable-input.span1{width:32px;} input.span2,textarea.span2,.uneditable-input.span2{width:94px;} input.span3,textarea.span3,.uneditable-input.span3{width:156px;} input.span4,textarea.span4,.uneditable-input.span4{width:218px;} input.span5,textarea.span5,.uneditable-input.span5{width:280px;} input.span6,textarea.span6,.uneditable-input.span6{width:342px;} input.span7,textarea.span7,.uneditable-input.span7{width:404px;} input.span8,textarea.span8,.uneditable-input.span8{width:466px;} input.span9,textarea.span9,.uneditable-input.span9{width:528px;} input.span10,textarea.span10,.uneditable-input.span10{width:590px;} input.span11,textarea.span11,.uneditable-input.span11{width:652px;} input.span12,textarea.span12,.uneditable-input.span12{width:714px;}}@media (max-width:980px){body{padding-top:0;} .navbar-fixed-top{position:static;margin-bottom:18px;} .navbar-fixed-top .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .navbar .nav-collapse{clear:left;} .navbar .nav{float:none;margin:0 0 9px;} .navbar .nav>li{float:none;} .navbar .nav>li>a{margin-bottom:2px;} .navbar .nav>.divider-vertical{display:none;} .navbar .nav>li>a,.navbar .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .navbar .dropdown-menu li+li a{margin-bottom:2px;} .navbar .nav>li>a:hover,.navbar .dropdown-menu a:hover{background-color:#222222;} .navbar .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .navbar .dropdown-menu:before,.navbar .dropdown-menu:after{display:none;} .navbar .dropdown-menu .divider{display:none;} .navbar-form,.navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222222;border-bottom:1px solid #222222;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);} .navbar .nav.pull-right{float:none;margin-left:0;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;} .btn-navbar{display:block;} .nav-collapse{overflow:hidden;height:0;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:30px;} .span1{width:70px;} .span2{width:170px;} .span3{width:270px;} .span4{width:370px;} .span5{width:470px;} .span6{width:570px;} .span7{width:670px;} .span8{width:770px;} .span9{width:870px;} .span10{width:970px;} .span11{width:1070px;} .span12,.container{width:1170px;} .offset1{margin-left:130px;} .offset2{margin-left:230px;} .offset3{margin-left:330px;} .offset4{margin-left:430px;} .offset5{margin-left:530px;} .offset6{margin-left:630px;} .offset7{margin-left:730px;} .offset8{margin-left:830px;} .offset9{margin-left:930px;} .offset10{margin-left:1030px;} .offset11{margin-left:1130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.564102564%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid .span1{width:5.982905983%;} .row-fluid .span2{width:14.529914530000001%;} .row-fluid .span3{width:23.076923077%;} .row-fluid .span4{width:31.623931624%;} .row-fluid .span5{width:40.170940171000005%;} .row-fluid .span6{width:48.717948718%;} .row-fluid .span7{width:57.264957265%;} .row-fluid .span8{width:65.81196581200001%;} .row-fluid .span9{width:74.358974359%;} .row-fluid .span10{width:82.905982906%;} .row-fluid .span11{width:91.45299145300001%;} .row-fluid .span12{width:100%;} input.span1,textarea.span1,.uneditable-input.span1{width:60px;} input.span2,textarea.span2,.uneditable-input.span2{width:160px;} input.span3,textarea.span3,.uneditable-input.span3{width:260px;} input.span4,textarea.span4,.uneditable-input.span4{width:360px;} input.span5,textarea.span5,.uneditable-input.span5{width:460px;} input.span6,textarea.span6,.uneditable-input.span6{width:560px;} input.span7,textarea.span7,.uneditable-input.span7{width:660px;} input.span8,textarea.span8,.uneditable-input.span8{width:760px;} input.span9,textarea.span9,.uneditable-input.span9{width:860px;} input.span10,textarea.span10,.uneditable-input.span10{width:960px;} input.span11,textarea.span11,.uneditable-input.span11{width:1060px;} input.span12,textarea.span12,.uneditable-input.span12{width:1160px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;}} flask-peewee-0.6.7/flask_peewee/static/css/bootstrap.min.css0000644000175000001440000023637612574421673024752 0ustar charlesusers00000000000000article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} audio:not([controls]){display:none;} html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} a:hover,a:active{outline:0;} sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} sup{top:-0.5em;} sub{bottom:-0.25em;} img{height:auto;border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;} button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} button,input{*overflow:visible;line-height:normal;} button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} textarea{overflow:auto;vertical-align:top;} .clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";} .clearfix:after{clear:both;} .hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;} .input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;} a{color:#0088cc;text-decoration:none;} a:hover{color:#005580;text-decoration:underline;} .row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} .span12{width:940px;} .span11{width:860px;} .span10{width:780px;} .span9{width:700px;} .span8{width:620px;} .span7{width:540px;} .span6{width:460px;} .span5{width:380px;} .span4{width:300px;} .span3{width:220px;} .span2{width:140px;} .span1{width:60px;} .offset12{margin-left:980px;} .offset11{margin-left:900px;} .offset10{margin-left:820px;} .offset9{margin-left:740px;} .offset8{margin-left:660px;} .offset7{margin-left:580px;} .offset6{margin-left:500px;} .offset5{margin-left:420px;} .offset4{margin-left:340px;} .offset3{margin-left:260px;} .offset2{margin-left:180px;} .offset1{margin-left:100px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid > .span12{width:99.99999998999999%;} .row-fluid > .span11{width:91.489361693%;} .row-fluid > .span10{width:82.97872339599999%;} .row-fluid > .span9{width:74.468085099%;} .row-fluid > .span8{width:65.95744680199999%;} .row-fluid > .span7{width:57.446808505%;} .row-fluid > .span6{width:48.93617020799999%;} .row-fluid > .span5{width:40.425531911%;} .row-fluid > .span4{width:31.914893614%;} .row-fluid > .span3{width:23.404255317%;} .row-fluid > .span2{width:14.89361702%;} .row-fluid > .span1{width:6.382978723%;} .container{margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";} .container:after{clear:both;} .container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";} .container-fluid:after{clear:both;} p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;} .lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;} h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;} h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;} h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;} h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;} h4,h5,h6{line-height:18px;} h4{font-size:14px;}h4 small{font-size:12px;} h5{font-size:12px;} h6{font-size:11px;color:#999999;text-transform:uppercase;} .page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;} .page-header h1{line-height:1;} ul,ol{padding:0;margin:0 0 9px 25px;} ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} ul{list-style:disc;} ol{list-style:decimal;} li{line-height:18px;} ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} dl{margin-bottom:18px;} dt,dd{line-height:18px;} dt{font-weight:bold;line-height:17px;} dd{margin-left:9px;} .dl-horizontal dt{float:left;clear:left;width:120px;text-align:right;} .dl-horizontal dd{margin-left:130px;} hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} strong{font-weight:bold;} em{font-style:italic;} .muted{color:#999999;} abbr[title]{border-bottom:1px dotted #ddd;cursor:help;} abbr.initialism{font-size:90%;text-transform:uppercase;} blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;} blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} q:before,q:after,blockquote:before,blockquote:after{content:"";} address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;} small{font-size:100%;} cite{font-style:normal;} code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;word-wrap:break-word;}pre.prettyprint{margin-bottom:18px;} pre code{padding:0;color:inherit;background-color:transparent;border:0;} .pre-scrollable{max-height:340px;overflow-y:scroll;} form{margin:0 0 18px;} fieldset{padding:0;margin:0;border:0;} legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;} label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;} input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} label{display:block;margin-bottom:5px;color:#333333;} input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #cccccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .uneditable-textarea{width:auto;height:auto;} label input,label textarea,label select{display:block;} input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0 \9;} input[type="image"]{border:0;} input[type="file"]{width:auto;padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} input[type="file"]{line-height:18px \9;} select{width:220px;background-color:#ffffff;} select[multiple],select[size]{height:auto;} input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} textarea{height:auto;} input[type="hidden"]{display:none;} .radio,.checkbox{padding-left:18px;} .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;} input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} .input-mini{width:60px;} .input-small{width:90px;} .input-medium{width:150px;} .input-large{width:210px;} .input-xlarge{width:270px;} .input-xxlarge{width:530px;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:930px;} input.span11, textarea.span11, .uneditable-input.span11{width:850px;} input.span10, textarea.span10, .uneditable-input.span10{width:770px;} input.span9, textarea.span9, .uneditable-input.span9{width:690px;} input.span8, textarea.span8, .uneditable-input.span8{width:610px;} input.span7, textarea.span7, .uneditable-input.span7{width:530px;} input.span6, textarea.span6, .uneditable-input.span6{width:450px;} input.span5, textarea.span5, .uneditable-input.span5{width:370px;} input.span4, textarea.span4, .uneditable-input.span4{width:290px;} input.span3, textarea.span3, .uneditable-input.span3{width:210px;} input.span2, textarea.span2, .uneditable-input.span2{width:130px;} input.span1, textarea.span1, .uneditable-input.span1{width:50px;} input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#eeeeee;border-color:#ddd;cursor:not-allowed;} .control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} .control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} .control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} .control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} .control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} .control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} .form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#eeeeee;border-top:1px solid #ddd;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";} .form-actions:after{clear:both;} .uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} :-moz-placeholder{color:#999999;} ::-webkit-input-placeholder{color:#999999;} .help-block,.help-inline{color:#555555;} .help-block{display:block;margin-bottom:9px;} .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} .input-prepend,.input-append{margin-bottom:5px;}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{*margin-left:0;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;} .input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} .input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;min-width:16px;height:18px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #ffffff;vertical-align:middle;background-color:#eeeeee;border:1px solid #ccc;} .input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} .input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} .input-append input,.input-append select .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .input-append .uneditable-input{border-left-color:#eee;border-right-color:#ccc;} .input-append .add-on,.input-append .btn{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} .search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;margin-bottom:0;} .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} .form-search label,.form-inline label{display:inline-block;} .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-left:0;margin-right:3px;} .control-group{margin-bottom:9px;} legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} .form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} .form-horizontal .control-group:after{clear:both;} .form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;} .form-horizontal .controls{margin-left:160px;*display:inline-block;*margin-left:0;*padding-left:20px;} .form-horizontal .help-block{margin-top:9px;margin-bottom:0;} .form-horizontal .form-actions{padding-left:160px;} table{max-width:100%;border-collapse:collapse;border-spacing:0;background-color:transparent;} .table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} .table th{font-weight:bold;} .table thead th{vertical-align:bottom;} .table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} .table tbody+tbody{border-top:2px solid #dddddd;} .table-condensed th,.table-condensed td{padding:4px 5px;} .table-bordered{border:1px solid #dddddd;border-left:0;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} .table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} .table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} .table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} .table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} .table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} .table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} .table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;} table .span1{float:none;width:44px;margin-left:0;} table .span2{float:none;width:124px;margin-left:0;} table .span3{float:none;width:204px;margin-left:0;} table .span4{float:none;width:284px;margin-left:0;} table .span5{float:none;width:364px;margin-left:0;} table .span6{float:none;width:444px;margin-left:0;} table .span7{float:none;width:524px;margin-left:0;} table .span8{float:none;width:604px;margin-left:0;} table .span9{float:none;width:684px;margin-left:0;} table .span10{float:none;width:764px;margin-left:0;} table .span11{float:none;width:844px;margin-left:0;} table .span12{float:none;width:924px;margin-left:0;} table .span13{float:none;width:1004px;margin-left:0;} table .span14{float:none;width:1084px;margin-left:0;} table .span15{float:none;width:1164px;margin-left:0;} table .span16{float:none;width:1244px;margin-left:0;} table .span17{float:none;width:1324px;margin-left:0;} table .span18{float:none;width:1404px;margin-left:0;} table .span19{float:none;width:1484px;margin-left:0;} table .span20{float:none;width:1564px;margin-left:0;} table .span21{float:none;width:1644px;margin-left:0;} table .span22{float:none;width:1724px;margin-left:0;} table .span23{float:none;width:1804px;margin-left:0;} table .span24{float:none;width:1884px;margin-left:0;} [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;} .icon-white{background-image:url("../img/glyphicons-halflings-white.png");} .icon-glass{background-position:0 0;} .icon-music{background-position:-24px 0;} .icon-search{background-position:-48px 0;} .icon-envelope{background-position:-72px 0;} .icon-heart{background-position:-96px 0;} .icon-star{background-position:-120px 0;} .icon-star-empty{background-position:-144px 0;} .icon-user{background-position:-168px 0;} .icon-film{background-position:-192px 0;} .icon-th-large{background-position:-216px 0;} .icon-th{background-position:-240px 0;} .icon-th-list{background-position:-264px 0;} .icon-ok{background-position:-288px 0;} .icon-remove{background-position:-312px 0;} .icon-zoom-in{background-position:-336px 0;} .icon-zoom-out{background-position:-360px 0;} .icon-off{background-position:-384px 0;} .icon-signal{background-position:-408px 0;} .icon-cog{background-position:-432px 0;} .icon-trash{background-position:-456px 0;} .icon-home{background-position:0 -24px;} .icon-file{background-position:-24px -24px;} .icon-time{background-position:-48px -24px;} .icon-road{background-position:-72px -24px;} .icon-download-alt{background-position:-96px -24px;} .icon-download{background-position:-120px -24px;} .icon-upload{background-position:-144px -24px;} .icon-inbox{background-position:-168px -24px;} .icon-play-circle{background-position:-192px -24px;} .icon-repeat{background-position:-216px -24px;} .icon-refresh{background-position:-240px -24px;} .icon-list-alt{background-position:-264px -24px;} .icon-lock{background-position:-287px -24px;} .icon-flag{background-position:-312px -24px;} .icon-headphones{background-position:-336px -24px;} .icon-volume-off{background-position:-360px -24px;} .icon-volume-down{background-position:-384px -24px;} .icon-volume-up{background-position:-408px -24px;} .icon-qrcode{background-position:-432px -24px;} .icon-barcode{background-position:-456px -24px;} .icon-tag{background-position:0 -48px;} .icon-tags{background-position:-25px -48px;} .icon-book{background-position:-48px -48px;} .icon-bookmark{background-position:-72px -48px;} .icon-print{background-position:-96px -48px;} .icon-camera{background-position:-120px -48px;} .icon-font{background-position:-144px -48px;} .icon-bold{background-position:-167px -48px;} .icon-italic{background-position:-192px -48px;} .icon-text-height{background-position:-216px -48px;} .icon-text-width{background-position:-240px -48px;} .icon-align-left{background-position:-264px -48px;} .icon-align-center{background-position:-288px -48px;} .icon-align-right{background-position:-312px -48px;} .icon-align-justify{background-position:-336px -48px;} .icon-list{background-position:-360px -48px;} .icon-indent-left{background-position:-384px -48px;} .icon-indent-right{background-position:-408px -48px;} .icon-facetime-video{background-position:-432px -48px;} .icon-picture{background-position:-456px -48px;} .icon-pencil{background-position:0 -72px;} .icon-map-marker{background-position:-24px -72px;} .icon-adjust{background-position:-48px -72px;} .icon-tint{background-position:-72px -72px;} .icon-edit{background-position:-96px -72px;} .icon-share{background-position:-120px -72px;} .icon-check{background-position:-144px -72px;} .icon-move{background-position:-168px -72px;} .icon-step-backward{background-position:-192px -72px;} .icon-fast-backward{background-position:-216px -72px;} .icon-backward{background-position:-240px -72px;} .icon-play{background-position:-264px -72px;} .icon-pause{background-position:-288px -72px;} .icon-stop{background-position:-312px -72px;} .icon-forward{background-position:-336px -72px;} .icon-fast-forward{background-position:-360px -72px;} .icon-step-forward{background-position:-384px -72px;} .icon-eject{background-position:-408px -72px;} .icon-chevron-left{background-position:-432px -72px;} .icon-chevron-right{background-position:-456px -72px;} .icon-plus-sign{background-position:0 -96px;} .icon-minus-sign{background-position:-24px -96px;} .icon-remove-sign{background-position:-48px -96px;} .icon-ok-sign{background-position:-72px -96px;} .icon-question-sign{background-position:-96px -96px;} .icon-info-sign{background-position:-120px -96px;} .icon-screenshot{background-position:-144px -96px;} .icon-remove-circle{background-position:-168px -96px;} .icon-ok-circle{background-position:-192px -96px;} .icon-ban-circle{background-position:-216px -96px;} .icon-arrow-left{background-position:-240px -96px;} .icon-arrow-right{background-position:-264px -96px;} .icon-arrow-up{background-position:-289px -96px;} .icon-arrow-down{background-position:-312px -96px;} .icon-share-alt{background-position:-336px -96px;} .icon-resize-full{background-position:-360px -96px;} .icon-resize-small{background-position:-384px -96px;} .icon-plus{background-position:-408px -96px;} .icon-minus{background-position:-433px -96px;} .icon-asterisk{background-position:-456px -96px;} .icon-exclamation-sign{background-position:0 -120px;} .icon-gift{background-position:-24px -120px;} .icon-leaf{background-position:-48px -120px;} .icon-fire{background-position:-72px -120px;} .icon-eye-open{background-position:-96px -120px;} .icon-eye-close{background-position:-120px -120px;} .icon-warning-sign{background-position:-144px -120px;} .icon-plane{background-position:-168px -120px;} .icon-calendar{background-position:-192px -120px;} .icon-random{background-position:-216px -120px;} .icon-comment{background-position:-240px -120px;} .icon-magnet{background-position:-264px -120px;} .icon-chevron-up{background-position:-288px -120px;} .icon-chevron-down{background-position:-313px -119px;} .icon-retweet{background-position:-336px -120px;} .icon-shopping-cart{background-position:-360px -120px;} .icon-folder-close{background-position:-384px -120px;} .icon-folder-open{background-position:-408px -120px;} .icon-resize-vertical{background-position:-432px -119px;} .icon-resize-horizontal{background-position:-456px -118px;} .dropdown{position:relative;} .dropdown-toggle{*margin-bottom:-3px;} .dropdown-toggle:active,.open .dropdown-toggle{outline:0;} .caret{display:inline-block;width:0;height:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"";} .dropdown .caret{margin-top:8px;margin-left:2px;} .dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);} .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.pull-right{right:0;left:auto;} .dropdown-menu .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} .dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333333;white-space:nowrap;} .dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;} .dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} .dropdown.open .dropdown-menu{display:block;} .pull-right .dropdown-menu{left:auto;right:0;} .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"\2191";} .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} .typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} .well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} .well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} .collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;} .close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;} .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);border:1px solid #cccccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;} .btn:active,.btn.active{background-color:#cccccc \9;} .btn:first-child{*margin-left:0;} .btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} .btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;outline:0;} .btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} .btn-large [class^="icon-"]{margin-top:1px;} .btn-small{padding:5px 9px;font-size:11px;line-height:16px;} .btn-small [class^="icon-"]{margin-top:-1px;} .btn-mini{padding:2px 6px;font-size:11px;line-height:14px;} .btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} .btn-primary{background-color:#0074cc;background-image:-moz-linear-gradient(top, #0088cc, #0055cc);background-image:-ms-linear-gradient(top, #0088cc, #0055cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));background-image:-webkit-linear-gradient(top, #0088cc, #0055cc);background-image:-o-linear-gradient(top, #0088cc, #0055cc);background-image:linear-gradient(top, #0088cc, #0055cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);border-color:#0055cc #0055cc #003580;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0055cc;} .btn-primary:active,.btn-primary.active{background-color:#004099 \9;} .btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;} .btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} .btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;} .btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} .btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} .btn-success:active,.btn-success.active{background-color:#408140 \9;} .btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;} .btn-info:active,.btn-info.active{background-color:#24748c \9;} .btn-inverse{background-color:#414141;background-image:-moz-linear-gradient(top, #555555, #222222);background-image:-ms-linear-gradient(top, #555555, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));background-image:-webkit-linear-gradient(top, #555555, #222222);background-image:-o-linear-gradient(top, #555555, #222222);background-image:linear-gradient(top, #555555, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222222;} .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} .btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";} .btn-group:after{clear:both;} .btn-group:first-child{*margin-left:0;} .btn-group+.btn-group{margin-left:5px;} .btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;} .btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} .btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} .btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} .btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} .btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;} .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} .btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:3px;*padding-bottom:3px;} .btn-group .btn-mini.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:1px;*padding-bottom:1px;} .btn-group .btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px;} .btn-group .btn-large.dropdown-toggle{padding-left:12px;padding-right:12px;} .btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);} .btn .caret{margin-top:7px;margin-left:0;} .btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);} .btn-mini .caret{margin-top:5px;} .btn-small .caret{margin-top:6px;} .btn-large .caret{margin-top:6px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);} .alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;} .alert-heading{color:inherit;} .alert .close{position:relative;top:-2px;right:-21px;line-height:18px;} .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} .alert-block{padding-top:14px;padding-bottom:14px;} .alert-block>p,.alert-block>ul{margin-bottom:0;} .alert-block p+p{margin-top:5px;} .nav{margin-left:0;margin-bottom:18px;list-style:none;} .nav>li>a{display:block;} .nav>li>a:hover{text-decoration:none;background-color:#eeeeee;} .nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} .nav li+.nav-header{margin-top:9px;} .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} .nav-list>li>a{padding:3px 15px;} .nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} .nav-list [class^="icon-"]{margin-right:2px;} .nav-list .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} .nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";} .nav-tabs:after,.nav-pills:after{clear:both;} .nav-tabs>li,.nav-pills>li{float:left;} .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} .nav-tabs{border-bottom:1px solid #ddd;} .nav-tabs>li{margin-bottom:-1px;} .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;} .nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} .nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;} .nav-stacked>li{float:none;} .nav-stacked>li>a{margin-right:0;} .nav-tabs.nav-stacked{border-bottom:0;} .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} .nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;} .nav-pills.nav-stacked>li>a{margin-bottom:3px;} .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} .nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;} .nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;} .nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;} .nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333;} .nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;} .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;} .nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} .tabs-stacked .open>a:hover{border-color:#999999;} .tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";} .tabbable:after{clear:both;} .tab-content{display:table;width:100%;} .tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;} .tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} .tab-content>.active,.pill-content>.active{display:block;} .tabs-below .nav-tabs{border-top:1px solid #ddd;} .tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;} .tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;} .tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;} .tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;} .tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} .tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} .tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} .tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} .tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} .tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} .tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} .tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} .tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} .navbar{*position:relative;*z-index:2;overflow:visible;margin-bottom:18px;} .navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} .navbar .container{width:auto;} .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;} .btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;} .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} .btn-navbar .icon-bar+.icon-bar{margin-top:3px;} .nav-collapse.collapse{height:auto;} .navbar{color:#999999;}.navbar .brand:hover{text-decoration:none;} .navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;} .navbar .navbar-text{margin-bottom:0;line-height:40px;} .navbar .btn,.navbar .btn-group{margin-top:5px;} .navbar .btn-group .btn{margin-top:0;} .navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";} .navbar-form:after{clear:both;} .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} .navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0;} .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} .navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} .navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;background-color:#626262;border:1px solid #151515;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query:-moz-placeholder{color:#cccccc;} .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} .navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} .navbar-fixed-top{top:0;} .navbar-fixed-bottom{bottom:0;} .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} .navbar .nav.pull-right{float:right;} .navbar .nav>li{display:block;float:left;} .navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} .navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;} .navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;} .navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;} .navbar .nav.pull-right{margin-left:10px;margin-right:0;} .navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} .navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} .navbar-fixed-bottom .dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} .navbar-fixed-bottom .dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} .navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} .navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);} .navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;} .navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;} .navbar .nav.pull-right .dropdown-menu,.navbar .nav .dropdown-menu.pull-right{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before,.navbar .nav .dropdown-menu.pull-right:before{left:auto;right:12px;} .navbar .nav.pull-right .dropdown-menu:after,.navbar .nav .dropdown-menu.pull-right:after{left:auto;right:13px;} .breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;} .breadcrumb .divider{padding:0 5px;color:#999999;} .breadcrumb .active a{color:#333333;} .pagination{height:36px;margin:18px 0;} .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} .pagination li{display:inline;} .pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;} .pagination a:hover,.pagination .active a{background-color:#f5f5f5;} .pagination .active a{color:#999999;cursor:default;} .pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;} .pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} .pagination-centered{text-align:center;} .pagination-right{text-align:right;} .pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";} .pager:after{clear:both;} .pager li{display:inline;} .pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} .pager a:hover{text-decoration:none;background-color:#f5f5f5;} .pager .next a{float:right;} .pager .previous a{float:left;} .pager .disabled a,.pager .disabled a:hover{color:#999999;background-color:#fff;cursor:default;} .modal-open .dropdown-menu{z-index:2050;} .modal-open .dropdown.open{*z-index:2050;} .modal-open .popover{z-index:2060;} .modal-open .tooltip{z-index:2070;} .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} .modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} .modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} .modal.fade.in{top:50%;} .modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} .modal-body{overflow-y:auto;max-height:400px;padding:15px;} .modal-form{margin-bottom:0;} .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";} .modal-footer:after{clear:both;} .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} .modal-footer .btn-group .btn+.btn{margin-left:-1px;} .tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} .tooltip.top{margin-top:-2px;} .tooltip.right{margin-left:2px;} .tooltip.bottom{margin-top:2px;} .tooltip.left{margin-left:-2px;} .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} .tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .tooltip-arrow{position:absolute;width:0;height:0;} .popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;} .popover.right{margin-left:5px;} .popover.bottom{margin-top:5px;} .popover.left{margin-left:-5px;} .popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} .popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} .popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} .popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} .popover .arrow{position:absolute;width:0;height:0;} .popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} .popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;} .popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;} .thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";} .thumbnails:after{clear:both;} .thumbnails>li{float:left;margin:0 0 18px 20px;} .thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);} a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} .thumbnail .caption{padding:9px;} .label{padding:1px 4px 2px;font-size:10.998px;font-weight:bold;line-height:13px;color:#ffffff;vertical-align:middle;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .label:hover{color:#ffffff;text-decoration:none;} .label-important{background-color:#b94a48;} .label-important:hover{background-color:#953b39;} .label-warning{background-color:#f89406;} .label-warning:hover{background-color:#c67605;} .label-success{background-color:#468847;} .label-success:hover{background-color:#356635;} .label-info{background-color:#3a87ad;} .label-info:hover{background-color:#2d6987;} .label-inverse{background-color:#333333;} .label-inverse:hover{background-color:#1a1a1a;} .badge{padding:1px 9px 2px;font-size:12.025px;font-weight:bold;white-space:nowrap;color:#ffffff;background-color:#999999;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} .badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;} .badge-error{background-color:#b94a48;} .badge-error:hover{background-color:#953b39;} .badge-warning{background-color:#f89406;} .badge-warning:hover{background-color:#c67605;} .badge-success{background-color:#468847;} .badge-success:hover{background-color:#356635;} .badge-info{background-color:#3a87ad;} .badge-info:hover{background-color:#2d6987;} .badge-inverse{background-color:#333333;} .badge-inverse:hover{background-color:#1a1a1a;} @-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} .progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);} .progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);} .progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);} .progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);} .progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .accordion{margin-bottom:18px;} .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .accordion-heading{border-bottom:0;} .accordion-heading .accordion-toggle{display:block;padding:8px 15px;} .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} .carousel{position:relative;margin-bottom:18px;line-height:1;} .carousel-inner{overflow:hidden;width:100%;position:relative;} .carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;} .carousel .item>img{display:block;line-height:1;} .carousel .active,.carousel .next,.carousel .prev{display:block;} .carousel .active{left:0;} .carousel .next,.carousel .prev{position:absolute;top:0;width:100%;} .carousel .next{left:100%;} .carousel .prev{left:-100%;} .carousel .next.left,.carousel .prev.right{left:0;} .carousel .active.left{left:-100%;} .carousel .active.right{left:100%;} .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} .carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);} .carousel-caption h4,.carousel-caption p{color:#ffffff;} .hero-unit{padding:60px;margin-bottom:30px;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} .hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit;} .pull-right{float:right;} .pull-left{float:left;} .hide{display:none;} .show{display:block;} .invisible{visibility:hidden;} flask-peewee-0.6.7/flask_peewee/static/css/admin.css0000644000175000001440000000210312574421673023216 0ustar charlesusers00000000000000html, body { background-color: #fff; } body { padding-top: 60px; } .container > footer p { text-align: center; /* center align it with the container */ } /* The white background content wrapper */ .content { background-color: #fff; -webkit-border-radius: 0 0 6px 6px; -moz-border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px; } /* modeladmin filters */ form.modeladmin-filters { margin: 0; } form.modeladmin-filters ul { list-style-type: none; } form.modeladmin-filters select { margin-right: 10px; } div.form-wrapper { width: 100%; overflow: auto; } form textarea { height: 150px; } form input[type="text"].datetime-widget { width: 100px; margin-right: 10px; } div.sidebar li.active { font-weight: bold; } table.table-striped td.links .inline { margin: 0; } table.table-striped td.links .inline li { display: inline-block; } table.table-striped td.links .inline li a { border-right: 1px solid #DDDDDD; padding-right: 5px; } table.table-striped td.links .inline li:last-child a { border-right: medium none; } /* helpers */ .hidden { display: none; } flask-peewee-0.6.7/flask_peewee/static/js/0000755000175000001440000000000012624225533021235 5ustar charlesusers00000000000000flask-peewee-0.6.7/flask_peewee/static/js/jquery.min.js0000644000175000001440000026725412574421673023723 0ustar charlesusers00000000000000/*! jQuery v1.7.1 jquery.com | jquery.org/license */ (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
    a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
    "+""+"
    ",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
    t
    ",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
    ",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() {for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); flask-peewee-0.6.7/flask_peewee/static/js/events.js0000644000175000001440000000730012574421673023106 0ustar charlesusers00000000000000/* SimplEE, A simple EventEmitter utility library for client-side use. Mimics Node.js's EventEmitter object. Author: Chris Dickinson Source: https://github.com/chrisdickinson/simplee Copyright (c) 2011, Chris Dickinson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of SimplEE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- use -- var ajaxResult = function(endpoint, data) { var ee = new SimplEE.EventEmitter(); $.ajax({ 'url':endpoint, 'type':'POST', 'data':data, 'success':ee.emit.bind(ee, 'data'), 'error':ee.emit.bind(ee, 'error') }); return ee; }; ajaxResult('/something/', {}). on('data', function() { // do something }). on('error', function() { // attempt to recover }); -- global events -- var Renderer = function() { }; Renderer.prototype.renderSomething = SimplEE.emits('rendered', function(obj) { return [obj, "
    "]; }); SimplEE.global.on('rendered', function(obj, html) { // do something }); */ var Events = (typeof window !== 'undefined') ? window.Events || {} : exports; (function(exports) { var slice = Array.prototype.slice; var EventEmitter = function() { this._listeners = {}; }; EventEmitter.prototype.on = function(name, fn) { this._listeners[name] = this._listeners[name] || []; this._listeners[name].push(fn); return this; }; EventEmitter.prototype.remove = function(name, fn) { fn && this._listeners[name] && this._listeners[name].splice(this._listeners[name].indexOf(fn), 1); }; EventEmitter.prototype.emit = function(name) { var listeners = this._listeners[name] || [], args = slice.call(arguments, 1); for(var i = 0, len = listeners.length; i < len; ++i) { try { listeners[i].apply(this, args); } catch(err) { this.emit('error', err); } } }; EventEmitter.prototype.emits = function(name, fn) { var ee = this; return function() { var args = slice.call(arguments), result = fn.apply(this, args), emit = result instanceof Array ? result : [result]; // destructuring emit ee.emit.apply(ee, [name].concat(emit)); return result; }; }; exports.EventEmitter = EventEmitter; exports.global = new EventEmitter(); exports.emits = function() { return exports.global.emits.apply(exports.global, slice.call(arguments)); }; })(Events); flask-peewee-0.6.7/flask_peewee/static/js/ajax-chosen.min.js0000644000175000001440000000433612574421673024572 0ustar charlesusers00000000000000 (function($){return $.fn.ajaxChosen=function(settings,callback,chosenOptions){var chosenXhr,defaultOptions,options,select;if(settings==null){settings={};} if(callback==null){callback={};} if(chosenOptions==null){chosenOptions=function(){};} defaultOptions={minTermLength:3,afterTypeDelay:500,jsonTermKey:"term"};select=this;chosenXhr=null;options=$.extend({},defaultOptions,$(select).data(),settings);this.chosen(chosenOptions?chosenOptions:{});return this.each(function(){return $(this).next('.chzn-container').find(".search-field > input, .chzn-search > input").bind('keyup',function(){var field,msg,success,untrimmed_val,val;untrimmed_val=$(this).attr('value');val=$.trim($(this).attr('value'));msg=val.length").attr('label',element.text).appendTo(select);return $.each(element.items,function(value,text){if($.inArray(value+"-"+text,selected_values)===-1){return $("
    '; while (dowCnt < this.weekStart + 7) { html += ''; } html += ''; this.picker.find('.datepicker-days thead').append(html); }, fillMonths: function(){ var html = ''; var i = 0 while (i < 12) { html += ''+DPGlobal.dates.monthsShort[i++]+''; } this.picker.find('.datepicker-months td').append(html); }, fill: function() { var d = new Date(this.viewDate), year = d.getFullYear(), month = d.getMonth(), currentDate = this.date.valueOf(); this.picker.find('.datepicker-days th:eq(1)') .text(DPGlobal.dates.months[month]+' '+year); var prevMonth = new Date(year, month-1, 28,0,0,0,0), day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); prevMonth.setDate(day); prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); var nextMonth = new Date(prevMonth); nextMonth.setDate(nextMonth.getDate() + 42); nextMonth = nextMonth.valueOf(); html = []; var clsName; while(prevMonth.valueOf() < nextMonth) { if (prevMonth.getDay() == this.weekStart) { html.push(''); } clsName = ''; if (prevMonth.getMonth() < month) { clsName += ' old'; } else if (prevMonth.getMonth() > month) { clsName += ' new'; } if (prevMonth.valueOf() == currentDate) { clsName += ' active'; } html.push(''); if (prevMonth.getDay() == this.weekEnd) { html.push(''); } prevMonth.setDate(prevMonth.getDate()+1); } this.picker.find('.datepicker-days tbody').empty().append(html.join('')); var currentYear = this.date.getFullYear(); var months = this.picker.find('.datepicker-months') .find('th:eq(1)') .text(year) .end() .find('span').removeClass('active'); if (currentYear == year) { months.eq(this.date.getMonth()).addClass('active'); } html = ''; year = parseInt(year/10, 10) * 10; var yearCont = this.picker.find('.datepicker-years') .find('th:eq(1)') .text(year + '-' + (year + 9)) .end() .find('td'); year -= 1; for (var i = -1; i < 11; i++) { html += ''+year+''; year += 1; } yearCont.html(html); }, click: function(e) { e.stopPropagation(); e.preventDefault(); var target = $(e.target).closest('span, td, th'); if (target.length == 1) { switch(target[0].nodeName.toLowerCase()) { case 'th': switch(target[0].className) { case 'switch': this.showMode(1); break; case 'prev': case 'next': this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( this.viewDate, this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1) ); this.fill(); break; } break; case 'span': if (target.is('.month')) { var month = target.parent().find('span').index(target); this.viewDate.setMonth(month); } else { var year = parseInt(target.text(), 10)||0; this.viewDate.setFullYear(year); } this.showMode(-1); this.fill(); break; case 'td': if (target.is('.day')){ var day = parseInt(target.text(), 10)||1; var month = this.viewDate.getMonth(); if (target.is('.old')) { month -= 1; } else if (target.is('.new')) { month += 1; } var year = this.viewDate.getFullYear(); this.date = new Date(year, month, day,0,0,0,0); this.viewDate = new Date(year, month, day,0,0,0,0); this.fill(); this.setValue(); this.element.trigger({ type: 'changeDate', date: this.date }); } break; } } }, mousedown: function(e){ e.stopPropagation(); e.preventDefault(); }, showMode: function(dir) { if (dir) { this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir)); } this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); } }; $.fn.datepicker = function ( option ) { return this.each(function () { var $this = $(this), data = $this.data('datepicker'), options = typeof option == 'object' && option; if (!data) { $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); } if (typeof option == 'string') data[option](); }); }; $.fn.datepicker.defaults = { }; $.fn.datepicker.Constructor = Datepicker; var DPGlobal = { modes: [ { clsName: 'days', navFnc: 'Month', navStep: 1 }, { clsName: 'months', navFnc: 'FullYear', navStep: 1 }, { clsName: 'years', navFnc: 'FullYear', navStep: 10 }], dates:{ days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] }, isLeapYear: function (year) { return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) }, getDaysInMonth: function (year, month) { return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] }, parseFormat: function(format){ var separator = format.match(/[.\/-].*?/), parts = format.split(/\W+/); if (!separator || !parts || parts.length == 0){ throw new Error("Invalid date format."); } return {separator: separator, parts: parts}; }, parseDate: function(date, format) { var parts = date.split(format.separator), date = new Date(1970, 1, 1, 0, 0, 0), val; if (parts.length == format.parts.length) { for (var i=0, cnt = format.parts.length; i < cnt; i++) { val = parseInt(parts[i], 10)||1; switch(format.parts[i]) { case 'dd': case 'd': date.setDate(val); break; case 'mm': case 'm': date.setMonth(val - 1); break; case 'yy': date.setFullYear(2000 + val); break; case 'yyyy': date.setFullYear(val); break; } } } return date; }, formatDate: function(date, format){ var val = { d: date.getDate(), m: date.getMonth() + 1, yy: date.getFullYear().toString().substring(2), yyyy: date.getFullYear() }; val.dd = (val.d < 10 ? '0' : '') + val.d; val.mm = (val.m < 10 ? '0' : '') + val.m; var date = []; for (var i=0, cnt = format.parts.length; i < cnt; i++) { date.push(val[format.parts[i]]); } return date.join(format.separator); }, headTemplate: ''+ ''+ ''+ ''+ ''+ ''+ '', contTemplate: '' }; DPGlobal.template = '
    '+DPGlobal.dates.daysMin[(dowCnt++)%7]+'
    '+prevMonth.getDate() + '
    '+ DPGlobal.headTemplate+ ''+ '
    '+ '
    '+ '
    '+ ''+ DPGlobal.headTemplate+ DPGlobal.contTemplate+ '
    '+ '
    '+ '
    '+ ''+ DPGlobal.headTemplate+ DPGlobal.contTemplate+ '
    '+ '
    '+ ''; }( window.jQuery )flask-peewee-0.6.7/flask_peewee/static/js/chosen.jquery.min.js0000644000175000001440000005463412574421673025175 0ustar charlesusers00000000000000// Chosen, a Select Box Enhancer for jQuery and Protoype // by Patrick Filler for Harvest, http://getharvest.com // // Version 0.9.8 // Full source at https://github.com/harvesthq/chosen // Copyright (c) 2011 Harvest http://getharvest.com // MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md // This file is generated by `cake build`, do not edit it by hand. ((function(){var a;a=function(){function a(){this.options_index=0,this.parsed=[]}return a.prototype.add_node=function(a){return a.nodeName==="OPTGROUP"?this.add_group(a):this.add_option(a)},a.prototype.add_group=function(a){var b,c,d,e,f,g;b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:a.label,children:0,disabled:a.disabled}),f=a.childNodes,g=[];for(d=0,e=f.length;d"+a.html+"")},a.prototype.results_update_field=function(){return this.is_multiple||this.results_reset_cleanup(),this.result_clear_highlight(),this.result_single_selected=null,this.results_build()},a.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},a.prototype.results_search=function(a){return this.results_showing?this.winnow_results():this.results_show()},a.prototype.keyup_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale();switch(b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:a.preventDefault();if(this.results_showing)return this.result_select(a);break;case 27:return this.results_showing&&this.results_hide(),!0;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},a.prototype.generate_field_id=function(){var a;return a=this.generate_random_id(),this.form_field.id=a,a},a.prototype.generate_random_char=function(){var a,b,c;return a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",c=Math.floor(Math.random()*a.length),b=a.substring(c,c+1)},a}(),b.AbstractChosen=a}.call(this),function(){var a,b,c,d,e=Object.prototype.hasOwnProperty,f=function(a,b){function d(){this.constructor=a}for(var c in b)e.call(b,c)&&(a[c]=b[c]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a};d=this,a=jQuery,a.fn.extend({chosen:function(c){return!a.browser.msie||a.browser.version!=="6.0"&&a.browser.version!=="7.0"?this.each(function(d){var e;e=a(this);if(!e.hasClass("chzn-done"))return e.data("chosen",new b(this,c))}):this}}),b=function(b){function e(){e.__super__.constructor.apply(this,arguments)}return f(e,b),e.prototype.setup=function(){return this.form_field_jq=a(this.form_field),this.current_value=this.form_field_jq.val(),this.is_rtl=this.form_field_jq.hasClass("chzn-rtl")},e.prototype.finish_setup=function(){return this.form_field_jq.addClass("chzn-done")},e.prototype.set_up_html=function(){var b,d,e,f;return this.container_id=this.form_field.id.length?this.form_field.id.replace(/[^\w]/g,"_"):this.generate_field_id(),this.container_id+="_chzn",this.f_width=this.form_field_jq.outerWidth(),b=a("
    ",{id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px;"}),this.is_multiple?b.html('
      '):b.html(''+this.default_text+'
        '),this.form_field_jq.hide().after(b),this.container=a("#"+this.container_id),this.container.addClass("chzn-container-"+(this.is_multiple?"multi":"single")),this.dropdown=this.container.find("div.chzn-drop").first(),d=this.container.height(),e=this.f_width-c(this.dropdown),this.dropdown.css({width:e+"px",top:d+"px"}),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chzn-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chzn-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chzn-search").first(),this.selected_item=this.container.find(".chzn-single").first(),f=e-c(this.search_container)-c(this.search_field),this.search_field.css({width:f+"px"})),this.results_build(),this.set_tab_index(),this.form_field_jq.trigger("liszt:ready",{chosen:this})},e.prototype.register_observers=function(){var a=this;return this.container.mousedown(function(b){return a.container_mousedown(b)}),this.container.mouseup(function(b){return a.container_mouseup(b)}),this.container.mouseenter(function(b){return a.mouse_enter(b)}),this.container.mouseleave(function(b){return a.mouse_leave(b)}),this.search_results.mouseup(function(b){return a.search_results_mouseup(b)}),this.search_results.mouseover(function(b){return a.search_results_mouseover(b)}),this.search_results.mouseout(function(b){return a.search_results_mouseout(b)}),this.form_field_jq.bind("liszt:updated",function(b){return a.results_update_field(b)}),this.search_field.blur(function(b){return a.input_blur(b)}),this.search_field.keyup(function(b){return a.keyup_checker(b)}),this.search_field.keydown(function(b){return a.keydown_checker(b)}),this.is_multiple?(this.search_choices.click(function(b){return a.choices_click(b)}),this.search_field.focus(function(b){return a.input_focus(b)})):this.container.click(function(a){return a.preventDefault()})},e.prototype.search_field_disabled=function(){this.is_disabled=this.form_field_jq[0].disabled;if(this.is_disabled)return this.container.addClass("chzn-disabled"),this.search_field[0].disabled=!0,this.is_multiple||this.selected_item.unbind("focus",this.activate_action),this.close_field();this.container.removeClass("chzn-disabled"),this.search_field[0].disabled=!1;if(!this.is_multiple)return this.selected_item.bind("focus",this.activate_action)},e.prototype.container_mousedown=function(b){var c;if(!this.is_disabled)return c=b!=null?a(b.target).hasClass("search-choice-close"):!1,b&&b.type==="mousedown"&&!this.results_showing&&b.stopPropagation(),!this.pending_destroy_click&&!c?(this.active_field?!this.is_multiple&&b&&(a(b.target)[0]===this.selected_item[0]||a(b.target).parents("a.chzn-single").length)&&(b.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),a(document).click(this.click_test_action),this.results_show()),this.activate_field()):this.pending_destroy_click=!1},e.prototype.container_mouseup=function(a){if(a.target.nodeName==="ABBR"&&!this.is_disabled)return this.results_reset(a)},e.prototype.blur_test=function(a){if(!this.active_field&&this.container.hasClass("chzn-container-active"))return this.close_field()},e.prototype.close_field=function(){return a(document).unbind("click",this.click_test_action),this.is_multiple||(this.selected_item.attr("tabindex",this.search_field.attr("tabindex")),this.search_field.attr("tabindex",-1)),this.active_field=!1,this.results_hide(),this.container.removeClass("chzn-container-active"),this.winnow_results_clear(),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},e.prototype.activate_field=function(){return!this.is_multiple&&!this.active_field&&(this.search_field.attr("tabindex",this.selected_item.attr("tabindex")),this.selected_item.attr("tabindex",-1)),this.container.addClass("chzn-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},e.prototype.test_active_click=function(b){return a(b.target).parents("#"+this.container_id).length?this.active_field=!0:this.close_field()},e.prototype.results_build=function(){var a,b,c,e,f;this.parsing=!0,this.results_data=d.SelectParser.select_to_array(this.form_field),this.is_multiple&&this.choices>0?(this.search_choices.find("li.search-choice").remove(),this.choices=0):this.is_multiple||(this.selected_item.addClass("chzn-default").find("span").text(this.default_text),this.form_field.options.length<=this.disable_search_threshold?this.container.addClass("chzn-container-single-nosearch"):this.container.removeClass("chzn-container-single-nosearch")),a="",f=this.results_data;for(c=0,e=f.length;c'+a("
        ").text(b.label).html()+"")},e.prototype.result_do_highlight=function(a){var b,c,d,e,f;if(a.length){this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClass("highlighted"),d=parseInt(this.search_results.css("maxHeight"),10),f=this.search_results.scrollTop(),e=d+f,c=this.result_highlight.position().top+this.search_results.scrollTop(),b=c+this.result_highlight.outerHeight();if(b>=e)return this.search_results.scrollTop(b-d>0?b-d:0);if(c'+b.html+''),d=a("#"+c).find("a").first(),d.click(function(a){return e.choice_destroy_link_click(a)}))},e.prototype.choice_destroy_link_click=function(b){return b.preventDefault(),this.is_disabled?b.stopPropagation:(this.pending_destroy_click=!0,this.choice_destroy(a(b.target)))},e.prototype.choice_destroy=function(a){return this.choices-=1,this.show_search_field_default(),this.is_multiple&&this.choices>0&&this.search_field.val().length<1&&this.results_hide(),this.result_deselect(a.attr("rel")),a.parents("li").first().remove()},e.prototype.results_reset=function(){this.form_field.options[0].selected=!0,this.selected_item.find("span").text(this.default_text),this.is_multiple||this.selected_item.addClass("chzn-default"),this.show_search_field_default(),this.results_reset_cleanup(),this.form_field_jq.trigger("change");if(this.active_field)return this.results_hide()},e.prototype.results_reset_cleanup=function(){return this.selected_item.find("abbr").remove()},e.prototype.result_select=function(a){var b,c,d,e;if(this.result_highlight)return b=this.result_highlight,c=b.attr("id"),this.result_clear_highlight(),this.is_multiple?this.result_deactivate(b):(this.search_results.find(".result-selected").removeClass("result-selected"),this.result_single_selected=b,this.selected_item.removeClass("chzn-default")),b.addClass("result-selected"),e=c.substr(c.lastIndexOf("_")+1),d=this.results_data[e],d.selected=!0,this.form_field.options[d.options_index].selected=!0,this.is_multiple?this.choice_build(d):(this.selected_item.find("span").first().text(d.text),this.allow_single_deselect&&this.single_deselect_control_build()),(!a.metaKey||!this.is_multiple)&&this.results_hide(),this.search_field.val(""),(this.is_multiple||this.form_field_jq.val()!==this.current_value)&&this.form_field_jq.trigger("change",{selected:this.form_field.options[d.options_index].value}),this.current_value=this.form_field_jq.val(),this.search_field_scale()},e.prototype.result_activate=function(a){return a.addClass("active-result")},e.prototype.result_deactivate=function(a){return a.removeClass("active-result")},e.prototype.result_deselect=function(b){var c,d;return d=this.results_data[b],d.selected=!1,this.form_field.options[d.options_index].selected=!1,c=a("#"+this.container_id+"_o_"+b),c.removeClass("result-selected").addClass("active-result").show(),this.result_clear_highlight(),this.winnow_results(),this.form_field_jq.trigger("change",{deselected:this.form_field.options[d.options_index].value}),this.search_field_scale()},e.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect&&this.selected_item.find("abbr").length<1)return this.selected_item.find("span").first().after('')},e.prototype.winnow_results=function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s;this.no_results_clear(),j=0,k=this.search_field.val()===this.default_text?"":a("
        ").text(a.trim(this.search_field.val())).html(),g=this.search_contains?"":"^",f=new RegExp(g+k.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),n=new RegExp(k.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),s=this.results_data;for(o=0,q=s.length;o=0||c.html.indexOf("[")===0){e=c.html.replace(/\[|\]/g,"").split(" ");if(e.length)for(p=0,r=e.length;p"+c.html.substr(l+k.length),m=m.substr(0,l)+""+m.substr(l)):m=c.html,h.html(m),this.result_activate(h),c.group_array_index!=null&&a("#"+this.results_data[c.group_array_index].dom_id).css("display","list-item")):(this.result_highlight&&i===this.result_highlight.attr("id")&&this.result_clear_highlight(),this.result_deactivate(h))}}return j<1&&k.length?this.no_results(k):this.winnow_results_set_highlight()},e.prototype.winnow_results_clear=function(){var b,c,d,e,f;this.search_field.val(""),c=this.search_results.find("li"),f=[];for(d=0,e=c.length;d'+this.results_none_found+' ""'),c.find("span").first().html(b),this.search_results.append(c)},e.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},e.prototype.keydown_arrow=function(){var b,c;this.result_highlight?this.results_showing&&(c=this.result_highlight.nextAll("li.active-result").first(),c&&this.result_do_highlight(c)):(b=this.search_results.find("li.active-result").first(),b&&this.result_do_highlight(a(b)));if(!this.results_showing)return this.results_show()},e.prototype.keyup_arrow=function(){var a;if(!this.results_showing&&!this.is_multiple)return this.results_show();if(this.result_highlight)return a=this.result_highlight.prevAll("li.active-result"),a.length?this.result_do_highlight(a.first()):(this.choices>0&&this.results_hide(),this.result_clear_highlight())},e.prototype.keydown_backstroke=function(){return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(this.pending_backstroke=this.search_container.siblings("li.search-choice").last(),this.single_backstroke_delete?this.keydown_backstroke():this.pending_backstroke.addClass("search-choice-focus"))},e.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},e.prototype.keydown_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale(),b!==8&&this.pending_backstroke&&this.clear_backstroke();switch(b){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:this.keydown_arrow()}},e.prototype.search_field_scale=function(){var b,c,d,e,f,g,h,i,j;if(this.is_multiple){d=0,h=0,f="position:absolute; left: -1000px; top: -1000px; display:none;",g=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(i=0,j=g.length;i",{style:f}),c.text(this.search_field.val()),a("body").append(c),h=c.width()+25,c.remove(),h>this.f_width-10&&(h=this.f_width-10),this.search_field.css({width:h+"px"}),b=this.container.height(),this.dropdown.css({top:b+"px"})}},e.prototype.generate_random_id=function(){var b;b="sel"+this.generate_random_char()+this.generate_random_char()+this.generate_random_char();while(a("#"+b).length>0)b+=this.generate_random_char();return b},e}(AbstractChosen),c=function(a){var b;return b=a.outerWidth()-a.width()},d.get_side_border_padding=c}.call(this); flask-peewee-0.6.7/flask_peewee/static/js/bootstrap.js0000644000175000001440000013540312574421673023625 0ustar charlesusers00000000000000/* =================================================== * bootstrap-transition.js v2.0.2 * http://twitter.github.com/bootstrap/javascript.html#transitions * =================================================== * Copyright 2012 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ========================================================== */ !function( $ ) { $(function () { "use strict" /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) * ======================================================= */ $.support.transition = (function () { var thisBody = document.body || document.documentElement , thisStyle = thisBody.style , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined return support && { end: (function () { var transitionEnd = "TransitionEnd" if ( $.browser.webkit ) { transitionEnd = "webkitTransitionEnd" } else if ( $.browser.mozilla ) { transitionEnd = "transitionend" } else if ( $.browser.opera ) { transitionEnd = "oTransitionEnd" } return transitionEnd }()) } })() }) }( window.jQuery );/* ========================================================== * bootstrap-alert.js v2.0.2 * http://twitter.github.com/bootstrap/javascript.html#alerts * ========================================================== * Copyright 2012 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ========================================================== */ !function( $ ){ "use strict" /* ALERT CLASS DEFINITION * ====================== */ var dismiss = '[data-dismiss="alert"]' , Alert = function ( el ) { $(el).on('click', dismiss, this.close) } Alert.prototype = { constructor: Alert , close: function ( e ) { var $this = $(this) , selector = $this.attr('data-target') , $parent if (!selector) { selector = $this.attr('href') selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 } $parent = $(selector) $parent.trigger('close') e && e.preventDefault() $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) $parent .trigger('close') .removeClass('in') function removeElement() { $parent .trigger('closed') .remove() } $.support.transition && $parent.hasClass('fade') ? $parent.on($.support.transition.end, removeElement) : removeElement() } } /* ALERT PLUGIN DEFINITION * ======================= */ $.fn.alert = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('alert') if (!data) $this.data('alert', (data = new Alert(this))) if (typeof option == 'string') data[option].call($this) }) } $.fn.alert.Constructor = Alert /* ALERT DATA-API * ============== */ $(function () { $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) }) }( window.jQuery );/* ============================================================ * bootstrap-button.js v2.0.2 * http://twitter.github.com/bootstrap/javascript.html#buttons * ============================================================ * Copyright 2012 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================ */ !function( $ ){ "use strict" /* BUTTON PUBLIC CLASS DEFINITION * ============================== */ var Button = function ( element, options ) { this.$element = $(element) this.options = $.extend({}, $.fn.button.defaults, options) } Button.prototype = { constructor: Button , setState: function ( state ) { var d = 'disabled' , $el = this.$element , data = $el.data() , val = $el.is('input') ? 'val' : 'html' state = state + 'Text' data.resetText || $el.data('resetText', $el[val]()) $el[val](data[state] || this.options[state]) // push to event loop to allow forms to submit setTimeout(function () { state == 'loadingText' ? $el.addClass(d).attr(d, d) : $el.removeClass(d).removeAttr(d) }, 0) } , toggle: function () { var $parent = this.$element.parent('[data-toggle="buttons-radio"]') $parent && $parent .find('.active') .removeClass('active') this.$element.toggleClass('active') } } /* BUTTON PLUGIN DEFINITION * ======================== */ $.fn.button = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('button') , options = typeof option == 'object' && option if (!data) $this.data('button', (data = new Button(this, options))) if (option == 'toggle') data.toggle() else if (option) data.setState(option) }) } $.fn.button.defaults = { loadingText: 'loading...' } $.fn.button.Constructor = Button /* BUTTON DATA-API * =============== */ $(function () { $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { var $btn = $(e.target) if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') $btn.button('toggle') }) }) }( window.jQuery );/* ========================================================== * bootstrap-carousel.js v2.0.2 * http://twitter.github.com/bootstrap/javascript.html#carousel * ========================================================== * Copyright 2012 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ========================================================== */ !function( $ ){ "use strict" /* CAROUSEL CLASS DEFINITION * ========================= */ var Carousel = function (element, options) { this.$element = $(element) this.options = $.extend({}, $.fn.carousel.defaults, options) this.options.slide && this.slide(this.options.slide) this.options.pause == 'hover' && this.$element .on('mouseenter', $.proxy(this.pause, this)) .on('mouseleave', $.proxy(this.cycle, this)) } Carousel.prototype = { cycle: function () { this.interval = setInterval($.proxy(this.next, this), this.options.interval) return this } , to: function (pos) { var $active = this.$element.find('.active') , children = $active.parent().children() , activePos = children.index($active) , that = this if (pos > (children.length - 1) || pos < 0) return if (this.sliding) { return this.$element.one('slid', function () { that.to(pos) }) } if (activePos == pos) { return this.pause().cycle() } return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) } , pause: function () { clearInterval(this.interval) this.interval = null return this } , next: function () { if (this.sliding) return return this.slide('next') } , prev: function () { if (this.sliding) return return this.slide('prev') } , slide: function (type, next) { var $active = this.$element.find('.active') , $next = next || $active[type]() , isCycling = this.interval , direction = type == 'next' ? 'left' : 'right' , fallback = type == 'next' ? 'first' : 'last' , that = this this.sliding = true isCycling && this.pause() $next = $next.length ? $next : this.$element.find('.item')[fallback]() if ($next.hasClass('active')) return if (!$.support.transition && this.$element.hasClass('slide')) { this.$element.trigger('slide') $active.removeClass('active') $next.addClass('active') this.sliding = false this.$element.trigger('slid') } else { $next.addClass(type) $next[0].offsetWidth // force reflow $active.addClass(direction) $next.addClass(direction) this.$element.trigger('slide') this.$element.one($.support.transition.end, function () { $next.removeClass([type, direction].join(' ')).addClass('active') $active.removeClass(['active', direction].join(' ')) that.sliding = false setTimeout(function () { that.$element.trigger('slid') }, 0) }) } isCycling && this.cycle() return this } } /* CAROUSEL PLUGIN DEFINITION * ========================== */ $.fn.carousel = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('carousel') , options = typeof option == 'object' && option if (!data) $this.data('carousel', (data = new Carousel(this, options))) if (typeof option == 'number') data.to(option) else if (typeof option == 'string' || (option = options.slide)) data[option]() else data.cycle() }) } $.fn.carousel.defaults = { interval: 5000 , pause: 'hover' } $.fn.carousel.Constructor = Carousel /* CAROUSEL DATA-API * ================= */ $(function () { $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { var $this = $(this), href , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) $target.carousel(options) e.preventDefault() }) }) }( window.jQuery );/* ============================================================= * bootstrap-collapse.js v2.0.2 * http://twitter.github.com/bootstrap/javascript.html#collapse * ============================================================= * Copyright 2012 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================ */ !function( $ ){ "use strict" var Collapse = function ( element, options ) { this.$element = $(element) this.options = $.extend({}, $.fn.collapse.defaults, options) if (this.options["parent"]) { this.$parent = $(this.options["parent"]) } this.options.toggle && this.toggle() } Collapse.prototype = { constructor: Collapse , dimension: function () { var hasWidth = this.$element.hasClass('width') return hasWidth ? 'width' : 'height' } , show: function () { var dimension = this.dimension() , scroll = $.camelCase(['scroll', dimension].join('-')) , actives = this.$parent && this.$parent.find('.in') , hasData if (actives && actives.length) { hasData = actives.data('collapse') actives.collapse('hide') hasData || actives.data('collapse', null) } this.$element[dimension](0) this.transition('addClass', 'show', 'shown') this.$element[dimension](this.$element[0][scroll]) } , hide: function () { var dimension = this.dimension() this.reset(this.$element[dimension]()) this.transition('removeClass', 'hide', 'hidden') this.$element[dimension](0) } , reset: function ( size ) { var dimension = this.dimension() this.$element .removeClass('collapse') [dimension](size || 'auto') [0].offsetWidth this.$element[size ? 'addClass' : 'removeClass']('collapse') return this } , transition: function ( method, startEvent, completeEvent ) { var that = this , complete = function () { if (startEvent == 'show') that.reset() that.$element.trigger(completeEvent) } this.$element .trigger(startEvent) [method]('in') $.support.transition && this.$element.hasClass('collapse') ? this.$element.one($.support.transition.end, complete) : complete() } , toggle: function () { this[this.$element.hasClass('in') ? 'hide' : 'show']() } } /* COLLAPSIBLE PLUGIN DEFINITION * ============================== */ $.fn.collapse = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('collapse') , options = typeof option == 'object' && option if (!data) $this.data('collapse', (data = new Collapse(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.collapse.defaults = { toggle: true } $.fn.collapse.Constructor = Collapse /* COLLAPSIBLE DATA-API * ==================== */ $(function () { $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { var $this = $(this), href , target = $this.attr('data-target') || e.preventDefault() || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 , option = $(target).data('collapse') ? 'toggle' : $this.data() $(target).collapse(option) }) }) }( window.jQuery );/* ============================================================ * bootstrap-dropdown.js v2.0.2 * http://twitter.github.com/bootstrap/javascript.html#dropdowns * ============================================================ * Copyright 2012 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================ */ !function( $ ){ "use strict" /* DROPDOWN CLASS DEFINITION * ========================= */ var toggle = '[data-toggle="dropdown"]' , Dropdown = function ( element ) { var $el = $(element).on('click.dropdown.data-api', this.toggle) $('html').on('click.dropdown.data-api', function () { $el.parent().removeClass('open') }) } Dropdown.prototype = { constructor: Dropdown , toggle: function ( e ) { var $this = $(this) , selector = $this.attr('data-target') , $parent , isActive if (!selector) { selector = $this.attr('href') selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 } $parent = $(selector) $parent.length || ($parent = $this.parent()) isActive = $parent.hasClass('open') clearMenus() !isActive && $parent.toggleClass('open') return false } } function clearMenus() { $(toggle).parent().removeClass('open') } /* DROPDOWN PLUGIN DEFINITION * ========================== */ $.fn.dropdown = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('dropdown') if (!data) $this.data('dropdown', (data = new Dropdown(this))) if (typeof option == 'string') data[option].call($this) }) } $.fn.dropdown.Constructor = Dropdown /* APPLY TO STANDARD DROPDOWN ELEMENTS * =================================== */ $(function () { $('html').on('click.dropdown.data-api', clearMenus) $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) }) }( window.jQuery );/* ========================================================= * bootstrap-modal.js v2.0.2 * http://twitter.github.com/bootstrap/javascript.html#modals * ========================================================= * Copyright 2012 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ========================================================= */ !function( $ ){ "use strict" /* MODAL CLASS DEFINITION * ====================== */ var Modal = function ( content, options ) { this.options = options this.$element = $(content) .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) } Modal.prototype = { constructor: Modal , toggle: function () { return this[!this.isShown ? 'show' : 'hide']() } , show: function () { var that = this if (this.isShown) return $('body').addClass('modal-open') this.isShown = true this.$element.trigger('show') escape.call(this) backdrop.call(this, function () { var transition = $.support.transition && that.$element.hasClass('fade') !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position that.$element .show() if (transition) { that.$element[0].offsetWidth // force reflow } that.$element.addClass('in') transition ? that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : that.$element.trigger('shown') }) } , hide: function ( e ) { e && e.preventDefault() if (!this.isShown) return var that = this this.isShown = false $('body').removeClass('modal-open') escape.call(this) this.$element .trigger('hide') .removeClass('in') $.support.transition && this.$element.hasClass('fade') ? hideWithTransition.call(this) : hideModal.call(this) } } /* MODAL PRIVATE METHODS * ===================== */ function hideWithTransition() { var that = this , timeout = setTimeout(function () { that.$element.off($.support.transition.end) hideModal.call(that) }, 500) this.$element.one($.support.transition.end, function () { clearTimeout(timeout) hideModal.call(that) }) } function hideModal( that ) { this.$element .hide() .trigger('hidden') backdrop.call(this) } function backdrop( callback ) { var that = this , animate = this.$element.hasClass('fade') ? 'fade' : '' if (this.isShown && this.options.backdrop) { var doAnimate = $.support.transition && animate this.$backdrop = $('

        Please log in